Resume after rollback of compacted turn replays discarded assistant output
Summary
Resuming a thread after rolling back a user turn that compacted mid-turn can replay assistant or tool output from the discarded turn into the model history.
Affected path
On current main (84696e3d57), codex-rs/core/src/session/rollout_reconstruction.rs selects the suffix after a Compacted { replacement_history: Some(_) } marker during the reverse scan. That selection happens before the active segment is finalized. The later ThreadRolledBack handling rejects that segment, but it does not clear the already-selected suffix.
Forward replay therefore starts after the rejected compaction marker. The subsequent rollback has no retained user-message boundary to remove, so post-compaction assistant or tool response items from the rolled-back turn remain in the reconstructed history.
Reproduction shape
Persist rollout items in this order:
- A completed surviving user turn.
- A second user turn with a user response item.
Compactedwithreplacement_history: Some(...)within that second turn.- A post-compaction assistant response item.
- Completion of the second turn.
ThreadRolledBack { num_turns: 1 }.
Resuming should reconstruct only the first turn. Instead, the post-compaction assistant response item from the rolled-back second turn is retained.
Expected behavior
All model-visible items belonging to a rolled-back user turn should be absent after resume, including items written after an in-turn compaction checkpoint.
Suggested regression and fix
Extend record_initial_history_resumed_rollback_drops_incomplete_user_turn_compaction_metadata in codex-rs/core/src/session/rollout_reconstruction_tests.rs with a post-compaction assistant response item and assert that the reconstructed raw history does not contain it.
Keep a checkpoint's replacement history and suffix on the active replay segment, then publish both only after finalize_active_segment has accepted the segment. The rollback-skip path should discard both together.