Skip to content

Codex App: Continue in new chat can retain steered messages past the fork boundary #36074

Description

@daizw

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:

  1. The fork boundary includes messages after the selected turn.
  2. After compaction, Codex responds again to a user message from the rolled-back portion of the parent task.

What steps can reproduce the bug?

  1. Start a task in the Codex App and complete an initial turn that will be used as the fork target.
  2. Start another turn.
  3. While that turn is active, send a steer message before the turn completes.
  4. Complete at least one additional turn after the steered turn.
  5. On the initial target turn, choose Continue in new chat.
  6. Inspect the new task history. Part of the steered turn can remain after the selected fork boundary.
  7. 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.numTurns as 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:

daizw@315c12e

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-core
  • just fix -p codex-app-server
  • just fmt

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions