import copy,hashlib,json,os,subprocess,tempfile,unittest from pathlib import Path from startup_timing_patch import patch_sidecar,ORIGINAL_SHA from startup_diagnostic import validate_pack_delta,validate_timing_sink,reject_sink_failure,post_run_integrity,finalize_diagnostic,PIN from diagnostic_lifecycle import DiagnosticChild,DiagnosticInspection from owned_processes import process_table,command_tokens,ProcessInspectionUnavailable from unittest.mock import patch from types import SimpleNamespace class FakeProcess: pid=111;returncode=0 def __init__(self,fail_wait=False):self.fail_wait=fail_wait def poll(self):return 0 def wait(self,timeout): if self.fail_wait:raise RuntimeError('wait failed') return 0 class FakeOwner: def __init__(self,fail_stop=False):self.fail_stop=fail_stop;self.stops=0 def observe(self,pid):pass def stop(self,pid): self.stops+=1 if self.fail_stop:raise RuntimeError('stop failed') return {'status':'stopped'} def live(self):return set() class DiagnosticTests(unittest.TestCase): @classmethod def setUpClass(cls):cls.original=Path(os.environ['PI_DIAGNOSTIC_ORIGINAL_SIDECAR']).read_bytes() def binding(self,root): p=root/'startup-timings.jsonl';p.touch(mode=0o600);s=p.stat() return p,{'path':str(p),**{k:str(getattr(s,'st_'+k)) for k in ['dev','ino','uid']}} def test_patch_is_exact_additions_only(self): sink={'path':'/private/tmp/pc-intel-diagnostic-fixture/startup-timings.jsonl','dev':'1','ino':'2','uid':'501'} patched,proof=patch_sidecar(self.original,sink);text=patched.decode();shift=0 for change in proof['insertions']: at=change['offset']+shift;self.assertEqual(text[at:at+len(change['inserted'])],change['inserted']);shift+=len(change['inserted']) for change in reversed(proof['insertions']): shift-=len(change['inserted']);at=change['offset']+shift;text=text[:at]+text[at+len(change['inserted']):] self.assertEqual(text.encode(),self.original);self.assertEqual(hashlib.sha256(text.encode()).hexdigest(),ORIGINAL_SHA) self.assertEqual(len(proof['phases']),54) def test_current_bba_patch_and_exact_retained_provenance(self): from startup_timing_patch import BBA_SHA from retained_qualification import validate_original,RetainedChild current=json.loads((Path(__file__).parent/'startup-diagnostic-bba-inputs.json').read_text()) original=Path(os.environ['PI_DIAGNOSTIC_BBA_SIDECAR']).read_bytes() modified,proof=patch_sidecar(original,{'path':'/private/tmp/pc-intel-diagnostic-fixture/startup-timings.jsonl','dev':'1','ino':'2','uid':'501'},BBA_SHA) self.assertEqual(proof['originalSha256'],BBA_SHA) text=modified.decode();shift=sum(len(x['inserted']) for x in proof['insertions']) for change in reversed(proof['insertions']): shift-=len(change['inserted']);at=change['offset']+shift self.assertEqual(text[at:at+len(change['inserted'])],change['inserted']) text=text[:at]+text[at+len(change['inserted']):] self.assertEqual(text.encode(),original);self.assertEqual(len(proof['phases']),54) self.assertEqual(current['sourceRevision'],'bba63f51207de8513ad2d9593694f718fc60ef17') self.assertEqual(current['artifactRunId'],'37004499595') self.assertTrue(current['repairedObserver']);self.assertTrue(current['compilerProvenanceValidated']) self.assertEqual(current['originalSidecarSha256'],BBA_SHA) self.assertEqual(current['testSha256'],PIN['testSha256']) validate_original(Path(os.environ['PI_DIAGNOSTIC_BBA_ORIGINAL_ARTIFACT']),current) with self.assertRaisesRegex(RuntimeError,'original digest mismatch'): patch_sidecar(original,{'path':'unused','dev':'1','ino':'2','uid':'3'}) workflow=(Path(__file__).parents[3]/'.github/workflows/docker-runner-check.yml').read_text() job=workflow.split(' manual_pi_startup_diagnostic:',1)[1].split(' manual_pi_startup_overlap:',1)[0] self.assertIn('--inputs bba',job);self.assertIn('artifacts/11226760000/zip',job) self.assertIn(current['artifactZipSha256'],job) fallback=workflow.split(' manual_image:',1)[1].split('\n needs:',1)[0] self.assertIn('!inputs.diagnose_pi_startup',fallback) def test_wrong_original_rejected(self): with self.assertRaises(RuntimeError):patch_sidecar(self.original+b' ',{'path':'unused','dev':'1','ino':'2','uid':'3'}) def test_retained_f5_pack_identity_and_original_test_contract(self): self.assertEqual(PIN['sourceRevision'],'f5c5fde380f60937ef26cc5a92e1d6a043e9cddc') self.assertEqual(PIN['artifactRunId'],'36984851998') self.assertEqual(PIN['artifactId'],'11218057612') self.assertEqual(PIN['originalSidecarSha256'],ORIGINAL_SHA) self.assertEqual(PIN['selectedFiles']['paperclip-runnerd']['sha256'],PIN['daemonSha256']) self.assertEqual(PIN['selectedFiles']['resolved-pnpm-lock.yaml']['sha256'],PIN['resolvedLockSha256']) self.assertEqual(PIN['testSha256'],'32bb057e1505082c0ed6b1d71cdd8cdb3271d920c2bea9cdc1ebddedf568c0c4') self.assertEqual((PIN['executionCount'],PIN['providerCalls'],PIN['timeoutChanges']),(1,0,False)) self.assertEqual((PIN['archiveBytesMaximum'],PIN['retentionDays']),(268435456,7)) def test_f5_markers_follow_outer_layout_and_snapshot_boundaries(self): _,proof=patch_sidecar(self.original,{'path':'/private/tmp/pc-intel-diagnostic-fixture/startup-timings.jsonl','dev':'1','ino':'2','uid':'501'}) phases=proof['phases'] self.assertFalse(any(p.startswith('pi.hash.') for p in phases)) for begin,end in [('pi.native_manifest.begin','pi.native_manifest.end'),('pi.discovery.begin','pi.discovery.end'),('pi.layout.begin','pi.layout.end'),('snapshot.directories.begin','snapshot.directories.end'),('snapshot.copy.begin','snapshot.copy.end'),('snapshot.seal.begin','snapshot.seal.end')]: self.assertEqual(phases.count(begin),1);self.assertEqual(phases.count(end),1) # Discovery recursion and descriptor-copy loops must not emit one row per file. source=self.original.decode() for begin,end in [(' const visit = async (directory) => {',' await visit(physicalRoot);'),(' const copyEntry = async (entry) => {',' const active = /* @__PURE__ */ new Set();')]: start=source.index(begin);finish=source.index(end,start) interior=[x for x in proof['insertions'] if start < x['offset'] < finish] self.assertEqual(interior,[]) def test_pi_acp_markers_preserve_actual_admission_and_no_native_rpc_claim(self): _,proof=patch_sidecar(self.original,{'path':'/private/tmp/pc-intel-diagnostic-fixture/startup-timings.jsonl','dev':'1','ino':'2','uid':'501'}) for phase in ['acp.initialize.begin','acp.initialize.response','pi.acp.session.request','pi.acp.correlated.response','pi.acp.mode.verified','pi.acp.thought_level.begin','pi.acp.thought_level.verified']: self.assertEqual(proof['phases'].count(phase),1) self.assertFalse(any('get_state' in phase for phase in proof['phases'])) source=self.original.decode() selected=next(x for x in proof['insertions'] if 'Mark("pi.acp.thought_level.verified")' in x['inserted']) self.assertTrue(source[:selected['offset']].endswith(' piThinking.assertReady();')) def test_unknown_rebind_profile_rejects_before_any_pack_access(self): result=subprocess.run([os.environ['PI_DIAGNOSTIC_TEST_NODE'],str(Path(__file__).parent/'rebind-diagnostic-pack.mjs'),'/nonexistent-pack','0'*64,'0'*40,'unknown'],capture_output=True,text=True,timeout=5) self.assertNotEqual(result.returncode,0);self.assertIn('Unexpected diagnostic profile mode',result.stderr);self.assertNotIn('ENOENT',result.stderr) def test_missing_terminal_retains_incomplete_classification(self): with tempfile.TemporaryDirectory() as tmp: p,b=self.binding(Path(tmp)) p.write_text(''.join(json.dumps({'phase':phase,'ns':str(i)})+'\n' for i,phase in enumerate(['sidecar.entry','session.open.begin','snapshot.copy.begin']))) with self.assertRaisesRegex(RuntimeError,'terminal marks missing'): validate_timing_sink(p,b,{'sidecar.entry','session.open.begin','snapshot.copy.begin','sidecar.exit'}) self.assertIn('snapshot.copy.begin',p.read_text()) def test_post_run_integrity_drains_checks_after_pack_failure(self): with tempfile.TemporaryDirectory() as tmp: root=Path(tmp);names=['daemon','test','source.tar','source-input-inventory.json','resolved-pnpm-lock.yaml'] for name in names:(root/name).write_bytes(name.encode()) digest=lambda name:hashlib.sha256(name.encode()).hexdigest() pin={'daemonSha256':digest('daemon'),'testSha256':digest('test'),'selectedFiles':{name:{'sha256':digest(name)} for name in names[2:]}} with patch('startup_diagnostic.closed_tree',side_effect=RuntimeError('mutation')): result=post_run_integrity(root,[],root/'daemon',root,root/'test',pin) self.assertFalse(result['passed']);self.assertTrue(result['complete']) self.assertEqual(result['checks'],{'pack':False,**{name:True for name in names}}) (root/'test').write_bytes(b'drift') with patch('startup_diagnostic.closed_tree',return_value=[]): result=post_run_integrity(root,[],root/'daemon',root,root/'test',pin) self.assertFalse(result['passed']);self.assertFalse(result['checks']['test']);self.assertTrue(result['checks']['resolved-pnpm-lock.yaml']) def test_partial_sink_finally_keeps_integrity_and_cleanup(self): proof={'status':'diagnostic_failed','timing':{'completeSink':False},'cleanupUncertain':False};calls=[] finalize_diagnostic(proof,None,lambda:(calls.append('integrity') or {'passed':True}),lambda:calls.append('retain'),lambda:calls.append('remove')) self.assertEqual(calls,['integrity','retain','remove']);self.assertTrue(proof['scratchRemoved']);self.assertFalse(proof['timing']['completeSink']);self.assertEqual(proof['status'],'diagnostic_failed') def test_finalization_integrity_and_retention_errors_do_not_block_cleanup(self): for failed_phase in ['integrity','retain']: proof={'cleanupUncertain':False};calls=[] def step(name): calls.append(name) if name==failed_phase:raise RuntimeError(name) return {'passed':True} with self.assertRaises(RuntimeError):finalize_diagnostic(proof,None,lambda:step('integrity'),lambda:step('retain'),lambda:step('remove')) self.assertEqual(calls,['integrity','retain','remove']);self.assertTrue(proof['scratchRemoved']);self.assertFalse(proof['cleanupUncertain']) def test_uncertain_cleanup_still_records_integrity_but_retains_scratch(self): active=DiagnosticChild(FakeOwner(fail_stop=True));active.child=FakeProcess();proof={'cleanupUncertain':False};calls=[] with self.assertRaises(RuntimeError):finalize_diagnostic(proof,active,lambda:(calls.append('integrity') or {'passed':True}),lambda:calls.append('retain'),lambda:self.fail('uncertain scratch removed')) self.assertEqual(calls,['integrity','retain']);self.assertTrue(proof['cleanupUncertain']) def test_numeric_inode_rejected(self): with self.assertRaises(RuntimeError):patch_sidecar(self.original,{'path':'/private/tmp/pc-intel-diagnostic-x/startup-timings.jsonl','dev':1,'ino':2,'uid':3}) def run_prelude(self,extra='',identity_mutation=None): with tempfile.TemporaryDirectory(prefix='pc-intel-diagnostic-',dir='/private/tmp') as tmp: root=Path(tmp);sink,binding=self.binding(root) if identity_mutation:identity_mutation(binding) _,proof=patch_sidecar(self.original,binding);prelude=next(r['inserted'] for r in proof['insertions'] if '// Explicit diagnostic derivative' in r['inserted']) script=root/'fixture.cjs';script.write_text(prelude+'\n__pcStartupDiagnosticMark("sidecar.entry");\n'+extra+'\n__pcStartupDiagnosticMark("session.open.begin");\n') run=subprocess.run([os.environ['PI_DIAGNOSTIC_TEST_NODE'],script],env={'PATH':'/usr/bin:/bin'},capture_output=True,text=True,timeout=10) self.assertEqual(run.returncode,0) if identity_mutation or extra: with self.assertRaises(RuntimeError):validate_timing_sink(sink,{k:str(getattr(sink.stat(),'st_'+k)) for k in ['dev','ino','uid']},set(proof['phases'])) else: rows=validate_timing_sink(sink,binding,set(proof['phases']))['rows'];self.assertEqual([r['phase'] for r in rows],['sidecar.entry','session.open.begin','sidecar.exit']) return run.stderr,sink.stat().st_size def test_sink_exact_identity_and_terminal(self):self.run_prelude() def test_sink_wrong_inode_is_failure(self):self.assertIn('SINK_FAILED',self.run_prelude(identity_mutation=lambda b:b.update(ino='0'))[0]) def test_sink_late_mode_change_prevents_complete_diagnosis(self):self.assertIn('SINK_FAILED',self.run_prelude('__pcStartupDiagnosticFs.chmodSync(__pcStartupDiagnosticBinding.path,0o400);')[0]) def test_sink_existing_near_cap_cannot_overflow(self): stderr,size=self.run_prelude('__pcStartupDiagnosticFs.appendFileSync(__pcStartupDiagnosticBinding.path,"x".repeat(32760-__pcStartupDiagnosticFs.statSync(__pcStartupDiagnosticBinding.path).size));') self.assertIn('SINK_FAILED',stderr);self.assertLessEqual(size,32768) def test_sink_row_cap_prevents_complete_diagnosis(self):self.assertIn('SINK_FAILED',self.run_prelude('for(let n=0;n<130;n++)__pcStartupDiagnosticMark("sidecar.dispatch");')[0]) def test_sink_parser_rejects_bad_rows(self): with tempfile.TemporaryDirectory() as tmp: root=Path(tmp);p,b=self.binding(root) for rows in [[{'phase':'sidecar.entry','ns':'2'},{'phase':'sidecar.exit','ns':'1'}],[{'phase':'unknown','ns':'1'}],[{'phase':'sidecar.entry','ns':'1','path':'secret'}]]: p.write_text(''.join(json.dumps(r)+'\n' for r in rows)) with self.assertRaises(RuntimeError):validate_timing_sink(p,b,{'sidecar.entry','sidecar.exit'}) def test_explicit_failure_marker_rejects_even_with_valid_terminal(self): with tempfile.TemporaryDirectory() as tmp: root=Path(tmp);p,b=self.binding(root) p.write_text(''.join(json.dumps({'phase':phase,'ns':str(i)})+'\n' for i,phase in enumerate(['sidecar.entry','session.open.begin','sidecar.exit']))) self.assertTrue(validate_timing_sink(p,b,{'sidecar.entry','session.open.begin','sidecar.exit'})['completeSink']) log=root/'runnerd.stderr.log';log.write_text('PC_STARTUP_DIAGNOSTIC_SINK_FAILED\n') with self.assertRaises(RuntimeError):reject_sink_failure([log]) def test_only_sidecar_and_manifest_delta(self): before=[{'path':p,'kind':'file','mode':0o644,'sha256':'a','size':1} for p in ['dist/cli/acpx-runtime-sidecar.cjs','provider-pack.json','vendor']] after=copy.deepcopy(before) for row in after[:2]:row['sha256']='b' self.assertEqual(len(validate_pack_delta(before,after)),2) after[2]['sha256']='b' with self.assertRaises(RuntimeError):validate_pack_delta(before,after) def test_complete_small_evidence_admitted_with_diagnostic_cap(self): from admit_evidence import admit_evidence from admit_diagnostic_evidence import MAX_DIAGNOSTIC_BYTES with tempfile.TemporaryDirectory() as tmp: root=Path(tmp);(root/'unique-sidecar').write_bytes(b'unique') result=admit_evidence(root,MAX_DIAGNOSTIC_BYTES) self.assertEqual(result['status'],'admitted_complete_evidence');self.assertEqual(result['maximumBytes'],268435456);self.assertEqual(result['retentionDays'],7) self.assertEqual((root/'unique-sidecar').read_bytes(),b'unique') def test_oversized_diagnostic_evidence_rejected_without_truncation(self): from admit_evidence import admit_evidence from admit_diagnostic_evidence import MAX_DIAGNOSTIC_BYTES with tempfile.TemporaryDirectory() as tmp: root=Path(tmp);p=root/'oversized-unique-evidence' with p.open('wb') as f:f.truncate(MAX_DIAGNOSTIC_BYTES+1) result=admit_evidence(root,MAX_DIAGNOSTIC_BYTES) self.assertEqual(result['status'],'rejected_storage_cap');self.assertFalse(result['truncated']);self.assertEqual(p.stat().st_size,MAX_DIAGNOSTIC_BYTES+1) def test_cancel_before_spawn(self): c=DiagnosticChild(FakeOwner());c.cancel('before');calls=[] with self.assertRaises(RuntimeError):c.execute(lambda:calls.append(True),1) self.assertEqual(calls,[]);self.assertFalse(c.uncertain) def test_cancel_during_spawn_publishes_then_retires(self): owner=FakeOwner();c=DiagnosticChild(owner);p=FakeProcess() def factory():c.cancel('during');return p with self.assertRaises(RuntimeError):c.execute(factory,1) self.assertIs(c.child,p);self.assertTrue(c.retired);self.assertEqual(owner.stops,1) def test_cancel_after_publication_retires_once(self): owner=FakeOwner();c=DiagnosticChild(owner) owner.observe=lambda pid:c.cancel('published') with self.assertRaises(RuntimeError):c.execute(lambda:FakeProcess(),1) self.assertTrue(c.retired);self.assertEqual(owner.stops,1) def test_stop_exception_sticky_and_no_second_launch(self): c=DiagnosticChild(FakeOwner(fail_stop=True)) with self.assertRaises(RuntimeError):c.execute(lambda:FakeProcess(),1) self.assertTrue(c.uncertain) with self.assertRaises(RuntimeError):c.execute(lambda:self.fail('second launch'),1) def test_wait_exception_sticky(self): c=DiagnosticChild(FakeOwner()) with self.assertRaises(RuntimeError):c.execute(lambda:FakeProcess(fail_wait=True),1) self.assertTrue(c.uncertain) def test_factory_exception_uncertain(self): c=DiagnosticChild(FakeOwner()) def factory():raise OSError('spawn uncertainty') with self.assertRaises(OSError):c.execute(factory,1) self.assertTrue(c.uncertain) class DiagnosticInspectionTests(unittest.TestCase): def fixture(self,now=10,active_end=80,cleanup_end=None): self.now=now owner=SimpleNamespace(stop_deadline=cleanup_end) child=SimpleNamespace(deadline=active_end,clock=lambda:self.now) return owner,child,DiagnosticInspection(owner,child) def test_shared_inspection_defaults_and_exact_commands(self): with patch('owned_processes.subprocess.check_output',return_value='') as run: self.assertEqual(process_table(),{}) run.assert_called_once_with(['/bin/ps','-axo','pid=,ppid=,lstart=,stat=,comm='],text=True,timeout=2) with patch('owned_processes.subprocess.check_output',return_value='node /owned/sidecar') as run: self.assertEqual(command_tokens(123),['node','/owned/sidecar']) run.assert_called_once_with(['/bin/ps','-p','123','-o','command='],text=True,stderr=subprocess.DEVNULL,timeout=2) def test_diagnostic_maximum_and_remaining_active_budget(self): _,_,inspection=self.fixture() with patch('owned_processes.subprocess.check_output',return_value='node') as run: inspection.table();self.assertEqual(run.call_args.kwargs['timeout'],5) inspection.argv(123);self.assertEqual(run.call_args.kwargs['timeout'],5) self.now=79.75;inspection.table();self.assertEqual(run.call_args.kwargs['timeout'],.25) self.now=79.9;inspection.argv(123);self.assertAlmostEqual(run.call_args.kwargs['timeout'],.1) def test_cleanup_budget_replaces_expired_active_deadline(self): owner,_,inspection=self.fixture(now=90,active_end=80,cleanup_end=190) with patch('owned_processes.subprocess.check_output',return_value='node') as run: inspection.table();self.assertEqual(run.call_args.kwargs['timeout'],5) self.now=189.75;inspection.argv(123);self.assertEqual(run.call_args.kwargs['timeout'],.25) def test_expired_or_unpublished_deadlines_never_launch_inspection(self): for active_end,cleanup_end in [(10,None),(None,None),(80,10)]: _,_,inspection=self.fixture(active_end=active_end,cleanup_end=cleanup_end) with patch('owned_processes.subprocess.check_output') as run: for invoke in [inspection.table,lambda:inspection.argv(123)]: with self.assertRaises(RuntimeError):invoke() run.assert_not_called() def test_active_argv_failure_fatal_cleanup_policy_preserved(self): owner,_,inspection=self.fixture() with patch('owned_processes.subprocess.check_output',side_effect=subprocess.TimeoutExpired('ps',5)) as run: with self.assertRaisesRegex(RuntimeError,'active argv inspection'):inspection.argv(123) self.assertEqual(run.call_count,1) owner.stop_deadline=110 with self.assertRaises(ProcessInspectionUnavailable):inspection.argv(123) self.assertEqual(run.call_count,2) def test_active_cadence_half_second_and_deadline_capped(self): owner=FakeOwner();child=DiagnosticChild(owner);process=FakeProcess();process.poll=lambda:None self.now=0;sleeps=[] def sleep(duration):sleeps.append(duration);self.now+=duration with self.assertRaisesRegex(RuntimeError,'outer deadline'): child.execute(lambda:process,1.2,clock=lambda:self.now,sleep=sleep) self.assertEqual(len(sleeps),3);self.assertEqual(sleeps[:2],[.5,.5]);self.assertAlmostEqual(sleeps[2],.2) self.assertTrue(child.retired);self.assertEqual(owner.stops,1) def test_active_table_timeout_fatal_retired_once_without_retry(self): owner=FakeOwner();child=DiagnosticChild(owner);process=FakeProcess();process.poll=lambda:None calls=[] def observe(pid): calls.append(pid) if len(calls)==2:raise subprocess.TimeoutExpired('ps',5) owner.observe=observe with self.assertRaises(subprocess.TimeoutExpired):child.execute(lambda:process,70) self.assertEqual(calls,[111,111]);self.assertEqual(owner.stops,1);self.assertTrue(child.retired) with self.assertRaises(RuntimeError):child.execute(lambda:self.fail('second launch'),70) def test_inspection_failure_with_cleanup_error_stays_uncertain(self): owner=FakeOwner(fail_stop=True);child=DiagnosticChild(owner) owner.observe=lambda pid:(_ for _ in ()).throw(subprocess.TimeoutExpired('ps',5)) with self.assertRaisesRegex(RuntimeError,'stop failed'):child.execute(lambda:FakeProcess(),70) self.assertTrue(child.uncertain);self.assertEqual(owner.stops,1) with self.assertRaises(RuntimeError):child.execute(lambda:self.fail('second launch'),70) if __name__=='__main__':unittest.main()