Files
ARCADIA-Studio/harness/experiments/save-diagnostics-package-20261001/raw/scripts/prepare-package46.py
T

234 lines
14 KiB
Python

"""Freeze existing #46 package inputs; no compilation, launch, or acceptance claim.
Run only after parent review. Failure preserves its partial fresh directory for
inspection; never delete/reuse that directory automatically.
"""
from pathlib import Path
import hashlib
import json
import shutil
import subprocess
ROOT = Path('C:/ar-save-01a0d717')
QA = ROOT / '.local/package46'
CHECKPOINT = 'ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47'
DESKTOP_SOURCE = '0e83157e09d52e6152df91208e41693b62da2d46'
SERVER_SOURCE = '715036e132677dd2bc2fb37ed316d93dc9987aec'
VERSION = '0.2.0-preview.save-diagnostics.20261001'
TARGET = 'x86_64-pc-windows-gnullvm'
COMPILER = 'rustc 1.98.1 (48a229cea 2026-09-01)'
DONOR = Path('C:/ar-compact-01a0d717/.local/package39/extracted/'
'ArcadiaStudio-0.2.0-preview.compact-help.20261001-x86_64-pc-windows-gnullvm')
NATIVE = ROOT / '.local/native46/bin'
PACKET = ROOT / 'harness/experiments/save-as-diagnostics-20261001'
RECOVERY = ROOT / '.local/package46-donor-recovery'
TOOLCHAIN = Path('C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/'
'llvm-mingw-20260826-ucrt-x86_64')
EXPECTED = {
'arcadia-studio.exe': 'e9cce9355525ecdc59bfae12608b1e0272167acef5a86b25368ef547e08886ff',
'arcadia-server.exe': '6cebacc117e46fdab023c6402a5cebd6929fb55993ae8ff6b89cd1c6c1170237',
'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
}
DESKTOP_PATHS = ['crates', 'Cargo.toml', 'Cargo.lock', 'examples', 'docs', 'scripts', 'LICENSE', 'README.md']
SERVER_PATHS = ['crates/oa-core', 'crates/oa-server', 'crates/vendor', 'Cargo.toml', 'Cargo.lock']
def require(condition, message):
if not condition:
raise RuntimeError(message)
def git(*args):
return subprocess.check_output(['git', *args], cwd=ROOT, text=True).strip()
def receipt(path):
return {'bytes': path.stat().st_size, 'sha256': hashlib.sha256(path.read_bytes()).hexdigest()}
def read_json(path):
return json.loads(path.read_text(encoding='utf-8-sig'))
def write_json(path, value):
with path.open('x', encoding='utf-8', newline='\n') as stream:
json.dump(value, stream, indent=2)
stream.write('\n')
def main():
require(not QA.exists(), 'Fresh package46 directory required; do not overwrite a prior attempt')
require(not git('status', '--porcelain'), 'Source changes must be reviewed and committed first')
require(git('rev-parse', 'HEAD') == CHECKPOINT, 'Checkpoint changed; parent must review and repin helper')
comparisons = []
for origin, paths in [(DESKTOP_SOURCE, DESKTOP_PATHS), (SERVER_SOURCE, SERVER_PATHS)]:
command = ['diff', '--exit-code', origin, CHECKPOINT, '--', *paths]
subprocess.run(['git', *command], cwd=ROOT, check=True)
comparisons.append({'command': ['git', *command], 'exit_code': 0, 'unchanged': True})
sources = {name: (DONOR if name == 'arcadia-server.exe' else NATIVE) / name for name in EXPECTED}
for name, source in sources.items():
require(receipt(source)['sha256'] == EXPECTED[name], f'Frozen input mismatch: {name}')
require(sources['arcadia-studio.exe'].stat().st_size == 119452672, 'Desktop size mismatch')
require(sources['libunwind.dll'].stat().st_size == 190976, 'Runtime size mismatch')
require(receipt(TOOLCHAIN / 'x86_64-w64-mingw32/bin/libunwind.dll')['sha256'] == EXPECTED['libunwind.dll'],
'Installed LLVM-MinGW runtime mismatch')
donor_manifest = DONOR / 'package.json'
require(receipt(donor_manifest)['sha256'] == '36bcff8a760c08674f3fc017bb5affc8a5f4f39174ac9d5a29298f2423155832',
'Donor package manifest changed')
manifest = read_json(donor_manifest)
donor_evidence = manifest['build_evidence']['evidence']
server_origin = donor_evidence['binary_origins']['arcadia-server.exe']
original = server_origin['original_build_evidence']
require(server_origin['source'] == original['source_identity'] == SERVER_SOURCE, 'Server origin mismatch')
require(original['binary_sha256']['arcadia-server.exe'] == EXPECTED['arcadia-server.exe'], 'Original server receipt mismatch')
require(manifest['input_sha256']['arcadia-server.exe'] == EXPECTED['arcadia-server.exe'], 'Donor server mismatch')
require(donor_evidence['binary_sha256']['arcadia-server.exe'] == EXPECTED['arcadia-server.exe'], 'Donor evidence mismatch')
require(donor_evidence['target'] == original['target'] == TARGET, 'Donor target mismatch')
require(donor_evidence['compiler'] == original['compiler'] == COMPILER, 'Donor compiler mismatch')
require(read_json(PACKET / 'donor/build-evidence.json') == donor_evidence, 'Recorded donor evidence mismatch')
baseline = read_json(PACKET / 'native/baseline.json')
require(baseline['source'] == DESKTOP_SOURCE, 'Desktop native source mismatch')
require(baseline['binary'] == receipt(sources['arcadia-studio.exe']), 'Desktop native identity mismatch')
require(baseline['runtime'] == receipt(sources['libunwind.dll']), 'Runtime native identity mismatch')
commands = read_json(PACKET / 'commands.json')
require(commands['source'] == DESKTOP_SOURCE and commands['target'] == TARGET, 'Desktop build source/target mismatch')
recovery_receipt = RECOVERY / 'receipt.json'
require(receipt(recovery_receipt)['sha256'] == '5d630ff25489262188b8e35f1a2f0208bffd90eed6051d8845250509e9fac8ef',
'Pinned donor recovery receipt mismatch')
recovered = read_json(recovery_receipt)
require(recovered['publication_commit'] == '206f3b969482241e01e2dfc6be955caf31747b89'
and recovered['source_commit'] == SERVER_SOURCE and recovered['verified_members'] == 462,
'Recovered publication/source mismatch')
for name, item in recovered['selected_files'].items():
path = RECOVERY / 'selected' / name
require(path.resolve().is_relative_to((RECOVERY / 'selected').resolve()), 'Recovery path escapes root')
require(receipt(path) == {k: item[k] for k in ['bytes', 'sha256']}, 'Recovered file mismatch: ' + name)
for key, item in recovered['recovered_original_receipts'].items():
require(item['original_assertion'] == original[key], 'Recovered original assertion mismatch: ' + key)
server_result = read_json(RECOVERY / 'selected/final-04/arcadia-server-build/result.json')
require(server_result['source_commit'] == SERVER_SOURCE and server_result['target'] == TARGET
and server_result['profile'] == 'dev' and server_result['exit_code'] == 0
and server_result['inputs_unchanged'], 'Recovered server build result mismatch')
relocation = read_json(RECOVERY / 'selected/final-04/artifact-relocation.json')
server_artifacts = [a for a in relocation['artifacts'] if a.get('cargo_artifact')
and a['cargo_artifact']['target']['name'] == 'arcadia-server']
require(len(server_artifacts) == 1 and server_artifacts[0]['preserved']['sha256'] == EXPECTED['arcadia-server.exe'],
'Recovered server Cargo artifact mismatch')
# This is a byte snapshot, not an assertion of a reproducible compiler build.
tracked = git('ls-files', '--', *DESKTOP_PATHS).splitlines()
tree = subprocess.check_output(['git', 'ls-tree', '-rz', CHECKPOINT, '--', *DESKTOP_PATHS], cwd=ROOT)
blobs = {}
for entry in tree.split(b'\0'):
if not entry:
continue
metadata, name = entry.split(b'\t', 1)
mode, kind, blob = metadata.decode('ascii').split()
require(kind == 'blob' and mode in ['100644', '100755'], 'Unexpected tracked input type')
blobs[name.decode('utf-8')] = blob
require(set(blobs) == set(tracked), 'Frozen Git input set mismatch')
inputs = {name: {'git_blob': blobs[name], **receipt(ROOT / name)} for name in tracked}
QA.mkdir(exist_ok=False)
for directory in ['bin', 'provenance', 'dist', 'extracted', 'qa', 'release-assets']:
(QA / directory).mkdir()
copies = {}
def copy(source, relative):
dest = QA / relative
require(not dest.exists(), f'Refusing overwrite: {relative}')
shutil.copyfile(source, dest)
identity = receipt(source)
require(receipt(dest) == identity, f'Copy mismatch: {relative}')
copies[relative] = {'original_path': str(source), **identity}
for name, source in sources.items():
copy(source, 'bin/' + name)
copy(donor_manifest, 'provenance/donor-package.json')
copy(recovery_receipt, 'provenance/recovered-donor-receipt.json')
copy(RECOVERY / 'manifest.json', 'provenance/recovered-donor-manifest.json')
recovered_copies = {}
for name in recovered['selected_files']:
relative = 'provenance/recovered-' + name.replace('/', '--')
copy(RECOVERY / 'selected' / name, relative)
recovered_copies[name] = relative
for relative in ['donor/build-evidence.json', 'native/baseline.json', 'commands.json',
'gates/save-diagnostics-build.log', 'gates/save-diagnostics-clippy.log',
'gates/save-diagnostics-corrected-tests.log']:
copy(PACKET / relative, 'provenance/' + relative.replace('/', '--'))
# Keep original assertions untouched, including their historical paths and
# hashes. Missing historical files are recorded, never silently re-created.
historical = {}
for key in ['mandatory_gate', 'source_manifest', 'environment', 'artifact_relocation']:
assertion = original[key]
path = Path(assertion['path'])
item = {'original_assertion': assertion, 'original_path_available': path.is_file()}
if path.is_file():
require(receipt(path) == {k: assertion[k] for k in ['bytes', 'sha256']}, f'Original receipt mismatch: {key}')
copy(path, 'provenance/original-' + key + '.json')
item['verified_copy'] = 'provenance/original-' + key + '.json'
else:
item['historical_path_note'] = 'Original path unavailable; exact bytes recovered from immutable published archive.'
portable = recovered['recovered_original_receipts'][key]
item['recovered_verified_copy'] = recovered_copies[portable['member']]
item['recovered_sha256'] = portable['sha256']
item['publication_commit'] = recovered['publication_commit']
historical[key] = item
evidence = {
'source_identity': f'Desktop: {DESKTOP_SOURCE}; unchanged reused server: {SERVER_SOURCE}; package documentation: {CHECKPOINT}',
'profile': 'dev, unoptimized, debug assertions enabled',
'compiler': COMPILER,
'target': TARGET,
'binary_sha256': {name: EXPECTED[name] for name in ['arcadia-studio.exe', 'arcadia-server.exe']},
'binary_origins': {
'arcadia-studio.exe': {
'source': DESKTOP_SOURCE, 'reuse': True,
'build_command': 'cargo build --locked -p oa-desktop --bin arcadia-studio',
'build_jobs': 1, 'incremental': False,
'evidence': 'harness/experiments/save-as-diagnostics-20261001/commands.json',
'build_log': 'harness/experiments/save-as-diagnostics-20261001/gates/save-diagnostics-build.log',
'native_evidence': 'harness/save-as-diagnostics-20261001.md',
'native_freeze_receipt': 'harness/experiments/save-as-diagnostics-20261001/native/baseline.json',
'unchanged_input_check': comparisons[0],
},
'arcadia-server.exe': {
'source': SERVER_SOURCE, 'reuse': True,
'release': server_origin['release'],
'immediate_donor_version': manifest['version'],
'immediate_donor_manifest': copies['provenance/donor-package.json'],
'original_build_evidence': original,
'historical_receipt_availability': historical,
'recovered_publication': recovered,
'recovered_portable_copies': recovered_copies,
'original_toolchain_note': 'Historical server build receipt names LLVM-MinGW 20260908; current packaging runtime distribution is separately recorded. No rebuild or environment rewrite.',
'unchanged_input_check': comparisons[1],
},
},
'package_documentation_source': CHECKPOINT,
'planned_version': VERSION,
'runtime_sha256': EXPECTED['libunwind.dll'],
'runtime_origin': {'distribution': 'llvm-mingw-20260826-ucrt-x86_64', 'path': str(TOOLCHAIN),
'note': 'Packaging script must include and verify the full distribution license.'},
'input_snapshot': 'source-inputs.json',
'preserved_provenance': copies,
'acceptance_scope': 'Preparation of existing frozen binaries only; no compilation or extracted-package/native acceptance. Contribution gates and inherited donor gates remain separate; no summed/full-suite, peer-union, new-platform, or complete OA/SA acceptance claim.',
}
write_json(QA / 'source-inputs.json', {'source': CHECKPOINT, 'files': inputs, 'unchanged_input_comparisons': comparisons})
write_json(QA / 'build-evidence.json', evidence)
require(git('rev-parse', 'HEAD') == CHECKPOINT and not git('status', '--porcelain'), 'Source changed during preparation')
for name, expected in inputs.items():
require(receipt(ROOT / name) == {k: expected[k] for k in ['bytes', 'sha256']}, f'Input changed during preparation: {name}')
for name in EXPECTED:
require(receipt(QA / 'bin' / name)['sha256'] == EXPECTED[name], f'Frozen copy changed: {name}')
write_json(QA / 'preparation-receipt.json', {'source': CHECKPOINT, 'version': VERSION,
'binary_sha256': EXPECTED, 'build_evidence': receipt(QA / 'build-evidence.json'),
'source_inputs': receipt(QA / 'source-inputs.json'), 'scope': 'Input preparation only; package and runtime checks pending.'})
print(json.dumps({'source': CHECKPOINT, 'prepared': str(QA), 'binary_sha256': EXPECTED}, indent=2))
if __name__ == '__main__':
main()