ask-handoff

Greeting capability gate (Reason+Critic) — TICKET-108744/108597

slug sophia-bot-2026-10-30-greeting-capability-gate project sophia-bot source cursor updated 10/30/2026, 5:47:26 PM

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) or execute inline
  • 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.py prompt 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_prompt pattern from test_graph_configuration.py)

Interfaces:

  • Consumes: create_reason_graph system 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/rates in 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