fix(goal): suppress reserved SILENT sentinel at /api/goal ingress - #7046
webtecnica wants to merge 1 commit into
Conversation
A wake relay POSTing the exact [SILENT] suppression sentinel to /api/goal lets it reach _start_chat_stream_for_session, which persists it as pending_user_message. If 8701 restarts while the turn is pending, session recovery materializes it as a visible _recovered user turn — the same phantom-recovered-turn exposure nesquena#7018 closed for chat ingress. Apply the shared _is_silent_control_message() guard immediately after /api/goal session-ID validation and before session lookup or goal-state mutation, returning the same 200 no-op. Matching stays exact and case-sensitive; ordinary kickoff text is unaffected. Add tests mirroring test_silent_control_suppression.py for the goal path (args and text fields, before-lookup suppression, exact-match semantics). Closes nesquena#7019
|
| Filename | Overview |
|---|---|
| api/routes.py | Adds the intended early sentinel guard; the runtime contract change lacks the repository-required documentation update. |
| tests/test_goal_silent_ingress_suppression.py | Covers suppression through both fields, pre-lookup ordering, ordinary input, and exact case-sensitive helper semantics. |
Reviews (1): Last reviewed commit: "fix(goal): suppress reserved SILENT sent..." | Re-trigger Greptile
| if _is_silent_control_message(body.get("args") or body.get("text")): | ||
| return j( | ||
| handler, | ||
| {"status": "suppressed", "reason": "silent_control_message"}, | ||
| status=200, | ||
| ) |
There was a problem hiding this comment.
Document the suppression contract
The new early return changes /api/goal into a successful no-op for the exact [SILENT] sentinel before session lookup, but repository documentation does not describe this response, its case-sensitive matching semantics, or its validation ordering.
Context Used: AGENTS.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
🔬 Exact-head gate certification — SAFE TO SHIP (queued for maintainer merge)Gated at head Root cause confirmed against source: Field correctness: the guard checks Gate results (this exact head):
Tight, additive, pure-backend, near-zero regression risk. Queued (Release-manager overnight gate — queued for maintainer merge, not autonomously tagged.) |
|
Shipped in experimental release exp-v0.52.229 (batched with 5 other low-risk gate-passed fixes). Merged onto master via the batch release PR #7089 — your commit content is in master and is live on the experimental channel now. Thanks @webtecnica for the fix (#7019). 🤖 Closed by the release-manager agent. |
|
Thank you for shipping this in exp-v0.52.229! 🚀 Glad the fix landed on master via the batch release #7089. Appreciate the kind words! |
Problem
/api/goalallows the exact reserved[SILENT]suppression sentinel to reach_start_chat_stream_for_session, which persists it aspending_user_message. If 8701 restarts while that turn is pending, session recovery materializes it as a visible_recovereduser turn — the same phantom-recovered-turn exposure #7018 closed for the/api/chat/startandstart_session_turningress paths, but via a different route.Fix
Apply the same
_is_silent_control_message()guard (single source of truth, introduced in #7018) immediately after/api/goalsession-ID validation and before session lookup (_session_is_subagent_view_only/get_session) or any goal-state mutation. It returns the same 200 no-op:{"status": "suppressed", "reason": "silent_control_message"}Matching is deliberately exact and case-sensitive (whitespace-normalized): only
[SILENT]is suppressed;[silent], prose containing[SILENT], and ordinary kickoff text are untouched.Verification
Added
tests/test_goal_silent_ingress_suppression.pymirroringtests/test_silent_control_suppression.pyfor the goal path:/api/goalwithargs="[SILENT]"returns 200 suppressed without session lookup.textfield (goal accepts both).Results:
7 passed(new file + existingtest_silent_control_suppression.py) and58 passedacross the goal/runtime-adapter suites (test_goal_command_webui.py,test_runtime_adapter_seam.py,test_issue_1932_goal_hook_unrelated_turns.py).Closes #7019