"""Real SQLite subcall durability for native cleanup/verification pairs.""" import multiprocessing import os from pathlib import Path import sys import uuid import pytest sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts')) from task_execution_journal import Binding,Cleanup,Journal,Refused def child_crash(directory,binding,obligation): journal=Journal(Path(directory)) with journal.locked(): journal.reserve(binding,(obligation,)) journal.transition(binding,'reserved','consume-confirmed') journal.before_cleanup(binding,0,obligation) journal.before_cleanup_call(binding,0,obligation,0,'c'*64) os._exit(29) def test_subcall_crash_persists_and_never_restores_admission(tmp_path): binding=Binding('fixture-approval','sha256:'+'a'*64,str(uuid.uuid4()),'b'*64) obligation=Cleanup('task-token-revoke','d'*64) os.chmod(tmp_path,0o700) context=multiprocessing.get_context('fork') process=context.Process(target=child_crash,args=(str(tmp_path),binding,obligation)) process.start();process.join(10) if process.is_alive():process.terminate();process.join();pytest.fail('crash fixture exceeded bound') assert process.exitcode==29 journal=Journal(tmp_path) try: assert journal.observe(binding)['external_outcome_unknown'] assert not journal.cleanup_status(binding)['confirmed'] with journal.locked(): with pytest.raises(Refused):journal.before_cleanup_call(binding,0,obligation,1,'c'*64) finally:journal.close() def test_pending_native_subcall_never_confirms_parent_and_survives_unconfirmed(tmp_path): os.chmod(tmp_path,0o700);journal=Journal(tmp_path) binding=Binding('fixture-approval','sha256:'+'a'*64,str(uuid.uuid4()),'b'*64) obligation=Cleanup('task-token-revoke','d'*64) try: with journal.locked(): journal.reserve(binding,(obligation,));journal.transition(binding,'reserved','consume-confirmed') journal.before_cleanup(binding,0,obligation) journal.before_cleanup_call(binding,0,obligation,0,'c'*64) with pytest.raises(Refused):journal.after_cleanup(binding,0,obligation,confirmed=True,evidence_digest='e'*64) with pytest.raises(Refused):journal.before_cleanup_call(binding,0,obligation,1,'c'*64) for step in [False,0.0,'0',-1,2]: with pytest.raises(Refused):journal.after_cleanup_call(binding,0,obligation,step,'c'*64,'e'*64) journal.after_cleanup(binding,0,obligation,confirmed=False,evidence_digest='e'*64) assert journal.observe(binding)['external_outcome_unknown'] with pytest.raises(Refused):journal.after_cleanup_call(binding,0,obligation,0,'c'*64,'e'*64) finally:journal.close()