Context
After the Codex harness restart on 2026-06-21, the repo-local Codex Stop hook live-fired and reported no lane-state block emitted at turn-terminal on a terminal that followed the older human-readable lane-state: convention. A later live-fire also showed the current no-hold policy can still block autonomous terminals even when the descriptor is valid; this ticket does not change that policy. It repairs the documentation/input-contract drift so lifecycle guidance tells agents to emit the fenced machine-readable block that parseLaneState() actually reads.
Live latest-open sweep: checked latest 20 open issues at 2026-06-21T04:39:52Z; no equivalent open ticket found. A2A in-flight claim sweep: latest 30 messages showed Ada's non-conflicting #13710 branch-freshness lane and older closed #13643 claim; no active claim on this narrow post-review-pickup §2.5 repair. Related duplicate-risk audit: closed NOT_PLANNED #13643 was broader (full emission contract, always-loaded pointer, hook directive example, dry-run readiness). This ticket is intentionally narrower and bounded to the existing lifecycle-boundary wording.
Release classification: boardless (MX substrate repair; not release-blocking).
The Problem
post-review-pickup is the lifecycle skill that tells agents what to emit at turn boundaries, but §2.5 still described only prose lane-state: examples. The live parser seam is stricter: ai/scripts/lifecycle/parseLaneState.mjs extracts only a fenced ```lane-state block and returns null when that block is absent. Agents following the old §2.5 wording therefore satisfy the human-readable convention while failing the machine seam, producing noisy Stop-hook diagnostics and weakening hook parity testing.
The Architectural Reality
ai/scripts/lifecycle/parseLaneState.mjs documents that the human-readable lane-state: prose line remains, while the machine seam is the fenced lane-state block.
.codex/hooks/codex-lane-state-stop.mjs and .claude/hooks/laneStateStopHook.mjs both route final assistant text through the shared parser/validator seam.
.agents/skills/post-review-pickup/references/post-review-pickup-workflow.md §2.5 is already the lifecycle-boundary place where agents are told to emit lane-state:.
The Fix
Update only post-review-pickup §2.5 so each lifecycle boundary emits both surfaces: prose for humans and a fenced JSON lane-state block for Stop hooks. Include the minimal descriptor example plus edge notes for no-gate (namedGates: []) and merge-claim evidence (mergeClaim plus field:"mergedAt").
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
.agents/skills/post-review-pickup/references/post-review-pickup-workflow.md §2.5 |
#13623 no-hold operationalization; parseLaneState.mjs; Codex/Claude Stop hooks |
Lifecycle boundaries document both human prose and fenced JSON machine emission |
Prose alone is explicitly not machine emission; no gate uses namedGates: []; merge claims name field:"mergedAt" |
Same skill payload only; no AGENTS.md or SKILL.md router expansion |
lint-skill-manifest, lint-agents, substrate size check, focused parser/hook unit tests |
Decision Record impact
aligned-with #13623. No ADR change. This keeps the full detail in the skill payload per Progressive Disclosure and does not add always-loaded substrate.
Acceptance Criteria
Out of Scope
- Reopening the full #13643 emission-contract substrate.
- Changing Codex or Claude Stop-hook allow/block policy.
- Adding an always-loaded
AGENTS.md pointer.
- Updating hook reminder prose to show a full descriptor template.
- #13710 branch-freshness guard work.
Avoided Traps
- Make
parseLaneState() accept prose: rejected because prose cannot carry structured gate evidence like checkedAt and merge-field claims.
- Resurrect #13643 wholesale: rejected because the operator already closed that broader substrate as too much context. This repair stays at the existing §2.5 lifecycle-boundary instruction.
- Claim this resolves all hook live-fire friction: rejected because the current no-hold policy can still block autonomous valid terminals by design; this ticket only removes the stale prose-only instruction.
Related
Related: #13623, #13643, #13710
Origin Session ID: 747ae298-5a6e-4416-b90d-7786e184aa54
Handoff Retrieval Hints: post-review-pickup fenced lane-state docs, parseLaneState prose alone not machine emission, Codex Stop hook no lane-state block emitted
Context
After the Codex harness restart on 2026-06-21, the repo-local Codex Stop hook live-fired and reported
no lane-state block emitted at turn-terminalon a terminal that followed the older human-readablelane-state:convention. A later live-fire also showed the current no-hold policy can still block autonomous terminals even when the descriptor is valid; this ticket does not change that policy. It repairs the documentation/input-contract drift so lifecycle guidance tells agents to emit the fenced machine-readable block thatparseLaneState()actually reads.Live latest-open sweep: checked latest 20 open issues at 2026-06-21T04:39:52Z; no equivalent open ticket found. A2A in-flight claim sweep: latest 30 messages showed Ada's non-conflicting #13710 branch-freshness lane and older closed #13643 claim; no active claim on this narrow
post-review-pickup§2.5 repair. Related duplicate-risk audit: closed NOT_PLANNED #13643 was broader (full emission contract, always-loaded pointer, hook directive example, dry-run readiness). This ticket is intentionally narrower and bounded to the existing lifecycle-boundary wording.Release classification: boardless (MX substrate repair; not release-blocking).
The Problem
post-review-pickupis the lifecycle skill that tells agents what to emit at turn boundaries, but §2.5 still described only proselane-state:examples. The live parser seam is stricter:ai/scripts/lifecycle/parseLaneState.mjsextracts only a fenced ```lane-state block and returnsnullwhen that block is absent. Agents following the old §2.5 wording therefore satisfy the human-readable convention while failing the machine seam, producing noisy Stop-hook diagnostics and weakening hook parity testing.The Architectural Reality
ai/scripts/lifecycle/parseLaneState.mjsdocuments that the human-readablelane-state:prose line remains, while the machine seam is the fencedlane-stateblock..codex/hooks/codex-lane-state-stop.mjsand.claude/hooks/laneStateStopHook.mjsboth route final assistant text through the shared parser/validator seam..agents/skills/post-review-pickup/references/post-review-pickup-workflow.md§2.5 is already the lifecycle-boundary place where agents are told to emitlane-state:.The Fix
Update only
post-review-pickup§2.5 so each lifecycle boundary emits both surfaces: prose for humans and a fenced JSONlane-stateblock for Stop hooks. Include the minimal descriptor example plus edge notes for no-gate (namedGates: []) and merge-claim evidence (mergeClaimplusfield:"mergedAt").Contract Ledger Matrix
.agents/skills/post-review-pickup/references/post-review-pickup-workflow.md§2.5parseLaneState.mjs; Codex/Claude Stop hooksnamedGates: []; merge claims namefield:"mergedAt"AGENTS.mdorSKILL.mdrouter expansionlint-skill-manifest,lint-agents, substrate size check, focused parser/hook unit testsDecision Record impact
aligned-with #13623. No ADR change. This keeps the full detail in the skill payload per Progressive Disclosure and does not add always-loaded substrate.
Acceptance Criteria
post-review-pickup§2.5 names both emission surfaces: human proselane-state:and fenced JSONlane-stateblock.laneContinuation,namedGates[].ref, andnamedGates[].checkedAt, plus notes for empty gates and merge-claim evidence.AGENTS.md,SKILL.md, hook policy, or parser behavior changes are required for this leaf.lint-skill-manifest,lint-agents, substrate size, and focused parser/hook unit coverage.Out of Scope
AGENTS.mdpointer.Avoided Traps
parseLaneState()accept prose: rejected because prose cannot carry structured gate evidence likecheckedAtand merge-field claims.Related
Related: #13623, #13643, #13710
Origin Session ID: 747ae298-5a6e-4416-b90d-7786e184aa54 Handoff Retrieval Hints:
post-review-pickup fenced lane-state docs,parseLaneState prose alone not machine emission,Codex Stop hook no lane-state block emitted