Skip to content

Unify rollout reconstruction with resume/fork TurnContext hydration#12612

Merged
charley-oai merged 64 commits intomainfrom
cc/unify-rollout-reconstruction-resume-hydration
Feb 27, 2026
Merged

Unify rollout reconstruction with resume/fork TurnContext hydration#12612
charley-oai merged 64 commits intomainfrom
cc/unify-rollout-reconstruction-resume-hydration

Conversation

@charley-oai
Copy link
Contributor

@charley-oai charley-oai commented Feb 23, 2026

Summary

This PR unifies rollout history reconstruction and resume/fork metadata hydration under a single Session::reconstruct_history_from_rollout implementation.

The key change from main is that replay metadata now comes from the same reconstruction pass that rebuilds model-visible history, instead of doing a second bespoke rollout scan to recover previous_model / reference_context_item.

What Changed

Unified reconstruction output

reconstruct_history_from_rollout now returns a single RolloutReconstruction bundle containing:

  • rebuilt history
  • previous_model
  • reference_context_item

Resume and fork both consume that shared output directly.

Reverse replay core

The reconstruction logic moved into codex-rs/core/src/codex/rollout_reconstruction.rs and now scans rollout items newest-to-oldest.

That reverse pass:

  • derives previous_model
  • derives whether reference_context_item is preserved or cleared
  • stops early once it has both resume metadata and a surviving replacement_history checkpoint

History materialization is still bridged eagerly for now by replaying only the surviving suffix forward, which keeps the history result stable while moving the control flow toward the future lazy reverse loader design.

Removed bespoke context lookup

This deletes last_rollout_regular_turn_context_lookup and its separate compaction-aware scan.

The previous model / baseline metadata is now computed from the same replay state that rebuilds history, so resume/fork cannot drift from the reconstructed transcript view.

TurnContextItem persistence contract

TurnContextItem is now treated as the replay source of truth for durable model-visible baselines.

This PR keeps the following contract explicit:

  • persist TurnContextItem for the first real user turn so resume can recover previous_model
  • persist it for later turns that emit model-visible context updates
  • if mid-turn compaction reinjects full initial context into replacement history, persist a fresh TurnContextItem after Compacted so resume/fork can re-establish the baseline from the rewritten history
  • do not treat manual compaction or pre-sampling compaction as creating a new durable baseline on their own

Behavior Preserved

  • rollback replay stays aligned with drop_last_n_user_turns
  • rollback skips only user turns
  • incomplete active user turns are dropped before older finalized turns when rollback applies
  • unmatched aborts do not consume the current active turn
  • missing abort IDs still conservatively clear stale compaction state
  • compaction clears reference_context_item until a later TurnContextItem re-establishes it
  • previous_model still comes from the newest surviving user turn that established one

Tests

Targeted validation run for the current branch shape:

  • cd codex-rs && cargo test -p codex-core --lib codex::rollout_reconstruction_tests -- --nocapture
  • cd codex-rs && just fmt

The branch also extracts the rollout reconstruction tests into codex-rs/core/src/codex/rollout_reconstruction_tests.rs so this logic has a dedicated home instead of living inline in codex.rs.

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 859ea16a31

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector
Copy link
Contributor

Security review completed. No security issues were found in this pull request.

View security finding report

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d4efe495b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1ab8c7d01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

@chatgpt-codex-connector
Copy link
Contributor

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9506d61000

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

@chatgpt-codex-connector
Copy link
Contributor

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(rollback)) => {
history.drop_last_n_user_turns(rollback.num_turns);
let mut turns_to_drop =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit strange to run two version of this logic in parallel, one to drop user messages, another to drop turns

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can't unify them because history only contains model-visible data whereas our stack of user turns contains metadata needed to fetch previous_model and reference_context_item

let push_replayed_turn = |replayed_segments: &mut Vec<RolloutReplayMetaSegment>,
active_turn: ActiveRolloutTurn| {
replayed_segments.push(RolloutReplayMetaSegment::Turn(Box::new(
ReplayedRolloutTurn {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are copying the struct into almost the same struct ActiveRolloutTurn -- >ReplayedRolloutTurn.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion serves to eliminate dead/unused fields

  • dropping turn_id, which is only needed while matching lifecycle events
  • dropping saw_user_message, which is only needed to decide whether the span counts as a user turn at all

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acec761d88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06f8e6b316

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37cacb2dab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

@chatgpt-codex-connector
Copy link
Contributor

Codex Review: Didn't find any major issues. Delightful!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai
Copy link
Contributor Author

@codex review this

@charley-oai charley-oai force-pushed the cc/unify-rollout-reconstruction-resume-hydration branch 2 times, most recently from 1198055 to ff0efdb Compare February 27, 2026 04:28
@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff0efdbbee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Materialize exact history semantics from the replay-derived suffix. The eventual lazy
// design should keep this same replay shape, but drive it from a resumable reverse source
// instead of an eagerly loaded `&[RolloutItem]`.
for item in rollout_suffix {
Copy link
Collaborator

@pakrym-oai pakrym-oai Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering we have a separate loop anyway (ideally we won't), can we drop rollout_suffix and add break to RolloutItem::Compacted branch?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, is it because the history is append to the end only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's hard to do the second as part of the first because of None replacement_history compacts which want the whole history so far (when going left to right)


let initial_context = self.build_initial_context(turn_context, None).await;
let mut history = ContextManager::new();
if let Some(base_replacement_history) = base_replacement_history {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have base_replacement_history? Wouldn't the loop below replace what's needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's needed to keep track of whether we can stop consuming backwards, and then at the beginning of the forward pass we use it to start off the history we build

// Thread rollback always targets the newest surviving user turns, so consume that
// skip budget before letting this segment contribute metadata or a compaction base.
if *pending_rollback_turns > 0 {
if active_segment.counts_as_user_turn {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the drop_last_n_user_turns is base on user messages, this logic is based on turns. Do they align?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this logic is based on user messages too, counts_as_user_turn is carefully designed to align with drop_last_n_user_turns logic (and I added a bunch of tests to ensure they align)

Copy link
Collaborator

@pakrym-oai pakrym-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is rollback behavior aligned?
Can we simplify by removing support for non-replacement_history compaction?
If we are keeping two loops, can we make them independent and bail compact item when loading ResponseItems - that will make me sleep a bit better at night.

@charley-oai
Copy link
Contributor Author

@codex review this

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25e8ea4acc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@charley-oai charley-oai merged commit 695957a into main Feb 27, 2026
29 of 31 checks passed
@charley-oai charley-oai deleted the cc/unify-rollout-reconstruction-resume-hydration branch February 27, 2026 21:50
@github-actions github-actions bot locked and limited conversation to collaborators Feb 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants