#!/usr/bin/env python3 """Archive an isolated native run and the exact current addon sources; never overwrite evidence. Run only after stopping the test and before editing/copying its source tree again. """ from pathlib import Path import argparse,hashlib,json,shutil,subprocess,sys ROOT=Path(__file__).resolve().parents[1] p=argparse.ArgumentParser(description=__doc__) p.add_argument('session',type=Path) p.add_argument('name',help='New evidence directory name, e.g. native-2026-09-19-003231') a=p.parse_args() if Path(a.name).name!=a.name or a.name in {'.','..'}:p.error('Name must be one directory component') source=a.session.resolve() if not (source/'console.log').is_file():p.error('Session has no console.log') dest=ROOT/'docs/evidence'/a.name try:dest.mkdir(parents=True,exist_ok=False) except FileExistsError:p.error('Evidence already exists; refusing to overwrite') for name in ['console.log','script.log','error.log','rereintroduced-hq.log','headless-launch.log','runner.json']: if (source/name).is_file():shutil.copyfile(source/name,dest/(name+'.txt')) for capture in sorted(source.glob('err-*.png')): if capture.is_file():shutil.copyfile(capture,dest/capture.name) suffixes={'.c','.conf','.meta','.et','.ent','.layer','.gproj','.layout','.emat'} manifest={str(f.relative_to(ROOT)):hashlib.sha256(f.read_bytes()).hexdigest() for f in sorted((ROOT/'addons').rglob('*')) if f.is_file() and f.suffix in suffixes} (dest/'source-sha256.json').write_text(json.dumps(manifest,indent=2)+'\n') with (dest/'report.json').open('w') as report: result=subprocess.run([sys.executable,str(ROOT/'tools/native_report.py'),str((dest/'console.log.txt').relative_to(ROOT))],cwd=ROOT,stdout=report) print(f'Archived {dest.relative_to(ROOT)}; native report exit={result.returncode} (nonzero retains failures)') sys.exit(result.returncode)