from pathlib import Path import sys,json,hashlib,zipfile,subprocess,ast R=Path('/home/jakub/devel/escapistsrereintroduced');B=Path(__file__).parent;F=R/'.build/playtest-source-2026-10-04-ui-bmp';C=R/'.build/playtest-2026-10-04-ui-bmp';N=R/'docs/evidence/native-2026-10-04-ui-bmp-normal-route';S=Path('/tmp/erri-native-root-20261004');P=Path('/tmp/erri-package-ui-bmp-20261004') sys.path.insert(0,str(F/'tools'));sys.path.insert(0,str(B)) from source_manifest import addon_manifest from source_bundle import build from pak_inventory import inventory as pak_inventory from packed_external import inventory from native_report import analyze from suite_binding import verify_suite_binding sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest();load=lambda p:json.loads(p.read_text()) def tree(p):return {str(q.relative_to(p)):sha(q) for q in sorted(p.rglob('*')) if q.is_file()} authored=addon_manifest(F);assert len(authored)==439 and authored==load(B/'authored.json')==load(P/'authored-before.json')==load(N/'source-sha256.json')==load(N/'launch-source-sha256.json') binding=verify_suite_binding(F,S,authored);assert binding['regression_programs']==309 code=load(S/'suite-result.json');assert len(code['programs'])==309 and code['exit']==0 and code['inputs_unchanged'] expected_bytes,manifest=build(F);assert expected_bytes==(C/'source.zip').read_bytes();assert sha(C/'source.zip')=='f33ed615d0b36770c8af4eb39eca3582b55006248daec57bda439cc128a97cea' with zipfile.ZipFile(C/'source.zip') as z: expected={n:hashlib.sha256(z.read(n)).hexdigest() for n in z.namelist()};assert len(expected)==len(z.namelist());assert tree(C/'source')==expected pak=pak_inventory(C/'packages/core/data.pak');actual={i['path']:i['sha256'] for i in pak['entries']};assert len(actual)==len(pak['entries'])==378 assert actual=={n.removeprefix('addons/core/'):v for n,v in authored.items() if not n.endswith('.meta') and not n.endswith('/addon.gproj')} runtime=inventory(C/'packages');assert len(runtime)==3 and runtime==inventory(P/'packages')==load(C/'handoff.json')['runtime_files'] report=load(N/'report.json');runner=load(N/'runner.json.txt');assert analyze((N/'console.log.txt').read_text(),report['log'])==report assert report['assertions_passed']==64 and report['smoke_completions']==1 and not report['script_or_runtime_failures'] and len(report['engine_errors'])==13 assert runner['result']=='smoke-completed' and runner['cleanup_confirmed'] and runner['source_unchanged_after_run'] and runner['external_addons_unchanged_after_run'] assert sha(N/'console.log.txt')==runner['console_sha256'] and sha(N/'launch-source-sha256.json')==runner['launch_source_sha256'] pkg=load(P/'package-report.json');attempt=pkg['projects'][0];assert pkg['project_order']==['core'] and len(pkg['projects'])==1 assert pkg['source_repository_unchanged'] and pkg['external_addons_unchanged_after_run'] and pkg['external_addon_count']==7 assert attempt['native_exit_code']==0 and attempt['runner_error'] is None and attempt['cleanup_confirmed'] and attempt['copied_authored_unchanged'] and attempt['profile_addons_unchanged'] and attempt['external_addons_unchanged_after_run'] assert not attempt['candidate_created'] and attempt['result']=='native-or-launcher-exited-prefix-active' base=load(B/'baseline.json');assert all(sha(R/n)==v for n,v in base['files'].items());assert addon_manifest(R)==authored assert hashlib.sha256(subprocess.check_output(['git','diff','--cached','--binary'],cwd=R)).hexdigest()==base['staged_diff_sha256'] orig=load(Path('/tmp/erri-heartbeat-20260930-1542-reference.json'));assert len(orig)==533 and all(sha(Path('/home/jakub/devel/escapists')/n)==v for n,v in orig.items()) prior={} for label in ['crash-start','depot-mines','ground-supply','mine-safety','mounted-pair']: m=R/f'docs/evidence/playtest-refresh-2026-10-03-{label}/candidate-sha256.json';assert tree(R/f'.build/playtest-2026-10-03-{label}')==load(m);prior[label]=sha(m) assert sha(B/'finish.py')=='268a26087aff4f765a1103d0015bc54b40b6bf33289c522bd12d0080b801dc20' r={'complete':False,'static_checks_complete':True,'pending':'Explicit packed verifier completion before final candidate file map/review','candidate':str(C),'authored_files':len(authored),'pak_payload_files':len(actual),'runtime':runtime,'zip_sha256':sha(C/'source.zip'),'zip_rederived_from_frozen_source':True,'extracted_source_exact_zip':True,'suite_binding':binding,'normal':{'passes':64,'completion':1,'script_failures':0,'engine_errors':13,'console_sha256':sha(N/'console.log.txt')},'package':{'report_sha256':sha(P/'package-report.json'),'native_exit_code':0,'strict_result':attempt['result'],'candidate_created':False,'cleanup_source_external_unchanged':True},'preservation':{'original_files':533,'original_manifest_sha256':sha(Path('/tmp/erri-heartbeat-20260930-1542-reference.json')),'prior_candidates':prior,'staged_diff_sha256':base['staged_diff_sha256'],'live_inputs_equal_baseline':True},'helpers':{n:sha(B/n) for n in ['freeze.py','suite_binding.py','assemble.py','verify.py','finish.py']},'finalizer_gap_closed':True} (B/'independent-static-review.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps({'static_checks':'PASS','sha256':sha(B/'independent-static-review.json')}))