Context
The active #13623 lane needs a PR-closeable leaf for the hook-only schema-display slice. The parent ticket remains open for AC4 ratio-over-window / COP observability, so the runtime reminder schema display must not magic-close #13623.
This successor is deliberately narrower than #13643. #13643 attempted to solve the emission contract with permanent skill / always-loaded substrate and was closed not_planned after the operator rejected that shape as context bloat. The sanctioned shape is hook-only: display the machine-readable lane-state block schema when the Stop hook actually blocks, with zero AGENTS.md pointer and no new skill payload.
The Problem
Agents repeatedly emitted prose lane-state: lines while the active parser only consumes the last fenced ```lane-state JSON block. The Stop-hook reminder said that no block was emitted, but did not show the exact machine block or the validator gotchas that make a well-formed block invalid.
That creates a recovery loop: a blocked agent can understand that a lane is required, but still cannot self-service the parser input shape from the runtime reminder alone.
The Architectural Reality
ai/scripts/lifecycle/parseLaneState.mjs extracts only a fenced ```lane-state JSON block. Prose remains the human ledger, not the machine seam.
ai/scripts/lifecycle/validateLaneStateTerminal.mjs rejects two recurring gotchas: active-lane cannot be only an own PR awaiting merge/review/CI, and every namedGates[] entry needs same-turn checkedAt; merge claims must cite field mergedAt.
.claude/hooks/laneStateStopHook.mjs and .codex/hooks/codex-lane-state-stop.mjs already inject no-hold reminders at the runtime point where the missing information matters.
The Fix
Add a compact shared runtime schema hint to the Stop-hook decision layer and include it in both Claude and Codex Stop-hook reminders. The hint must show:
- the fenced
```lane-state block label;
- required descriptor keys:
wakeDisposition, laneContinuation, namedGates, awaitingOwnPrOnly;
- the two validator gotchas above.
Keep this hook-only. Do not add permanent skill payload, AGENTS.md pointer, parser changes, or a new validator rule.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
| Claude Stop-hook reminder |
parseLaneState.mjs, validateLaneStateTerminal.mjs, #13623 runtime friction |
On block, display the fenced lane-state JSON shape plus validator gotchas after the existing no-hold directive. |
Missing/invalid lane-state still blocks; schema text is guidance only, not a stop permission. Hook-internal failures still fail open. |
JSDoc remains aligned with runtime reminder behavior. |
Focused hook unit tests assert the schema label, required keys, and gotcha text. |
| Codex Stop-hook reminder |
Same shared parser/validator seam and parity requirement |
Include the same shared schema hint in Codex buildNoHoldReminder(). |
Keep the no-hold directive first so compact transports still surface the core action. |
No new Codex config or skill substrate. |
Focused Codex hook tests assert the same schema/gotcha anchors. |
| Shared lifecycle helper |
Existing shared stopHookDecision.mjs decision module |
Export one schema-hint constant consumed by both hooks so Claude/Codex wording cannot drift. |
No change to parse, validation, allow/block decisions, or operator-in-loop semantics. |
Inline JSDoc only. |
Shared helper spec asserts the hint shape. |
Decision Record impact
None. This is aligned with #13623 AC1/AC5 and the existing parser/validator seam. It explicitly avoids resurrecting the rejected #13643 always-loaded / skill-substrate shape.
Acceptance Criteria
Out of Scope
- #13623 AC4 ratio-over-window observability.
- COP rendering.
- Contribution ledgers or shipper scoring.
- Stop-hook validator changes.
- Any new valid terminal, hold state, or permission to stop.
- Reopening #13643's rejected permanent-substrate approach.
Avoided Traps
- Permanent skill / AGENTS.md substrate: rejected because #13643 already proved that shape is context bloat for a machine-format detail the hook can convey on block.
- Parser relaxation to accept prose: rejected because prose cannot carry the structured gate evidence the validator checks.
- Keys-only schema display: rejected after Vega's contract review; it leaves the recurring
active-lane + awaitingOwnPrOnly:true and stale-gate traps intact.
Related
Parent: #13623
Related: #13643
Live latest-open sweep: checked latest 20 open issues on 2026-06-21T08:15Z; no equivalent active leaf found. #13643 found as prior rejected shape, not an active close target.
A2A in-flight claim sweep: checked latest 30 inbox messages across read states on 2026-06-21T08:15Z; no competing claim. Ada confirmed hook-only display as the #13643 boundary; Vega requested the validator gotcha text.
KB duplicate sweep: queried hook-only runtime reminder / fenced lane-state schema / validator gotchas; surfaced closed historical parser/validator work (#12633 / #13575) and no equivalent active leaf.
Release classification: boardless (post-hook substrate refinement, not release-blocking).
Origin Session ID: 747ae298-5a6e-4416-b90d-7786e184aa54
Retrieval Hint: hook-only lane-state schema display, closed #13643 substrate bloat boundary, parseLaneState fenced lane-state block, validateLaneStateTerminal gotchas
Context
The active #13623 lane needs a PR-closeable leaf for the hook-only schema-display slice. The parent ticket remains open for AC4 ratio-over-window / COP observability, so the runtime reminder schema display must not magic-close #13623.
This successor is deliberately narrower than #13643. #13643 attempted to solve the emission contract with permanent skill / always-loaded substrate and was closed
not_plannedafter the operator rejected that shape as context bloat. The sanctioned shape is hook-only: display the machine-readablelane-stateblock schema when the Stop hook actually blocks, with zero AGENTS.md pointer and no new skill payload.The Problem
Agents repeatedly emitted prose
lane-state:lines while the active parser only consumes the last fenced```lane-stateJSON block. The Stop-hook reminder said that no block was emitted, but did not show the exact machine block or the validator gotchas that make a well-formed block invalid.That creates a recovery loop: a blocked agent can understand that a lane is required, but still cannot self-service the parser input shape from the runtime reminder alone.
The Architectural Reality
ai/scripts/lifecycle/parseLaneState.mjsextracts only a fenced```lane-stateJSON block. Prose remains the human ledger, not the machine seam.ai/scripts/lifecycle/validateLaneStateTerminal.mjsrejects two recurring gotchas:active-lanecannot be only an own PR awaiting merge/review/CI, and everynamedGates[]entry needs same-turncheckedAt; merge claims must cite fieldmergedAt..claude/hooks/laneStateStopHook.mjsand.codex/hooks/codex-lane-state-stop.mjsalready inject no-hold reminders at the runtime point where the missing information matters.The Fix
Add a compact shared runtime schema hint to the Stop-hook decision layer and include it in both Claude and Codex Stop-hook reminders. The hint must show:
```lane-stateblock label;wakeDisposition,laneContinuation,namedGates,awaitingOwnPrOnly;Keep this hook-only. Do not add permanent skill payload, AGENTS.md pointer, parser changes, or a new validator rule.
Contract Ledger Matrix
parseLaneState.mjs,validateLaneStateTerminal.mjs, #13623 runtime frictionlane-stateJSON shape plus validator gotchas after the existing no-hold directive.buildNoHoldReminder().stopHookDecision.mjsdecision moduleDecision Record impact
None. This is aligned with #13623 AC1/AC5 and the existing parser/validator seam. It explicitly avoids resurrecting the rejected #13643 always-loaded / skill-substrate shape.
Acceptance Criteria
lane-stateJSON schema.awaitingOwnPrOnlyand same-turncheckedAt/mergedAtevidence.Out of Scope
Avoided Traps
active-lane + awaitingOwnPrOnly:trueand stale-gate traps intact.Related
Parent: #13623 Related: #13643
Live latest-open sweep: checked latest 20 open issues on 2026-06-21T08:15Z; no equivalent active leaf found. #13643 found as prior rejected shape, not an active close target. A2A in-flight claim sweep: checked latest 30 inbox messages across read states on 2026-06-21T08:15Z; no competing claim. Ada confirmed hook-only display as the #13643 boundary; Vega requested the validator gotcha text. KB duplicate sweep: queried hook-only runtime reminder / fenced lane-state schema / validator gotchas; surfaced closed historical parser/validator work (#12633 / #13575) and no equivalent active leaf. Release classification: boardless (post-hook substrate refinement, not release-blocking).
Origin Session ID: 747ae298-5a6e-4416-b90d-7786e184aa54 Retrieval Hint:
hook-only lane-state schema display,closed #13643 substrate bloat boundary,parseLaneState fenced lane-state block,validateLaneStateTerminal gotchas