docs: preserve verified save diagnostics package and provenance
This commit is contained in:
+57
@@ -0,0 +1,57 @@
|
||||
"""Verify staging/archive/manifest equality, then extract into a fresh empty directory."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
import hashlib, json, stat, zipfile
|
||||
|
||||
root = Path(__file__).resolve().parent / 'package46'
|
||||
archives = list((root / 'dist').glob('*.zip'))
|
||||
assert len(archives) == 1
|
||||
archive = archives[0]
|
||||
sha = lambda data: hashlib.sha256(data).hexdigest()
|
||||
checksum_lines = Path(str(archive) + '.sha256').read_text().splitlines()
|
||||
assert len(checksum_lines) == 1
|
||||
expected, checksum_name = checksum_lines[0].split(' ', 1)
|
||||
assert checksum_name == archive.name
|
||||
assert sha(archive.read_bytes()) == expected
|
||||
stage = archive.with_suffix('')
|
||||
assert stage.is_dir()
|
||||
prefix = stage.name + '/'
|
||||
|
||||
def inventory(directory):
|
||||
return {p.relative_to(directory).as_posix(): sha(p.read_bytes())
|
||||
for p in directory.rglob('*') if p.is_file()}
|
||||
|
||||
stage_inventory = inventory(stage)
|
||||
manifest = {}
|
||||
for line in (stage / 'SHA256SUMS.txt').read_text().splitlines():
|
||||
digest, name = line.split(' ', 1)
|
||||
path = PurePosixPath(name)
|
||||
assert name and not path.is_absolute() and '..' not in path.parts and '\\' not in name and ':' not in name
|
||||
assert name not in manifest
|
||||
assert stage_inventory[name] == digest
|
||||
manifest[name] = digest
|
||||
assert set(stage_inventory) == set(manifest) | {'SHA256SUMS.txt'}
|
||||
target = root / 'extracted'
|
||||
assert target.is_dir() and not list(target.iterdir()), 'Never overwrite a previous extraction'
|
||||
with zipfile.ZipFile(archive) as z:
|
||||
names = z.namelist()
|
||||
assert len(names) == len({n.casefold() for n in names}) == len(stage_inventory)
|
||||
assert set(names) == {prefix + n for n in stage_inventory}
|
||||
for entry in z.infolist():
|
||||
path = PurePosixPath(entry.filename)
|
||||
assert not path.is_absolute() and '..' not in path.parts and '\\' not in entry.filename and ':' not in entry.filename
|
||||
assert entry.filename.startswith(prefix) and not entry.is_dir()
|
||||
assert not stat.S_ISLNK(entry.external_attr >> 16)
|
||||
assert sha(z.read(entry)) == stage_inventory[entry.filename[len(prefix):]]
|
||||
assert z.testzip() is None
|
||||
z.extractall(target)
|
||||
bundle = target / stage.name
|
||||
assert inventory(bundle) == stage_inventory
|
||||
package = json.loads((bundle / 'package.json').read_text(encoding='utf-8-sig'))
|
||||
assert package['version'] == '0.2.0-preview.save-diagnostics.20261001'
|
||||
assert package['target'] == 'x86_64-pc-windows-gnullvm'
|
||||
report = {'status': 'PASS', 'archive': archive.name, 'archive_bytes': archive.stat().st_size,
|
||||
'archive_sha256': expected, 'files': len(stage_inventory), 'bundle': str(bundle),
|
||||
'stage_archive_extraction_exact': True, 'sha256': stage_inventory}
|
||||
with (root / 'extraction-check.json').open('x', encoding='utf-8') as f:
|
||||
json.dump(report, f, indent=2); f.write('\n')
|
||||
print(json.dumps({k: v for k, v in report.items() if k != 'sha256'}, indent=2))
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
from pathlib import Path
|
||||
import datetime, hashlib, json, os, platform, subprocess
|
||||
|
||||
root = Path(__file__).resolve().parent / 'package46'
|
||||
record = json.loads((root / 'extraction-check.json').read_text())
|
||||
bundle = Path(record['bundle'])
|
||||
native = root / 'qa/native46'
|
||||
work = root / 'working'
|
||||
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
def inventory(p):
|
||||
return {f.relative_to(p).as_posix(): sha(f) for f in p.rglob('*') if f.is_file()}
|
||||
assert inventory(bundle) == record['sha256']
|
||||
system = os.environ['SystemRoot']
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = str(Path(system) / 'System32') + ';' + system
|
||||
for key in list(env):
|
||||
if key.startswith(('CARGO_', 'RUST', 'LLVM', 'WGPU', 'ARCADIA_')):
|
||||
del env[key]
|
||||
command = [str(bundle / 'arcadia-studio.exe')]
|
||||
receipt = {'source': '0e83157e09d52e6152df91208e41693b62da2d46',
|
||||
'package_documentation_source': 'ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47',
|
||||
'start': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'command': command, 'cwd': str(work), 'path': env['PATH'], 'platform': platform.platform(),
|
||||
'archive_sha256': record['archive_sha256'],
|
||||
'binary_sha256': sha(Path(command[0])), 'runtime_sha256': sha(bundle / 'libunwind.dll')}
|
||||
with (native / 'stdout.log').open('xb') as out, (native / 'stderr.log').open('xb') as err:
|
||||
child = subprocess.Popen(command, cwd=work, env=env, stdout=out, stderr=err,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
receipt['pid'] = child.pid
|
||||
(native / 'started.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
|
||||
print(json.dumps(receipt, indent=2), flush=True)
|
||||
code = child.wait()
|
||||
receipt.update({'exit_code': code, 'finished': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'stdout_bytes': (native / 'stdout.log').stat().st_size,
|
||||
'stderr_bytes': (native / 'stderr.log').stat().st_size,
|
||||
'package_files_unchanged': inventory(bundle) == record['sha256']})
|
||||
(native / 'finished.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
|
||||
print(json.dumps(receipt, indent=2), flush=True)
|
||||
assert code == 0 and receipt['stdout_bytes'] == receipt['stderr_bytes'] == 0 and receipt['package_files_unchanged']
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
from pathlib import Path
|
||||
import datetime, hashlib, json, os, platform, subprocess
|
||||
|
||||
root = Path(__file__).resolve().parent / 'package46'
|
||||
record = json.loads((root / 'extraction-check.json').read_text())
|
||||
bundle = Path(record['bundle'])
|
||||
native = root / 'qa/reopen46'
|
||||
native.mkdir(exist_ok=False)
|
||||
work = root / 'working'
|
||||
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
def inventory(p):
|
||||
return {f.relative_to(p).as_posix(): sha(f) for f in p.rglob('*') if f.is_file()}
|
||||
assert inventory(bundle) == record['sha256']
|
||||
system = os.environ['SystemRoot']
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = str(Path(system) / 'System32') + ';' + system
|
||||
for key in list(env):
|
||||
if key.startswith(('CARGO_', 'RUST', 'LLVM', 'WGPU', 'ARCADIA_')):
|
||||
del env[key]
|
||||
command = [str(bundle / 'arcadia-studio.exe')]
|
||||
receipt = {'source': '0e83157e09d52e6152df91208e41693b62da2d46',
|
||||
'package_documentation_source': 'ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47',
|
||||
'start': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'command': command, 'cwd': str(work), 'path': env['PATH'], 'platform': platform.platform(),
|
||||
'archive_sha256': record['archive_sha256'],
|
||||
'binary_sha256': sha(Path(command[0])), 'runtime_sha256': sha(bundle / 'libunwind.dll')}
|
||||
with (native / 'stdout.log').open('xb') as out, (native / 'stderr.log').open('xb') as err:
|
||||
child = subprocess.Popen(command, cwd=work, env=env, stdout=out, stderr=err,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
receipt['pid'] = child.pid
|
||||
(native / 'started.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
|
||||
print(json.dumps(receipt, indent=2), flush=True)
|
||||
code = child.wait()
|
||||
receipt.update({'exit_code': code, 'finished': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'stdout_bytes': (native / 'stdout.log').stat().st_size,
|
||||
'stderr_bytes': (native / 'stderr.log').stat().st_size,
|
||||
'package_files_unchanged': inventory(bundle) == record['sha256']})
|
||||
(native / 'finished.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
|
||||
print(json.dumps(receipt, indent=2), flush=True)
|
||||
assert code == 0 and receipt['stdout_bytes'] == receipt['stderr_bytes'] == 0 and receipt['package_files_unchanged']
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Package46 preparation helper review handoff
|
||||
|
||||
Only `.local/prepare-package46.py` and this note were authored. The helper was
|
||||
not executed; no package46 directory, binaries, archive, GUI run, API mutation,
|
||||
commit, or release was produced by this subtask. Parent owns review/execution.
|
||||
|
||||
Read-only comparisons found no relevant changes from desktop source
|
||||
`0e83157e09d52e6152df91208e41693b62da2d46` or server source
|
||||
`715036e132677dd2bc2fb37ed316d93dc9987aec` to checkpoint
|
||||
`ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47`. Helper repeats these checks,
|
||||
requires clean status and exact checkpoint, hashes original/copy bytes, snapshots
|
||||
tracked package inputs, and refuses an existing `.local/package46` directory.
|
||||
An interrupted/failed attempt remains for inspection; no automatic cleanup.
|
||||
|
||||
The immediate donor `package.json` was hashed read-only as
|
||||
`36bcff8a760c08674f3fc017bb5affc8a5f4f39174ac9d5a29298f2423155832`.
|
||||
Its original server source is read from nested `original_build_evidence`, not
|
||||
from the mixed desktop/server/documentation `source_identity`. Both original
|
||||
and immediate donor source assertions survive separately, and its entire raw
|
||||
package manifest is copied without rewriting historical paths or hashes.
|
||||
|
||||
The historical final-04 directory named in donor source-manifest/environment/
|
||||
mandatory-gate/artifact-relocation assertions is absent at its original path.
|
||||
The helper explicitly records that limitation, preserving the original hashes.
|
||||
It does not claim to have recovered raw original product-build receipts from
|
||||
those assertions. Parent should attach available relocated originals to the
|
||||
new evidence packet before claiming stronger donor verification. Desktop
|
||||
commands/build/Clippy/test/native-freeze receipts are copied as raw bytes.
|
||||
|
||||
After review, run from the scoped checkout using bundled Python:
|
||||
|
||||
```powershell
|
||||
& 'C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe' .local/prepare-package46.py
|
||||
```
|
||||
|
||||
Then use the explicitly adapted matching packaging environment, preserving
|
||||
`CARGO_BUILD_JOBS=1`, GNU LLVM target, rustc 1.98.1 and LLVM-MinGW 20260826:
|
||||
|
||||
```powershell
|
||||
./scripts/package-windows.ps1 -Target x86_64-pc-windows-gnullvm `
|
||||
-Version '0.2.0-preview.save-diagnostics.20261001' `
|
||||
-BinaryDirectory 'C:/ar-save-01a0d717/.local/package46/bin' `
|
||||
-BuildEvidence 'C:/ar-save-01a0d717/.local/package46/build-evidence.json' `
|
||||
-LlvmMinGWRoot 'C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/llvm-mingw-20260826-ucrt-x86_64' `
|
||||
-Python 'C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe' `
|
||||
-OutputRoot 'C:/ar-save-01a0d717/.local/package46/dist'
|
||||
```
|
||||
|
||||
These are proposed commands, not execution evidence. Neither preparation nor
|
||||
packaging is compilation or native acceptance. New extraction, exact archive
|
||||
inventory, server smoke, native workflows, evidence review and publication
|
||||
remain parent work as detailed in `save-diagnostics-package-plan.md`. Existing
|
||||
release 7/8 and donor records remain unchanged. If the packaging checkpoint
|
||||
changes, review the comparisons and explicitly repin CHECKPOINT; the helper
|
||||
intentionally fails instead of accepting an arbitrary new HEAD.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
from pathlib import Path
|
||||
root = Path(__file__).resolve().parent
|
||||
original = (root / 'native46/native-model-oracle.py').read_text(encoding='utf-8')
|
||||
text = original
|
||||
changes = [
|
||||
("proof=json.loads(Path('C:/ar-compact-01a0d717/.local/package39/extraction-check.json').read_text(encoding='utf-8'))", "proof=json.loads((root/'extraction-check.json').read_text(encoding='utf-8'))"),
|
||||
("[(bundle/'examples/release1','project.arcadia'),(root/'fresh-c','project.arcadia')]", "[(bundle/'examples/release1','project.arcadia'),(root/'working/collision-a','project.arcadia'),(root/'working/fresh-c','project.arcadia')]"),
|
||||
('Assess pressure alarm QA46', 'Assess pressure alarm Package46'),
|
||||
("assert models[1]==expected,'Complete saved Project must have only declared Activity-name delta'", "assert models[1]==models[2]==expected,'Both complete saved Projects must have only declared Activity-name delta'"),
|
||||
]
|
||||
for before, after in changes:
|
||||
expected_occurrences = 2 if before == 'Assess pressure alarm QA46' else 1
|
||||
assert text.count(before) == expected_occurrences, before
|
||||
text = text.replace(before, after)
|
||||
assert text != original and 'C:/ar-compact-' not in text and 'QA46' not in text
|
||||
output = root / 'package46/native-model-oracle.py'
|
||||
with output.open('x', encoding='utf-8', newline='\n') as f:
|
||||
f.write(text)
|
||||
print('Adapted known complete model/source oracle to the actual #46 extraction and both edited source destinations; execution pending')
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from pathlib import Path
|
||||
root = Path(__file__).resolve().parent
|
||||
source = (root / 'launch-package46-native.py').read_text(encoding='utf-8')
|
||||
assert source.count("native = root / 'qa/native46'") == 1
|
||||
source = source.replace("native = root / 'qa/native46'", "native = root / 'qa/reopen46'\nnative.mkdir(exist_ok=False)")
|
||||
with (root / 'launch-package46-reopen.py').open('x', encoding='utf-8', newline='\n') as f:
|
||||
f.write(source)
|
||||
print('Created fresh-session watcher with separate exclusive logs/receipts.')
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
from pathlib import Path
|
||||
root = Path(__file__).resolve().parent / 'package46'
|
||||
source = Path('C:/ar-compact-01a0d717/.local/package39/read-model-warnings.py').read_bytes()
|
||||
with (root / 'read-model-warnings.py').open('xb') as f:
|
||||
f.write(source)
|
||||
print('Copied unchanged read-only warning probe; root is derived from helper location.')
|
||||
+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()
|
||||
@@ -0,0 +1,119 @@
|
||||
"""Read-only public donor retrieval; never executes archive contents."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import stat
|
||||
import urllib.request
|
||||
import zipfile
|
||||
import zlib
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
COMMIT = '206f3b969482241e01e2dfc6be955caf31747b89'
|
||||
BASE = ('http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/raw/commit/' + COMMIT
|
||||
+ '/harness/prerelease37-windows-gates-20260924/final04-complete/')
|
||||
|
||||
|
||||
class NoRedirect(urllib.request.HTTPRedirectHandler):
|
||||
def redirect_request(self, *args, **kwargs):
|
||||
raise RuntimeError('Redirect refused')
|
||||
|
||||
|
||||
def require(value, message):
|
||||
if not value:
|
||||
raise RuntimeError(message)
|
||||
|
||||
|
||||
def safe(name):
|
||||
p = PurePosixPath(name)
|
||||
require(name and not p.is_absolute() and '\\' not in name and ':' not in name
|
||||
and all(x not in ('', '.', '..') for x in name.split('/')),
|
||||
'Unsafe archive path')
|
||||
require(all(x.rstrip(' .') == x and x.split('.')[0].upper() not in
|
||||
{'CON', 'PRN', 'AUX', 'NUL', *('COM' + str(i) for i in range(10)),
|
||||
*('LPT' + str(i) for i in range(10))} for x in p.parts), 'Unsafe Windows path')
|
||||
return name
|
||||
|
||||
|
||||
def main():
|
||||
data = (ROOT / 'manifest.json').read_bytes()
|
||||
require(len(data) == 103364 and hashlib.sha1(b'blob 103364\0' + data).hexdigest()
|
||||
== '5d246cc2ca69c6aaaffaa5dc70ec1be2bdae4262', 'Manifest Git blob mismatch')
|
||||
m = json.loads(data)
|
||||
require(m['source_commit'] == '715036e132677dd2bc2fb37ed316d93dc9987aec', 'Source mismatch')
|
||||
require(m['archive'] == 'final04-complete-715036e.zip', 'Unexpected archive name')
|
||||
expected_size = 6588421
|
||||
expected_hash = '7cead0b6aa36a6af8fc9f8987186bfe0decd8fa2ebab094fc45387ae9daea632'
|
||||
require(m['archive_bytes'] == expected_size and m['archive_sha256'] == expected_hash,
|
||||
'Archive manifest mismatch')
|
||||
with urllib.request.build_opener(NoRedirect).open(BASE + m['archive'], timeout=45) as response:
|
||||
require(response.status == 200, 'Unexpected HTTP status')
|
||||
archive = response.read(expected_size + 1)
|
||||
require(len(archive) == expected_size and hashlib.sha256(archive).hexdigest() == expected_hash,
|
||||
'Archive bytes mismatch')
|
||||
members = m['members']
|
||||
require(len(members) == 462, 'Manifest count mismatch')
|
||||
expected = {safe(f['path']): f for f in members}
|
||||
require(len(expected) == len(members) and len({p.casefold() for p in expected}) == len(expected),
|
||||
'Duplicate manifest paths')
|
||||
require(sum(f['bytes'] for f in members) <= 45000000, 'Expanded size cap exceeded')
|
||||
selected = {'final-04/' + name for name in
|
||||
['summary.json', 'inputs-before.json', 'environment.json', 'artifact-relocation.json']}
|
||||
selected.update(p for p in expected if p.startswith(('final-04/arcadia-server-build/',
|
||||
'final-04/arcadia-studio-build/')))
|
||||
payloads = {}
|
||||
with zipfile.ZipFile(io.BytesIO(archive)) as z:
|
||||
infos = z.infolist()
|
||||
require(len(infos) == 462 and len({f.filename.casefold() for f in infos}) == 462,
|
||||
'Archive duplicate/count mismatch')
|
||||
require({safe(f.filename) for f in infos} == set(expected), 'Archive set mismatch')
|
||||
# Verify every member before reading any payload as structured data or
|
||||
# writing selected portable files. CRC is also checked by ZipFile.read.
|
||||
for info in infos:
|
||||
require(not info.is_dir() and not stat.S_ISLNK(info.external_attr >> 16)
|
||||
and not (info.flag_bits & 1), 'Directory, symlink or encrypted member refused')
|
||||
f = expected[info.filename]
|
||||
require(info.file_size == f['bytes'] and info.file_size <= 5000000, 'Member size mismatch/cap')
|
||||
require(f'{info.CRC:08x}' == f['crc32'], 'Member header CRC mismatch')
|
||||
payload = z.read(info)
|
||||
require(len(payload) == f['bytes'] and hashlib.sha256(payload).hexdigest() == f['sha256']
|
||||
and f'{zlib.crc32(payload):08x}' == f['crc32'], 'Member integrity mismatch')
|
||||
if info.filename in selected:
|
||||
payloads[info.filename] = payload
|
||||
|
||||
assertions = json.loads((ROOT.parent.parent / 'harness/experiments/save-as-diagnostics-20261001/donor/build-evidence.json').read_text())['binary_origins']['arcadia-server.exe']['original_build_evidence']
|
||||
recovered = {}
|
||||
for key, name in [('mandatory_gate', 'summary.json'), ('source_manifest', 'inputs-before.json'),
|
||||
('environment', 'environment.json'), ('artifact_relocation', 'artifact-relocation.json')]:
|
||||
member = 'final-04/' + name
|
||||
f = expected[member]
|
||||
require(all(f[k] == assertions[key][k] for k in ['bytes', 'sha256']), 'Original assertion mismatch: ' + key)
|
||||
recovered[key] = {'member': member, 'portable_path': 'selected/' + member,
|
||||
'bytes': f['bytes'], 'sha256': f['sha256'], 'original_assertion': assertions[key]}
|
||||
require(not (ROOT / 'selected').exists() and not (ROOT / 'receipt.json').exists(), 'Recovery already exists')
|
||||
with (ROOT / m['archive']).open('xb') as stream:
|
||||
stream.write(archive)
|
||||
for name, payload in payloads.items():
|
||||
dest = ROOT / 'selected' / name
|
||||
require(dest.resolve().is_relative_to((ROOT / 'selected').resolve()), 'Extraction escape')
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
with dest.open('xb') as stream:
|
||||
stream.write(payload)
|
||||
result = {'publication_commit': COMMIT, 'source_commit': m['source_commit'],
|
||||
'manifest_url': BASE + 'manifest.json', 'manifest_git_blob': '5d246cc2ca69c6aaaffaa5dc70ec1be2bdae4262',
|
||||
'manifest_bytes': len(data), 'manifest_sha256': hashlib.sha256(data).hexdigest(),
|
||||
'archive_url': BASE + m['archive'], 'archive_bytes': len(archive), 'archive_sha256': expected_hash,
|
||||
'verified_members': len(members), 'verified_expanded_bytes': sum(f['bytes'] for f in members),
|
||||
'all_member_checks': 'Safe unique relative paths, exact set/count, size, CRC32 and SHA256; no archive code executed.',
|
||||
'recovered_original_receipts': recovered,
|
||||
'selected_files': {name: expected[name] for name in sorted(payloads)},
|
||||
'scope': 'Public immutable receipt recovery only; historical donor claims retained; not new build/native/package acceptance.'}
|
||||
with (ROOT / 'receipt.json').open('x', encoding='utf-8') as stream:
|
||||
json.dump(result, stream, indent=2)
|
||||
stream.write('\n')
|
||||
print(json.dumps({'archive_sha256': expected_hash, 'verified_members': len(members),
|
||||
'selected_count': len(payloads), 'recovered_keys': list(recovered)}, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
from pathlib import Path
|
||||
import hashlib, json, shutil
|
||||
|
||||
root = Path(__file__).resolve().parent / 'package46'
|
||||
record = json.loads((root / 'extraction-check.json').read_text())
|
||||
bundle = Path(record['bundle'])
|
||||
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
assert sha(bundle / 'arcadia-studio.exe') == 'e9cce9355525ecdc59bfae12608b1e0272167acef5a86b25368ef547e08886ff'
|
||||
assert sha(bundle / 'libunwind.dll') == 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4'
|
||||
native = root / 'qa/native46'
|
||||
native.mkdir()
|
||||
(native / 'captures').mkdir()
|
||||
work = root / 'working'
|
||||
work.mkdir()
|
||||
fixture = bundle / 'examples/release1'
|
||||
def inventory(p):
|
||||
return {f.relative_to(p).as_posix(): {'bytes': f.stat().st_size, 'sha256': sha(f)}
|
||||
for f in p.rglob('*') if f.is_file()}
|
||||
baseline = inventory(fixture)
|
||||
assert len(baseline) == 37
|
||||
for name in ['collision-a', 'external-b']:
|
||||
shutil.copytree(fixture, work / name)
|
||||
assert inventory(work / name) == baseline
|
||||
fresh = work / 'fresh-c'
|
||||
fresh.mkdir()
|
||||
for f in fixture.rglob('*'):
|
||||
if f.is_file() and f.suffix != '.arcadia':
|
||||
p = fresh / f.relative_to(fixture)
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(f, p)
|
||||
assert len(inventory(fresh)) == 7 and not list(fresh.rglob('*.arcadia'))
|
||||
receipt = {'source': '0e83157e09d52e6152df91208e41693b62da2d46',
|
||||
'package_documentation_source': 'ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47',
|
||||
'archive_sha256': record['archive_sha256'], 'bundle': str(bundle),
|
||||
'baseline': baseline, 'fresh_companions': inventory(fresh),
|
||||
'declared_rename': {'activity': '61f7bbfb-74a4-5540-9182-2583dfb27a49',
|
||||
'before': 'Assess pressure alarm', 'after': 'Assess pressure alarm Package46'},
|
||||
'external_dependency': 'oa/activities/activity_oa_restore_work.arcadia',
|
||||
'external_comment': '\n// Package46 observed external-edit probe\n'}
|
||||
with (native / 'baseline.json').open('x', encoding='utf-8') as f:
|
||||
json.dump(receipt, f, indent=2); f.write('\n')
|
||||
print(json.dumps({k: v for k, v in receipt.items() if k not in ['baseline', 'fresh_companions']}, indent=2))
|
||||
Reference in New Issue
Block a user