"""Read-only exact source/build preflight. No metadata, compiler or application run.""" from pathlib import Path, PurePosixPath import argparse import datetime import hashlib import json import os import subprocess import tomllib ROOT = Path(__file__).resolve().parents[2] WORK = ROOT / '.local/canvas-union-ytr83r-20260911' GATES = ROOT / '.local/repair-union-windows-20260911' SOURCE = '33e30c1cd7a6c99513a0ebd02ba68fccbad8f58d' SERVER_SOURCE = '321897fd55af9e07afa2c6ebf1e50be49e86f7d9' FREEZE = '0f21b9a852cf44699bf29fce0a35ec460744c85f5e26f0ea4920e8568211e312' SERVER = 'aba87a5fb795deb995029a737c2ebb9d2b44c8d274edaa2295363b226d9af6be' DLL = 'aa282fa47bb2c4e210cea5e470cdbdca58568f0be0bc73e404d86ab9cd95ef6a' TREES = {'crates/oa-core': 'a9c71e2c3fc9260d06f191c0d65b1e63e41edbec', 'crates/oa-server': '99dbbe3a17d45d7030fc14a31fad2c07332d8d86'} PACKAGING = { 'scripts/package-windows.ps1': '82d690683a76f1e9eb6b35eaecf97d59b0f781f9a71ae9aec1434b4a84298142', 'scripts/package-common.ps1': '22d60b19df0f6d5ed37b743f5175678f72f6a9b24658f8bcd90a20bb9d98a931', 'scripts/package-artifacts.py': '655711b051a3cd2d478d9b15ba27be9b63c5b056be80ade8da4dabc6bb46a91c', 'scripts/windows-notices.ps1': 'ac70b61937076416c50b104fd9f7e127880748764fa59c21105312cb291369ed', } def require(condition, message): if not condition: raise RuntimeError(message) def digest(data): return hashlib.sha256(data).hexdigest() def ordinary(path): require(path.is_file(), f'Missing file: {path}') for current in [path, *path.parents]: require(not current.is_symlink() and not (getattr(current.stat(), 'st_file_attributes', 0) & 0x400), f'Reparse input is unsupported: {current}') return path def read_json(path): return json.loads(ordinary(path).read_text(encoding='utf-8-sig')) def file_record(path): data = ordinary(path).read_bytes() return {'path': str(path), 'bytes': len(data), 'sha256': digest(data)} def git(*args, data=None): options = {'creationflags': subprocess.CREATE_NO_WINDOW} if os.name == 'nt' else {} return subprocess.run(['git', '--no-optional-locks', '-C', str(WORK), *args], input=data, capture_output=True, check=True, **options).stdout def verify_source(): for path, expected in PACKAGING.items(): require(file_record(WORK / path)['sha256'] == expected, f'Reviewed packaging script changed: {path}') manifest_path = GATES / 'inputs.json' require(digest(ordinary(manifest_path).read_bytes()) == FREEZE, 'Unexpected input manifest') manifest = read_json(manifest_path) files = manifest['files'] require(len(files) == 530 and sum(f['bytes'] for f in files) == 9727025, 'Unexpected frozen input count/size') names = [f['path'] for f in files] require(names == sorted(set(names)), 'Duplicate or unordered frozen input paths') paths = git('ls-files', '-co', '--exclude-standard', '--', 'crates', 'assets', 'build', '.cargo', 'examples', 'docs', 'harness/fixtures', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain', 'rust-toolchain.toml').decode().splitlines() require(sorted(set(paths)) == names, 'Current input inventory differs from freeze') for item in files: path = PurePosixPath(item['path']) require(not path.is_absolute() and '..' not in path.parts and '\\' not in item['path'] and ':' not in item['path'], 'Invalid manifest path') actual = file_record(WORK.joinpath(*path.parts)) require(actual['bytes'] == item['bytes'] and actual['sha256'] == item['sha256'], f'Working source differs from freeze: {path}') for ref in (SOURCE, 'HEAD'): response = git('cat-file', '--batch', data=''.join(f'{ref}:{n}\n' for n in names).encode()) offset = 0 for item in files: end = response.index(b'\n', offset) header = response[offset:end].split() require(len(header) == 3 and header[1] == b'blob', f'Missing {ref}:{item["path"]}') size = int(header[2]) data = response[end + 1:end + 1 + size] require(size == item['bytes'] and digest(data) == item['sha256'], f'Raw committed source differs: {ref}:{item["path"]}') offset = end + size + 2 require(offset == len(response), 'Unexpected Git batch output') for path, expected in TREES.items(): for ref in (SOURCE, SERVER_SOURCE): require(git('rev-parse', f'{ref}:{path}').decode().strip() == expected, f'Server component tree mismatch: {ref}:{path}') require(git('show', f'{SOURCE}:Cargo.toml') == git('show', f'{SERVER_SOURCE}:Cargo.toml'), 'Workspace manifest changed since server build') old_lock = tomllib.loads(git('show', f'{SERVER_SOURCE}:Cargo.lock').decode()) new_lock = tomllib.loads(git('show', f'{SOURCE}:Cargo.lock').decode()) old_desktop = [p for p in old_lock['package'] if p['name'] == 'oa-desktop'] new_desktop = [p for p in new_lock['package'] if p['name'] == 'oa-desktop'] require(len(old_desktop) == len(new_desktop) == 1, 'Ambiguous desktop lock record') require('unicode-segmentation' not in old_desktop[0]['dependencies'], 'Unexpected old lock') old_desktop[0]['dependencies'].append('unicode-segmentation') old_desktop[0]['dependencies'].sort() require(old_lock == new_lock, 'Cargo.lock differs beyond desktop-only segmentation edge') server_manifest = read_json(ROOT / '.local/server-windows-321897f/manifest.json') require(server_manifest['source_commit'] == SERVER_SOURCE and server_manifest['core_tree'] == TREES['crates/oa-core'] and server_manifest['server_tree'] == TREES['crates/oa-server'] and server_manifest['profile'] == 'debug', 'Server provenance mismatch') server_file = file_record(ROOT / '.local/server-windows-321897f/arcadia-server.exe') require(server_file['sha256'] == SERVER and server_file['bytes'] == 39621120, 'Immutable server changed') return {'source_commit': SOURCE, 'head': git('rev-parse', 'HEAD').decode().strip(), 'manifest_sha256': FREEZE, 'files': len(files), 'bytes': 9727025, 'server_manifest': server_manifest, 'server_file': server_file, 'server_reuse': 'Identical core/server trees and workspace manifest; sole lock delta is oa-desktop unicode-segmentation edge.'} def verify_build(result): statuses = {} for name in ('focused', 'desktop-tests', 'desktop-clippy', 'studio-build'): path = GATES / f'{name}-status.json' status = read_json(path) require(status.get('exit') == 0 and status.get('completed_utc') and status.get('name') == f'repair-union-windows-20260911/{name}', f'Missing, failed or mismatched terminal gate: {name}') ordinary(Path(status['log'])) statuses[name] = status manifest = read_json(GATES / 'binary-manifest.json') require(manifest['source_identity'].split(';')[0] == SOURCE and manifest['input_manifest_sha256'].lower() == FREEZE and manifest['verified_inputs'] == 530 and manifest['verified_input_bytes'] == 9727025, 'Binary manifest is not the matching freeze') require(manifest['gate_statuses'] == statuses, 'Preserved gate records differ from terminal statuses') verified = read_json(GATES / 'verify-after-build.json') require(verified.get('pass') is True and verified['mode'] == 'verify-head' and verified['files'] == 530 and verified['bytes'] == 9727025 and verified['manifest_sha256'].lower() == FREEZE, 'Missing matching post-build verification') binaries = {} for name in ('arcadia-studio.exe', 'libunwind.dll'): actual = file_record(GATES / 'bin' / name) records = [r for r in manifest['binaries'] if Path(r['copy']).name == name] require(len(records) == 1, f'Binary manifest missing/duplicates {name}') rec = records[0] require(Path(rec['copy']).resolve() == (GATES / 'bin' / name).resolve() and rec['bytes'] == actual['bytes'], f'Wrong preserved binary: {name}') require(all(rec[k].lower() == actual['sha256'] for k in ('source_sha256', 'copy_sha256', 'source_after_sha256')), f'Preserved binary hash mismatch: {name}') binaries[name] = actual require(binaries['libunwind.dll']['sha256'] == DLL, 'Preserved runtime differs') runtime = file_record(ROOT / '.local/toolchain/llvm-mingw-20260908-ucrt-x86_64/x86_64-w64-mingw32/bin/libunwind.dll') require(runtime['sha256'] == DLL, 'Packaging runtime differs') environment = read_json(GATES / 'environment.json') require(environment['rustup_toolchain'] == 'stable-x86_64-pc-windows-gnullvm' and environment['rustc_version'].startswith('rustc 1.98.1 '), 'Unexpected build compiler') result.update(gate_statuses=statuses, binary_manifest=manifest, binaries=binaries, environment=environment, packaging_runtime=runtime) return result if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--source-only', action='store_true', help='Verify existing source/server only; never sufficient to package.') args = parser.parse_args() # Refuse absent/failed gates before paying for the complete source inventory. result = {} if args.source_only else verify_build({}) result.update(verify_source()) result.update(pass_preflight=True, scope='source-only' if args.source_only else 'source-and-build', verified_utc=datetime.datetime.now(datetime.timezone.utc).isoformat()) print(json.dumps(result, indent=2))