@@ -2705,14 +2705,15 @@ impl Session {
27052705 self . record_conversation_items ( turn_context, & context_items)
27062706 . await ;
27072707 }
2708- if previous_user_turn_model. is_none ( )
2709- || ( !should_inject_full_context && !context_items. is_empty ( ) )
2708+ if should_inject_full_context
2709+ || previous_user_turn_model. is_none ( )
2710+ || !context_items. is_empty ( )
27102711 {
2711- // Keep rollout TurnContext entries to:
2712+ // Keep rollout TurnContext entries for any turn that establishes or changes the
2713+ // persisted model-visible baseline:
27122714 // - the first real user turn (to recover `previous_model` on resume)
2715+ // - full-context reinjection after the baseline was cleared
27132716 // - steady-state turns that emitted explicit context diffs
2714- // Full reinjection after compaction is tracked in runtime state only; resume will
2715- // conservatively fall back to a missing baseline and reinject again if needed.
27162717 self . persist_rollout_items ( & [ RolloutItem :: TurnContext ( turn_context_item. clone ( ) ) ] )
27172718 . await ;
27182719 }
@@ -5952,6 +5953,10 @@ mod tests {
59525953 use crate :: protocol:: TokenCountEvent ;
59535954 use crate :: protocol:: TokenUsage ;
59545955 use crate :: protocol:: TokenUsageInfo ;
5956+ use crate :: protocol:: UserMessageEvent ;
5957+ use crate :: rollout:: policy:: EventPersistenceMode ;
5958+ use crate :: rollout:: recorder:: RolloutRecorder ;
5959+ use crate :: rollout:: recorder:: RolloutRecorderParams ;
59555960 use crate :: state:: TaskKind ;
59565961 use crate :: tasks:: SessionTask ;
59575962 use crate :: tasks:: SessionTaskContext ;
@@ -7978,6 +7983,83 @@ mod tests {
79787983 ) ;
79797984 }
79807985
7986+ #[ tokio:: test]
7987+ async fn record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout ( )
7988+ {
7989+ let ( session, previous_context) = make_session_and_context ( ) . await ;
7990+ let next_model = if previous_context. model_info . slug == "gpt-5.1" {
7991+ "gpt-5"
7992+ } else {
7993+ "gpt-5.1"
7994+ } ;
7995+ let turn_context = previous_context
7996+ . with_model ( next_model. to_string ( ) , & session. services . models_manager )
7997+ . await ;
7998+ let config = session. get_config ( ) . await ;
7999+ let recorder = RolloutRecorder :: new (
8000+ config. as_ref ( ) ,
8001+ RolloutRecorderParams :: new (
8002+ ThreadId :: default ( ) ,
8003+ None ,
8004+ SessionSource :: Exec ,
8005+ BaseInstructions :: default ( ) ,
8006+ Vec :: new ( ) ,
8007+ EventPersistenceMode :: Limited ,
8008+ ) ,
8009+ None ,
8010+ None ,
8011+ )
8012+ . await
8013+ . expect ( "create rollout recorder" ) ;
8014+ let rollout_path = recorder. rollout_path ( ) . to_path_buf ( ) ;
8015+ {
8016+ let mut rollout = session. services . rollout . lock ( ) . await ;
8017+ * rollout = Some ( recorder) ;
8018+ }
8019+
8020+ session
8021+ . persist_rollout_items ( & [ RolloutItem :: EventMsg ( EventMsg :: UserMessage (
8022+ UserMessageEvent {
8023+ message : "seed rollout" . to_string ( ) ,
8024+ images : None ,
8025+ local_images : Vec :: new ( ) ,
8026+ text_elements : Vec :: new ( ) ,
8027+ } ,
8028+ ) ) ] )
8029+ . await ;
8030+ {
8031+ let mut state = session. state . lock ( ) . await ;
8032+ state. set_reference_context_item ( None ) ;
8033+ }
8034+
8035+ session
8036+ . record_context_updates_and_set_reference_context_item (
8037+ & turn_context,
8038+ Some ( previous_context. model_info . slug . as_str ( ) ) ,
8039+ )
8040+ . await ;
8041+ session. ensure_rollout_materialized ( ) . await ;
8042+ session. flush_rollout ( ) . await ;
8043+
8044+ let InitialHistory :: Resumed ( resumed) = RolloutRecorder :: get_rollout_history ( & rollout_path)
8045+ . await
8046+ . expect ( "read rollout history" )
8047+ else {
8048+ panic ! ( "expected resumed rollout history" ) ;
8049+ } ;
8050+ let persisted_turn_context = resumed. history . iter ( ) . find_map ( |item| match item {
8051+ RolloutItem :: TurnContext ( ctx) => Some ( ctx. clone ( ) ) ,
8052+ _ => None ,
8053+ } ) ;
8054+
8055+ assert_eq ! (
8056+ serde_json:: to_value( persisted_turn_context)
8057+ . expect( "serialize persisted turn context item" ) ,
8058+ serde_json:: to_value( Some ( turn_context. to_turn_context_item( ) ) )
8059+ . expect( "serialize expected turn context item" )
8060+ ) ;
8061+ }
8062+
79818063 #[ tokio:: test]
79828064 async fn run_user_shell_command_does_not_set_reference_context_item ( ) {
79838065 let ( session, _turn_context, rx) = make_session_and_context_with_rx ( ) . await ;
0 commit comments