fix(templates): silence inbound WARN + guard blank auto-replies (EVO-1720)#150
Conversation
…1720) Non-blocking follow-up (6.11) to the EVO-1235 [6.6] wire-call-sites review. - #1 [Medium] The inbound public endpoint Public::Api::V1::Inboxes::MessagesController#create included TemplateConsumerLogging and fired the "deprecated inline content" WARN on every message. Inbound messages always carry content and have no template alternative, so the WARN was pure spam polluting the signal meant to flag legacy OUTBOUND consumers. Removed the include + call; outbound (the legitimate WARN site) and the concern are unchanged. - #3 [Low] Greeting/Out-of-Office could deliver a blank auto-reply: when a referenced template raises ArgumentError (required var outside first_name/name/email), TemplateContent falls back to the inline column, and Message has no content-presence validation, so a blank :template message persisted. perform now resolves content once and returns early when it is blank (skip silently). Skipping the blank :template message keeps HookExecutionService#first_message_from_contact? accurate, so a later valid greeting can still fire. - #2 [Low] Dormant message_template_id accept-paths in bot/macro/automation are intentionally untouched (no producer feeds the id yet). Specs: inbound request spec inverted to assert no deprecated WARN (+ asserts the incoming message persists); new greeting/out_of_office service specs cover the blank-skip, render-raise-to-inline fallback, and no-template-to-inline paths, asserting the template render actually raises before relying on the guard. 14 examples, 0 failures; RuboCop clean.
Reviewer's GuideRefines template-based auto-reply behavior to avoid blank messages and removes deprecated inline-content logging from inbound messages, while adding focused service and request specs to cover the new behavior and guardrails. Sequence diagram for guarded greeting/OOO auto-reply generationsequenceDiagram
participant Conversation
participant GreetingService as MessageTemplates_Template_Greeting
participant OutOfOfficeService as MessageTemplates_Template_OutOfOffice
participant Inbox
participant Message as Conversation_messages
Conversation->>GreetingService: perform
GreetingService->>Inbox: greeting_content
Inbox-->>GreetingService: template_content_for(...) || greeting_message
alt [content.blank?]
GreetingService-->>Conversation: return (no message created)
else [content present]
GreetingService->>Message: create!(inbox_id, message_type: :template, content)
end
Conversation->>OutOfOfficeService: perform
OutOfOfficeService->>Inbox: out_of_office_content
Inbox-->>OutOfOfficeService: template_content_for(...) || out_of_office_message
alt [content.blank?]
OutOfOfficeService-->>Conversation: return (no message created)
else [content present]
OutOfOfficeService->>Message: create!(inbox_id, message_type: :template, content)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The greeting and out-of-office template services now share nearly identical
*_contentresolution, blank-guard, andmessages.create!logic; consider extracting a small shared helper/module (e.g., a base template auto-reply service) to reduce duplication and keep future behavior changes (like new message attributes) in one place.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The greeting and out-of-office template services now share nearly identical `*_content` resolution, blank-guard, and `messages.create!` logic; consider extracting a small shared helper/module (e.g., a base template auto-reply service) to reduce duplication and keep future behavior changes (like new message attributes) in one place.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
dpaes
left a comment
There was a problem hiding this comment.
Review — EVO-1720 [6.11] follow-up · APPROVED ✅
Non-blocking follow-up to the EVO-1235 [6.6] wire-call-sites review. All three findings verified against the code; no blockers.
🟡 #1 [Medium] Inbound deprecated-content WARN — fixed. Public::Api::V1::Inboxes::MessagesController no longer includes TemplateConsumerLogging nor calls warn_legacy_inline_content. The legitimate site (OutboundMessagesController#outbound_content) and the concern itself are untouched, and no dangling reference to the removed methods remains in the inbound controller. The request spec is correctly inverted to assert the WARN does NOT fire and the incoming message still persists with message_type=incoming.
🟢 #3 [Low] Blank auto-reply — fixed (greeting + out-of-office). perform resolves content once and return if content.blank? before create!. Traced the raise path: a required variable missing from the auto-reply's {first_name,name,email} makes MessageTemplate#render_with_variables raise ArgumentError; TemplateContent#template_content_for rescues to nil; the inline column is the fallback; a blank inline column is now skipped. Skipping (rather than persisting) the blank :template message keeps HookExecutionService#first_message_from_contact? — which counts messages.template — accurate, so a later valid greeting can still fire. That regression is genuinely closed.
🟢 #2 [Low] Dormant accept-paths (bot/macro/automation) intentionally untouched — documented in the commit.
Spec quality: the "render actually raises" guard tests are genuine — extract_variables_from_content (before_save) strips variables absent from content, so keeping {{order_id}} in the content is required to preserve the explicit required:true; the specs do exactly that. Setup mirrors the existing request spec, and MessageTemplate.create! without language is valid (column default pt_BR).
Non-blocking notes:
- This repo does not run RSpec in CI (Sourcery + contract only), so "14 examples, 0 failures" is self-reported — recommend a local
bundle exec rspec spec/services/message_templates/template/ spec/requests/public/api/v1/inboxes/messages_controller_spec.rbbefore relying on it. - Minor test-symmetry gap:
greeting_spechas the "later valid greeting fires" case (AC6);out_of_office_spechas no equivalent. Skip behavior is identical, so non-blocking. - Pre-existing (not introduced here):
delegate :inbox, to: :messageingreeting.rb/out_of_office.rbpoints to a non-existentmessagemethod (dead code) — worth removing while in the area.
Approving and merging. 🟢
Summary
Non-blocking follow-up (6.11) to the EVO-1235 [6.6] wire-call-sites review. Three findings raised; two fixed, one documented.
🟡 [Medium] False-positive "deprecated inline content" WARN on INBOUND.
Public::Api::V1::Inboxes::MessagesController#createincludedTemplateConsumerLoggingand firedwarn_legacy_inline_contentwhenevercontentwas present. But an inbound message (from the contact) always carriescontentand has no template alternative — there is nothing to migrate. The WARN fired on every inbound message, spamming the very signal meant to identify legacy outbound consumers. Removed theinclude+ the call (and its coexistence comment). Theoutbound_messages_controller(the legitimate WARN site) and theTemplateConsumerLoggingconcern are untouched;permitted_params/message_paramsare preserved.🟢 [Low] Blank auto-reply edge. Greeting/Out-of-Office fire when
*_message_template_idis present. If the referenced template has arequired: truevariable outside{first_name, name, email},render_with_variablesraisesArgumentError;TemplateContent#template_content_forrescues it and falls back to the inline column.Messagehas nocontentpresence validation, so a blank inline column produced a blank:templatemessage.performnow resolves the content once (via a*_contenthelper, so the guard adds no extraSendResolverlookup) andreturn if content.blank?— skip silently. Skipping the blank:templatemessage keepsHookExecutionService#first_message_from_contact?accurate, so a later valid greeting can still fire.🟢 [Low / Documented] Dormant
message_template_idaccept-paths in agent-bot/macro/automation are intentionally untouched — no producer feeds the id yet (expected until a UI does).No migration, no schema change.
Test plan
POSTGRES_PORT=5433 ... bundle exec rspec spec/services/message_templates/template/greeting_spec.rb spec/services/message_templates/template/out_of_office_spec.rb spec/requests/public/api/v1/inboxes/messages_controller_spec.rb spec/requests/public/api/v1/inboxes/outbound_messages_controller_spec.rb→ 14 examples, 0 failures.incoming, with the posted content) and the deprecated WARN is not emitted (allow → have_receivedso unrelated warns don't interfere).MessageTemplatewith a survivingrequiredvariable ({{order_id}}in content + explicitrequired: true, sinceextract_variables_from_contentstrips vars absent from content) and assertrender_with_variablesactually raises before relying on the guard (no vacuous test). Cover: blank-skip, render-raise→inline fallback, and no-template→inline. Created fallback message ismessage_type: :template,content_type: 'text'.Notes
roles.rband does not include FactoryBot syntax (csat_survey_specusingcreate(:inbox)is itself non-running) — the new specs use plainActiveRecord.create!, mirroring the request specs.Summary by Sourcery
Silence deprecated inline-content warnings for inbound messages and prevent sending blank auto-reply template messages for greeting and out-of-office flows.
Bug Fixes:
Tests: