Files
ARCADIA-Studio/harness/experiments/nested-lifecycle-union-20260912/tools/archive-lifecycle-union-f6595eb.py
T

224 lines
11 KiB
Python

"""Archive f659 source evidence, or verify it; never stage, apply, build, or commit.
From repository root:
python .local/archive-lifecycle-union-f6595eb.py create
python .local/archive-lifecycle-union-f6595eb.py verify
# After the integration owner stages the archive:
python .local/archive-lifecycle-union-f6595eb.py verify-index
The archived tools/ copy supports the same commands from repository root.
Creation refuses overwrite. A failed partial archive is retained for diagnosis.
"""
from pathlib import Path, PurePosixPath
from datetime import datetime, timezone
import argparse
import hashlib
import json
import subprocess
BASE = 'd61f1f38779ab70a77efcde523ae31c432aefcfd'
SOURCE = 'f6595ebf66e88ec42c37b5c1a3c014f5e52cb32d'
PREFIX = 'harness/experiments/nested-lifecycle-union-20260912'
SCRIPT_NAME = 'archive-lifecycle-union-f6595eb.py'
PATCH_PATH = 'patches/d61f1f3-to-f6595eb.patch'
FILES = {
'crates/oa-desktop/src/behavior.rs': ('0a0c4df479ff1c46f935735e508144ca2ec3052f', 133741),
'crates/oa-desktop/src/behavior/scenario_activation.rs': ('88fa4d6e861fc96f4dc5497088cd9119cf25e151', 17694),
'crates/oa-desktop/src/behavior/scenario_lifecycle.rs': ('6fe044890864ecf3095d0fedf590104f6121abf7', 9348),
'crates/oa-desktop/src/behavior/scenario_lifecycle/render.rs': ('989fb2d5b173fc68e50705f8d406f7786ba9c979', 14820),
'crates/oa-desktop/src/behavior/scenario_lifecycle/render_tests.rs': ('e0d9ee812a49fb1f8b24b0e9e460e08cd42aa34f', 35358),
'crates/oa-desktop/src/behavior/scenario_lifecycle/union_tests.rs': ('86fa0cceff11ff66497c3514e43659a0ca003a52', 18024),
}
NOTES = {
'source-handoff.md': ('.local/nested-lifecycle-union-handoff-20260912.md', 8668,
'2c28f4ffca8e84626cf4bf7580504a008fe971dda7eb0e9b83d94695bcb42410'),
'independent-review.md': ('.local/nested-lifecycle-union-independent-review-20260912.md', 9736,
'3b5b116ca7a15f2b5bac313fab9a91966e2fa64f75cc7fc4509332208dd8f29c'),
}
README = '''# Nested lifecycle / typed activation source union
Source: `f6595ebf66e88ec42c37b5c1a3c014f5e52cb32d`.
Base: `d61f1f38779ab70a77efcde523ae31c432aefcfd`.
- [Source handoff](source-handoff.md)
- [Independent source review](independent-review.md)
- [Exact committed source snapshot](source/crates/oa-desktop/src/behavior.rs)
- [Full-index binary Git patch](patches/d61f1f3-to-f6595eb.patch)
- [Payload manifest](manifest.json)
- [Archive/verification helper](tools/archive-lifecycle-union-f6595eb.py)
The six source files are extracted from committed Git blobs; they are evidence,
not an additional production tree. Notes retain their original bytes, including
historical local paths and source-scoped statements. The manifest lists portable
archive-relative paths plus original source provenance. It does not claim tests,
native acceptance, import, or publication succeeded. Subsequent gates remain
separate source-identified records owned by the integration owner.
From repository root, run the helper with `verify` to compare payload bytes,
manifest metadata, source blobs and regenerated patch. After owner-controlled
staging, run `verify-index` to additionally compare every payload and manifest
with Git index blobs. Neither mode stages or rewrites files. If Git attributes
normalize archived bytes, index verification fails; the owner must resolve that
explicitly. No patch is applied by this helper.
'''.encode('utf-8')
def require(condition, message):
if not condition:
raise RuntimeError(message)
def git(root, *args, data=None):
return subprocess.run(['git', '--no-pager', *args], cwd=root, input=data,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True).stdout
def digest(raw):
return {'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()}
def safe_path(base, relative):
parts = PurePosixPath(relative)
require(not parts.is_absolute() and '..' not in parts.parts and '\\' not in relative,
f'Unsafe relative path: {relative}')
path = base.joinpath(*parts.parts)
require(path.resolve().is_relative_to(base.resolve()), f'Path escapes archive: {relative}')
for ancestor in [path, *path.parents]:
require(not ancestor.is_symlink(), f'Symlinks are not archive evidence: {ancestor}')
if ancestor == base:
break
return path
def committed_payloads(root):
require(git(root, 'cat-file', '-t', SOURCE).strip() == b'commit', 'Source is not a commit')
require(git(root, 'cat-file', '-t', BASE).strip() == b'commit', 'Base is not a commit')
require(git(root, 'rev-parse', SOURCE + '^').decode().strip() == BASE,
'Source parent differs from reviewed base')
changed = git(root, 'diff', '--no-ext-diff', '--no-textconv', '--name-only', '-z',
BASE, SOURCE, '--').decode().rstrip('\0').split('\0')
require(set(changed) == set(FILES) and len(changed) == len(FILES),
'Commit delta differs from the reviewed six files')
payloads = {}
for path, (oid, size) in FILES.items():
actual = git(root, 'rev-parse', f'{SOURCE}:{path}').decode().strip()
require(actual == oid, f'Unexpected committed blob: {path}')
require(git(root, 'cat-file', '-t', oid).strip() == b'blob', path)
require(int(git(root, 'cat-file', '-s', oid)) == size, path)
raw = git(root, 'cat-file', 'blob', oid)
require(len(raw) == size, f'Incomplete cat-file data: {path}')
require(git(root, 'hash-object', '--stdin', data=raw).decode().strip() == oid,
f'Git object identity mismatch: {path}')
payloads['source/' + path] = (raw, {
'kind': 'committed-source', 'source_commit': SOURCE,
'source_path': path, 'git_blob': oid,
})
# All changed paths are enforced above; full repository diff retains binary,
# executable-mode, rename and new-file metadata. No working-tree diff is read.
patch = git(root, 'diff', '--binary', '--full-index', '--no-renames',
'--diff-algorithm=myers', '--no-indent-heuristic', '--unified=3',
'--inter-hunk-context=0', '--no-ext-diff', '--no-textconv',
'--no-color', '--src-prefix=a/', '--dst-prefix=b/', BASE, SOURCE, '--')
require(patch.startswith(b'diff --git '), 'Missing binary Git patch')
payloads[PATCH_PATH] = (patch, {'kind': 'git-binary-patch',
'base_commit': BASE, 'source_commit': SOURCE})
return payloads
def expected_paths():
return {'source/' + p for p in FILES} | set(NOTES) | {
PATCH_PATH, 'README.md', 'tools/' + SCRIPT_NAME,
}
def verify(root, destination, index=False):
manifest_raw = safe_path(destination, 'manifest.json').read_bytes()
manifest = json.loads(manifest_raw)
require(manifest['schema'] == 1 and manifest['source_commit'] == SOURCE
and manifest['base_commit'] == BASE and manifest['archive_path'] == PREFIX,
'Manifest provenance mismatch')
rows = manifest['files']
require({r['path'] for r in rows} == expected_paths()
and len(rows) == len(expected_paths()), 'Manifest payload list mismatch')
actual = {p.relative_to(destination).as_posix() for p in destination.rglob('*')
if p.is_file() or p.is_symlink()}
require(actual == expected_paths() | {'manifest.json'}, 'Unexpected/missing archive file')
committed = committed_payloads(root)
for row in rows:
path = safe_path(destination, row['path'])
raw = path.read_bytes()
require(digest(raw) == {k: row[k] for k in ('bytes', 'sha256')},
f'Payload digest mismatch: {path}')
if row['path'] in committed:
expected, metadata = committed[row['path']]
require(raw == expected, f'Committed bytes/patch mismatch: {path}')
require(all(row.get(k) == v for k, v in metadata.items()), f'Provenance mismatch: {path}')
elif row['path'] in NOTES:
origin, size, sha = NOTES[row['path']]
require(digest(raw) == {'bytes': size, 'sha256': sha}
and row['source_path'] == origin, f'Approved note changed: {path}')
elif row['path'] == 'README.md':
require(raw == README, 'Archive navigation changed')
if index:
indexed = git(root, 'cat-file', 'blob', ':' + PREFIX + '/' + row['path'])
require(indexed == raw, f'Git index bytes differ: {path}')
if index:
require(git(root, 'cat-file', 'blob', ':' + PREFIX + '/manifest.json') == manifest_raw,
'Git index manifest differs')
print(f'PASS {len(rows)} payloads: manifest, workspace, committed source and patch'
+ ('; payloads and manifest also match Git index' if index else ''))
def create(root, destination):
require(not destination.exists() and not destination.is_symlink(),
f'Refusing to overwrite existing archive: {destination}')
payloads = committed_payloads(root)
# Preflight every approved local input and gather all bytes before creating anything.
for target, (origin, size, sha) in NOTES.items():
raw = safe_path(root, origin).read_bytes()
require(digest(raw) == {'bytes': size, 'sha256': sha}, f'Approved note changed: {origin}')
payloads[target] = (raw, {'kind': 'source-review-record', 'source_path': origin,
'reviewed_source_commit': SOURCE})
payloads['README.md'] = (README, {'kind': 'archive-navigation'})
payloads['tools/' + SCRIPT_NAME] = (Path(__file__).read_bytes(), {
'kind': 'archive-helper', 'source_path': '.local/' + SCRIPT_NAME,
})
require(set(payloads) == expected_paths(), 'Internal payload list mismatch')
manifest = {
'schema': 1, 'archive_path': PREFIX, 'base_commit': BASE, 'source_commit': SOURCE,
'created_utc': datetime.now(timezone.utc).isoformat(),
'evidence_scope': 'Committed source and source-only review; no combined test/native pass asserted',
'files': [{'path': path, **metadata, **digest(raw)}
for path, (raw, metadata) in sorted(payloads.items())],
}
destination.mkdir(parents=False, exist_ok=False)
for relative, (raw, _) in sorted(payloads.items()):
target = safe_path(destination, relative)
target.parent.mkdir(parents=True, exist_ok=True)
with target.open('xb') as stream:
stream.write(raw)
with (destination / 'manifest.json').open('xb') as stream:
stream.write((json.dumps(manifest, indent=2) + '\n').encode('utf-8'))
verify(root, destination)
print(f'Created {PREFIX}; not staged, applied, tested, integrated or published')
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('mode', choices=('create', 'verify', 'verify-index'))
parser.add_argument('--repo', type=Path, default=Path.cwd())
args = parser.parse_args()
root = Path(git(args.repo.resolve(), 'rev-parse', '--show-toplevel').decode().strip()).resolve()
destination = safe_path(root, PREFIX)
require(destination.parent.is_dir(), 'Existing harness/experiments directory required')
if args.mode == 'create':
create(root, destination)
else:
require(destination.is_dir(), 'Archive does not exist')
verify(root, destination, index=args.mode == 'verify-index')
if __name__ == '__main__':
main()