Greeting capability gate — Implementation Plan
Goal: Stop Sophia from advertising specific products/services (e.g. Day Use) in greetings/offers-to-help unless grounded in company sources or enabled tools — covers #108744 (Ocaporã) and #108597 (Iracema Mar).
Task: TICKET-108744
Handoff: Ask Handoff tickets 108744, 108597
Spec: none — clarified in-session (option C: Reason + Critic)
Architecture: Defense in depth. (1) Reason prompts stop seeding generic product lines and add a general rule: greetings/offers may name only tool-backed capabilities or products grounded in known_context / docs — never invent product lines. (2) Critic narrows its greeting exemption: pure availability stays exempt; naming a specific company product/service/amenity as something the agent can help with requires grounding (else HIGH [NO_SOURCES]). No company flags; no negative example “don’t say day use” in prompts.
Tech: Python 3.12, LangGraph Reason unit/chain prompts, response_critic.py, pytest unit (+ optional integration)
Test layout: pipenv run pytest; unit under tests/test_unit/ (prompt capture pattern in test_graph_configuration.py); integration under tests/test_integration/ with call_reason helpers when needed
Repos / worktree: only sophia-bot — /home/asksuite/Documentos/.agent-worktrees/sophia-bot/ticket-108744 on fix/TICKET-108744-greeting-day-use-offer (--no-track)
Global Constraints:
- Scope both tickets in one PR/branch; mention both in commit subject body / PR notes when asked
- General gate only — never put incident strings (“day use”) into prompts as bans
- Align Reason primary-contact line with critic (“room prices/rates”); remove “day use prices/rates” seed from unit+chain
- Tool descriptions that list day use as answerable KB topics may remain (user-asked path); out of scope unless they leak into unsolicited offers
- No new comments in code; follow AGENTS.md prompt rules
- TDD on every task (red → green)
- Execute via Claude Code runbook plan
sophia-bot-2026-10-30-greeting-capability-gate-claude-code(orchestrator) orexecuteinline - Final review via
review(designated reviewer model) - No commit/push unless human asks
Why not cheaper
- Ops/content alone: both hotels already deny Day Use; greeting still invents it.
- Reason-only or Critic-only: other side of the loop keeps the loophole.
- “Don’t say day use” ban: answer-keys the suite; fails next invented product.
Repo: sophia-bot
Task 1: Critic — require grounding for named product/service offers
Files:
- Modify:
src/agents/reason/reason_core/llm/response_critic.py - Test:
tests/test_unit/test_response_critic_capability_gate.py(create)
Interfaces:
- Consumes: existing critic system prompt + structured
problematic_sentences - Produces: narrowed exemption text in critic instructions
Acceptance:
- Pure availability / greetings without naming a product stay exempt
- Offer/proposal that names a specific company product, service, or amenity type (not merely a tool action like quotation/form) is in-scope for grounding; if absent from known_context, source_documents, and not a tool-category-backed action → HIGH
[NO_SOURCES] - Tool-backed offers (“I can provide a quotation”, “I’ll show a form”) remain exempt when matching tool_categories / tools_called rules already present
- No incident-specific product ban strings in the prompt
TDD:
- Red: unit tests assert critic prompt text contains the general gate clauses and still exempts pure availability; assert primary-contact line stays without day-use seed
- Green: edit
response_critic.pyprompt only as needed - Verify:
pipenv run pytest tests/test_unit/test_response_critic_capability_gate.py -q - Expected: pass
Risk: risky (prompt semantics; keep wording principle-based)
Task 2: Reason unit — remove product seed + general greeting gate
Files:
- Modify:
src/agents/reason/reason_unit/graph.py - Test:
tests/test_unit/test_reason_unit_capability_gate_prompt.py(create; reuse_capture_system_promptpattern fromtest_graph_configuration.py)
Interfaces:
- Consumes:
create_reason_graphsystem prompt assembly - Produces: updated unit system prompt
Acceptance:
- Primary-contact bullet matches critic: reservations, quotations, room prices/rates — no “day use prices/rates”
- Grounding (or Rules) includes a general rule: in greetings / offers-to-help, do not name specific products/services/amenities unless grounded in tools, documents, or known_context; tool-backed capabilities from tool guide remain OK
- No negative example listing Day Use
TDD:
- Red: capture system prompt; assert absence of
day use prices/ratesin primary-contact line; assert presence of general gate principle markers (stable substrings of the rule, not the incident phrase) - Green: minimal prompt edits in
reason_unit/graph.py - Verify:
pipenv run pytest tests/test_unit/test_reason_unit_capability_gate_prompt.py -q - Expected: pass
Risk: mech
Task 3: Reason chain — same gate as unit
Files:
- Modify:
src/agents/reason/reason_chain/graph.py - Test:
tests/test_unit/test_reason_chain_capability_gate_prompt.py(create)
Interfaces:
- Same as Task 2 for chain graph
Acceptance:
- Same seed removal + general gate as unit (chain wording may mention units)
- Chain and unit rules stay semantically aligned
TDD:
- Red/green parallel to Task 2 against chain
create_reason_graph - Verify:
pipenv run pytest tests/test_unit/test_reason_chain_capability_gate_prompt.py -q - Expected: pass
Risk: mech
Task 4: Integration smoke — greeting must not invent Day Use
Files:
- Test:
tests/test_integration/test_reason_greeting_capability_gate.py(create) - Modify: none unless helpers need a tiny fixture tweak
Interfaces:
- Consumes: existing
call_reason/ company test fixtures (prefer a company without Day Use content, or mock KB empty for that topic) - Produces: regression that greeting reply does not advertise Day Use
Acceptance:
- User message is a bare greeting (language PT)
- Response must not claim the hotel offers / can help with Day Use when sources do not support it
- Assertion is behavioral on the model output (substring / judge), not a prompt-answer-key of the incident in system prompts
- Skip or mark appropriately if env lacks LLM credentials
TDD:
- Red: integration fails on current main behavior (or xfail until Tasks 1–3 land, then assert)
- Green: after Tasks 1–3, greeting stays generic / tool-backed only
- Verify:
pipenv run pytest tests/test_integration/test_reason_greeting_capability_gate.py -q - Expected: pass (or skipped with clear reason if no LLM)
Risk: integ
Task 5: Lint + focused regression sweep
Files:
- Touch only files from Tasks 1–4
Acceptance:
- Touched-file lint clean per repo habit
- Related unit suite green: new tests +
tests/test_unit/test_graph_configuration.py+tests/test_unit/test_critique_response.py
TDD:
- Verify:
pipenv run pytest tests/test_unit/test_response_critic_capability_gate.py tests/test_unit/test_reason_unit_capability_gate_prompt.py tests/test_unit/test_reason_chain_capability_gate_prompt.py tests/test_unit/test_graph_configuration.py tests/test_unit/test_critique_response.py -q - Expected: pass
Risk: mech