[codex] Defer fork context injection until first turn (#15699)

## Summary
- remove the fork-startup `build_initial_context` injection
- keep the reconstructed `reference_context_item` as the fork baseline
until the first real turn
- update fork-history tests and the request snapshot, and add a
`TODO(ccunningham)` for remaining nondiffable initial-context inputs

## Why
Fork startup was appending current-session initial context immediately
after reconstructing the parent rollout, then the first real turn could
emit context updates again. That duplicated model-visible context in the
child rollout.

## Impact
Forked sessions now behave like resume for context seeding: startup
reconstructs history and preserves the prior baseline, and the first
real turn handles any current-session context emission.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charley Cunningham
2026-03-24 18:34:44 -07:00
committed by GitHub
parent 2e03d8b4d2
commit d72fa2a209
6 changed files with 24 additions and 31 deletions

View File

@@ -125,9 +125,8 @@ async fn fork_thread_twice_drops_to_first_message() {
// GetHistory on fork1 flushed; the file is ready.
let fork1_items = read_items(&fork1_path);
assert!(fork1_items.len() > expected_after_first.len());
pretty_assertions::assert_eq!(
serde_json::to_value(&fork1_items[..expected_after_first.len()]).unwrap(),
serde_json::to_value(&fork1_items).unwrap(),
serde_json::to_value(&expected_after_first).unwrap()
);
@@ -156,9 +155,8 @@ async fn fork_thread_twice_drops_to_first_message() {
.unwrap_or(0);
let expected_after_second: Vec<RolloutItem> = fork1_items[..cut_last_on_fork1].to_vec();
let fork2_items = read_items(&fork2_path);
assert!(fork2_items.len() > expected_after_second.len());
pretty_assertions::assert_eq!(
serde_json::to_value(&fork2_items[..expected_after_second.len()]).unwrap(),
serde_json::to_value(&fork2_items).unwrap(),
serde_json::to_value(&expected_after_second).unwrap()
);
}

View File

@@ -443,14 +443,14 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
let body4 = req4.single_request().body_json();
let input4 = body4["input"].as_array().expect("input array");
let permissions_fork = permissions_texts(input4);
assert_eq!(permissions_fork.len(), permissions_base.len() + 2);
assert_eq!(permissions_fork.len(), permissions_base.len() + 1);
assert_eq!(
&permissions_fork[..permissions_base.len()],
permissions_base.as_slice()
);
let new_permissions = &permissions_fork[permissions_base.len()..];
assert_eq!(new_permissions.len(), 2);
assert_eq!(new_permissions[0], new_permissions[1]);
assert_eq!(new_permissions.len(), 1);
assert_eq!(permissions_fork, permissions_resume);
assert!(!permissions_base.contains(&new_permissions[0]));
Ok(())