from pathlib import Path import hashlib import io import json import re import zipfile root = Path(__file__).resolve().parent def digest(data): return {'bytes':len(data), 'sha256':hashlib.sha256(data).hexdigest()} def require(ok, message): if not ok: raise SystemExit(message) manifest = json.loads((root / 'files.json').read_text()) actual = {p.relative_to(root).as_posix() for p in root.rglob('*') if p.is_file() and p.name != 'files.json' and '__pycache__' not in p.parts} require(actual == set(manifest), 'Outer membership mismatch') for name, expected in manifest.items(): require(digest((root/name).read_bytes()) == expected, f'Outer hash: {name}') with zipfile.ZipFile(root / 'evidence.zip') as evidence: def read(name): return json.loads(evidence.read(name)) payloads = read('capture-files.json') require(set(evidence.namelist()) == set(payloads) | {'capture-files.json'}, 'Capture membership mismatch') for name, expected in payloads.items(): require(digest(evidence.read(name)) == expected, f'Capture hash: {name}') for gate, status in [('production-focused-1',0),('production-core-1',101)]: result = read(gate+'/result.json') require(result['exitCode'] == status and result['inputsUnchanged'], f'{gate}: outcome') require(all(result[k] == v for k,v in read(gate+'/started.json').items()), f'{gate}: start') for key, file in [('inputs','inputs.json'),('archive','inputs.zip'),('stdout','stdout.log'),('stderr','stderr.log')]: require(digest(evidence.read(gate+'/'+file)) == result[key], f'{gate}: {key}') require(digest(evidence.read('gate-policy.py')) == result['helper'], f'{gate}: runner') inputs = read(gate+'/inputs.json') require(len(inputs) == result['inputCount'], f'{gate}: input count') with zipfile.ZipFile(io.BytesIO(evidence.read(gate+'/inputs.zip'))) as sources: require(set(sources.namelist()) == set(inputs), f'{gate}: source membership') for path, expected in inputs.items(): require(digest(sources.read(path)) == expected, f'{gate}: source {path}') def totals(prefix, filenames): rows = [tuple(map(int,m)) for f in filenames for m in re.findall(r'test result: (?:ok|FAILED)\. (\d+) passed; (\d+) failed; (\d+) ignored;', evidence.read(prefix+f).decode())] return tuple(sum(row[i] for row in rows) for i in range(3)) require(totals('production-focused-1/', ['stdout.log']) == (75,0,0), 'Focused totals') require(b'No space left on device' in evidence.read('production-core-1/stdout.log'), 'Missing disk failure evidence') built = read('production-built-tests-1/results.json') compiler = {r['cargo']['target']['name']:r for r in read('production-core-1/result.json')['artifacts']} require(len(built) == 36, 'Built test inventory') for run in built: name = run['name'] require(run['binary'] == compiler[name]['readback'], f'{name}: binary receipt') for stream in ['stdout','stderr']: require(digest(evidence.read(f'production-built-tests-1/{name}.{stream}.log')) == run[stream], f'{name}: stream') require(totals('production-built-tests-1/', [r['name']+'.stdout.log' for r in built]) == (354,2,1), 'Built test totals') receipt = read('production-built-tests-1/receipt.json') require(receipt['inputsUnchanged'] and receipt['testsRun'] == 36, 'Execution receipt') teaching = read('production-teaching-1/result.json') require(teaching['nonSourceFilesUnchanged'] and len(teaching['changed']) == 29, 'Teaching delta') require(all(p.endswith('.arcadia') for p in teaching['changed']), 'Non-source teaching change') for run in teaching['runs']: require(run['exitCode'] == 0 and run['binary'] == compiler[run['name']]['readback'], 'Teaching runner receipt') require(totals('production-teaching-1/', ['release1_teaching.stdout.log']) == (4,0,0), 'Teaching rerun') require(read('language-doc-3/result.json')['warnings']['bytes'] == 0, 'Documentation warnings') print('Verified captures: focused 75 pass; disk-limited build; separately executed 354 pass/2 fail/1 ignored; teaching rerun 4 pass.') print('Final candidate still needs corrected anchor test, full core, strict Clippy, native/public-consumer and release verification.')