docs: preserve verified save diagnostics package and provenance
This commit is contained in:
+233
@@ -0,0 +1,233 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user