LearnNewsExamplesServices
Frontmatter
id14308
titleCodex Stop hook needs operator-dialogue fallback
stateClosed
labels
bugaitestingregressionarchitecturemodel-experience
assigneesneo-gpt
createdAtJun 28, 2026, 11:52 PM
updatedAtJun 29, 2026, 12:53 AM
githubUrlhttps://github.com/neomjs/neo/issues/14308
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 29, 2026, 12:53 AM

Codex Stop hook needs operator-dialogue fallback

Closed v13.1.0/archive-v13-1-0-chunk-7 bugaitestingregressionarchitecturemodel-experience
neo-gpt
neo-gpt commented on Jun 28, 2026, 11:52 PM

Context

Friction surfaced live on 2026-06-28 while trying to end an operator-directed Codex turn as operator dialogue/planning. Claude/Grace can stop on this path; Codex kept receiving the Stop-hook no-hold reminder instead.

This is not a request to weaken §no_hold_state. It is the hook's own friction→gold clause firing: when a human operator is actively in dialogue, the hook must provide a stop option that is externally confirmable even when the Codex Stop payload cannot directly expose the prompt text.

The Problem

The current Codex Stop-hook path can fail closed into autonomous/no-hold even for a live operator turn.

Live V-B-A from the current session:

  • Claude Stop audit logs show repeated ALLOW operatorInLoop=true entries for operator-dialogue turns.
  • Codex Stop audit logs for the same period show BLOCK ... promptSource=transcript_path, operatorInLoop=false, including the operator-dialogue attempt.
  • Running the current Codex helper against the live Codex transcript returned userLength: 0, assistantLength: 0, promptSource: transcript_path, operatorInLoop: false.
  • Inspecting the live Codex transcript shape showed messages under record.payload (payload.type="message", payload.role="user"). The Codex JSONL helpers currently inspect only root/message/item-shaped records, so the transcript exists but the prompt and assistant text are not extracted.

That explains today's failure, but the operator highlighted the wider contract: even if a Stop payload or transcript cannot expose the prompt directly, operator dialogue still needs a safe stop path. Otherwise the hook becomes a leash during live human dialogue, exactly the false-positive class the friction→gold clause says to turn into substrate.

The Architectural Reality

  • Shared semantics already live in ai/scripts/lifecycle/stopHookDecision.mjs: live operator dialogue is the only voluntary allow; autonomous [WAKE] / stop-hook continuations must continue driving.
  • Harness adapters are still split across .claude/hooks/laneStateStopHook.mjs and .codex/hooks/codex-lane-state-stop.mjs.
  • Codex has .codex/hooks/codex-context.mjs on UserPromptSubmit, which is a plausible external prompt-class capture point before Stop runs.
  • There is no shared ai/agent/hooks substrate yet. Current parity is shared decision primitives only, not shared payload normalization, prompt provenance, or adapter contract.
  • #13796 is the broad generic-adapter design surface. This ticket is the narrow bug leaf needed now: operator-dialogue stop fallback + live Codex transcript-schema coverage.

The Fix

Implement a Codex Stop-hook fallback that preserves the no-hold invariant while allowing operator dialogue when it is externally confirmable.

Expected shape:

  1. Teach Codex transcript extraction to parse the real Codex JSONL schema where message records live under record.payload.
  2. Treat synthetic hook records such as <hook_prompt ...> and <turn_aborted> as hook noise for operator-dialogue classification, so they do not hide the preceding human operator prompt.
  3. Add a fallback confirmation path for cases where Stop cannot see a prompt directly: the UserPromptSubmit hook should persist a short-lived same-turn prompt-class/nonce record that the Stop hook can read. The fallback must be external to the assistant final text; a self-declared final-response marker is not enough.
  4. Keep autonomous [WAKE], stop_hook_active, handoff-to-autonomous, and missing-evidence cases blocked/continued. The fallback is for confirmed operator dialogue, not for self-authorized idle.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
Codex Stop prompt extraction .codex/hooks/codex-lane-state-stop.mjs; real Codex transcript schema Extract user/assistant text from root, message, item, and payload records Malformed transcript fails open as hook-internal failure only when extraction throws; empty prompt remains non-operator unless another external prompt-class record confirms it Hook JSDoc Unit fixture using real Codex JSONL response_item.payload records
Operator-dialogue fallback .codex/hooks/codex-context.mjs UserPromptSubmit; stopHookDecision.mjs operator-in-loop rule Stop hook can confirm same-turn operator dialogue even when Stop payload lacks direct prompt text [WAKE], hook-generated prompts, autonomous handoffs, and stop_hook_active remain non-operator CODEX.md / hook JSDoc if behavior is user-visible Spawned-hook test: operator dialogue allows; wake/hook continuation blocks
Shared hook substrate direction #13796 and v13.2 #14304 planning Keep the immediate fix narrow, but do not add more duplicated semantics to harness-local adapters Broad extraction into ai/agent/hooks or equivalent stays a follow-up unless this fix needs a tiny shared helper Related ticket/comment Regression tests prove Codex/Claude parity at the contract boundary

Decision Record impact

Aligned with #13796's generic-by-default harness adapter direction and #14304's v13.2 architecture-quality work. No ADR change required for the narrow bug fix; a later shared ai/agent/hooks extraction may need a Decision Record if it establishes a new cross-harness substrate boundary.

Acceptance Criteria

  • Codex JSONL extraction supports real response_item.payload message records for both user and assistant text.
  • Codex operator-dialogue classification skips synthetic hook/noise user records such as <hook_prompt ...> and <turn_aborted> when finding the human prompt for the current turn.
  • Codex has an externally confirmable operator-dialogue fallback when Stop cannot directly see prompt text, preferably via a same-turn prompt-class/nonce written by UserPromptSubmit and read by Stop.
  • The fallback does not accept assistant self-declaration as authority; it must be tied to a hook/prompt provenance record.
  • Regression tests cover: real Codex transcript fixture, direct operator prompt allow, missing-Stop-prompt fallback allow, [WAKE] block, stop_hook_active block, handoff-to-autonomous block, and malformed transcript fail-open behavior.
  • Claude behavior remains unchanged or has matching shared-helper coverage if extraction is factored.

Out of Scope

  • Rewriting the full harness adapter surface from #13796.
  • Relaxing §no_hold_state for autonomous turns.
  • Adding a broad ai/agent/hooks domain unless the narrow fix proves the shared helper is needed immediately.
  • Changing PR merge / issue close human-authority gates.

Avoided Traps

  • Self-declared operator dialogue: rejected. The assistant final text cannot authorize its own stop.
  • PromptSource-none equals permanent block: rejected. It is safe for autonomous uncertainty, but live operator dialogue needs an external fallback path.
  • Broad architecture rewrite first: rejected. Fix the live parity bug, then feed any shared-substrate extraction into #13796 / #14304.

Related

  • #14034 — prior operator-dialogue wording/hint work; closed, but did not cover the live Codex transcript-schema/fallback failure.
  • #14093 — adjacent operator-gated closeout tension; related but not equivalent.
  • #13796 — broad generic harness adapter surface.
  • #13623 / #13822 — no-hold and value-floor design surfaces.
  • #14304 — v13.2 Agent OS architecture-quality umbrella.

Live latest-open sweep: checked latest 20 open issues at 2026-06-28T21:51:14Z; no equivalent found. Nearby non-duplicates checked: #14093, #13796, #13623, #13822. Exact GitHub searches for Codex Stop hook operator dialogue and promptSource transcript_path operatorInLoop found prior closed/adjacent work but no open equivalent.

A2A in-flight claim sweep: checked latest 30 A2A messages across read states at 2026-06-28T21:51:14Z; no competing [lane-claim] / [lane-intent] on this exact fallback scope found.

Origin Session ID: 3990502e-346a-47d6-8376-490e4802829c

Handoff Retrieval Hints: query_raw_memories("operator dialogue stop option missing prompt visible Codex Stop hook friction gold"); query_raw_memories("Codex Claude Stop hook operator dialogue lane-state parity fail-open promptSource none"); current live evidence centered on Codex session 019f0f79-7af4-7a70-893a-dd58e03337d6.

tobiu closed this issue on Jun 29, 2026, 12:53 AM
tobiu referenced in commit 0b61dc5 - "fix(codex): restore operator stop fallback (#14308) (#14309)" on Jun 29, 2026, 12:53 AM