88 lines
5.6 KiB
Python
88 lines
5.6 KiB
Python
"""Exact closed-run evidence preservation; no oracle execution or mutable work reads."""
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
destination = Path(__file__).resolve().parent
|
|
repository = destination.parents[2]
|
|
source = repository / '.local/native-qa/scenario-20260911-v5'
|
|
def digest(data):
|
|
return hashlib.sha256(data).hexdigest()
|
|
records = []
|
|
def copy(src, relative):
|
|
data = src.read_bytes()
|
|
target = destination / relative
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
if target.exists():
|
|
assert target.read_bytes() == data, f'Existing evidence differs: {relative}'
|
|
else:
|
|
with target.open('xb') as output:
|
|
output.write(data)
|
|
assert src.read_bytes() == target.read_bytes() == data
|
|
record = {'path': relative, 'original_path': src.relative_to(repository).as_posix(),
|
|
'bytes': len(data), 'sha256': digest(data)}
|
|
records.append(record)
|
|
return record
|
|
|
|
checkpoints = []
|
|
baseline = None
|
|
baseline_sources = []
|
|
directories = sorted(p for p in source.iterdir() if p.is_dir() and p.name.startswith('checkpoint-'))
|
|
assert len(directories) == 14, 'Unexpected checkpoint inventory; review instead of omitting data'
|
|
for checkpoint in directories:
|
|
files = sorted(p for p in checkpoint.rglob('*') if p.is_file())
|
|
names = [p.relative_to(checkpoint).as_posix() for p in files]
|
|
assert names == ['expected-baseline.json', 'project.arcadia', 'rationale.arcadia'], (checkpoint.name, names)
|
|
physical = []
|
|
for path in files:
|
|
relative = path.relative_to(checkpoint).as_posix()
|
|
data = path.read_bytes()
|
|
if relative == 'expected-baseline.json':
|
|
if baseline is None:
|
|
baseline = data
|
|
copy(path, 'common/expected-baseline.json')
|
|
else:
|
|
assert data == baseline, 'Baseline JSON is not identical across checkpoints'
|
|
saved = 'common/expected-baseline.json'
|
|
baseline_sources.append(path.relative_to(repository).as_posix())
|
|
else:
|
|
saved = checkpoint.name + '/' + relative
|
|
copy(path, saved)
|
|
physical.append({'name': relative, 'original_path': path.relative_to(repository).as_posix(),
|
|
'bytes': len(data), 'sha256': digest(data), 'preserved_path': saved})
|
|
checkpoints.append({'name': checkpoint.name, 'physical_files': physical,
|
|
'reachable_source_files': ['project.arcadia', 'rationale.arcadia'],
|
|
'baseline_json_role': 'Immutable expected evidence copied with the fixture; not model source or a fresh post-edit expectation.'})
|
|
|
|
for path in sorted(source.iterdir()):
|
|
if path.is_file() and (path.suffix in ('.log', '.png') or path.name == 'oracle-provenance.json'):
|
|
folder = 'screenshots' if path.suffix == '.png' else 'logs' if path.suffix == '.log' else 'provenance'
|
|
copy(path, folder + '/' + path.name)
|
|
|
|
provenance = json.loads((destination / 'provenance/oracle-provenance.json').read_text(encoding='utf-8-sig'))
|
|
report = repository / 'harness/release-scenario-native-local-20260911.md'
|
|
result = {'format_version': 1,
|
|
'scope': 'Closed D4D9 native v5: OA four B2 creations with individual Undo/Redo and final OA reopen; prior OA wide/minimum and SA minimum B3 navigation. No local SA B2 or later contextual/B4 acceptance.',
|
|
'original_directory': source.relative_to(repository).as_posix(),
|
|
'source_report': {'path': report.relative_to(repository).as_posix(), 'sha256_at_preservation': digest(report.read_bytes())},
|
|
'gui_sha256_from_source_report': 'd4d9c2bd937e301ff1009d7cb93a34ee5aa6dfc837ff7e87d468c85371b20c31',
|
|
'oracle_provenance': provenance,
|
|
'copy_method': 'Original and destination bytes compared after copy; no executable invocation, source parsing/normalization, model expectation changes or mutable work reads.',
|
|
'checkpoints': checkpoints,
|
|
'deduplicated_baseline': {'path': 'common/expected-baseline.json', 'bytes': len(baseline),
|
|
'sha256': digest(baseline), 'identical_original_paths': baseline_sources},
|
|
'excluded': {'directories': ['work'], 'files': ['scenario-authoring-contract.exe', 'libunwind.dll'],
|
|
'already_committed_contracts': ['harness/scenario-authoring-contract.rs', 'harness/fixtures/scenario-authoring/base/']},
|
|
'counts': {'checkpoints': len(checkpoints), 'original_physical_checkpoint_files': sum(len(c['physical_files']) for c in checkpoints),
|
|
'copied_payload_files': len(records), 'copied_payload_bytes': sum(r['bytes'] for r in records),
|
|
'source_files': sum(r['path'].endswith('.arcadia') for r in records),
|
|
'unique_baseline_json': 1, 'logs': sum(r['path'].startswith('logs/') for r in records),
|
|
'screenshots': sum(r['path'].startswith('screenshots/') for r in records),
|
|
'provenance_files': sum(r['path'].startswith('provenance/') for r in records)},
|
|
'files': records}
|
|
(destination / 'manifest.json').write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8', newline='\n')
|
|
(destination / 'SHA256SUMS.txt').write_text(''.join(f"{item['sha256']} {item['path']}\n" for item in sorted(records, key=lambda x: x['path'])), encoding='utf-8', newline='\n')
|
|
print(json.dumps({'status': 'PASS exact preservation', 'counts': result['counts'],
|
|
'manifest_sha256': digest((destination / 'manifest.json').read_bytes()),
|
|
'payload_checksums_sha256': digest((destination / 'SHA256SUMS.txt').read_bytes())}, indent=2))
|