LearnNewsExamplesServices
Frontmatter
id13661
titleActivate Codex Stop-hook blocking
stateClosed
labels
bugaiarchitecturemodel-experience
assigneesneo-gpt
createdAtJun 20, 2026, 10:36 PM
updatedAtJun 20, 2026, 10:53 PM
githubUrlhttps://github.com/neomjs/neo/issues/13661
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 20, 2026, 10:53 PM

Activate Codex Stop-hook blocking

Closed v13.1.0/archive-v13-1-0-chunk-4 bugaiarchitecturemodel-experience
neo-gpt
neo-gpt commented on Jun 20, 2026, 10:36 PM

Context

The post-restart Codex Stop hook validation exposed a live activation gap in the hook lane. PR #13657 landed the Codex hook parity surface, but the Codex adapter still logs WOULD-BLOCK and exits successfully for invalid autonomous turn-end. The operator explicitly rejected the dry-run behavior on 2026-06-20 and directed a P0 activation lane: Codex must block like the Claude Stop hook.

Live latest-open sweep: checked the latest 20 open issues at 2026-06-20T20:35Z; no equivalent Codex-blocking activation ticket found. Closest active work is #13659 / PR #13660, which only adds dedicated stopHookDecision spec coverage and does not activate Codex blocking.

A2A in-flight sweep: checked the latest 30 A2A messages at 2026-06-20T20:35Z. No active lane claim owns Codex Stop-hook blocking activation; Grace's latest message is #13660 for #13659 test coverage only.

Release classification: P0 operator-directed Agent OS harness reliability fix; boardless for now because this is an immediate hook activation lane, not a release-board scope expansion.

The Problem

The Codex Stop hook is currently wired but intentionally fail-open:

  • .codex/hooks/codex-lane-state-stop.mjs exports CODEX_STOP_BLOCK_INJECTION_SUPPORTED = false.
  • .codex/hooks.json invokes the hook without NEO_CODEX_LANE_STATE_ENFORCE=1.
  • The live audit log at ~/.neo-ai-data/codex-lane-state-hook/codex-lane-state-stop-hook.log recorded WOULD-BLOCK after the restart instead of blocking the invalid terminal.

This means the hook can detect the no-hold violation but cannot enforce it. That misses the operator's intended P0 behavior and leaves Codex in a weaker state than Claude.

The Architectural Reality

Claude and Codex already share the pure decision substrate in ai/scripts/lifecycle/stopHookDecision.mjs; the divergence is in the harness adapter:

  • Claude: .claude/settings.json wires NEO_LANE_STATE_ENFORCE=1, and .claude/hooks/laneStateStopHook.mjs writes {"decision":"block","reason":...} on enforcement.
  • Codex: .codex/hooks.json wires the hook without enforce env, and .codex/hooks/codex-lane-state-stop.mjs always logs WOULD-BLOCK / WOULD-ALLOW and exits.

The correct substrate for this change is the Codex hook adapter plus its focused unit tests. The shared decision helper should not be redefined.

The Fix

  • Enable Codex Stop-hook enforcement in .codex/hooks.json.
  • Switch the Codex adapter from fail-open would-block to real block when enforcement is enabled and no live operator dialogue is present.
  • Emit the same {"decision":"block","reason":...} JSON shape Claude uses, so the harness has a concrete block directive.
  • Update test/playwright/unit/hooks/codexLaneStateStopHook.spec.mjs to prove enforced invalid/autonomous terminals write a block decision to stdout while operator dialogue still allows.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
.codex/hooks.json Stop command Operator P0 directive + merged hook surface Invoke Codex Stop hook with NEO_CODEX_LANE_STATE_ENFORCE=1 Hook-internal failures still fail open by design .codex/CODEX.md runtime notes and hook JSDoc Unit spawned-hook test plus live restart audit
.codex/hooks/codex-lane-state-stop.mjs Claude Stop-hook adapter precedent On enforced block action, write {"decision":"block","reason":...} to stdout Payload parse / hook errors still allow and audit Hook JSDoc Focused unit tests

Decision Record impact

none — this aligns the Codex adapter with the already-accepted no-hold Stop-hook behavior.

Acceptance Criteria

  • .codex/hooks.json enables Codex lane-state enforcement for the Stop hook.
  • Enforced Codex Stop hook writes a JSON block decision for autonomous invalid/absent/malformed lane-state terminals.
  • Live operator dialogue remains an allow path.
  • Hook-internal failures still fail open and audit, so a hook bug cannot trap a turn-end.
  • Focused unit tests cover the enforced block path and operator allow path.

Out of Scope

  • Changing the shared no-hold decision helper beyond what is required for Codex adapter activation.
  • Reviewing or merging #13660.
  • Broad redesign of lane-state emission substrate.

Avoided Traps

  • Do not leave Codex as a dry-run audit hook. The operator explicitly rejected that state.
  • Do not weaken Claude enforcement. Claude is already wired to real block through NEO_LANE_STATE_ENFORCE=1.
  • Do not use this ticket to add new stop machinery or a new idle state.

Related

Related: #13655, #13657, #13659, #13660, #13623, #13624

Origin Session ID: 810318e6-b644-474e-a255-a07d19825aa5 Retrieval Hint: "Codex Stop hook WOULD-BLOCK fail-open activate NEO_CODEX_LANE_STATE_ENFORCE CODEX_STOP_BLOCK_INJECTION_SUPPORTED"