Context
Rule Friction Capture (AGENTS.md §self_evolving_systems) with same-session empirical evidence, filed under the stop-hook's own friction→gold clause ("if it fired wrong — a false positive… open a ticket to sharpen it rather than silently absorbing it"). Session 29b2ae13 (2026-07-24) hit three consecutive stop refusals on valid lane-state terminals while in a state the hook's key classes structurally cannot license: an authorship-heavy lane at artifact-completion, with every named gate awaiting a non-self actor and an armed background mechanism driving the last self-side action.
This is calibration of the two existing autonomous stops, not stop-machinery: no new hold state, no self-declarable license, no change to the L3 principle. The shipped boilerplate itself anticipates the successor: "an own-PR RC-response cycle is real work but not yet a key class."
The Problem
The session's shape: one self-assigned spine ticket driven through 6 pushed commits (feature + tests + a reviewer RC1 cycle cleared + a cycle-2 nit + an ADR amendment), the ticket's 7-item AC matrix checked with landing notes, the reviewer converged ("approve at flip, no further cycle"), every epic successor DAG-blocked behind the unmerged spine, and the only remaining self-side action (ready-flip) armed on a background CI watcher whose completion re-invokes the agent.
Three refusals followed, because:
- The material-artifact key (
#15404/#15435) recognizes exactly two transcript classes — standalone gh pr create and manage_pr_review create. Pushed (#N)-bound commits on the self-assigned lane count toward neither.
- The clean-terminal acceptance (
#15274/#15371) requires the session drive-ratchet, whose event source is hook-written drives — the same two classes. An authorship day that opens its PR early (the sanctioned draft-early pattern) and then deepens it can therefore never reach either stop.
The perverse-incentive cost is the sharp part: under refusal pressure the available key-minting actions are (a) open another PR — which the one-ticket-one-lane ratchet ban exists to prevent, or (b) submit a formal review — which cross-family seating constraints may forbid (this session: the only adjacent claimable ticket was claimed by a peer 4 minutes before the hook's pressure would have pushed a collision; the pre-claim sweep caught it). A discipline hook whose escape valve points at two anti-patterns is miscalibrated, and each refusal cycle burns a full re-entry (mailbox re-sweep, gate re-poll, lane re-derivation) at deep-context cost.
The Architectural Reality
.claude/hooks/laneStateStopHook.mjs:251 — the boilerplate naming the two key classes and the "not yet a key class" stance (aligned with implementation TODAY via #15778/#15779).
.claude/hooks/laneStateStopHook.mjs:787-799 — the drive-ratchet (hook-written drives log) + the material-artifact key evaluation ("transcript-verified").
ai/scripts/lifecycle/stopHookDecision.mjs — the shared decision module (the substrate-owned half; the hook consumes it).
- The design lineage is deliberate and recent:
#15274/#15371 (audited clean-terminal — "the one autonomous stop"), #15404/#15435 (material-artifact key — "the primary"), #15401/#15433 (active-lane dialogue refusals). This ticket extends the evidence classes those tickets defined; it does not reopen L3 (any "valid hold" proposal remains rejected by construction).
- Background-task semantics: a harness background task (
run_in_background / Monitor) re-invokes the agent on completion — completion is mechanically guaranteed to produce the next drive, which is what distinguishes an armed mechanism from passive waiting.
The Fix
Two evidence-class additions, both transcript-verified, both feeding the EXISTING stops (the material key's class set stays unchanged for its primary role; the ratchet and terminal-classification widen):
- Pushed-commit drive events (ratchet, not key): a transcript-verified
git push containing commits whose subjects end (#N) where #N is a ticket assigned to the session's agent counts as a drive-ratchet event. Effect: clean-terminal acceptance becomes reachable for deep authorship sessions — the acceptance itself remains the hook's external call with its audited [clean-terminal] line, exactly as #15371 designed it. Never a self-declared stop.
- Armed-mechanism gate classification: a namedGates[] entry whose watcher is a live harness background task (verifiable task id; the completion re-invokes the agent) classifies as driven, not parked, for terminal evaluation. The audit line carries the task id so the peer-visible ledger shows what is armed. A dead/expired watcher reverts the gate to parked (fail-closed).
Acceptance semantics unchanged: dialogue stops still require the confirmable operator prompt; artifact-less autonomous turns still do not stop; the L3 taxonomy is untouched.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
drive-ratchet event classes (stopHookDecision.mjs + hook :787) |
#15274/#15371 design + this ticket |
+ transcript-verified own-ticket (#N) commit pushes |
absent evidence = no event (unchanged) |
hook header + boilerplate line |
unit fixtures on the decision module |
| namedGates terminal classification |
#15404/#15435 + this ticket |
live-watcher gates classify driven (task id audited) |
dead watcher ⇒ parked (fail-closed) |
boilerplate + audit line format |
unit fixtures + one transcript replay |
stop-hook boilerplate text :251 |
#15778/#15779 alignment discipline |
drop "not yet a key class" once shipped; name the two evidence classes |
n/a |
same file |
text-implementation alignment check |
Decision Record impact
none (hook-internal evidence calibration; no ADR governs the key classes). Any AGENTS.md-side wording change routes through ADR 0007 compaction taxonomy as usual. The L3 firewall text is explicitly out of scope.
Acceptance Criteria
Out of Scope
- Any change to L3/no-hold-state taxonomy, the firewall text, or the dialogue-stop rules.
- New stop classes beyond the two existing autonomous stops.
- The material-artifact key's primary classes (
gh pr create / manage_pr_review) — unchanged.
Related
#15274/#15371 (clean-terminal), #15404/#15435 (material key), #15401/#15433, #15778/#15779 (today's text alignment), #11455 (post-review-pickup lineage). Evidence session: three refusals across the #15799 spine build (PR #15811).
Live latest-open sweep: checked latest 20 open issues at 2026-07-24T13:23Z — no equivalent (the #15778/#15779 lineage closed today; no successor exists). A2A herd-window sweep (last 15, all read-states): no overlapping claim.
Origin Session ID: 29b2ae13-4801-48ef-835d-f2e6f5423565
Retrieval Hint: query_raw_memories("stop-hook refusal artifact-complete armed watcher drive-ratchet key class")
Context
Rule Friction Capture (
AGENTS.md §self_evolving_systems) with same-session empirical evidence, filed under the stop-hook's own friction→gold clause ("if it fired wrong — a false positive… open a ticket to sharpen it rather than silently absorbing it"). Session29b2ae13(2026-07-24) hit three consecutive stop refusals on valid lane-state terminals while in a state the hook's key classes structurally cannot license: an authorship-heavy lane at artifact-completion, with every named gate awaiting a non-self actor and an armed background mechanism driving the last self-side action.This is calibration of the two existing autonomous stops, not stop-machinery: no new hold state, no self-declarable license, no change to the L3 principle. The shipped boilerplate itself anticipates the successor: "an own-PR RC-response cycle is real work but not yet a key class."
The Problem
The session's shape: one self-assigned spine ticket driven through 6 pushed commits (feature + tests + a reviewer RC1 cycle cleared + a cycle-2 nit + an ADR amendment), the ticket's 7-item AC matrix checked with landing notes, the reviewer converged ("approve at flip, no further cycle"), every epic successor DAG-blocked behind the unmerged spine, and the only remaining self-side action (ready-flip) armed on a background CI watcher whose completion re-invokes the agent.
Three refusals followed, because:
#15404/#15435) recognizes exactly two transcript classes — standalonegh pr createandmanage_pr_reviewcreate. Pushed(#N)-bound commits on the self-assigned lane count toward neither.#15274/#15371) requires the session drive-ratchet, whose event source is hook-written drives — the same two classes. An authorship day that opens its PR early (the sanctioned draft-early pattern) and then deepens it can therefore never reach either stop.The perverse-incentive cost is the sharp part: under refusal pressure the available key-minting actions are (a) open another PR — which the one-ticket-one-lane ratchet ban exists to prevent, or (b) submit a formal review — which cross-family seating constraints may forbid (this session: the only adjacent claimable ticket was claimed by a peer 4 minutes before the hook's pressure would have pushed a collision; the pre-claim sweep caught it). A discipline hook whose escape valve points at two anti-patterns is miscalibrated, and each refusal cycle burns a full re-entry (mailbox re-sweep, gate re-poll, lane re-derivation) at deep-context cost.
The Architectural Reality
.claude/hooks/laneStateStopHook.mjs:251— the boilerplate naming the two key classes and the "not yet a key class" stance (aligned with implementation TODAY via#15778/#15779)..claude/hooks/laneStateStopHook.mjs:787-799— the drive-ratchet (hook-written drives log) + the material-artifact key evaluation ("transcript-verified").ai/scripts/lifecycle/stopHookDecision.mjs— the shared decision module (the substrate-owned half; the hook consumes it).#15274/#15371(audited clean-terminal — "the one autonomous stop"),#15404/#15435(material-artifact key — "the primary"),#15401/#15433(active-lane dialogue refusals). This ticket extends the evidence classes those tickets defined; it does not reopen L3 (any "valid hold" proposal remains rejected by construction).run_in_background/ Monitor) re-invokes the agent on completion — completion is mechanically guaranteed to produce the next drive, which is what distinguishes an armed mechanism from passive waiting.The Fix
Two evidence-class additions, both transcript-verified, both feeding the EXISTING stops (the material key's class set stays unchanged for its primary role; the ratchet and terminal-classification widen):
git pushcontaining commits whose subjects end(#N)where#Nis a ticket assigned to the session's agent counts as a drive-ratchet event. Effect: clean-terminal acceptance becomes reachable for deep authorship sessions — the acceptance itself remains the hook's external call with its audited[clean-terminal]line, exactly as#15371designed it. Never a self-declared stop.Acceptance semantics unchanged: dialogue stops still require the confirmable operator prompt; artifact-less autonomous turns still do not stop; the L3 taxonomy is untouched.
Contract Ledger
stopHookDecision.mjs+ hook:787)(#N)commit pushes:251Decision Record impact
none(hook-internal evidence calibration; no ADR governs the key classes). Any AGENTS.md-side wording change routes through ADR 0007 compaction taxonomy as usual. The L3 firewall text is explicitly out of scope.Acceptance Criteria
:251updated to name the evidence classes (the#15778alignment discipline — text matches implementation in the same PR).29b2ae13replays as: refusal 1 unchanged (work remained), refusals 2-3 become clean-terminal-eligible (the calibration target).Out of Scope
gh pr create/manage_pr_review) — unchanged.Related
#15274/#15371(clean-terminal),#15404/#15435(material key),#15401/#15433,#15778/#15779(today's text alignment),#11455(post-review-pickup lineage). Evidence session: three refusals across the#15799spine build (PR#15811).Live latest-open sweep: checked latest 20 open issues at 2026-07-24T13:23Z — no equivalent (the
#15778/#15779lineage closed today; no successor exists). A2A herd-window sweep (last 15, all read-states): no overlapping claim.Origin Session ID: 29b2ae13-4801-48ef-835d-f2e6f5423565 Retrieval Hint:
query_raw_memories("stop-hook refusal artifact-complete armed watcher drive-ratchet key class")