@@ -87,7 +87,7 @@ def _last_page(request):
8787 + [(host , surface , False , True , False ) for host in ("benchmark" , "code_mode" )
8888 for surface in ("quota_packet" , "turn_envelope" )]
8989 + [("code_mode" , surface , False , True , True ) for surface in ("quota_packet" , "turn_envelope" )])
90- def test_native_cli_capture_delta_and_compact_recovery (tmp_path , monkeypatch , host , surface , failed_primary , resumed , adaptive , hook_loss = None , shared_root = False , checkpoint_handoff = False , handoff_socket = None , native_pragma = False , native_read_batch = 2 , native_history_tokens = None , resume_loss = None , bounded_pages = False , ssh_goal = False , reader_output_bytes = None ):
90+ def test_native_cli_capture_delta_and_compact_recovery (tmp_path , monkeypatch , host , surface , failed_primary , resumed , adaptive , hook_loss = None , shared_root = False , checkpoint_handoff = False , handoff_socket = None , native_pragma = False , native_read_batch = 2 , native_history_tokens = None , resume_loss = None , bounded_pages = False , ssh_goal = False , reader_output_bytes = None , recovery_resume = False ):
9191 # Real worker qualification follows returned cursors; output budgets can
9292 # shrink a page, so precomputed fixed offsets are not its production path.
9393 bounded_pages = bounded_pages or host == "benchmark"
@@ -399,11 +399,27 @@ def response(request, number, message):
399399 return tool (page ["next_command" ], number )
400400 stages ["phase" ] = "recovered"
401401 return response (request , number , message )
402+ elif phase == "recovery_resuming" :
403+ # The actual host has exited and reconstructed history again. Its
404+ # model input must retain the recovered full body, and SessionStart
405+ # must preserve that new baseline without another recovery read.
406+ from loopx .control_plane .turn_driver .codex_context import _state
407+
408+ assert delivered (request , "recovery" ) == Path (wires ["warm" ]["recovery" ]["path" ]).read_text ().rstrip ("\n " )
409+ journal = _state (lifecycle )
410+ assert journal ["candidate" ]["target" ]["context_epoch" ] == stages ["recovered_epoch" ]
411+ assert journal ["candidate" ]["capture_sha256" ] == page_digests ["recovery" ]
412+ stages ["phase" ] = "done"
413+ return message
402414 else :
403415 assert phase == "recovered"
404416 recovered = delivered (request , "recovery" )
405417 assert recovered == Path (wires ["warm" ]["recovery" ]["path" ]).read_text ().rstrip ("\n " )
406- stages ["phase" ] = "done"
418+ if recovery_resume :
419+ from loopx .control_plane .turn_driver .codex_context import _state
420+
421+ stages ["recovered_epoch" ] = _state (lifecycle )["context_epoch" ]
422+ stages ["phase" ] = "recovery_resuming" if recovery_resume else "done"
407423 return message
408424 return tool (cmd , number )
409425
@@ -587,6 +603,9 @@ def held(*args, **kwargs):
587603 if resumed :
588604 assert _app_server (binary , env , workspace , home , True , sandbox = sandbox ,
589605 resume = session_id , turn_timeout_sec = 60 ) == session_id
606+ if recovery_resume :
607+ assert _app_server (binary , env , workspace , home , True , sandbox = sandbox ,
608+ resume = session_id , turn_timeout_sec = 60 ) == session_id
590609 assert not errors , errors
591610
592611 assert stages ["phase" ] == "done"
@@ -678,6 +697,12 @@ def held(*args, **kwargs):
678697 assert bounded_sizes and max (bounded_sizes ) > 3072
679698
680699
700+ @pytest .mark .parametrize ("surface" , ["quota_packet" , "turn_envelope" ])
701+ def test_native_compact_recovery_survives_process_resume (tmp_path , monkeypatch , surface ):
702+ test_native_cli_capture_delta_and_compact_recovery (tmp_path , monkeypatch ,
703+ "code_mode" , surface , False , True , True , bounded_pages = True , recovery_resume = True )
704+
705+
681706@pytest .mark .parametrize ("surface" , ["quota_packet" , "turn_envelope" ])
682707@pytest .mark .parametrize ("loss" , ["replace" , "unqualified_profile" ])
683708def test_native_worker_resume_history_change_reads_current_full (tmp_path , monkeypatch , surface , loss ):
0 commit comments