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