204 lines
10 KiB
Python
204 lines
10 KiB
Python
"""Read-only entry producer gate reconciliation. Run only after the final five gates.
|
|
|
|
Usage: python -I -B inspect_runtime.py FULL_SOURCE_SHA PIN7 EXPECTED_NEW_COUNT
|
|
Only Git read commands are executed; Cargo, launchers and binaries are never run.
|
|
"""
|
|
from pathlib import Path
|
|
import hashlib
|
|
import io
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
|
|
if sys.flags.optimize:
|
|
raise SystemExit('Optimized Python forbidden: verification uses assertions')
|
|
assert len(sys.argv) == 4
|
|
source, stem, expected_added = sys.argv[1], sys.argv[2], int(sys.argv[3])
|
|
assert re.fullmatch(r'[0-9a-f]{40}', source)
|
|
assert stem == source[:7]
|
|
assert 1 <= expected_added <= 100
|
|
base = Path(__file__).resolve().parents[2]
|
|
root = base / '.local/as3batch'
|
|
directory = base / '.local/analysis-entry-producer-gates-20260925'
|
|
prior = base / '.local/analysis-text-producer-gates-20260925'
|
|
destination = Path(__file__).with_name('ENTRY-PRODUCER-RUNTIME-READBACK.json')
|
|
assert not destination.exists(), 'Preserve prior readback; do not overwrite'
|
|
BASELINE = '97a8703adc75467a7f8e75f5c6cb00ca542b707c'
|
|
ARCHIVE_SHA = '252ea94e7c7f500a2afb3d0fa47c43a051f39d9c844328337289eea0c463becd'
|
|
sha = lambda raw: hashlib.sha256(raw).hexdigest()
|
|
|
|
|
|
def git(*args):
|
|
return subprocess.check_output(['git', '--no-replace-objects', *args], cwd=root)
|
|
|
|
|
|
def within(folder, relative):
|
|
candidate = (folder / relative).resolve()
|
|
assert candidate.is_relative_to(folder.resolve()), relative
|
|
return candidate
|
|
|
|
|
|
def receipt(folder, name):
|
|
raw_receipt = (folder / (name + '.result.json')).read_bytes()
|
|
data = json.loads(raw_receipt)
|
|
raw = (folder / (name + '.log')).read_bytes()
|
|
assert data['log_sha256'] == sha(raw)
|
|
return data, raw, raw_receipt
|
|
|
|
|
|
def outcomes(raw):
|
|
rows = re.findall(r'^test ([^\r\n]+) \.\.\. (ok|FAILED|ignored)\r?$', raw.decode(), re.M)
|
|
assert len(rows) == len(dict(rows)), 'Duplicate runtime name'
|
|
return rows
|
|
|
|
|
|
def members(raw):
|
|
names = re.findall(r'^([^\r\n]+): test\r?$', raw.decode(), re.M)
|
|
assert len(names) == len(set(names)), 'Duplicate listing name'
|
|
return names
|
|
|
|
|
|
def failure_blocks(raw):
|
|
# Preserve every byte of block whitespace/body except the numeric thread PID.
|
|
rows = re.findall(rb'^---- ([^\r\n]+) stdout ----\r?\n(.*?)(?=^---- |^failures:|\Z)',
|
|
raw, re.M | re.S)
|
|
assert len(rows) == len(dict(rows)), 'Duplicate failure block'
|
|
return {name.decode(): re.sub(rb"(?m)^(thread '[^\r\n]*') \(\d+\) panicked",
|
|
rb'\1 (<PID>) panicked', body) for name, body in rows}
|
|
|
|
|
|
# Anchor baseline local full/list/fmt logs AND receipts to the immutable locally committed ZIP (server publication is blocked).
|
|
archive_raw = (base / 'harness/experiments/analysis-text-producer-20260925/evidence.zip').read_bytes()
|
|
assert sha(archive_raw) == ARCHIVE_SHA
|
|
baseline = {}
|
|
with zipfile.ZipFile(io.BytesIO(archive_raw)) as archive:
|
|
names = archive.namelist()
|
|
assert len(names) == len(set(names))
|
|
for mode in ('full', 'list', 'fmt'):
|
|
name = f'text-producer-{mode}-97a8703-1'
|
|
data, raw, raw_receipt = receipt(prior, name)
|
|
assert data['source'] == data['head_after'] == BASELINE
|
|
for suffix, content in [('.log', raw), ('.result.json', raw_receipt)]:
|
|
matches = [n for n in names if n == name + suffix or n.endswith('/' + name + suffix)]
|
|
assert len(matches) == 1, (name, suffix, matches)
|
|
assert archive.read(matches[0]) == content
|
|
baseline[mode] = (data, raw)
|
|
old, old_raw = baseline['full']
|
|
old_rows = outcomes(old_raw)
|
|
assert old_rows == [tuple(x) for x in old['outcomes']]
|
|
assert len(old_rows) == 275 and old['exit'] == 101
|
|
assert sum(v == 'ok' for _, v in old_rows) == 259
|
|
assert sum(v == 'FAILED' for _, v in old_rows) == 16
|
|
old_out = dict(old_rows)
|
|
old_listing = members(baseline['list'][1])
|
|
assert old_listing == baseline['list'][0]['listing_members']
|
|
assert baseline['list'][0]['exit'] == 0 and set(old_listing) == set(old_out)
|
|
assert baseline['fmt'][0]['exit'] == 1
|
|
|
|
assert git('rev-parse', 'HEAD').decode().strip() == source
|
|
assert not git('status', '--porcelain', '--untracked-files=no').strip()
|
|
scope = ['Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo', 'build', 'crates',
|
|
'assets', 'docs', 'examples', 'harness/fixtures', 'vendor']
|
|
paths = git('ls-tree', '-r', '--name-only', source, *scope).decode().splitlines()
|
|
blobs = subprocess.check_output(['git', '--no-replace-objects', 'cat-file', '--batch'], cwd=root,
|
|
input=''.join(f'{source}:{p}\n' for p in paths).encode())
|
|
offset, expected_inputs = 0, []
|
|
for path in paths:
|
|
end = blobs.index(b'\n', offset)
|
|
_, kind, count = blobs[offset:end].split()
|
|
count = int(count)
|
|
raw = blobs[end + 1:end + 1 + count]
|
|
assert kind == b'blob' and within(root, path).read_bytes() == raw, path
|
|
expected_inputs.append({'path': path, 'bytes': count, 'sha256': sha(raw)})
|
|
offset = end + count + 2
|
|
assert offset == len(blobs)
|
|
|
|
prefix = ['cargo', 'test', '--locked', '--offline', '-p', 'oa-core', '--lib']
|
|
commands = {
|
|
'focused': prefix + ['entry_producer', '--', '--test-threads=1'],
|
|
'full': prefix + ['--', '--test-threads=1'],
|
|
'list': prefix + ['--', '--list'],
|
|
'clippy': ['cargo', 'clippy', '--locked', '--offline', '-p', 'oa-core', '--all-targets', '--', '-D', 'warnings'],
|
|
'fmt': ['cargo', 'fmt', '--all', '--', '--check'],
|
|
}
|
|
expected_env = baseline['full'][0]['environment']
|
|
assert expected_env['CARGO_BUILD_JOBS'] == '1' and expected_env['CARGO_INCREMENTAL'] == '0'
|
|
for key in ('RUSTFLAGS', 'RUSTC', 'RUSTUP_TOOLCHAIN', 'ARCADIA_CODEC_LIFECYCLE_PHASE', 'RUST_MIN_STACK'):
|
|
assert expected_env[key] is None
|
|
verified, all_receipts, raw_logs = {}, {}, {}
|
|
artifact_identity = launcher_identity = None
|
|
for mode, command in commands.items():
|
|
name = f'entry-{mode}-{stem}-1'
|
|
data, raw, receipt_raw = receipt(directory, name)
|
|
assert data['source'] == data['head_after'] == source
|
|
assert data['mode'] == mode and data['command'] == command
|
|
assert data['invocation'] == 'cargo' and data['test_target'] is None
|
|
assert data['filter'] == ('entry_producer' if mode == 'focused' else '')
|
|
assert not data['changed_inputs'] and not data['verification_failures']
|
|
assert data['cwd'] == str(root) and data['environment'] == expected_env
|
|
manifest_raw = within(directory, data['inputs']).read_bytes()
|
|
assert sha(manifest_raw) == data['inputs_sha256']
|
|
assert json.loads(manifest_raw) == {'source': source, 'inputs': expected_inputs}
|
|
launcher = within(directory, data['launcher_copy']).read_bytes()
|
|
assert sha(launcher) == data['launcher_sha256'] == data['launcher_sha256_after']
|
|
assert source.encode() in launcher
|
|
if launcher_identity is None:
|
|
launcher_identity = sha(launcher)
|
|
assert sha(launcher) == launcher_identity, 'Unexpected mixed launchers: review explicitly'
|
|
rows = outcomes(raw)
|
|
assert rows == [tuple(x) for x in data['outcomes']]
|
|
listing = members(raw) if mode == 'list' else []
|
|
assert listing == data['listing_members'] and len(listing) == data['listing_count']
|
|
if mode in ('focused', 'full'):
|
|
counts = tuple(sum(v == state for _, v in rows) for state in ('ok', 'FAILED', 'ignored'))
|
|
summary = re.findall(r'^test result: (ok|FAILED)\. (\d+) passed; (\d+) failed; (\d+) ignored; 0 measured; (\d+) filtered out;', raw.decode(), re.M)
|
|
assert len(summary) == 1 and tuple(map(int, summary[0][1:4])) == counts
|
|
assert summary[0][0] == ('FAILED' if counts[1] else 'ok')
|
|
assert int(summary[0][4]) == (275 if mode == 'focused' else 0)
|
|
else:
|
|
assert not rows
|
|
assert data['exit'] == {'focused': 0, 'full': 101, 'list': 0, 'clippy': 0, 'fmt': 1}[mode]
|
|
assert len(data['artifacts']) == (1 if mode in ('focused', 'full', 'list') else 0)
|
|
for artifact in data['artifacts']:
|
|
path = Path(artifact['path'])
|
|
assert path.resolve().is_relative_to(Path(expected_env['CARGO_TARGET_DIR']).resolve())
|
|
actual = path.read_bytes()
|
|
assert len(actual) == artifact['bytes'] and sha(actual) == artifact['sha256']
|
|
assert str(path).replace('\\', '/') in raw.decode().replace('\\', '/')
|
|
if artifact_identity is None:
|
|
artifact_identity = artifact
|
|
assert artifact == artifact_identity, 'Test/list artifact mismatch'
|
|
all_receipts[mode], raw_logs[mode] = data, raw
|
|
verified[name] = {'source': source, 'exit': data['exit'], 'outcomes': len(rows),
|
|
'listing': len(listing), 'log_sha256': sha(raw), 'result_sha256': sha(receipt_raw),
|
|
'inputs_sha256': sha(manifest_raw), 'launcher_sha256': sha(launcher)}
|
|
|
|
new_out = dict(all_receipts['full']['outcomes'])
|
|
assert len(new_out) == 275 + expected_added
|
|
assert all(new_out.get(k) == v for k, v in old_out.items())
|
|
added = set(new_out) - set(old_out)
|
|
assert len(added) == expected_added
|
|
assert all(new_out[k] == 'ok' and 'entry_producer' in k for k in added)
|
|
assert set(dict(all_receipts['focused']['outcomes'])) == added
|
|
assert all(status == 'ok' for _, status in all_receipts['focused']['outcomes'])
|
|
assert set(all_receipts['list']['listing_members']) == set(new_out)
|
|
old_blocks, new_blocks = failure_blocks(old_raw), failure_blocks(raw_logs['full'])
|
|
assert len(old_blocks) == len(new_blocks) == 16
|
|
assert set(old_blocks) == {k for k, v in old_out.items() if v == 'FAILED'}
|
|
assert old_blocks == new_blocks, 'Failure bodies differ beyond thread PID'
|
|
assert raw_logs['fmt'] == baseline['fmt'][1]
|
|
|
|
result = {'source': source, 'baseline': BASELINE, 'baseline_archive_sha256': ARCHIVE_SHA,
|
|
'checker_sha256': sha(Path(__file__).read_bytes()), 'inputs': len(expected_inputs),
|
|
'unchanged_old_outcomes': 275, 'added_passed': expected_added, 'added_names': sorted(added),
|
|
'full_passed': sum(v == 'ok' for v in new_out.values()), 'full_failed': 16,
|
|
'identical_failure_blocks_after_pid_only_normalization': 16,
|
|
'identical_fmt_sha256': sha(raw_logs['fmt']), 'artifact': artifact_identity,
|
|
'environment': expected_env, 'receipts': verified,
|
|
'scope': 'Committed declared inputs, pinned baseline archive, raw logs and current artifact bytes; no Cargo/executable execution. Launcher semantics require independent source review.'}
|
|
with destination.open('x', encoding='utf-8', newline='\n') as stream:
|
|
stream.write(json.dumps(result, indent=2) + '\n')
|
|
print(json.dumps(result, indent=2))
|