SIGN IN SIGN UP

fix(codex): keep deny/resubmit de-duplication working on the rollout-fallback path (#1539)

The `stop_hook_active` guard in `findPlanInTurn` anchors on the
`<hook_prompt>` USER message Codex records when a Stop hook blocks. That item
only arrived in rust-v0.117.0 (`build_hook_prompt_message`): rust-v0.114.0,
v0.115.0 and v0.116.0 — the exact versions #1534's rollout turn-id fallback
newly enables — record the continuation as
`DeveloperInstructions::new(continuation_prompt)`, i.e. a developer-role
message, and then continue the SAME turn with `stop_hook_active = true`.

The guard was therefore inert there: after "Request changes", if the model
answered without emitting a fresh `<proposed_plan>`, the next Stop resolved the
same turn, found no boundary, and re-served the unchanged denied plan for
review. Codex's continuation loop has no iteration cap, so denying again just
repeated it.

Generalize the boundary: the `<hook_prompt>` item stays authoritative, and the
last developer-role message in the turn is accepted as the boundary only on the
rollout-fallback path (a Stop payload with no `turn_id`), so every Codex that
sends `turn_id` keeps byte-identical behaviour.

Also:

- Correct the troubleshooting version table. Hooks became default-enabled at
  rust-v0.124.0 (`0.124.0-alpha.3`, `Stage::Stable` + `default_enabled: true`),
  not 0.125.0, and the `codex_hooks` -> `hooks` key rename landed at
  rust-v0.129.0 (`0.129.0-alpha.5`), not 0.131.0 — verified against
  `codex-rs/features/src/lib.rs` at each tag, with 0.128.0 still on
  `codex_hooks`. The derived prose now names the real codex_hooks-only range.
- Fail closed instead of throwing on a non-string `turn_id`: the coercion now
  lives inside `resolveCodexStopPlan` rather than only at the CLI call site, and
  the debug breadcrumb says the id was present but unusable rather than missing.
M
Michael Ramos committed
9f77a2bda10cf141b229d9a6d269adf5bc1d4cc9
Parent: 2ec1b40
Committed by GitHub <noreply@github.com> on 9/15/2026, 2:16:43 PM