Codex App: Continue in new chat can retain steered messages past the fork boundary
What version of the Codex App are you using (from the About Codex dialog)?
26.721.4979.0
What subscription do you have?
Unknown (API-key-authenticated local setup; no subscription tier is exposed in the available diagnostics).
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What issue are you seeing?
Using Continue in new chat on an earlier turn can create a child task whose history extends past the selected fork point when one of the later turns was steered.
The residual user message can then survive auto-compaction and be answered again, even though it was sent before the fork and should have been removed from the child task.
The two visible symptoms are:
- The fork boundary includes messages after the selected turn.
- After compaction, Codex responds again to a user message from the rolled-back portion of the parent task.
What steps can reproduce the bug?
- Start a task in the Codex App and complete an initial turn that will be used as the fork target.
- Start another turn.
- While that turn is active, send a steer message before the turn completes.
- Complete at least one additional turn after the steered turn.
- On the initial target turn, choose Continue in new chat.
- Inspect the new task history. Part of the steered turn can remain after the selected fork boundary.
- Continue using the child task until auto-compaction occurs. The residual pre-fork user message can be surfaced and answered again.
The code-level reproduction is to create an app-server turn with both an initial user message and a later turn/steer message sharing the same durable turn_id, add another turn, and then call thread/rollback for the two app-server turns after the target.
What is the expected behavior?
The child task should end exactly at the selected fork point. All later app-server turns should be removed, including every initial and steer message belonging to those turns. Auto-compaction must not reintroduce or replay any removed message.
Additional information
The root cause appears to be a counting-unit mismatch in rollback:
- The app passes
thread/rollback.numTurnsas a count of app-server turns after the selected target. - Core history rollback currently treats each ordinary user message as a separate turn boundary.
- A steered app-server turn persists multiple ordinary user messages with the same non-empty durable
turn_id. - As a result, rollback can remove too few app-server turns and leave the initial message of the steered turn behind.
A focused fix groups consecutive ordinary user-message boundaries with the same non-empty durable turn_id, while retaining legacy behavior for messages without a turn ID and for inter-agent instruction boundaries:
https://github.com/daizw/codex/commit/315c12e02ea732c062caeedd5169b038925066b9
Validation performed on that commit:
just test -p codex-core drop_last_n_user_turns(7/7 passed)just test -p codex-app-server thread_rollback(4/4 passed)just fix -p codex-corejust fix -p codex-app-serverjust fmt
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Thanks for flagging this. The post-compaction symptom overlaps with #34862, but this appears to have a distinct deterministic cause.
In this report, the incorrect history is already observable before compaction: Continue in new chat retains messages beyond the selected fork boundary when a later app-server turn contains a
turn/steermessage.thread/rollback.numTurnscounts app-server turns, while core rollback counts each ordinary user message as a separate boundary. The initial prompt and steer message share the same durableturn_id, so rollback removes too little history. Compaction only makes the residual pre-fork message surface again.The linked commit includes focused core and app-server regression tests for this exact rollback path. Therefore, #34862 may share the final symptom, but #36074 should remain open as a separate fork/rollback bug unless maintainers confirm both paths have the same underlying cause.