Seal Phase 4AM whole-brain plastic interface audit without learning claim

This commit is contained in:
Digital Drosophila Archive
2026-09-30 16:11:14 +08:00
parent 6d5f66bcc3
commit de61cf14b1
3051 changed files with 415090 additions and 13 deletions
@@ -0,0 +1,340 @@
"""Fetch only externally anchored Phase 4AM small evidence and model source.
No SSH connection is made at import. The API accepts an already authenticated
SFTP client; the CLI rejects unknown host keys. This is not a trajectory backup
or a local re-verification of remote bulk payloads/scientific gates.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
from pathlib import Path, PurePosixPath
import re
import stat
REMOTE_ROOT = '/data/digital-drosophila'
MODEL_RELATIVE = 'models/male-cns-lif/wholebrain-plastic-interface-v1'
EXPERIMENT_RELATIVE = 'experiments/phase4am-wholebrain-plastic-interface'
REGISTRY_RELATIVE = 'registry/phase4am-wholebrain-plastic-interface'
MODEL_ROOT = REMOTE_ROOT + '/' + MODEL_RELATIVE
REGISTRY_ROOT = REMOTE_ROOT + '/' + REGISTRY_RELATIVE
DEFAULT_DESTINATION = Path(__file__).resolve().parents[2] / 'reports/phase4am-wholebrain-plastic-interface'
MAX_FILE_BYTES = 4 * 1024**2
MAX_TOTAL_BYTES = 1024**3
EVIDENCE_SUFFIXES = frozenset(('.json', '.csv', '.md', '.log', '.sha256'))
SOURCE_SUFFIXES = frozenset(('.py', '.json', '.md', '.yaml', '.yml', '.toml', '.txt', '.sha256', '.cpp', '.cu', '.h', '.hpp'))
CONTROLS = ('manifest.json', 'checksums.sha256')
GENERATED = ('seal-verification.json', 'evidence-index.json')
SHA = re.compile(r'[0-9a-f]{64}\Z')
def require(condition, message):
if not condition:
raise ValueError(message)
def sha(data):
return hashlib.sha256(data).hexdigest()
def unique_object(pairs):
result = {}
for key, value in pairs:
require(key not in result, 'Duplicate JSON key: ' + key)
result[key] = value
return result
def json_bytes(data):
def bad(value):
raise ValueError('Nonfinite JSON constant: ' + value)
return json.loads(data.decode('utf-8'), object_pairs_hook=unique_object, parse_constant=bad)
def relative_name(value):
require(isinstance(value, str) and value and not any(c in value for c in ('\\', '\0', '\r', '\n', ':')),
'Invalid relative filename')
path = PurePosixPath(value)
require(not path.is_absolute() and path.as_posix() == value and
all(part not in ('', '.', '..', '__pycache__') and not part.endswith((' ', '.')) for part in path.parts),
'Noncanonical/escaping/cache filename: ' + value)
devices = {'CON', 'PRN', 'AUX', 'NUL', *(f'COM{i}' for i in range(1, 10)), *(f'LPT{i}' for i in range(1, 10))}
require(all(part.split('.')[0].upper() not in devices for part in path.parts), 'Reserved local filename')
return path
def file_row(row, *, small=False):
require(isinstance(row, dict) and set(row) == {'path', 'bytes', 'sha256'}, 'Invalid hash-inventory row')
relative_name(row['path'])
require(type(row['bytes']) is int and row['bytes'] >= 0 and isinstance(row['sha256'], str) and
SHA.fullmatch(row['sha256']), 'Invalid file size/SHA')
if small:
require(row['bytes'] <= MAX_FILE_BYTES, 'Receipt file exceeds 4 MiB: ' + row['path'])
return row
class BoundedSFTP:
def __init__(self, sftp):
self.sftp = sftp
self.directories = set()
def read(self, remote, size=None, checksum=None):
require(remote.startswith(REGISTRY_ROOT + '/') or remote.startswith(MODEL_ROOT + '/'),
'Remote request outside fixed AM registry/model scope')
# Never list a remote directory or discover unregistered sidecars.
parent = PurePosixPath(remote).parent
for directory in reversed((parent, *parent.parents)):
name = str(directory)
if name not in self.directories:
require(stat.S_ISDIR(self.sftp.lstat(name).st_mode), 'Remote symlink/non-directory: ' + name)
self.directories.add(name)
info = self.sftp.lstat(remote)
require(stat.S_ISREG(info.st_mode), 'Remote symlink/nonregular file: ' + remote)
require(0 <= info.st_size <= MAX_FILE_BYTES and (size is None or info.st_size == size),
'Remote size outside expected small-file limit: ' + remote)
chunks, count = [], 0
with self.sftp.open(remote, 'rb') as source:
while True:
block = source.read(min(1 << 20, MAX_FILE_BYTES + 1 - count))
if not block:
break
count += len(block)
require(count <= MAX_FILE_BYTES, 'Remote file grew beyond download limit')
chunks.append(block)
data = b''.join(chunks)
require(len(data) == info.st_size and (size is None or len(data) == size), 'Remote size changed during read')
if checksum is not None:
require(sha(data) == checksum, 'Remote file SHA mismatch: ' + remote)
return data
def validate_receipt(data, expected_sha):
require(sha(data) == expected_sha, 'External publication-receipt SHA mismatch')
receipt = json_bytes(data)
require(isinstance(receipt, dict) and receipt.get('publication_complete') is True and
receipt.get('registry') == REGISTRY_RELATIVE and receipt.get('project_root') == REMOTE_ROOT,
'Wrong/incomplete AM publication receipt')
for key in ('source_trees_verified_before_and_after_copy', 'publication_success_is_not_scientific_pass'):
require(receipt.get(key) is True, 'Missing publication qualification: ' + key)
for key in ('complete_bulk_backup', 'scientific_gate_executed_by_publisher',
'scientific_gate_certified_by_publication', 'candidate_generated', 'learning_achieved'):
require(receipt.get(key) is False, 'Unexpected publication claim: ' + key)
require(receipt.get('limits') == dict(max_selected_evidence_file_bytes=MAX_FILE_BYTES,
selected_suffixes=sorted(EVIDENCE_SUFFIXES)), 'Unexpected publication selection limits')
for key in ('model_manifest_sha256', 'experiment_manifest_sha256'):
require(isinstance(receipt.get(key), str) and SHA.fullmatch(receipt[key]), 'Missing manifest anchor: ' + key)
rows = {}
require(isinstance(receipt.get('files'), list) and receipt['files'], 'Empty receipt inventory')
for row in receipt['files']:
file_row(row, small=True)
name = row['path']
require(name not in rows, 'Duplicate receipt file: ' + name)
allowed = name in GENERATED or name in ('model/manifest.json', 'model/checksums.sha256') or (
name.startswith('evidence/') and PurePosixPath(name).suffix.lower() in EVIDENCE_SUFFIXES)
require(allowed, 'Receipt attempts a non-evidence/sidecar download: ' + name)
rows[name] = row
required = {'model/manifest.json', 'model/checksums.sha256', 'evidence/manifest.json',
'evidence/checksums.sha256', 'evidence/audit/final-status.json',
'evidence/regression/old-integrity-after.json', 'evidence/audit/scientific-summary.json',
'evidence/protocol/preregistered.json', 'evidence/audit/zero-complete.json',
'evidence/audit/static25-complete.json', 'evidence/regression/frozen-five.json', *GENERATED}
require(required.issubset(rows), 'Receipt omits required AM evidence/seal controls')
return receipt, rows
def validate_manifest(manifest_data, checksums_data, expected_root, expected_sha):
require(sha(manifest_data) == expected_sha, 'Receipt/manifest SHA mismatch')
manifest = json_bytes(manifest_data)
require(isinstance(manifest, dict) and set(manifest) == {'root', 'files'} and
manifest['root'] == expected_root and isinstance(manifest['files'], list) and manifest['files'],
'Wrong seal manifest schema/root')
rows = {}
for row in manifest['files']:
file_row(row)
require(row['path'] not in rows and row['path'] not in CONTROLS, 'Duplicate/control manifest payload')
rows[row['path']] = row
checksums = {}
for line in checksums_data.decode('utf-8').splitlines():
require(len(line) >= 67 and line[64:66] == ' ' and SHA.fullmatch(line[:64]), 'Invalid checksum line')
name = line[66:]
relative_name(name)
require(name not in checksums, 'Duplicate checksum filename')
checksums[name] = line[:64]
require(checksums == {**{name: row['sha256'] for name, row in rows.items()}, 'manifest.json': expected_sha},
'Manifest self-SHA/checksum inventory mismatch')
return rows
def local_name(registry_name):
if registry_name.startswith('evidence/'):
return registry_name[len('evidence/'):]
if registry_name.startswith('model/'):
return registry_name
return 'registry/' + registry_name
def _check_local_target(destination):
require(destination.is_absolute(), 'Report destination must be absolute')
for part in (destination, *destination.parents):
require(not part.is_symlink() and not getattr(part, 'is_junction', lambda: False)(),
'Local symlink/junction destination is forbidden')
require(not destination.exists(), 'Report destination exists; no overwrite/resume')
def _write(path, data):
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('xb') as output:
output.write(data)
require(path.stat().st_size == len(data) and sha(path.read_bytes()) == sha(data), 'Local write verification failed')
def fetch(sftp, destination, receipt_sha256, *, max_total_bytes=MAX_TOTAL_BYTES):
"""SFTP read-only API. Destination is exclusive; receipt SHA is out-of-band.
Registry evidence/* mirrors into the report root, model/* into model/, and
receipt/generated publication metadata into registry/. Only source-whitelisted
model payloads are added; every transferred file is individually SHA checked.
"""
require(isinstance(receipt_sha256, str) and SHA.fullmatch(receipt_sha256.lower()), 'External receipt SHA256 is required')
receipt_sha256 = receipt_sha256.lower()
require(type(max_total_bytes) is int and max_total_bytes > 0, 'Invalid total download budget')
destination = Path(destination)
_check_local_target(destination)
remote = BoundedSFTP(sftp)
receipt_bytes = remote.read(REGISTRY_ROOT + '/publication-receipt.json', checksum=receipt_sha256)
receipt, rows = validate_receipt(receipt_bytes, receipt_sha256)
cached = {}
for prefix in ('model/', 'evidence/'):
for control in CONTROLS:
name = prefix + control; row = rows[name]
cached[name] = remote.read(REGISTRY_ROOT + '/' + name, row['bytes'], row['sha256'])
model_rows = validate_manifest(cached['model/manifest.json'], cached['model/checksums.sha256'],
MODEL_ROOT, receipt['model_manifest_sha256'])
experiment_rows = validate_manifest(cached['evidence/manifest.json'], cached['evidence/checksums.sha256'],
REMOTE_ROOT + '/' + EXPERIMENT_RELATIVE, receipt['experiment_manifest_sha256'])
# Model source is fetched from its sealed model path, not the registry. Bind
# its current controls to the receipt before reading any source payload.
for control in CONTROLS:
row = rows['model/' + control]
remote.read(MODEL_ROOT + '/' + control, row['bytes'], row['sha256'])
for name, row in rows.items():
if name.startswith('evidence/') and name[len('evidence/'):] not in CONTROLS:
original = experiment_rows.get(name[len('evidence/'):])
require(original is not None and all(row[key] == original[key] for key in ('bytes', 'sha256')),
'Registry evidence disagrees with experiment seal: ' + name)
for name in GENERATED:
row = rows[name]
cached[name] = remote.read(REGISTRY_ROOT + '/' + name, row['bytes'], row['sha256'])
proof = json_bytes(cached['seal-verification.json'])
for key, root, manifest_rows, prefix in (('model', MODEL_ROOT, model_rows, 'model/'),
('experiment', REMOTE_ROOT + '/' + EXPERIMENT_RELATIVE, experiment_rows, 'evidence/')):
item = proof.get(key, {})
require(item.get('pass_all') is True and item.get('root') == root and
item.get('manifest_sha256') == receipt[key + '_manifest_sha256'] and
item.get('checksums_sha256') == rows[prefix + 'checksums.sha256']['sha256'] and
item.get('payload_file_count') == len(manifest_rows) and
item.get('payload_bytes') == sum(row['bytes'] for row in manifest_rows.values()),
'Publication seal-verification disagrees with manifest: ' + key)
index = json_bytes(cached['evidence-index.json'])
require(isinstance(index, list), 'Invalid publication evidence index')
indexed = set()
for item in index:
require(isinstance(item, dict) and set(item) == {'source', 'copy', 'bytes', 'sha256'}, 'Invalid evidence-index row')
name = item['copy']
require(name in rows and name not in GENERATED and name not in indexed, 'Duplicate/unexpected evidence-index copy')
indexed.add(name)
expected_source = (EXPERIMENT_RELATIVE + '/' + name[len('evidence/'):] if name.startswith('evidence/')
else MODEL_RELATIVE + '/' + name[len('model/'):])
require(item['source'] == expected_source and all(item[key] == rows[name][key] for key in ('bytes', 'sha256')),
'Evidence-index source/hash mismatch')
require(indexed == set(rows) - set(GENERATED), 'Evidence-index coverage mismatch')
plan = [(REGISTRY_ROOT + '/' + name, local_name(name), row, cached.get(name)) for name, row in sorted(rows.items())]
omitted = []
for name, row in sorted(model_rows.items()):
if PurePosixPath(name).suffix.lower() in SOURCE_SUFFIXES and row['bytes'] <= MAX_FILE_BYTES:
plan.append((MODEL_ROOT + '/' + name, 'model/' + name, row, None))
else:
omitted.append(dict(row, reason='model_non_source_or_over_4_MiB'))
paths = ['registry/publication-receipt.json', 'fetch-verification.json', 'fetch-failure.json'] + [entry[1] for entry in plan]
lowered = [relative_name(name).as_posix().casefold() for name in paths]
require(len(set(lowered)) == len(lowered) and not any(
parent.as_posix().casefold() in set(lowered) for name in paths for parent in PurePosixPath(name).parents if str(parent) != '.'),
'Local case-insensitive/path-prefix collision')
planned_bytes = len(receipt_bytes) + sum(entry[2]['bytes'] for entry in plan)
require(planned_bytes <= max_total_bytes, 'Selected evidence exceeds total download budget')
_check_local_target(destination)
destination.mkdir(parents=True, exist_ok=False)
try:
_write(destination / 'registry/publication-receipt.json', receipt_bytes)
downloaded = []
for source, local, row, data in plan:
if data is None:
data = remote.read(source, row['bytes'], row['sha256'])
require(len(data) == row['bytes'] and sha(data) == row['sha256'], 'Cached/downloaded file hash mismatch')
_write(destination / local, data)
downloaded.append(dict(remote=source, local=local, bytes=len(data), sha256=sha(data)))
final = json_bytes((destination / 'audit/final-status.json').read_bytes())
require(final.get('status') == receipt.get('declared_audit_status'), 'Receipt/final-status declaration mismatch')
for key, value in receipt.get('declared_gate_results', {}).items():
require(final.get(key) == value and type(final.get(key)) is type(value), 'Receipt/final gate flag mismatch')
for key, value in receipt.get('declared_audit_counts', {}).items():
require(final.get(key) == value and type(final.get(key)) is type(value), 'Receipt/final coverage mismatch')
# Re-read immutable anchors, not unselected experiment payloads.
remote.read(REGISTRY_ROOT + '/publication-receipt.json', len(receipt_bytes), receipt_sha256)
for control in CONTROLS:
row = rows['model/' + control]
remote.read(MODEL_ROOT + '/' + control, row['bytes'], row['sha256'])
result = dict(fetch_complete=True, publication_receipt_sha256=receipt_sha256,
external_receipt_anchor_required=True, declared_audit_status=final['status'],
model_manifest_sha256=receipt['model_manifest_sha256'], experiment_manifest_sha256=receipt['experiment_manifest_sha256'],
both_manifest_self_checksums_verified=True, every_downloaded_file_sha256_verified=True,
files=downloaded, file_count=len(downloaded), selected_bytes=planned_bytes,
model_payload_not_downloaded=omitted, all_remote_experiment_bulk_rehashed_locally=False,
full_remote_seal_verification_is_publisher_receipt_claim=True, complete_bulk_backup=False,
scientific_gate_executed=False, scientific_pass_certified_by_fetch=False,
fetch_success_is_not_scientific_pass=True, candidate_generated=False, learning_achieved=False,
unregistered_sidecar_requested=False, existing_files_modified=False)
_write(destination / 'fetch-verification.json', (json.dumps(result, ensure_ascii=False, indent=2, allow_nan=False) + '\n').encode())
return result
except Exception as error:
failure = destination / 'fetch-failure.json'
if not failure.exists():
_write(failure, (json.dumps(dict(fetch_complete=False, type=type(error).__name__, message=str(error),
partial_outputs_preserved=True, existing_files_modified=False), allow_nan=False) + '\n').encode())
raise
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--receipt-sha256', required=True, help='Out-of-band SHA printed by the verified AM publisher')
parser.add_argument('--destination', type=Path, default=DEFAULT_DESTINATION)
parser.add_argument('--host', default='192.168.10.51')
parser.add_argument('--user', default='qishizhe')
parser.add_argument('--port', type=int, default=22)
parser.add_argument('--password-env', default='MALECNS_REMOTE_PASSWORD')
parser.add_argument('--known-hosts', type=Path, default=Path.home() / '.ssh/known_hosts',
help='Explicit existing user known_hosts; unknown hosts are always rejected')
args = parser.parse_args()
require(SHA.fullmatch(args.receipt_sha256.lower()), 'External receipt SHA256 is required')
_check_local_target(args.destination)
require(args.known_hosts.is_file(), 'Known-hosts file is missing; configure trust externally, never auto-add')
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys(str(args.known_hosts))
client.set_missing_host_key_policy(paramiko.RejectPolicy())
try:
client.connect(args.host, port=args.port, username=args.user, password=os.environ.get(args.password_env),
timeout=15, auth_timeout=15, banner_timeout=15)
with client.open_sftp() as sftp:
result = fetch(sftp, args.destination, args.receipt_sha256)
print(json.dumps({key: result[key] for key in ('fetch_complete', 'publication_receipt_sha256',
'declared_audit_status', 'file_count', 'fetch_success_is_not_scientific_pass')}), flush=True)
finally:
client.close()
if __name__ == '__main__':
main()
@@ -0,0 +1,354 @@
"""Exclusive small-evidence publication after both Phase 4AM seals verify.
Publication verifies and copies bytes. It never runs a brain, re-evaluates a
scientific gate, converts FAIL/INCOMPLETE into PASS, or changes frozen sources.
The source-pinned Phase 4AI verification/copy helpers are executed unchanged.
"""
from __future__ import annotations
import hashlib
import importlib.util
import json
import math
from pathlib import Path, PurePosixPath
ROOT = Path('/data/digital-drosophila')
MODEL_RELATIVE = Path('models/male-cns-lif/wholebrain-plastic-interface-v1')
EXPERIMENT_RELATIVE = Path('experiments/phase4am-wholebrain-plastic-interface')
REGISTRY_RELATIVE = Path('registry/phase4am-wholebrain-plastic-interface')
HELPER_RELATIVE = Path('models/male-cns-lif/pn-recruitment-audit-v1/publication.py')
HELPER_SHA256 = '7a79c499098b74163e7bb16adabcbc54e7069dafa204d0b99c7f4c03d79f8016'
MAX_EVIDENCE_BYTES = 4 * 1024 ** 2
EVIDENCE_SUFFIXES = frozenset(('.json', '.csv', '.md', '.log', '.sha256'))
FINAL_STATUS = 'PASS-EXACT-WHOLEBRAIN-PLASTIC-INTERFACE-NOT-LEARNING'
# Finalize currently seals only this completed diagnostic status. A partial
# run is not promoted; future failure sealing needs an explicit new contract.
FINAL_STATUSES = frozenset((FINAL_STATUS,))
REQUIRED_EVIDENCE = ('audit/final-status.json', 'regression/old-integrity-after.json',
'audit/scientific-summary.json', 'protocol/preregistered.json',
'audit/zero-complete.json', 'audit/static25-complete.json')
REFERENCE_EVIDENCE = 'regression/frozen-five.json'
GATE_FIELDS = ('zero_overlay_exact', 'static25_repeat_exact', 'old_integrity_pass',
'frozen_five_reference_pass', 'frozen_eligibility_and_mask_unchanged', 'base_weights_unchanged')
COUNT_FIELDS = ('primary_trials_per_stage', 'repeats_per_stage')
COHORTS = ('seed_validation', 'novel_to_aj')
MODES = ('physiological', 'matched_energy')
STAGES = ('zero', 'static25')
POPULATIONS = ('KC', 'MBON', 'mask_recipient_MBON', 'DAN', 'MBON_downstream', 'descending', 'motor')
REFERENCE_NAMES = ('auditory-10hz', 'auditory-100hz', 'olfactory-50hz',
'mechanosensory-50hz', 'gustatory-50hz')
EXPECTED_CONFIG = dict(phase='4AM',
purpose='Exact D18 trial-boundary plastic-overlay interface and closed-loop transfer gate',
neurons=166700, edges=25582938, candidate_edges=14232, primary_trials=120, technical_repeats=24,
steps=1000, dt_ms=.1, apl_delay_steps=18, stages=list(STAGES), max_fractional_depression=.25,
virtual_gate_tick=900, gpu_uuid='GPU-79f3a85d-adce-7833-7003-6488140ca596', output_budget_bytes=17179869184,
training=False, candidate_generation=False, static_test_is_learning=False,
precision_bridge='base float64 SI plus separate float64(delta float32 mV) times 0.001; zero rows untouched',
future_learning='Original frozen eligibility-v2 and additive trial-boundary update; artificial scalar D remains separate from actual DAN events')
SCIENCE_SCOPE = 'Valid interface and recording; reported static response is not an associative learning PASS'
def require(condition, message):
if not condition:
raise ValueError(message)
def load_helpers(path):
"""Instantiate the unchanged module from its exact pinned source bytes.
Using module_from_spec plus the source bytes avoids writing/importing a pyc
inside the sealed old model, even if the publisher was invoked without -B.
No old module global is redirected or modified after module initialization.
"""
path = Path(path)
require(path.is_absolute() and path.is_file() and not path.is_symlink(), 'Invalid frozen helper path')
data = path.read_bytes()
require(hashlib.sha256(data).hexdigest() == HELPER_SHA256, 'Frozen AI publication helper hash mismatch')
spec = importlib.util.spec_from_file_location('phase4am_frozen_ai_publication_helpers', path)
require(spec is not None and spec.loader is not None, 'Unable to define frozen helper module')
module = importlib.util.module_from_spec(spec)
exec(compile(data, str(path), 'exec'), module.__dict__)
require(module._digest(path) == HELPER_SHA256, 'Helper source changed while loading')
return module
def _copy(helper, source, destination, size, checksum):
"""Separate local delegation point for interruption-only synthetic tests."""
helper._copy_verified(source, destination, size, checksum)
def _write_small_json(helper, path, value):
data = (json.dumps(value, indent=2, ensure_ascii=False, allow_nan=False) + '\n').encode('utf-8')
require(len(data) <= MAX_EVIDENCE_BYTES, 'Generated registry evidence exceeds 4 MiB: ' + str(path))
with Path(path).open('xb') as stream:
stream.write(data)
require(Path(path).stat().st_size == len(data), 'Generated registry evidence size changed')
def _small_json(helper, experiment, rows, relative):
require(relative in rows, 'Required finalized evidence absent from seal: ' + relative)
require(rows[relative]['bytes'] <= MAX_EVIDENCE_BYTES, 'Required finalized evidence exceeds 4 MiB')
return helper._json_bytes((experiment / relative).read_bytes())
def _planned_inventory(registration, config):
require(registration.get('config') == config and registration.get('training') is False and
registration.get('candidate_generated') is False and registration.get('before_new_brain_trajectories') is True,
'Preregistration configuration/scope mismatch')
planned = registration.get('planned')
require(isinstance(planned, list) and len(planned) == 144, 'Planned inventory must contain 144 records')
primary, repeated = {}, {}
for row in planned:
require(isinstance(row, dict) and isinstance(row.get('name'), str) and row['name'] and
PurePosixPath(row['name']).name == row['name'] and row['name'] not in ('.', '..') and
not any(c in row['name'] for c in ('\\', ':', '\0', '\r', '\n')), 'Invalid planned case name')
require(row.get('cohort') in COHORTS and row.get('mode') in MODES and type(row.get('seed')) is int and
isinstance(row.get('odor_id'), str) and row['odor_id'] and type(row.get('repeat')) is int and
row['repeat'] in (0, 1), 'Invalid planned cohort/mode/seed/repeat')
target = primary if row['repeat'] == 0 else repeated
require(row['name'] not in target, 'Duplicate planned case/repeat')
target[row['name']] = row
require(len(primary) == 120 and len(repeated) == 24, 'Planned primary/repeat coverage mismatch')
seeds = {row['seed'] for row in primary.values()}
require(len(seeds) == 5, 'Planned inventory requires five seeds')
identities = {(r['cohort'], r['mode'], r['odor_id'], r['seed']) for r in primary.values()}
require(len(identities) == 120, 'Duplicate planned scientific identity')
for cohort in COHORTS:
odors_by_mode = []
for mode in MODES:
block = [r for r in primary.values() if r['cohort'] == cohort and r['mode'] == mode]
odors = {r['odor_id'] for r in block}
require(len(block) == 30 and len(odors) == 6 and
{(r['odor_id'], r['seed']) for r in block} == {(o, s) for o in odors for s in seeds},
'Incomplete planned cohort-mode inventory')
odors_by_mode.append(odors)
require(odors_by_mode[0] == odors_by_mode[1], 'Modes use different odor identities')
require(len({r['odor_id'] for r in primary.values()}) == 12, 'Cohorts must retain twelve distinct frozen odors')
expected_repeats = {name for name, r in primary.items() if r['seed'] == min(seeds)}
require(set(repeated) == expected_repeats and all(repeated[name] == dict(primary[name], repeat=1)
for name in repeated), 'Repeats do not match the complete first-seed inventory')
return planned, primary
def _stage_coverage(helper, experiment, rows, stage, planned):
receipt = _small_json(helper, experiment, rows, 'audit/' + stage + '-complete.json')
require(receipt.get('stage') == stage and receipt.get('pass_all') is True and receipt.get('training') is False and
all(type(receipt.get(k)) is int and receipt[k] == v for k, v in
(('trials', 144), ('primary_trials', 120), ('technical_repeats', 24))), 'Incomplete stage gate receipt: ' + stage)
completed = receipt.get('completed')
require(isinstance(completed, list) and len(completed) == 144, 'Stage receipt lacks 144 completed records')
project = experiment.parents[1]
for plan, entry in zip(planned, completed):
require(isinstance(entry, dict) and set(entry) == {'name', 'repeat', 'output_hashes_sha256', 'comparison_sha256'}
and entry['name'] == plan['name'] and type(entry['repeat']) is int and entry['repeat'] == plan['repeat'],
'Stage receipt inventory order/identity mismatch')
prefix = 'gpu/' + stage + '/' + plan['name'] + '-r' + str(plan['repeat']) + '/'
for filename, key in (('output-hashes.json', 'output_hashes_sha256'), ('comparison.json', 'comparison_sha256')):
require(prefix + filename in rows and rows[prefix + filename]['sha256'] == entry[key],
'Stage receipt does not bind sealed output evidence: ' + prefix + filename)
report = _small_json(helper, experiment, rows, prefix + 'comparison.json')
mode = 'zero' if stage == 'zero' else ('repeat' if plan['repeat'] else 'self')
folder = experiment / prefix.rstrip('/')
case = project / 'experiments/phase4ak-apl-timing-validation/cases' / plan['cohort'] / plan['name']
left = (project / 'experiments/phase4ak-apl-timing-validation/gpu' / plan['cohort'] /
(plan['name'] + '-r' + str(plan['repeat'])) if stage == 'zero' else
(experiment / 'gpu' / stage / (plan['name'] + '-r0') if plan['repeat'] else folder))
require(report.get('pass_all') is True and report.get('overlay_name') == stage and report.get('mode') == mode and
report.get('case_dir') == str(case) and report.get('left') == str(left) and report.get('right') == str(folder),
'Stage comparison evidence has wrong case/stage/repeat identity')
inventory = _small_json(helper, experiment, rows, prefix + 'output-hashes.json')
require(isinstance(inventory, list) and inventory, 'Empty trial output inventory')
expected = {name[len(prefix):]: {**r, 'path': name[len(prefix):]} for name, r in rows.items()
if name.startswith(prefix) and name != prefix + 'output-hashes.json'}
actual = {}
for item in inventory:
require(isinstance(item, dict) and set(item) == {'path', 'bytes', 'sha256'} and
item['path'] not in actual, 'Invalid/duplicate trial output inventory')
actual[item['path']] = item
require(actual == expected, 'Trial output inventory contradicts complete experiment seal')
return dict(pass_all=True, trials=144, primary_trials=120, technical_repeats=24,
receipt_sha256=rows['audit/' + stage + '-complete.json']['sha256'])
def _status_evidence(helper, experiment, rows, model):
"""Verify declarations and their sealed coverage, never recompute science."""
evidence = {name: _small_json(helper, experiment, rows, name) for name in REQUIRED_EVIDENCE}
status = evidence['audit/final-status.json']
science = evidence['audit/scientific-summary.json']
integrity = evidence['regression/old-integrity-after.json']
config = helper._json_bytes((model / 'config.json').read_bytes())
require(isinstance(config, dict) and set(config) == set(EXPECTED_CONFIG) and all(
type(config[k]) is type(v) and config[k] == v for k, v in EXPECTED_CONFIG.items()),
'Changed Phase 4AM configuration/design contract')
require(isinstance(status, dict) and status.get('status') in FINAL_STATUSES, 'Unrecognized Phase 4AM final status')
require(all(status.get(key) is True for key in GATE_FIELDS), 'Declared PASS contradicts finalized gate flags')
require(type(status.get('primary_trials_per_stage')) is int and status['primary_trials_per_stage'] == 120 and
type(status.get('repeats_per_stage')) is int and status['repeats_per_stage'] == 24, 'Invalid finalized coverage')
require(status.get('training') is False and status.get('learned_candidate') is False, 'Unexpected finalized scope claim')
for record in (status, science):
require(isinstance(record, dict) and all(record.get(k, False) is False for k in
('learning_achieved', 'candidate_generated', 'conditioning_executed', 'full_scientific_goal_achieved')),
'Unexpected learning/candidate scope claim')
require(status.get('scientific_summary_sha256') == rows['audit/scientific-summary.json']['sha256'],
'Final status scientific-summary SHA mismatch')
require(isinstance(science, dict) and science.get('status') == status['status'] and
science.get('zero_overlay_exact') is True and science.get('static25_repeat_exact') is True and
science.get('training') is False and science.get('learned_candidate') is False and
science.get('conditional_AL_not_a_nonzero_arithmetic_oracle') is True and science.get('scope') == SCIENCE_SCOPE,
'Scientific summary scope/status contradiction')
require(type(science.get('primary_trials_per_stage')) is int and science['primary_trials_per_stage'] == 120 and
type(science.get('technical_repeats_per_stage')) is int and science['technical_repeats_per_stage'] == 24,
'Scientific summary coverage mismatch')
require('summaries/per-MBON-static-effects.parquet' in rows and science.get('per_MBON_sha256') ==
rows['summaries/per-MBON-static-effects.parquet']['sha256'], 'Scientific per-MBON payload SHA mismatch')
require(isinstance(integrity, dict) and integrity and all(isinstance(r, dict) and r.get('pass') is True
for r in integrity.values()), 'Final status contradicts its frozen-integrity report')
reference = _small_json(helper, experiment, rows, REFERENCE_EVIDENCE)
require(isinstance(reference, dict), 'Invalid frozen reference report')
trials = reference.get('trials')
require(reference.get('pass_all') is True and isinstance(trials, list) and
[r.get('trial') for r in trials if isinstance(r, dict)] == list(REFERENCE_NAMES) and len(trials) == 5 and
all(isinstance(r.get('exact'), dict) and set(r['exact']) == {'step', 'neuron_idx', 'counts', 'v', 'g'} and
all(value is True for value in r['exact'].values()) for r in trials),
'Declared frozen-five PASS requires five exact trial records with the original ordered names')
blocks = science.get('blocks')
require(isinstance(blocks, dict) and set(blocks) == {c + '/' + m for c in COHORTS for m in MODES},
'Missing/extra cohort-mode blocks')
for block in blocks.values():
require(isinstance(block, dict) and type(block.get('trials')) is int and block['trials'] == 30 and
isinstance(block.get('populations'), dict) and set(block['populations']) == set(POPULATIONS),
'Incomplete cohort-mode population block')
for metrics in block['populations'].values():
require(isinstance(metrics, dict) and set(metrics) == {'trials_event_change', 'trials_count_change',
'mean_count_l1', 'mean_recruited_cells', 'mean_lost_cells'}, 'Invalid population metric fields')
for key in ('trials_event_change', 'trials_count_change'):
require(type(metrics[key]) is int and 0 <= metrics[key] <= 30, 'Invalid diagnostic count')
for key in ('mean_count_l1', 'mean_recruited_cells', 'mean_lost_cells'):
require(type(metrics[key]) in (int, float) and math.isfinite(metrics[key]) and metrics[key] >= 0,
'Nonfinite/negative population metric')
require(metrics['trials_count_change'] <= metrics['trials_event_change'], 'Count change without event change')
# Zero effects remain publishable: this is not an effect-size gate.
planned, primary = _planned_inventory(evidence['protocol/preregistered.json'], config)
timing = science.get('timing')
require(isinstance(timing, list) and len(timing) == 240 and all(isinstance(r, dict) for r in timing) and
{(r.get('stage'), r.get('case')) for r in timing} == {(s, n) for s in STAGES for n in primary},
'Scientific timing inventory lacks all 240 primary runs')
for item in timing:
require(all(type(item.get(k)) in (int, float) and math.isfinite(item[k]) and item[k] >= 0
for k in ('wall_seconds', 'simulation_seconds')), 'Invalid diagnostic timing value')
stages = {stage: _stage_coverage(helper, experiment, rows, stage, planned) for stage in STAGES}
return status, reference, integrity, stages
def publish(root=ROOT, helper_path=None):
"""Publish the fixed AM registry exclusively; root override is for tests.
Only sealed small experiment evidence and the two model seal controls are
copied. Every bulk payload is nevertheless verified before and after copying.
An interrupted registry is preserved and cannot be overwritten or resumed.
"""
root = Path(root)
require(root.is_absolute() and root.is_dir() and not root.is_symlink(), 'Invalid project root')
root = root.resolve(strict=True)
model, experiment, registry = (root / part for part in
(MODEL_RELATIVE, EXPERIMENT_RELATIVE, REGISTRY_RELATIVE))
require(not registry.exists() and not registry.is_symlink(), 'Registry already exists; no overwrite/resume')
helper_path = root / HELPER_RELATIVE if helper_path is None else Path(helper_path)
helper = load_helpers(helper_path)
for path in (model, experiment, registry.parent):
current = root
for part in path.relative_to(root).parts:
current = current / part
require(not current.is_symlink(), 'Symlink in publication root path: ' + str(current))
verified = {'model': helper.verify_seal(model), 'experiment': helper.verify_seal(experiment)}
experiment_rows = {row['path']: row for row in verified['experiment']['files']}
status, reference, integrity, stages = _status_evidence(helper, experiment, experiment_rows, model)
plans, omitted = [], []
for row in verified['experiment']['files'] + helper._control_rows(experiment, verified['experiment']):
if PurePosixPath(row['path']).suffix.lower() in EVIDENCE_SUFFIXES and row['bytes'] <= MAX_EVIDENCE_BYTES:
plans.append((experiment, row, 'evidence/' + row['path']))
else:
omitted.append(dict(path=row['path'], bytes=row['bytes'], sha256=row['sha256'],
reason='exceeds_4_MiB' if row['bytes'] > MAX_EVIDENCE_BYTES else 'bulk_or_non_evidence_extension'))
for row in helper._control_rows(model, verified['model']):
require(row['bytes'] <= MAX_EVIDENCE_BYTES, 'Model seal control exceeds small-evidence limit')
plans.append((model, row, 'model/' + row['path']))
destinations = {target for _, _, target in plans}
required_copies = ['manifest.json', 'checksums.sha256', *REQUIRED_EVIDENCE]
if reference is not None:
required_copies.append(REFERENCE_EVIDENCE)
for relative in required_copies:
require('evidence/' + relative in destinations, 'Required experiment evidence cannot be copied: ' + relative)
require(len(destinations) == len(plans), 'Duplicate planned evidence destination')
registry.parent.mkdir(parents=True, exist_ok=True)
registry.mkdir(exist_ok=False)
try:
records = []
for source_root, row, relative in plans:
source = helper._regular_file(source_root.resolve(), row['path'])
_copy(helper, source, registry / relative, row['bytes'], row['sha256'])
records.append(dict(source=source.relative_to(root).as_posix(), copy=relative,
bytes=row['bytes'], sha256=row['sha256']))
after = {'model': helper.verify_seal(model), 'experiment': helper.verify_seal(experiment)}
require(after == verified, 'A sealed tree changed during publication')
require(helper._digest(helper_path) == HELPER_SHA256, 'Frozen helper changed during publication')
proof = {name: {key: value for key, value in report.items() if key != 'files'}
for name, report in verified.items()}
_write_small_json(helper, registry / 'seal-verification.json', proof)
_write_small_json(helper, registry / 'evidence-index.json', records)
files = [dict(path=path.relative_to(registry).as_posix(), bytes=path.stat().st_size,
sha256=helper._digest(path)) for path in sorted(registry.rglob('*')) if path.is_file()]
receipt = dict(publication_complete=True, registry=registry.relative_to(root).as_posix(),
project_root=str(root), declared_audit_status=status['status'],
declared_gate_results={key: status[key] for key in GATE_FIELDS},
declared_audit_counts={key: status[key] for key in COUNT_FIELDS},
declared_diagnostic_scope='Exact zero-overlay D18 identity and fixed whole-brain static25 interface; no training or associative learning',
declared_stage_coverage=stages, declared_scientific_summary_scope=SCIENCE_SCOPE,
static_effect_size_gate_defined=False,
scientific_summary_sha256=status['scientific_summary_sha256'],
frozen_reference_report=dict(present=reference is not None,
path='evidence/' + REFERENCE_EVIDENCE if reference is not None else None,
sha256=experiment_rows[REFERENCE_EVIDENCE]['sha256'] if reference is not None else None,
declared_pass_all=reference['pass_all'] if reference is not None else None,
reported_trial_count=len(reference['trials']) if reference is not None else None,
missing_is_not_a_success_or_fabricated_trial_failure=True),
frozen_integrity_report=dict(path='evidence/regression/old-integrity-after.json',
sha256=experiment_rows['regression/old-integrity-after.json']['sha256'],
declared_pass_by_root={name: row['pass'] for name, row in integrity.items()}),
frozen_helper_source=str(helper_path), frozen_helper_sha256=HELPER_SHA256,
publisher_sha256=helper._digest(Path(__file__)), helper_globals_redirected=False,
model_manifest_sha256=verified['model']['manifest_sha256'],
experiment_manifest_sha256=verified['experiment']['manifest_sha256'],
source_trees_verified_before_and_after_copy=True,
copied_evidence_files=len(records), copied_evidence_bytes=sum(row['bytes'] for row in records),
files=files, experiment_payload_not_copied=omitted,
model_payload_not_duplicated=True, model_payload_remains_at=MODEL_RELATIVE.as_posix(),
bulk_remains_at=EXPERIMENT_RELATIVE.as_posix(), complete_bulk_backup=False,
scientific_gate_executed_by_publisher=False, scientific_gate_certified_by_publication=False,
publication_success_is_not_scientific_pass=True, candidate_generated=False,
learning_achieved=False, full_scientific_goal_achieved=False,
old_heldout_dynamic_results_parsed=False, existing_files_modified=False,
receipt_self_hash='Not self-referential; returned by publish() and printed by main()',
limits=dict(max_selected_evidence_file_bytes=MAX_EVIDENCE_BYTES,
selected_suffixes=sorted(EVIDENCE_SUFFIXES)))
receipt_path = registry / 'publication-receipt.json'
_write_small_json(helper, receipt_path, receipt)
return dict(publication_complete=True, registry=str(registry), declared_audit_status=status['status'],
copied_evidence_files=len(records), receipt_sha256=helper._digest(receipt_path),
scientific_gate_executed_by_publisher=False, publication_success_is_not_scientific_pass=True)
except Exception as error:
failure = registry / 'publication-failure.json'
if not failure.exists():
_write_small_json(helper, failure, dict(publication_complete=False, type=type(error).__name__,
message=str(error), partial_outputs_preserved=True, existing_files_modified=False))
raise
def main():
print(json.dumps(publish(), ensure_ascii=False, allow_nan=False), flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,245 @@
"""Pure in-memory SFTP plus temporary local destinations, never a real server."""
import io
import json
from pathlib import Path
import stat
import tempfile
import types
import unittest
import fetch_phase4am as fetcher
def data(value):
return (json.dumps(value, sort_keys=True, allow_nan=False) + '\n').encode()
def row(name, content):
return dict(path=name, bytes=len(content), sha256=fetcher.sha(content))
def sealed(root, payload):
rows = [row(name, content) for name, content in sorted(payload.items())]
manifest = data(dict(root=root, files=rows))
checksums = '\n'.join([entry['sha256'] + ' ' + entry['path'] for entry in rows] +
[fetcher.sha(manifest) + ' manifest.json']).encode() + b'\n'
return dict(payload, **{'manifest.json': manifest, 'checksums.sha256': checksums}), dict(
pass_all=True, root=root, payload_file_count=len(rows), payload_bytes=sum(x['bytes'] for x in rows),
manifest_sha256=fetcher.sha(manifest), checksums_sha256=fetcher.sha(checksums))
class FakeSFTP:
def __init__(self, files):
self.files = files
self.opened = []
self.hook = None
self.symlinks = set()
def lstat(self, name):
if name in self.symlinks:
return types.SimpleNamespace(st_mode=stat.S_IFLNK | 0o777, st_size=1)
if name in self.files:
return types.SimpleNamespace(st_mode=stat.S_IFREG | 0o644, st_size=len(self.files[name]))
if any(path.startswith(name.rstrip('/') + '/') for path in self.files):
return types.SimpleNamespace(st_mode=stat.S_IFDIR | 0o755, st_size=0)
raise FileNotFoundError(name)
def open(self, name, mode):
if mode != 'rb':
raise AssertionError('Remote write attempted')
self.opened.append(name)
if self.hook:
self.hook(name)
return io.BytesIO(self.files[name])
def fixture(extra_experiment=None, extra_model=None):
status = dict(status='INCOMPLETE-SYNTHETIC-AM-EVIDENCE', zero_overlay_exact=False,
primary_trials_per_stage=120, candidate_generated=False, learning_achieved=False)
mp = {'module.py': b'# synthetic, not model execution\n', 'config.json': data({'synthetic': True}),
'never-download.npy': b'raw model bulk'}
mp.update(extra_model or {})
ep = {'audit/final-status.json': data(status), 'regression/old-integrity-after.json': data({'tree': {'pass': True}}),
'audit/scientific-summary.json': data({'synthetic_scope': 'not scientific output'}),
'protocol/preregistered.json': data({'synthetic_only': True}),
'audit/zero-complete.json': data({'pass_all': False, 'synthetic_only': True}),
'audit/static25-complete.json': data({'pass_all': False, 'synthetic_only': True}),
'regression/frozen-five.json': data({'pass_all': False, 'trials': []}),
'REPORT.md': b'Synthetic incomplete evidence.\n', 'tests.log': b'Synthetic test log.\n',
'gpu/example/state.npz': b'large trajectory placeholder not requested',
'gpu/example/tick-state-hashes.jsonl': b'non-whitelisted suffix'}
ep.update(extra_experiment or {})
model, model_proof = sealed(fetcher.MODEL_ROOT, mp)
experiment, exp_proof = sealed(fetcher.REMOTE_ROOT + '/' + fetcher.EXPERIMENT_RELATIVE, ep)
registry = {}
index = []
for name, content in experiment.items():
if Path(name).suffix.lower() in fetcher.EVIDENCE_SUFFIXES and len(content) <= fetcher.MAX_FILE_BYTES:
dest = 'evidence/' + name
registry[dest] = content
index.append(dict(source=fetcher.EXPERIMENT_RELATIVE + '/' + name,
copy=dest, bytes=len(content), sha256=fetcher.sha(content)))
for name in fetcher.CONTROLS:
dest = 'model/' + name; content = model[name]
registry[dest] = content
index.append(dict(source=fetcher.MODEL_RELATIVE + '/' + name,
copy=dest, bytes=len(content), sha256=fetcher.sha(content)))
registry['seal-verification.json'] = data(dict(model=model_proof, experiment=exp_proof))
registry['evidence-index.json'] = data(index)
receipt = dict(publication_complete=True, registry=fetcher.REGISTRY_RELATIVE, project_root=fetcher.REMOTE_ROOT,
source_trees_verified_before_and_after_copy=True, publication_success_is_not_scientific_pass=True,
complete_bulk_backup=False, scientific_gate_executed_by_publisher=False,
scientific_gate_certified_by_publication=False, candidate_generated=False, learning_achieved=False,
model_manifest_sha256=model_proof['manifest_sha256'], experiment_manifest_sha256=exp_proof['manifest_sha256'],
files=[row(name, content) for name, content in sorted(registry.items())],
limits=dict(max_selected_evidence_file_bytes=fetcher.MAX_FILE_BYTES, selected_suffixes=sorted(fetcher.EVIDENCE_SUFFIXES)),
declared_audit_status=status['status'], declared_gate_results={'zero_overlay_exact': False},
declared_audit_counts={'primary_trials_per_stage': 120})
registry['publication-receipt.json'] = data(receipt)
files = {fetcher.MODEL_ROOT + '/' + name: content for name, content in model.items()}
files.update({fetcher.REGISTRY_ROOT + '/' + name: content for name, content in registry.items()})
return FakeSFTP(files), fetcher.sha(registry['publication-receipt.json'])
class FetchTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix='phase4am-fetch-synthetic-')
self.addCleanup(self.temp.cleanup)
self.destination = Path(self.temp.name).resolve() / 'report'
self.sftp, self.receipt_sha = fixture()
def receipt(self):
return fetcher.json_bytes(self.sftp.files[fetcher.REGISTRY_ROOT + '/publication-receipt.json'])
def resign(self, receipt):
raw = data(receipt)
self.sftp.files[fetcher.REGISTRY_ROOT + '/publication-receipt.json'] = raw
self.receipt_sha = fetcher.sha(raw)
def get(self, **kwargs):
return fetcher.fetch(self.sftp, self.destination, self.receipt_sha, **kwargs)
def test_only_receipt_small_files_and_model_source_with_hashes(self):
result = self.get()
self.assertTrue(result['fetch_complete'])
self.assertTrue(result['both_manifest_self_checksums_verified'])
self.assertTrue(result['fetch_success_is_not_scientific_pass'])
self.assertFalse(result['complete_bulk_backup'])
self.assertFalse(result['all_remote_experiment_bulk_rehashed_locally'])
self.assertEqual(result['declared_audit_status'], 'INCOMPLETE-SYNTHETIC-AM-EVIDENCE')
self.assertTrue((self.destination / 'audit/final-status.json').is_file())
self.assertTrue((self.destination / 'model/module.py').is_file())
self.assertTrue((self.destination / 'registry/publication-receipt.json').is_file())
self.assertFalse((self.destination / 'gpu/example/state.npz').exists())
self.assertFalse((self.destination / 'model/never-download.npy').exists())
self.assertFalse(any('interpretation' in path or 'phase4aj' in path or path.endswith(('.npy', '.npz', '.jsonl'))
for path in self.sftp.opened))
for entry in result['files']:
self.assertEqual(fetcher.sha((self.destination / entry['local']).read_bytes()), entry['sha256'])
def test_out_of_band_sha_is_mandatory_and_checked_before_other_remote_reads(self):
for checksum in ('', 'g' * 64, '0' * 64):
self.sftp.opened.clear()
with self.subTest(checksum=checksum), self.assertRaises(ValueError):
fetcher.fetch(self.sftp, self.destination, checksum)
self.assertFalse(self.destination.exists())
self.assertTrue(all(path.endswith('/publication-receipt.json') for path in self.sftp.opened))
def test_no_overwrite_or_resume_even_empty_existing_directory(self):
self.destination.mkdir()
with self.assertRaisesRegex(ValueError, 'exists'):
self.get()
self.assertFalse(self.sftp.opened)
self.assertEqual(list(self.destination.iterdir()), [])
def test_malformed_or_non_small_receipt_paths_fail_without_download(self):
for name, size in (('../escape.json', 1), ('evidence/bulk.npy', 1), ('interpretation-metrics.json', 1),
('evidence/huge.json', fetcher.MAX_FILE_BYTES + 1), ('evidence/C:/escape.json', 1)):
with self.subTest(name=name):
self.sftp, self.receipt_sha = fixture()
receipt = self.receipt()
receipt['files'].append(dict(path=name, bytes=size, sha256='a' * 64))
self.resign(receipt)
with self.assertRaises(ValueError):
self.get()
self.assertFalse(self.destination.exists())
self.assertEqual(self.sftp.opened, [fetcher.REGISTRY_ROOT + '/publication-receipt.json'])
def test_manifest_self_checksum_is_not_trusted_from_receipt_alone(self):
name = 'evidence/checksums.sha256'; path = fetcher.REGISTRY_ROOT + '/' + name
lines = self.sftp.files[path].decode().splitlines()
lines[-1] = '0' * 64 + ' manifest.json'
changed = ('\n'.join(lines) + '\n').encode()
self.sftp.files[path] = changed
receipt = self.receipt()
next(entry for entry in receipt['files'] if entry['path'] == name).update(bytes=len(changed), sha256=fetcher.sha(changed))
self.resign(receipt)
with self.assertRaisesRegex(ValueError, 'self-SHA'):
self.get()
self.assertFalse(self.destination.exists())
def test_model_original_seal_must_equal_registry_anchor(self):
self.sftp.files[fetcher.MODEL_ROOT + '/manifest.json'] += b' '
with self.assertRaises(ValueError):
self.get()
self.assertFalse(self.destination.exists())
def test_corrupt_selected_payload_preserves_partial_and_blocks_resume(self):
path = fetcher.REGISTRY_ROOT + '/evidence/REPORT.md'
self.sftp.files[path] = b'x' * len(self.sftp.files[path])
with self.assertRaisesRegex(ValueError, 'SHA'):
self.get()
self.assertTrue((self.destination / 'fetch-failure.json').is_file())
self.assertFalse((self.destination / 'fetch-verification.json').exists())
with self.assertRaisesRegex(ValueError, 'exists'):
self.get()
def test_model_source_hash_is_verified_without_fetching_other_payloads(self):
path = fetcher.MODEL_ROOT + '/module.py'
self.sftp.files[path] = b'x' * len(self.sftp.files[path])
with self.assertRaisesRegex(ValueError, 'SHA'):
self.get()
self.assertTrue((self.destination / 'fetch-failure.json').is_file())
self.assertFalse(any(path.endswith('never-download.npy') for path in self.sftp.opened))
def test_local_path_collision_and_total_budget_fail_before_destination(self):
self.sftp, self.receipt_sha = fixture(extra_experiment={'model/module.py.json': data({'not_source': True}),
'model/config.json': data({'collision': True})})
with self.assertRaisesRegex(ValueError, 'collision'):
self.get()
self.assertFalse(self.destination.exists())
self.sftp, self.receipt_sha = fixture()
with self.assertRaisesRegex(ValueError, 'total download budget'):
self.get(max_total_bytes=1)
self.assertFalse(self.destination.exists())
def test_remote_symlink_rejected_without_open(self):
path = fetcher.REGISTRY_ROOT + '/publication-receipt.json'
self.sftp.symlinks.add(path)
with self.assertRaisesRegex(ValueError, 'symlink'):
self.get()
self.assertFalse(self.sftp.opened)
def test_anchor_changed_during_copy_fails_final_check(self):
receipt_path = fetcher.REGISTRY_ROOT + '/publication-receipt.json'
def change_on_source(name):
if name == fetcher.MODEL_ROOT + '/module.py':
self.sftp.files[receipt_path] += b' '
self.sftp.hook = change_on_source
with self.assertRaises(ValueError):
self.get()
self.assertTrue((self.destination / 'fetch-failure.json').is_file())
self.assertFalse((self.destination / 'fetch-verification.json').exists())
def test_no_import_network_and_cli_rejects_unknown_hosts(self):
source = Path(fetcher.__file__).read_text(encoding='utf-8')
self.assertIn('paramiko.RejectPolicy()', source)
self.assertIn('client.load_system_host_keys(str(args.known_hosts))', source)
self.assertIn("default=Path.home() / '.ssh/known_hosts'", source)
self.assertNotIn('AutoAddPolicy', source)
self.assertNotIn('interpretation-metrics.json', source)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,411 @@
"""Temporary synthetic seals only; never publish/register any real evidence."""
import hashlib
import copy
import json
from pathlib import Path
import tempfile
import unittest
from unittest import mock
import publish_phase4am as publication
HELPER = Path(__file__).resolve().parents[1] / 'pn-recruitment-audit-v1/publication.py'
if not HELPER.is_file():
HELPER = publication.ROOT / publication.HELPER_RELATIVE
def sha(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def write(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(value, indent=2), encoding='utf-8')
def seal(root):
rows = [dict(path=path.relative_to(root).as_posix(), bytes=path.stat().st_size, sha256=sha(path))
for path in sorted(root.rglob('*')) if path.is_file() and
path.name not in ('manifest.json', 'checksums.sha256') and '__pycache__' not in path.parts]
write(root / 'manifest.json', dict(root=str(root), files=rows))
lines = [row['sha256'] + ' ' + row['path'] for row in rows]
lines.append(sha(root / 'manifest.json') + ' manifest.json')
(root / 'checksums.sha256').write_text('\n'.join(lines) + '\n', encoding='utf-8')
class PublicationTests(unittest.TestCase):
def setUp(self):
temporary = tempfile.TemporaryDirectory(prefix='phase4am-publication-synthetic-')
self.addCleanup(temporary.cleanup)
self.root = Path(temporary.name).resolve()
self.model = self.root / publication.MODEL_RELATIVE
self.experiment = self.root / publication.EXPERIMENT_RELATIVE
self.registry = self.root / publication.REGISTRY_RELATIVE
self.model.mkdir(parents=True)
self.experiment.mkdir(parents=True)
(self.model / 'module.py').write_text('# synthetic, not a model\n', encoding='utf-8')
self.config = copy.deepcopy(publication.EXPECTED_CONFIG)
write(self.model / 'config.json', self.config)
self.planned = []
for cohort in publication.COHORTS:
for mode in publication.MODES:
for odor in range(6):
for seed in range(11, 16):
name = f'{cohort}-{mode}-odor{odor}-seed{seed}'
for repeat in ((0, 1) if seed == 11 else (0,)):
self.planned.append(dict(name=name, cohort=cohort, mode=mode,
odor_id=f'{cohort}-odor{odor}', seed=seed, repeat=repeat))
self.registration = dict(config=self.config, planned=self.planned, training=False,
candidate_generated=False, before_new_brain_trajectories=True)
write(self.experiment / 'protocol/preregistered.json', self.registration)
for stage in publication.STAGES:
completed = []
for row in self.planned:
key = row['name'] + '-r' + str(row['repeat'])
folder = self.experiment / 'gpu' / stage / key
case = self.root / 'experiments/phase4ak-apl-timing-validation/cases' / row['cohort'] / row['name']
mode = 'zero' if stage == 'zero' else ('repeat' if row['repeat'] else 'self')
left = (self.root / 'experiments/phase4ak-apl-timing-validation/gpu' / row['cohort'] / key
if stage == 'zero' else (self.experiment / 'gpu' / stage / (row['name'] + '-r0')
if row['repeat'] else folder))
write(folder / 'comparison.json', dict(pass_all=True, overlay_name=stage, mode=mode,
case_dir=str(case), left=str(left), right=str(folder)))
item = folder / 'comparison.json'
write(folder / 'output-hashes.json', [dict(path=item.name, bytes=item.stat().st_size, sha256=sha(item))])
completed.append(dict(name=row['name'], repeat=row['repeat'],
output_hashes_sha256=sha(folder / 'output-hashes.json'), comparison_sha256=sha(item)))
write(self.experiment / 'audit' / (stage + '-complete.json'), dict(stage=stage, pass_all=True,
trials=144, primary_trials=120, technical_repeats=24, completed=completed, training=False))
table = self.experiment / 'summaries/per-MBON-static-effects.parquet'
table.parent.mkdir(parents=True)
table.write_bytes(b'synthetic table placeholder, never parsed as science')
self.science = dict(status=publication.FINAL_STATUS, primary_trials_per_stage=120,
technical_repeats_per_stage=24, zero_overlay_exact=True, static25_repeat_exact=True,
training=False, learned_candidate=False, conditional_AL_not_a_nonzero_arithmetic_oracle=True,
scope=publication.SCIENCE_SCOPE, per_MBON_sha256=sha(table),
timing=[dict(stage=s, case=r['name'], wall_seconds=.01, simulation_seconds=.005)
for s in publication.STAGES for r in self.planned if r['repeat'] == 0],
blocks={c + '/' + m: dict(trials=30, populations={p: dict(trials_event_change=0,
trials_count_change=0, mean_count_l1=0., mean_recruited_cells=0., mean_lost_cells=0.)
for p in publication.POPULATIONS}) for c in publication.COHORTS for m in publication.MODES})
write(self.experiment / 'audit/scientific-summary.json', self.science)
self.status = dict(status=publication.FINAL_STATUS, primary_trials_per_stage=120, repeats_per_stage=24,
zero_overlay_exact=True, static25_repeat_exact=True, old_integrity_pass=True,
frozen_five_reference_pass=True, frozen_eligibility_and_mask_unchanged=True, base_weights_unchanged=True,
training=False, learned_candidate=False,
scientific_summary_sha256=sha(self.experiment / 'audit/scientific-summary.json'))
write(self.experiment / 'audit/final-status.json', self.status)
write(self.experiment / 'regression/frozen-five.json', dict(pass_all=True,
trials=[dict(trial=name, exact={k: True for k in ('step', 'neuron_idx', 'counts', 'v', 'g')})
for name in publication.REFERENCE_NAMES]))
write(self.experiment / 'regression/old-integrity-after.json', {'synthetic-old-tree': {'pass': True}})
write(self.experiment / 'nested/case/summary.json', {'synthetic': True})
(self.experiment / 'REPORT.md').write_text('Synthetic zero-effect diagnostic.\n', encoding='utf-8')
(self.experiment / 'tests.log').write_text('Synthetic log\n', encoding='utf-8')
for suffix in ('.npy', '.npz', '.parquet'):
(self.experiment / ('bulk' + suffix)).write_bytes(b'synthetic bulk bytes, not scientific data')
seal(self.model)
seal(self.experiment)
def publish(self):
return publication.publish(self.root, HELPER)
def check_declarations(self):
seal(self.experiment)
rows = {r['path']: r for r in json.loads((self.experiment / 'manifest.json').read_text())['files']}
return publication._status_evidence(publication.load_helpers(HELPER), self.experiment, rows, self.model)
def write_science(self, science):
write(self.experiment / 'audit/scientific-summary.json', science)
write(self.experiment / 'audit/final-status.json', dict(self.status,
scientific_summary_sha256=sha(self.experiment / 'audit/scientific-summary.json')))
def test_stage_receipts_require_both_full_144_inventories(self):
for stage in publication.STAGES:
path = self.experiment / 'audit' / (stage + '-complete.json')
original = json.loads(path.read_text())
for change in ({'trials': 143}, {'primary_trials': 119}, {'technical_repeats': 23},
{'completed': original['completed'][:-1]}, {'pass_all': False}, {'stage': 'other'}):
with self.subTest(stage=stage, change=list(change)):
write(path, dict(original, **change))
with self.assertRaises(ValueError):
self.check_declarations()
write(path, original)
def test_stage_receipt_hash_and_order_cannot_hide_wrong_case(self):
path = self.experiment / 'audit/static25-complete.json'
original = json.loads(path.read_text())
for bad in ('hash', 'duplicate', 'reorder'):
receipt = copy.deepcopy(original)
if bad == 'hash':
receipt['completed'][0]['comparison_sha256'] = '0' * 64
elif bad == 'duplicate':
receipt['completed'][1] = copy.deepcopy(receipt['completed'][0])
else:
receipt['completed'][0], receipt['completed'][1] = receipt['completed'][1], receipt['completed'][0]
with self.subTest(bad=bad):
write(path, receipt)
with self.assertRaises(ValueError):
self.check_declarations()
def test_reanchored_comparison_cannot_change_stage_case_or_repeat_mode(self):
stage_path = self.experiment / 'audit/static25-complete.json'
original_stage = json.loads(stage_path.read_text())
plan = self.planned[0]
folder = self.experiment / 'gpu/static25' / (plan['name'] + '-r0')
comparison = folder / 'comparison.json'
inventory = folder / 'output-hashes.json'
original_report = json.loads(comparison.read_text())
for key, value in (('mode', 'repeat'), ('overlay_name', 'zero'), ('case_dir', '/wrong-case'),
('left', '/wrong-reference'), ('right', '/wrong-output')):
with self.subTest(key=key):
write(comparison, dict(original_report, **{key: value}))
write(inventory, [dict(path=comparison.name, bytes=comparison.stat().st_size, sha256=sha(comparison))])
receipt = copy.deepcopy(original_stage)
receipt['completed'][0].update(comparison_sha256=sha(comparison), output_hashes_sha256=sha(inventory))
write(stage_path, receipt)
with self.assertRaisesRegex(ValueError, 'wrong case/stage/repeat identity'):
self.check_declarations()
def test_preregistered_scientific_coverage_and_first_seed_repeats_required(self):
for mode in ('missing', 'duplicate', 'wrong_repeat_seed', 'training'):
reg = copy.deepcopy(self.registration)
if mode == 'missing':
reg['planned'].pop()
elif mode == 'duplicate':
reg['planned'][-1] = copy.deepcopy(reg['planned'][0])
elif mode == 'wrong_repeat_seed':
next(r for r in reg['planned'] if r['repeat'] == 1)['seed'] += 1
else:
reg['training'] = True
with self.subTest(mode=mode):
write(self.experiment / 'protocol/preregistered.json', reg)
with self.assertRaises(ValueError):
self.check_declarations()
def test_scientific_population_metrics_and_explicit_scopes_required(self):
for defect in ('missing_population', 'nonfinite', 'negative', 'bool_count', 'more_than30',
'count_without_event', 'AL_oracle_claim', 'learning', 'timing_missing', 'table_hash'):
science = copy.deepcopy(self.science)
pops = science['blocks'][next(iter(science['blocks']))]['populations']
if defect == 'missing_population':
pops.pop('motor')
elif defect in ('nonfinite', 'negative'):
pops['KC']['mean_count_l1'] = float('nan') if defect == 'nonfinite' else -1.
elif defect in ('bool_count', 'more_than30'):
pops['KC']['trials_event_change'] = True if defect == 'bool_count' else 31
elif defect == 'count_without_event':
pops['KC']['trials_count_change'] = 1
elif defect == 'AL_oracle_claim':
science['conditional_AL_not_a_nonzero_arithmetic_oracle'] = False
elif defect == 'learning':
science['learning_achieved'] = True
elif defect == 'timing_missing':
science['timing'].pop()
else:
science['per_MBON_sha256'] = '0' * 64
with self.subTest(defect=defect):
self.write_science(science)
with self.assertRaises(ValueError):
self.check_declarations()
def test_five_refs_require_original_names_and_nonempty_exact_keys(self):
path = self.experiment / 'regression/frozen-five.json'
original = json.loads(path.read_text())
for defect in ('duplicate_name', 'unknown_name', 'empty_exact', 'missing_exact', 'non_bool'):
refs = copy.deepcopy(original)
if defect == 'duplicate_name':
refs['trials'][1]['trial'] = refs['trials'][0]['trial']
elif defect == 'unknown_name':
refs['trials'][0]['trial'] = 'invented-reference'
elif defect == 'empty_exact':
refs['trials'][0]['exact'] = {}
elif defect == 'missing_exact':
refs['trials'][0]['exact'].pop('g')
else:
refs['trials'][0]['exact']['g'] = 1
with self.subTest(defect=defect):
write(path, refs)
with self.assertRaises(ValueError):
self.check_declarations()
def test_completed_zero_effect_diagnostic_is_not_regraded_as_learning(self):
before = {str(p): sha(p) for base in (self.model, self.experiment) for p in base.rglob('*') if p.is_file()}
result = self.publish()
self.assertTrue(result['publication_complete'])
receipt = json.loads((self.registry / 'publication-receipt.json').read_text(encoding='utf-8'))
self.assertEqual(receipt['declared_audit_status'], publication.FINAL_STATUS)
self.assertFalse(receipt['static_effect_size_gate_defined'])
self.assertEqual(set(receipt['declared_stage_coverage']), {'zero', 'static25'})
self.assertEqual(receipt['declared_audit_counts'], {'primary_trials_per_stage': 120, 'repeats_per_stage': 24})
self.assertFalse(receipt['learning_achieved'])
self.assertTrue(receipt['publication_success_is_not_scientific_pass'])
self.assertEqual(receipt['scientific_summary_sha256'], self.status['scientific_summary_sha256'])
for suffix in ('.npy', '.npz', '.parquet'):
self.assertFalse((self.registry / ('evidence/bulk' + suffix)).exists())
for row in receipt['files']:
self.assertEqual(sha(self.registry / row['path']), row['sha256'])
self.assertEqual(before, {str(p): sha(p) for base in (self.model, self.experiment) for p in base.rglob('*') if p.is_file()})
def test_changed_config_blocks_before_destination(self):
for key, value in (('phase', '4AK'), ('primary_trials', 119), ('candidate_edges', 14231),
('max_fractional_depression', .5), ('training', True), ('virtual_gate_tick', 901),
('apl_delay_steps', 0)):
with self.subTest(key=key):
write(self.model / 'config.json', dict(self.config, **{key: value}))
seal(self.model)
with self.assertRaisesRegex(ValueError, 'configuration/design'):
self.publish()
self.assertFalse(self.registry.exists())
def test_summary_hash_counts_and_scope_must_match(self):
for changed in ({'scientific_summary_sha256': '0' * 64}, {'primary_trials_per_stage': 119},
{'repeats_per_stage': 23}, {'learned_candidate': True}, {'zero_overlay_exact': 'true'},
{'old_integrity_pass': False}, {'base_weights_unchanged': False}):
with self.subTest(changed=changed):
write(self.experiment / 'audit/final-status.json', dict(self.status, **changed))
seal(self.experiment)
with self.assertRaises(ValueError):
self.publish()
self.assertFalse(self.registry.exists())
def test_missing_or_corrupt_scientific_summary_is_rejected(self):
path = self.experiment / 'audit/scientific-summary.json'
path.unlink()
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'Required finalized evidence absent'):
self.publish()
self.assertFalse(self.registry.exists())
def test_complete_status_requires_all_four_complete_blocks(self):
value = dict(self.science, blocks={})
write(self.experiment / 'audit/scientific-summary.json', value)
write(self.experiment / 'audit/final-status.json', dict(self.status,
scientific_summary_sha256=sha(self.experiment / 'audit/scientific-summary.json')))
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'cohort-mode blocks'):
self.publish()
def test_false_reference_exactness_is_not_hidden_by_pass_all(self):
write(self.experiment / 'regression/frozen-five.json', dict(pass_all=True,
trials=[dict(exact={'step': False})] * 5))
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'five exact trial'):
self.publish()
self.assertFalse(self.registry.exists())
def test_unknown_or_unfinalized_status_is_not_promoted(self):
for status in ('INCOMPLETE-NOT-SEALED', 'PASS-FROZEN-D18-INDEPENDENT-VALIDATION'):
write(self.experiment / 'audit/final-status.json', dict(self.status, status=status))
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'Unrecognized Phase 4AM'):
self.publish()
self.assertFalse(self.registry.exists())
def test_manifest_path_escape_rejected_before_destination(self):
path = self.experiment / 'manifest.json'
manifest = json.loads(path.read_text(encoding='utf-8'))
manifest['files'][0]['path'] = '../escape.json'
write(path, manifest)
controls = self.experiment / 'checksums.sha256'
controls.write_text('\n'.join([r['sha256'] + ' ' + r['path'] for r in manifest['files']] +
[sha(path) + ' manifest.json']) + '\n', encoding='utf-8')
with self.assertRaisesRegex(ValueError, 'escaping relative path'):
self.publish()
self.assertFalse(self.registry.exists())
def test_completed_status_without_frozen_reference_is_not_publishable(self):
(self.experiment / 'regression/frozen-five.json').unlink()
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'Required finalized evidence absent'):
self.publish()
self.assertFalse(self.registry.exists())
def test_existing_registry_never_overwritten_or_resumed(self):
self.registry.mkdir(parents=True)
sentinel = self.registry / 'keep.txt'
sentinel.write_bytes(b'keep these bytes')
with self.assertRaisesRegex(ValueError, 'Registry already exists'):
self.publish()
self.assertEqual(sentinel.read_bytes(), b'keep these bytes')
self.assertEqual(list(self.registry.iterdir()), [sentinel])
def test_missing_integrity_report_blocks_before_destination(self):
(self.experiment / 'regression/old-integrity-after.json').unlink()
seal(self.experiment)
with self.assertRaisesRegex(ValueError, 'Required finalized evidence absent'):
self.publish()
self.assertFalse(self.registry.exists())
def test_bulk_corruption_blocks_even_though_bulk_is_not_copied(self):
path = self.experiment / 'bulk.npy'
path.write_bytes(b'x' * path.stat().st_size)
with self.assertRaisesRegex(ValueError, 'Payload SHA-256 mismatch'):
self.publish()
self.assertFalse(self.registry.exists())
def test_unlisted_payload_and_bad_manifest_self_hash_fail(self):
extra = self.experiment / 'unlisted.csv'
extra.write_text('unlisted\n')
with self.assertRaisesRegex(ValueError, 'unlisted/missing'):
self.publish()
extra.unlink()
controls = self.experiment / 'checksums.sha256'
lines = controls.read_text().splitlines()
lines[-1] = '0' * 64 + ' manifest.json'
controls.write_text('\n'.join(lines) + '\n')
with self.assertRaisesRegex(ValueError, 'manifest self-checksum'):
self.publish()
self.assertFalse(self.registry.exists())
def test_large_json_verified_but_not_copied(self):
path = self.experiment / 'large.json'
path.write_bytes(b' ' * (publication.MAX_EVIDENCE_BYTES + 1))
seal(self.experiment)
self.publish()
self.assertFalse((self.registry / 'evidence/large.json').exists())
receipt = json.loads((self.registry / 'publication-receipt.json').read_text(encoding='utf-8'))
self.assertEqual(next(r for r in receipt['experiment_payload_not_copied'] if r['path'] == 'large.json')['reason'],
'exceeds_4_MiB')
def test_interrupted_copy_retained_and_cannot_resume(self):
with mock.patch.object(publication, '_copy', side_effect=OSError('synthetic interrupted copy')):
with self.assertRaisesRegex(OSError, 'synthetic interrupted copy'):
self.publish()
self.assertTrue((self.registry / 'publication-failure.json').is_file())
self.assertFalse((self.registry / 'publication-receipt.json').exists())
with self.assertRaisesRegex(ValueError, 'Registry already exists'):
self.publish()
def test_after_copy_full_verification_detects_bulk_change(self):
original = publication._copy
changed = False
def copy_then_change(helper, source, destination, size, checksum):
nonlocal changed
original(helper, source, destination, size, checksum)
if not changed:
changed = True
(self.experiment / 'bulk.npy').write_bytes(b'changed after initial seal check')
with mock.patch.object(publication, '_copy', side_effect=copy_then_change):
with self.assertRaises(ValueError):
self.publish()
self.assertTrue((self.registry / 'publication-failure.json').is_file())
self.assertFalse((self.registry / 'publication-receipt.json').exists())
def test_helper_pin_checked_without_modifying_old_globals_or_cache(self):
helper = publication.load_helpers(HELPER)
self.assertEqual(helper.MODEL_RELATIVE, Path('models/male-cns-lif/pn-recruitment-audit-v1'))
self.assertEqual(helper.FINAL_STATUS, 'PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT')
wrong = self.root / 'wrong-helper.py'
wrong.write_bytes(b'raise RuntimeError("must never execute")\n')
with self.assertRaisesRegex(ValueError, 'helper hash mismatch'):
publication.publish(self.root, wrong)
self.assertFalse(self.registry.exists())
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,270 @@
"""Synthetic temporary Git repositories only; no real publication or science."""
import contextlib
import io
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
import verify_git_payload as verifier
def encoded(value):
return (json.dumps(value, sort_keys=True, indent=2) + '\n').encode('utf-8')
def sealed(relative, payload):
rows = [dict(path=path, bytes=len(data), sha256=verifier.sha(data)) for path, data in sorted(payload.items())]
manifest = encoded(dict(root=verifier.PROJECT + '/' + relative, files=rows))
checksums = ''.join(row['sha256'] + ' ' + row['path'] + '\n' for row in rows)
checksums += verifier.sha(manifest) + ' manifest.json\n'
controls = {'manifest.json': manifest, 'checksums.sha256': checksums.encode('utf-8')}
proof = dict(pass_all=True, root=verifier.PROJECT + '/' + relative,
payload_file_count=len(rows), payload_bytes=sum(row['bytes'] for row in rows),
manifest_sha256=verifier.sha(manifest), checksums_sha256=verifier.sha(controls['checksums.sha256']),
excluded_pycache_files=0, verification_scope='synthetic test only')
return rows, controls, proof
@unittest.skipUnless(shutil.which('git'), 'Git executable is required')
class GitPayloadTests(unittest.TestCase):
def setUp(self):
temporary = tempfile.TemporaryDirectory(prefix='phase4am-git-payload-synthetic-')
self.addCleanup(temporary.cleanup)
self.repo = Path(temporary.name).resolve()
self.git('init', '--quiet')
self.git('config', 'user.name', 'Synthetic Test')
self.git('config', 'user.email', 'synthetic@example.invalid')
self.git('config', 'core.autocrlf', 'false')
self.git('config', 'commit.gpgsign', 'false')
self.model = {'module.py': b'# synthetic, not a brain\nx = 1\n', 'config.json': b'{"synthetic": true}\n'}
self.exp = {'audit/final-status.json': encoded(dict(status='FAIL-SYNTHETIC-AM-INTERFACE')),
'case/summary.json': b'{"synthetic": true}\n', 'bulk.npy': b'not-a-real-array\x00'}
self.build()
def git(self, *args, data=None):
env = os.environ.copy()
for key in ('GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_COMMON_DIR',
'GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES'):
env.pop(key, None)
result = subprocess.run(['git', '-C', str(self.repo), *args], input=data,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, check=False)
self.assertEqual(result.returncode, 0, result.stderr.decode('utf-8', 'replace'))
return result.stdout
def write(self, path, data):
target = self.repo / path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(data)
def build(self):
_, model_controls, model_proof = sealed(verifier.MODEL, self.model)
exp_rows, exp_controls, exp_proof = sealed(verifier.EXPERIMENT, self.exp)
for path, data in {**self.model, **model_controls}.items():
self.write(verifier.MODEL + '/' + path, data)
registry = {}
index = []
omitted = []
for path, data in {**self.exp, **exp_controls}.items():
row = dict(path=path, bytes=len(data), sha256=verifier.sha(data))
if Path(path).suffix in verifier.SUFFIXES and len(data) <= verifier.MAX_EVIDENCE:
registry['evidence/' + path] = data
index.append(dict(source=verifier.EXPERIMENT + '/' + path, copy='evidence/' + path,
bytes=len(data), sha256=verifier.sha(data)))
else:
omitted.append(dict(row, reason='bulk_or_non_evidence_extension'))
for path, data in model_controls.items():
registry['model/' + path] = data
index.append(dict(source=verifier.MODEL + '/' + path, copy='model/' + path,
bytes=len(data), sha256=verifier.sha(data)))
registry['evidence-index.json'] = encoded(index)
registry['seal-verification.json'] = encoded(dict(model=model_proof, experiment=exp_proof))
self.receipt = dict(publication_complete=True, registry=verifier.REGISTRY, project_root=verifier.PROJECT,
model_payload_remains_at=verifier.MODEL, bulk_remains_at=verifier.EXPERIMENT,
model_manifest_sha256=model_proof['manifest_sha256'],
experiment_manifest_sha256=exp_proof['manifest_sha256'],
copied_evidence_files=len(index), copied_evidence_bytes=sum(row['bytes'] for row in index),
files=[dict(path=path, bytes=len(data), sha256=verifier.sha(data)) for path, data in sorted(registry.items())],
experiment_payload_not_copied=omitted, declared_audit_status='FAIL-SYNTHETIC-AM-INTERFACE')
for path, data in registry.items():
self.write(verifier.REGISTRY + '/' + path, data)
self.receipt_write()
self.git('add', '--', verifier.MODEL, verifier.REGISTRY)
def receipt_write(self):
data = encoded(self.receipt)
self.write(verifier.REGISTRY + '/publication-receipt.json', data)
self.anchor = verifier.sha(data)
def anchored_registry_change(self, relative, data):
self.write(verifier.REGISTRY + '/' + relative, data)
row = next(row for row in self.receipt['files'] if row['path'] == relative)
row.update(bytes=len(data), sha256=verifier.sha(data))
self.receipt_write()
self.git('add', '--', verifier.REGISTRY)
def verify(self, **kwargs):
return verifier.verify_git_payload(self.repo, self.anchor, **({'staged': True} if not kwargs else kwargs))
def test_staged_verifies_blob_bytes_and_leaves_index_unchanged(self):
before = (self.repo / '.git/index').read_bytes()
result = self.verify()
self.assertTrue(result['pass_all'])
self.assertEqual(result['model_payload_files'], 2)
self.assertEqual(result['declared_audit_status'], 'FAIL-SYNTHETIC-AM-INTERFACE')
self.assertFalse(result['experiment_bulk_verified_by_this_tool'])
self.assertFalse(result['scientific_gate_executed'])
self.assertTrue(result['publication_integrity_is_not_scientific_pass'])
self.assertEqual(before, (self.repo / '.git/index').read_bytes())
self.assertFalse((self.repo / verifier.EXPERIMENT).exists())
def test_dirty_or_missing_worktree_payload_does_not_replace_good_index(self):
(self.repo / verifier.MODEL / 'module.py').write_bytes(b'working copy differs')
(self.repo / verifier.REGISTRY / 'publication-receipt.json').unlink()
self.assertTrue(self.verify()['pass_all'])
def test_correct_worktree_cannot_hide_corrupt_staged_blob(self):
relative = verifier.MODEL + '/module.py'
self.write(relative, self.model['module.py'].replace(b'x = 1', b'x = 2'))
self.git('add', '--', relative)
self.write(relative, self.model['module.py'])
with self.assertRaisesRegex(ValueError, 'Git blob SHA-256 mismatch'):
self.verify()
def test_commit_verifies_immutable_commit_not_current_index(self):
self.git('commit', '--quiet', '-m', 'synthetic only')
commit = self.git('rev-parse', 'HEAD').decode().strip()
self.write(verifier.MODEL + '/module.py', b'bad newer index')
self.git('add', '--', verifier.MODEL)
result = self.verify(commit='HEAD')
self.assertEqual(result['commit'], commit)
self.assertEqual(result['source'], 'commit')
self.assertTrue(result['pass_all'])
def test_external_receipt_anchor_is_mandatory_and_checked(self):
for anchor in (None, '', '0' * 64, self.anchor.upper()):
with self.subTest(anchor=anchor), self.assertRaises(ValueError):
verifier.verify_git_payload(self.repo, anchor, staged=True)
def test_extra_model_file_is_rejected_but_outside_scope_is_ignored(self):
self.write('unrelated/old-file.txt', b'outside audit scope')
self.git('add', '--', 'unrelated')
self.assertTrue(self.verify()['pass_all'])
self.write(verifier.MODEL + '/extra.py', b'extra')
self.git('add', '--', verifier.MODEL)
with self.assertRaisesRegex(ValueError, 'Model Git inventory'):
self.verify()
def test_extra_registry_file_is_rejected(self):
self.write(verifier.REGISTRY + '/unlisted.json', b'{}')
self.git('add', '--', verifier.REGISTRY)
with self.assertRaisesRegex(ValueError, 'Registry Git inventory'):
self.verify()
def test_missing_staged_model_file_is_rejected(self):
self.git('update-index', '--force-remove', verifier.MODEL + '/module.py')
with self.assertRaisesRegex(ValueError, 'Model Git inventory'):
self.verify()
def test_symlink_blob_mode_is_rejected_without_following_it(self):
path = verifier.MODEL + '/module.py'
oid = self.git('rev-parse', ':' + path).decode().strip()
self.git('update-index', '--cacheinfo', '120000,' + oid + ',' + path)
with self.assertRaisesRegex(ValueError, 'Symlink/gitlink/nonregular'):
self.verify()
def test_gitlink_is_rejected(self):
self.git('commit', '--quiet', '-m', 'synthetic only')
oid = self.git('rev-parse', 'HEAD').decode().strip()
self.git('update-index', '--add', '--cacheinfo', '160000,' + oid + ',' + verifier.MODEL + '/submodule')
with self.assertRaisesRegex(ValueError, 'Symlink/gitlink/nonregular'):
self.verify()
def test_unmerged_index_is_rejected(self):
path = verifier.MODEL + '/module.py'
oid = self.git('rev-parse', ':' + path).decode().strip()
self.git('update-index', '--force-remove', path)
self.git('update-index', '--index-info', data=('100644 ' + oid + ' 1\t' + path + '\n').encode())
with self.assertRaisesRegex(ValueError, 'Unmerged index'):
self.verify()
def test_anchored_index_source_escape_is_rejected(self):
data = json.loads((self.repo / verifier.REGISTRY / 'evidence-index.json').read_bytes())
data[0]['source'] = 'experiments/another-phase/audit/final-status.json'
self.anchored_registry_change('evidence-index.json', encoded(data))
with self.assertRaisesRegex(ValueError, 'Evidence index differs'):
self.verify()
def test_anchored_registry_copy_cannot_disagree_with_model(self):
data = (self.repo / verifier.REGISTRY / 'model/checksums.sha256').read_bytes()
self.anchored_registry_change('model/checksums.sha256', b'0' * 64 + data[64:])
with self.assertRaisesRegex(ValueError, 'Checksum inventory'):
self.verify()
def test_anchored_receipt_cannot_change_model_manifest_anchor(self):
self.receipt['model_manifest_sha256'] = '0' * 64
self.receipt_write(); self.git('add', '--', verifier.REGISTRY)
with self.assertRaisesRegex(ValueError, 'Receipt-bound manifest'):
self.verify()
def test_registry_payload_corruption_is_rejected(self):
path = verifier.REGISTRY + '/evidence/case/summary.json'
self.write(path, b'{"synthetic":false}\n')
self.git('add', '--', path)
with self.assertRaisesRegex(ValueError, 'Git blob (byte count|SHA-256) mismatch'):
self.verify()
def test_anchored_receipt_path_escape_and_duplicate_fail(self):
self.receipt['files'][0]['path'] = '../outside.json'
self.receipt_write(); self.git('add', '--', verifier.REGISTRY)
with self.assertRaisesRegex(ValueError, 'Noncanonical or escaping path'):
self.verify()
def test_duplicate_json_key_fails_even_with_external_anchor(self):
data = encoded(self.receipt).replace(b'{\n', b'{\n "publication_complete": true,\n', 1)
self.write(verifier.REGISTRY + '/publication-receipt.json', data)
self.anchor = verifier.sha(data)
self.git('add', '--', verifier.REGISTRY)
with self.assertRaisesRegex(ValueError, 'Duplicate JSON key'):
self.verify()
def test_incomplete_status_is_preserved_not_regraded(self):
self.receipt['declared_audit_status'] = 'INCOMPLETE-SYNTHETIC-AM-EXECUTION'
self.receipt_write(); self.git('add', '--', verifier.REGISTRY)
result = self.verify()
self.assertEqual(result['declared_audit_status'], 'INCOMPLETE-SYNTHETIC-AM-EXECUTION')
self.assertTrue(result['publication_integrity_is_not_scientific_pass'])
def test_anchored_bulk_omission_inventory_mismatch_fails(self):
self.receipt['experiment_payload_not_copied'] = []
self.receipt_write(); self.git('add', '--', verifier.REGISTRY)
with self.assertRaisesRegex(ValueError, 'omitted-bulk inventory mismatch'):
self.verify()
def test_anchored_seal_proof_contradiction_fails(self):
proof = json.loads((self.repo / verifier.REGISTRY / 'seal-verification.json').read_bytes())
proof['model']['payload_file_count'] += 1
self.anchored_registry_change('seal-verification.json', encoded(proof))
with self.assertRaisesRegex(ValueError, 'Seal-verification evidence contradicts'):
self.verify()
def test_both_or_neither_git_sources_fail(self):
for kwargs in ({}, {'staged': True, 'commit': 'HEAD'}):
with self.subTest(kwargs=kwargs), self.assertRaisesRegex(ValueError, 'Select exactly one'):
verifier.verify_git_payload(self.repo, self.anchor, **kwargs)
def test_cli_success_and_failure_are_json_with_exit_status(self):
for anchor, expected in ((self.anchor, 0), ('0' * 64, 1)):
with self.subTest(expected=expected), contextlib.redirect_stdout(io.StringIO()) as output:
code = verifier.main(['--repo', str(self.repo), '--staged', '--receipt-sha256', anchor])
result = json.loads(output.getvalue())
self.assertEqual(code, expected)
self.assertEqual(result['pass_all'], expected == 0)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,325 @@
"""Verify fixed Phase 4AM Git blobs, not working-tree files or scientific gates.
The publication receipt SHA-256 must come from an external trusted record.
Only the index or one resolved commit is read. No publish, checkout, index
mutation, network fetch, or scientific execution is performed.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
from pathlib import Path, PurePosixPath
import re
import subprocess
import sys
PROJECT = '/data/digital-drosophila'
MODEL = 'models/male-cns-lif/wholebrain-plastic-interface-v1'
EXPERIMENT = 'experiments/phase4am-wholebrain-plastic-interface'
REGISTRY = 'registry/phase4am-wholebrain-plastic-interface'
CONTROLS = frozenset(('manifest.json', 'checksums.sha256'))
SHA256 = re.compile(r'[0-9a-f]{64}\Z')
OID = re.compile(r'(?:[0-9a-f]{40}|[0-9a-f]{64})\Z')
MAX_EVIDENCE = 4 * 1024 ** 2
MAX_BLOB = 64 * 1024 ** 2
SUFFIXES = frozenset(('.json', '.csv', '.md', '.log', '.sha256'))
def require(condition, message):
if not condition:
raise ValueError(message)
def sha(data):
return hashlib.sha256(data).hexdigest()
def relative(value):
require(isinstance(value, str) and bool(value) and
not any(char in value for char in '\\\x00\n\r\t'), 'Invalid relative path')
path = PurePosixPath(value)
require(not path.is_absolute() and str(path) == value and
all(part not in ('', '.', '..') and ':' not in part for part in path.parts),
'Noncanonical or escaping path: ' + value)
return value
def unique_object(pairs):
value = {}
for key, item in pairs:
require(key not in value, 'Duplicate JSON key: ' + key)
value[key] = item
return value
def json_bytes(data):
def nonfinite(value):
raise ValueError('Nonfinite JSON value: ' + value)
return json.loads(data.decode('utf-8'), object_pairs_hook=unique_object,
parse_constant=nonfinite)
def rows_by_path(rows, label):
require(isinstance(rows, list) and bool(rows), 'Missing/empty ' + label)
result = {}
for row in rows:
require(isinstance(row, dict) and set(row) == {'path', 'bytes', 'sha256'},
'Invalid ' + label + ' row schema')
path = relative(row['path'])
require(path not in result and '__pycache__' not in PurePosixPath(path).parts,
'Duplicate/cache ' + label + ' path: ' + path)
require(type(row['bytes']) is int and row['bytes'] >= 0 and
isinstance(row['sha256'], str) and SHA256.fullmatch(row['sha256']),
'Invalid bytes/SHA-256 in ' + label + ': ' + path)
result[path] = row
return result
class GitBlobs:
"""Snapshot inventory plus immutable object reads; no work-tree fallback."""
def __init__(self, repo, *, staged, commit):
require(type(staged) is bool and (staged != (commit is not None)),
'Select exactly one of staged or commit')
self.repo = Path(repo).resolve(strict=True)
require(self.repo.is_dir(), 'Repository must be a directory')
self.env = os.environ.copy()
# The explicitly supplied repo/index must not be redirected by caller env.
for key in ('GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_COMMON_DIR',
'GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES'):
self.env.pop(key, None)
self.env.update(GIT_OPTIONAL_LOCKS='0', GIT_NO_REPLACE_OBJECTS='1', GIT_NO_LAZY_FETCH='1')
self.base = ['git', '--no-optional-locks', '-c', 'core.fsmonitor=false',
'-c', 'gc.auto=0', '-C', str(self.repo)]
top = self.command('rev-parse', '--show-toplevel').decode('utf-8').strip()
require(Path(top).resolve(strict=True) == self.repo, 'Supply the Git repository top-level directory')
if staged:
self.commit = None
else:
require(isinstance(commit, str) and bool(commit) and not commit.startswith('-') and
not any(c in commit for c in '\x00\n\r'), 'Invalid commit selector')
self.commit = self.command('rev-parse', '--verify', '--end-of-options',
commit + '^{commit}').decode('ascii').strip()
require(OID.fullmatch(self.commit), 'Commit did not resolve to a full object ID')
self.staged = staged
self.inventory_bytes = self.inventory()
self.entries = self.parse_inventory(self.inventory_bytes)
self.verified = {}
def command(self, *args):
result = subprocess.run(self.base + list(args), env=self.env, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, check=False)
require(result.returncode == 0, 'Git read failed: ' + result.stderr.decode('utf-8', 'replace').strip())
return result.stdout
def inventory(self):
if self.staged:
return self.command('ls-files', '--stage', '--full-name', '-z', '--', MODEL, REGISTRY)
return self.command('ls-tree', '-r', '-z', '--full-tree', self.commit, '--', MODEL, REGISTRY)
def parse_inventory(self, data):
result = {}
require(data.endswith(b'\x00'), 'Empty/malformed scoped Git inventory')
for entry in data[:-1].split(b'\x00'):
metadata, raw_path = entry.split(b'\t', 1)
fields = metadata.decode('ascii').split(' ')
require(len(fields) == 3, 'Malformed Git entry')
if self.staged:
mode, oid, stage = fields
require(stage == '0', 'Unmerged index entry is forbidden')
else:
mode, kind, oid = fields
require(kind == 'blob', 'Non-blob Git entry is forbidden')
path = relative(raw_path.decode('utf-8'))
require(path.startswith(MODEL + '/') or path.startswith(REGISTRY + '/'),
'Git entry escapes the fixed AM scopes: ' + path)
require(mode in ('100644', '100755') and OID.fullmatch(oid),
'Symlink/gitlink/nonregular Git entry is forbidden: ' + path)
require(path not in result, 'Duplicate Git path: ' + path)
result[path] = dict(mode=mode, oid=oid)
return result
def read(self, path):
relative(path)
require(path in self.entries, 'Missing Git blob: ' + path)
oid = self.entries[path]['oid']
size = int(self.command('cat-file', '-s', oid).decode('ascii').strip())
require(0 <= size <= MAX_BLOB, 'Git blob exceeds publication verifier limit: ' + path)
# cat-file blob addresses the object, so attributes/filters/autocrlf do
# not turn a corrupt staged blob into a good working-tree substitute.
data = self.command('cat-file', 'blob', oid)
require(len(data) == size, 'Git object size changed: ' + path)
self.verified[path] = dict(path=path, bytes=len(data), sha256=sha(data),
git_oid=oid, git_mode=self.entries[path]['mode'])
return data
def match(self, path, row):
data = self.read(path)
require(len(data) == row['bytes'], 'Git blob byte count mismatch: ' + path)
require(sha(data) == row['sha256'], 'Git blob SHA-256 mismatch: ' + path)
return data
def finish(self):
require(self.inventory() == self.inventory_bytes, 'Scoped Git inventory changed during verification')
def seal_controls(manifest_data, checksum_data, expected_relative, expected_sha):
"""Validate control syntax/inventory; does not claim absent bulk was read."""
require(sha(manifest_data) == expected_sha, 'Receipt-bound manifest SHA-256 mismatch')
manifest = json_bytes(manifest_data)
require(isinstance(manifest, dict) and set(manifest) == {'root', 'files'} and
manifest['root'] == PROJECT + '/' + expected_relative, 'Wrong seal manifest schema/root')
rows = rows_by_path(manifest['files'], 'manifest')
require(not (set(rows) & CONTROLS), 'Seal controls listed as payload')
checksums = {}
for line in checksum_data.decode('utf-8').splitlines():
require(len(line) >= 67 and line[64:66] == ' ' and SHA256.fullmatch(line[:64]),
'Malformed checksum line')
path = relative(line[66:])
require(path not in checksums, 'Duplicate checksum path: ' + path)
checksums[path] = line[:64]
require(checksums == {**{name: row['sha256'] for name, row in rows.items()},
'manifest.json': sha(manifest_data)},
'Checksum inventory or manifest self-checksum mismatch')
return rows
def control_rows(manifest_data, checksum_data):
return {name: dict(path=name, bytes=len(data), sha256=sha(data)) for name, data in
(('manifest.json', manifest_data), ('checksums.sha256', checksum_data))}
def verify_git_payload(repo, receipt_sha256, *, staged=False, commit=None):
require(isinstance(receipt_sha256, str) and SHA256.fullmatch(receipt_sha256),
'External publication receipt SHA-256 is required')
blobs = GitBlobs(repo, staged=staged, commit=commit)
receipt_data = blobs.read(REGISTRY + '/publication-receipt.json')
require(len(receipt_data) <= MAX_EVIDENCE and sha(receipt_data) == receipt_sha256,
'External publication receipt SHA-256 mismatch')
receipt = json_bytes(receipt_data)
require(isinstance(receipt, dict) and receipt.get('publication_complete') is True and
receipt.get('registry') == REGISTRY and receipt.get('project_root') == PROJECT and
receipt.get('model_payload_remains_at') == MODEL and receipt.get('bulk_remains_at') == EXPERIMENT,
'Wrong/incomplete AM publication receipt or fixed scope')
for key in ('model_manifest_sha256', 'experiment_manifest_sha256'):
require(isinstance(receipt.get(key), str) and SHA256.fullmatch(receipt[key]),
'Invalid receipt manifest anchor: ' + key)
registry_rows = rows_by_path(receipt.get('files'), 'receipt files')
require('publication-receipt.json' not in registry_rows, 'Receipt must not list itself')
require({'evidence-index.json', 'seal-verification.json', 'model/manifest.json',
'model/checksums.sha256', 'evidence/manifest.json', 'evidence/checksums.sha256'} <= set(registry_rows),
'Required registry evidence/control missing')
observed_registry = {path[len(REGISTRY) + 1:] for path in blobs.entries if path.startswith(REGISTRY + '/')}
require(observed_registry == set(registry_rows) | {'publication-receipt.json'},
'Registry Git inventory has unlisted/missing files: ' + repr(sorted(
observed_registry ^ (set(registry_rows) | {'publication-receipt.json'}))))
controls_data = {}
for path, row in registry_rows.items():
require(row['bytes'] <= MAX_EVIDENCE, 'Registry receipt file exceeds 4 MiB')
data = blobs.match(REGISTRY + '/' + path, row)
if path in ('evidence-index.json', 'seal-verification.json', 'model/manifest.json',
'model/checksums.sha256', 'evidence/manifest.json', 'evidence/checksums.sha256'):
controls_data[path] = data
model_manifest, model_checksums = (controls_data['model/' + name] for name in ('manifest.json', 'checksums.sha256'))
model_rows = seal_controls(model_manifest, model_checksums, MODEL, receipt['model_manifest_sha256'])
model_controls = control_rows(model_manifest, model_checksums)
observed_model = {path[len(MODEL) + 1:] for path in blobs.entries if path.startswith(MODEL + '/')}
require(observed_model == set(model_rows) | CONTROLS,
'Model Git inventory has unlisted/missing files: ' + repr(sorted(observed_model ^ (set(model_rows) | CONTROLS))))
for path, row in {**model_rows, **model_controls}.items():
blobs.match(MODEL + '/' + path, row)
exp_manifest, exp_checksums = (controls_data['evidence/' + name] for name in ('manifest.json', 'checksums.sha256'))
exp_rows = seal_controls(exp_manifest, exp_checksums, EXPERIMENT, receipt['experiment_manifest_sha256'])
exp_controls = control_rows(exp_manifest, exp_checksums)
expected_index = {}
omitted = []
for path, row in {**exp_rows, **exp_controls}.items():
if PurePosixPath(path).suffix.lower() in SUFFIXES and row['bytes'] <= MAX_EVIDENCE:
expected_index['evidence/' + path] = dict(source=EXPERIMENT + '/' + path,
copy='evidence/' + path, bytes=row['bytes'], sha256=row['sha256'])
else:
omitted.append(dict(row, reason='exceeds_4_MiB' if row['bytes'] > MAX_EVIDENCE
else 'bulk_or_non_evidence_extension'))
for path, row in model_controls.items():
expected_index['model/' + path] = dict(source=MODEL + '/' + path,
copy='model/' + path, bytes=row['bytes'], sha256=row['sha256'])
index = json_bytes(controls_data['evidence-index.json'])
require(isinstance(index, list), 'Evidence index must be a list')
actual_index = {}
for row in index:
require(isinstance(row, dict) and set(row) == {'source', 'copy', 'bytes', 'sha256'},
'Invalid evidence-index row schema')
path = relative(row['copy']); relative(row['source'])
require(path not in actual_index and type(row['bytes']) is int and row['bytes'] >= 0 and
isinstance(row['sha256'], str) and SHA256.fullmatch(row['sha256']),
'Invalid/duplicate evidence-index row')
actual_index[path] = row
require(actual_index == expected_index, 'Evidence index differs from receipt-bound seals/selection policy')
require(set(registry_rows) == set(expected_index) | {'evidence-index.json', 'seal-verification.json'},
'Receipt files disagree with copied evidence index')
for path, row in expected_index.items():
require(registry_rows[path] == dict(path=path, bytes=row['bytes'], sha256=row['sha256']),
'Evidence-index SHA/bytes disagree with receipt files: ' + path)
require(type(receipt.get('copied_evidence_files')) is int and
receipt['copied_evidence_files'] == len(expected_index) and
type(receipt.get('copied_evidence_bytes')) is int and
receipt['copied_evidence_bytes'] == sum(row['bytes'] for row in expected_index.values()),
'Receipt copied-evidence totals mismatch')
omitted_receipt = receipt.get('experiment_payload_not_copied')
require(isinstance(omitted_receipt, list) and all(isinstance(row, dict) for row in omitted_receipt) and
sorted(omitted_receipt, key=lambda row: row.get('path', '')) == sorted(omitted, key=lambda row: row['path']),
'Receipt omitted-bulk inventory mismatch')
proof = json_bytes(controls_data['seal-verification.json'])
require(isinstance(proof, dict) and set(proof) == {'model', 'experiment'}, 'Invalid seal-verification evidence')
for name, prefix, payload, controls in (('model', MODEL, model_rows, model_controls),
('experiment', EXPERIMENT, exp_rows, exp_controls)):
record = proof[name]
require(isinstance(record, dict) and record.get('pass_all') is True and
record.get('root') == PROJECT + '/' + prefix and
record.get('payload_file_count') == len(payload) and
record.get('payload_bytes') == sum(row['bytes'] for row in payload.values()) and
record.get('manifest_sha256') == controls['manifest.json']['sha256'] and
record.get('checksums_sha256') == controls['checksums.sha256']['sha256'],
'Seal-verification evidence contradicts receipt-bound ' + name + ' controls')
blobs.finish()
return dict(pass_all=True, verification='Phase 4AM actual Git blob publication integrity',
source='staged-index' if staged else 'commit', commit=blobs.commit,
fixed_scopes=[MODEL, REGISTRY], receipt_sha256=receipt_sha256,
model_manifest_sha256=receipt['model_manifest_sha256'],
experiment_manifest_sha256=receipt['experiment_manifest_sha256'],
declared_audit_status=receipt.get('declared_audit_status'),
model_payload_files=len(model_rows), registry_receipt_files=len(registry_rows),
verified_blob_count=len(blobs.verified), verified_bytes=sum(row['bytes'] for row in blobs.verified.values()),
scoped_inventory_sha256=sha(blobs.inventory_bytes),
verified_blobs=[blobs.verified[path] for path in sorted(blobs.verified)],
working_tree_payload_used=False, git_index_modified=False,
experiment_bulk_verified_by_this_tool=False, scientific_gate_executed=False,
publication_integrity_is_not_scientific_pass=True)
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--repo', required=True, help='Git repository top-level directory')
parser.add_argument('--receipt-sha256', required=True, help='Trusted external publication-receipt.json SHA-256')
choice = parser.add_mutually_exclusive_group(required=True)
choice.add_argument('--staged', action='store_true', help='Verify the actual stage-0 index blobs')
choice.add_argument('--commit', help='Resolve and verify this commit without checking it out')
args = parser.parse_args(argv)
try:
result = verify_git_payload(args.repo, args.receipt_sha256, staged=args.staged, commit=args.commit)
except (ValueError, OSError, UnicodeError) as error:
result = dict(pass_all=False, verification='Phase 4AM actual Git blob publication integrity',
error_type=type(error).__name__, error=str(error), scientific_gate_executed=False,
publication_integrity_is_not_scientific_pass=True)
print(json.dumps(result, ensure_ascii=False, allow_nan=False))
return 1
print(json.dumps(result, ensure_ascii=False, allow_nan=False))
return 0
if __name__ == '__main__':
sys.exit(main())