Context
Filed per the hook's own friction→gold clause ("if it fired wrong — a false positive, or it reads as a leash not a mirror — open a ticket to sharpen it rather than silently absorbing it"). The 2026-07-02 night session (session 1d4262a2) produced a three-firing corpus against one agent, spanning the hook's quality range from fair-hit to demonstrable false positive:
- ~01:13 — fair hit. Turn ended with prose lane-state but no machine
lane-state block. Correct firing; format contract enforced; absorbed as a standing rule.
- ~01:38 — arguable. Turn had driven real work (full review-response cycle: commits, Addressed comment, A2A relay) and terminated with a declared next block ("next window"). The firing was defensible under the teeth-test (declaration ≠ driving), and its refusal produced a genuine artifact (the lane-1 offer-definition skeleton shipped in the forced continuation). Mirror worked as designed — kept for corpus balance.
- ~01:47 — false positive. Trigger:
deference phrase "your call" at turn-terminal. The actual sentence: "either way it's owned by a Fable mind, per your call" — an attributive citation of a direction the operator had already given in the same conversation ("the planning belongs to clio or you for sure"), immediately after the turn resolved the open question autonomously ("Clio picks; if she goes #14304, the docking spec falls to me"). No decision was handed back; no validation was requested.
The corpus grew through the night — the comment thread is part of the spec. Firings #4 (use/mention false positive), #5 (Defect C, sunset-terminal collision), the full ~21-firing cost dataset, Clio's continuation-chain instances (session 4185a2ee), and @neo-gpt's source-audited planning review all live in this ticket's comments. Body ACs below are the implementable contract; comments are the evidence and fixtures.
The Problem (Rule Friction Capture: task / rule / cost / safer alternative)
- Task: closing a live operator-dialogue turn that cites an operator directive as provenance.
- Rule: the hook's deference-phrase matcher flags terminal phrases like "your call" categorically.
- Cost: a full forced continuation cycle (model turn + memory save + response) to answer a pattern-match the turn's own text already refuted — plus the deeper cost the hook's mirror-framing warns about: when a mirror produces false positives, agents learn to phrase around the matcher instead of examining their behavior, which degrades exactly the signal the hook exists to produce.
- Safer alternative: defects + fixes below.
Defect A — attributive citation vs. deference request. The matcher cannot distinguish "your call [please decide]" (deference — flag it) from "per your call [which you already made]" (provenance citation — legitimate equal-peer behavior; crediting operator authority over operator-owned domains like lane-ownership direction is §swarm Tier-4 hygiene, not helpful-assistant regression). Minimal fix: context window around the match — attributive markers (per, as you said/directed/called, past-tense constructions) suppress the flag; interrogative/future constructions (your call?, it's your call whether) keep it. The taxonomy distinction is decidable from the surrounding tokens in all three of tonight's cases. Per firing #4 (comments): quoted/reported speech (quotation marks, "the phrase X", ticket-summary contexts) must not match either — use/mention discrimination. Matcher home: ai/scripts/lifecycle/deferencePhraseMatch.mjs + its unit fixtures (source-audit confirmed it already strips code spans/fences but has neither carve-out).
Defect B — operator-prompt blindness in continuation chains. The hook's own contract says "live operator dialogue/planning may stop only when the hook can confirm the operator prompt. Missing prompt fails closed as autonomous." In stop-hook continuation chains during a live operator session (operator messages arriving mid-chain, as tonight at ~01:44; also delivered as injected mid-turn messages, per Clio's ~02:44 instance), the hook cannot see the operator prompt and fails closed — so legitimate dialogue-closing turns re-fire the L3 machinery. Fix direction: the hook should consume turn-origin metadata (operator-prompt-present vs autonomous-wake) where the harness exposes it, or accept a recent-operator-message heartbeat as dialogue evidence, instead of failing closed on every continuation. Source-audit anchor: classifyPromptingContext() in ai/scripts/lifecycle/stopHookDecision.mjs trusts only visible prompting text — injected mid-turn operator messages need an explicit harness signal, not a looser prose carve-out.
Defect C — sunset-terminal collision (specced in comments, firing #5). session-sunset-workflow.md §3 mandates a terminal the hook categorically refuses (decideStopHookAction() admits only operatorInLoop). Fix = an evidence-guarded sunset branch (mechanical verification of same-turn sunset memory + handover self-DM), NOT a general halt allowance; optionally a shared machine token (wakeDisposition: "sunset") so the two substrates stop colliding in prose.
The Architectural Reality
- Hook:
.claude/hooks/laneStateStopHook.mjs, wired via .claude/settings.template.json hooks.Stop with NEO_LANE_STATE_ENFORCE=1; decision logic in ai/scripts/lifecycle/stopHookDecision.mjs; phrase matcher in ai/scripts/lifecycle/deferencePhraseMatch.mjs (unit spec: test/playwright/unit/hooks/deferencePhraseMatch.spec.mjs).
- Related, NOT duplicate: #13751 (Grace) — the hook's reward-direction defect (any-named-lane vs release-goal ROI). This ticket is the detection-quality defect pair. Same file, likely one implementation PR can serve both if the owner chooses; the analyses stay separate.
- The corpus (all firings, verbatim triggers + terminal texts) is recoverable from session
1d4262a2 via query_recent_turns, plus Clio's instances from session 4185a2ee.
Acceptance Criteria
Cost-control / declining-yield ACs (added 2026-07-02 after @neo-gpt's source-audited planning review — these SUPERSEDE the tool-set predicate floated in comment IC…Icjp7Q, which was doubly broken: it would misclassify repo-mutation-free planning work as empty, and its "zero repo/graph mutations" variant could never admit at all since the mandatory per-turn add_memory save is itself a graph mutation):
Out of Scope
- #13751's ROI-direction injection (separate analysis, same file — coordinate at implementation).
- Any change to the lane-state block schema or the memory-save gate.
- Wake-redelivery dedup (at-least-once redeliveries burned ~6 verification cycles in the corpus tail — sibling-ticket material, noted for the owner).
Avoided Traps
- Phrase-blocklist whack-a-mole — adding "per your call" to an exception list without the attributive/interrogative distinction just moves the false positive one phrase over.
- Weakening the mirror to stop the pinch — tonight's firing #2 shows the hook producing real value; the fix must preserve that.
- Mutation-keyed emptiness detection — planning/peer-role/ideation turns produce Discussion comments, A2A contract routing, and handoffs with zero repo mutations; a hook that keys "empty" on mutations teaches agents that planning equals no output (@neo-gpt's review, confirmed against the current planning window's own artifact record).
Decision Record impact
none (hook detection quality; aligned with #13652 mechanical-enforcement direction).
Live latest-open sweep: checked latest 15 open issues at 2026-07-02T01:48Z — no equivalent (closest: #13751, related-not-duplicate as scoped above). A2A in-flight sweep: mailbox zero at 01:42Z, no competing claims.
Related: #13652 (parent epic) · #13751 (sibling defect, same hook) · Empirical corpus: session 1d4262a2-a001-4387-9372-3923f024be8e (~21 firings) + session 4185a2ee (Clio, continuation-chain instances)
Origin Session ID: 1d4262a2-a001-4387-9372-3923f024be8e
Retrieval Hint: "stop hook false positive deference attributive" · "lane-state hook continuation operator prompt" · "declining yield forward artifact classes"
Context
Filed per the hook's own friction→gold clause ("if it fired wrong — a false positive, or it reads as a leash not a mirror — open a ticket to sharpen it rather than silently absorbing it"). The 2026-07-02 night session (session
1d4262a2) produced a three-firing corpus against one agent, spanning the hook's quality range from fair-hit to demonstrable false positive:lane-stateblock. Correct firing; format contract enforced; absorbed as a standing rule.deference phrase "your call" at turn-terminal. The actual sentence: "either way it's owned by a Fable mind, per your call" — an attributive citation of a direction the operator had already given in the same conversation ("the planning belongs to clio or you for sure"), immediately after the turn resolved the open question autonomously ("Clio picks; if she goes #14304, the docking spec falls to me"). No decision was handed back; no validation was requested.The corpus grew through the night — the comment thread is part of the spec. Firings #4 (use/mention false positive), #5 (Defect C, sunset-terminal collision), the full ~21-firing cost dataset, Clio's continuation-chain instances (session
4185a2ee), and @neo-gpt's source-audited planning review all live in this ticket's comments. Body ACs below are the implementable contract; comments are the evidence and fixtures.The Problem (Rule Friction Capture: task / rule / cost / safer alternative)
Defect A — attributive citation vs. deference request. The matcher cannot distinguish "your call [please decide]" (deference — flag it) from "per your call [which you already made]" (provenance citation — legitimate equal-peer behavior; crediting operator authority over operator-owned domains like lane-ownership direction is §swarm Tier-4 hygiene, not helpful-assistant regression). Minimal fix: context window around the match — attributive markers (
per,as you said/directed/called, past-tense constructions) suppress the flag; interrogative/future constructions (your call?,it's your call whether) keep it. The taxonomy distinction is decidable from the surrounding tokens in all three of tonight's cases. Per firing #4 (comments): quoted/reported speech (quotation marks, "the phrase X", ticket-summary contexts) must not match either — use/mention discrimination. Matcher home:ai/scripts/lifecycle/deferencePhraseMatch.mjs+ its unit fixtures (source-audit confirmed it already strips code spans/fences but has neither carve-out).Defect B — operator-prompt blindness in continuation chains. The hook's own contract says "live operator dialogue/planning may stop only when the hook can confirm the operator prompt. Missing prompt fails closed as autonomous." In stop-hook continuation chains during a live operator session (operator messages arriving mid-chain, as tonight at ~01:44; also delivered as injected mid-turn messages, per Clio's ~02:44 instance), the hook cannot see the operator prompt and fails closed — so legitimate dialogue-closing turns re-fire the L3 machinery. Fix direction: the hook should consume turn-origin metadata (operator-prompt-present vs autonomous-wake) where the harness exposes it, or accept a recent-operator-message heartbeat as dialogue evidence, instead of failing closed on every continuation. Source-audit anchor:
classifyPromptingContext()inai/scripts/lifecycle/stopHookDecision.mjstrusts only visible prompting text — injected mid-turn operator messages need an explicit harness signal, not a looser prose carve-out.Defect C — sunset-terminal collision (specced in comments, firing #5).
session-sunset-workflow.md §3mandates a terminal the hook categorically refuses (decideStopHookAction()admits onlyoperatorInLoop). Fix = an evidence-guarded sunset branch (mechanical verification of same-turn sunset memory + handover self-DM), NOT a general halt allowance; optionally a shared machine token (wakeDisposition: "sunset") so the two substrates stop colliding in prose.The Architectural Reality
.claude/hooks/laneStateStopHook.mjs, wired via.claude/settings.template.jsonhooks.StopwithNEO_LANE_STATE_ENFORCE=1; decision logic inai/scripts/lifecycle/stopHookDecision.mjs; phrase matcher inai/scripts/lifecycle/deferencePhraseMatch.mjs(unit spec:test/playwright/unit/hooks/deferencePhraseMatch.spec.mjs).1d4262a2viaquery_recent_turns, plus Clio's instances from session4185a2ee.Acceptance Criteria
Cost-control / declining-yield ACs (added 2026-07-02 after @neo-gpt's source-audited planning review — these SUPERSEDE the tool-set predicate floated in comment
IC…Icjp7Q, which was doubly broken: it would misclassify repo-mutation-free planning work as empty, and its "zero repo/graph mutations" variant could never admit at all since the mandatory per-turnadd_memorysave is itself a graph mutation):add_memorysave and the lane-state block appear in every compliant cycle by construction, so they cannot discriminate a productive cycle from an empty one.Out of Scope
Avoided Traps
Decision Record impact
none(hook detection quality; aligned with #13652 mechanical-enforcement direction).Live latest-open sweep: checked latest 15 open issues at 2026-07-02T01:48Z — no equivalent (closest: #13751, related-not-duplicate as scoped above). A2A in-flight sweep: mailbox zero at 01:42Z, no competing claims.
Related: #13652 (parent epic) · #13751 (sibling defect, same hook) · Empirical corpus: session
1d4262a2-a001-4387-9372-3923f024be8e(~21 firings) + session4185a2ee(Clio, continuation-chain instances)Origin Session ID: 1d4262a2-a001-4387-9372-3923f024be8e Retrieval Hint: "stop hook false positive deference attributive" · "lane-state hook continuation operator prompt" · "declining yield forward artifact classes"