"""Exact, read-only Phase 4AM output comparison; never a learning gate. The sealed AJ comparator is loaded from verified bytes without modifying its globals. Full-graph queue identities and refractory acceptance are additionally reconstructed from actual events, including zero-weight edges. Only declared performance fields may differ. New AM provenance is checked separately, not mistaken for the inherited AJ implementation provenance. """ from __future__ import annotations import argparse import ast import copy from functools import lru_cache import hashlib import importlib.util import json import math from pathlib import Path import numpy as np N = 166700 E = 25582938 K = 4064 CANDIDATES = 14232 STEPS = 1000 AJ_SHA = 'af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b' HELPER_SHA = '9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734' CPP_SHA = '208a937d17bbb041b9bf6b25b89264ee566830b60609e58491b44583d8541f15' CUDA_SHA = '669f166e18ce9a3f63fc723db8b0a8b74f7fa4757194b1bd65b4cf6008a7787e' SEALED = { 'ag_gpu': '69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a', 'ag_worker': '21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291', 'ae_backend': '03758d07572f4b44d272059d9308fac534268ad201b57bdd77d69fee95e67278', 'af_queue': 'd72003d98f0f1624b12126eff50bd361c43d888f4a64d90ba9247a58976f1961', } ADAPTER_PINS = { 'apl-timing-lab-v1/gpu_timing.py': AJ_SHA, 'apl-timing-lab-v1/timing_queue.py': '54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e', 'author-apl-lab-v2/gpu_apl.py': SEALED['ag_gpu'], 'author-apl-lab-v2/legacy_apl_worker.py': SEALED['ag_worker'], 'author-runtime-lab-v1/gpu_backend.py': SEALED['ae_backend'], 'author-runtime-lab-v1/author_ext.cpp': CPP_SHA, 'author-runtime-lab-v1/author_ext.cu': CUDA_SHA, 'author-fullgraph-lab-v1/oracle_full.py': SEALED['af_queue'], } HOOK_CODE = '_phase4am_install_overlay(weights, graph, apl_out_mask, upload, out_dir, source_provenance)' PERFORMANCE = frozenset(('wall_seconds', 'diagnostic_simulation_seconds', 'build_or_cache_seconds', 'peak_allocated_vram_bytes', 'peak_reserved_vram_bytes')) BRIDGE = 'baseSI64 + (delta32 widened to float64) * float64(0.001); nonzero rows only' SCHEDULE = 'before tick 0; after fast APL zeroing' GRAPH_FIELDS = ('nodes', 'edge_id', 'src', 'dst', 'ptr', 'signed_raw', 'weights') _WEIGHT_CACHE = {} _BASE_RAW_CACHE = {} def require(condition, message): if not condition: raise ValueError(message) def _fingerprint(path): path = Path(path).resolve() stat = path.stat() require(path.is_file(), 'Not a regular evidence file: ' + str(path)) return str(path), stat.st_dev, stat.st_ino, stat.st_size, stat.st_mtime_ns, stat.st_ctime_ns def _digest_fingerprint(identity): # Do not cache byte hashes by stat metadata. Same-size writes can share # inode, mtime_ns and ctime_ns even on the actual server filesystem. value = hashlib.sha256() with Path(identity[0]).open('rb') as source: for block in iter(lambda: source.read(8 << 20), b''): value.update(block) require(_fingerprint(identity[0]) == identity, 'Evidence changed while hashing') return value.hexdigest() def file_hash(path): return _digest_fingerprint(_fingerprint(path)) def raw_hash(array): return hashlib.sha256(np.ascontiguousarray(array).tobytes()).hexdigest() @lru_cache(maxsize=2) def _helper_from_bytes(identity): require(file_hash(identity[0]) == HELPER_SHA, 'Sealed AJ comparator hash changed') spec = importlib.util.spec_from_file_location('phase4am_readonly_sealed_aj_compare', identity[0]) module = importlib.util.module_from_spec(spec) exec(compile(Path(identity[0]).read_bytes(), identity[0], 'exec'), module.__dict__) return module def _helper(used): path = Path(__file__).resolve().parent.parent / 'apl-timing-lab-v1/compare_timing.py' used.add(path) sha = file_hash(path) require(sha == HELPER_SHA, 'Sealed AJ comparator hash changed') return _helper_from_bytes(_fingerprint(path) + (sha,)) def _json(path, used): path = Path(path) used.add(path) def unique(pairs): result = {} for key, value in pairs: require(key not in result, 'Duplicate JSON key: ' + key) result[key] = value return result return json.loads(path.read_text(encoding='utf-8'), object_pairs_hook=unique, parse_constant=lambda value: (_ for _ in ()).throw(ValueError('Nonfinite JSON: ' + value))) def _npz(path, used): path = Path(path) used.add(path) with np.load(path, allow_pickle=False) as data: require(len(data.files) == len(set(data.files)), 'Duplicate NPZ key') return {key: data[key].copy() for key in data.files} @lru_cache(maxsize=2) def _static_arrays(identities): arrays = {Path(identity[0]).name: np.load(identity[0], mmap_mode='r', allow_pickle=False) for identity in identities} require(all(_fingerprint(identity[0]) == identity[:-1] and file_hash(identity[0]) == identity[-1] for identity in identities), 'Static inputs changed while loading') return arrays def _load_case(case_dir, used): spec = _json(case_dir / 'spec.json', used) require(type(spec['steps']) is int and spec['steps'] == STEPS and spec['dt_ms'] == .1 and spec['duration_ms'] == 100. and spec['record_history'] is False and type(spec['apl_delay_steps']) is int and spec['apl_delay_steps'] == 18, 'Phase 4AM comparison requires the unchanged full 100-ms D18 case') model = spec['model'] for key, value in (('synaptic_delay_ms', 1.8), ('refractory_ms', 2.2), ('w_syn_mv_per_anatomical_synapse', .275), ('resting_potential_mv', -52.), ('reset_potential_mv', -52.), ('threshold_mv', -45.)): require(type(model[key]) in (int, float) and model[key] == value, 'Frozen model field changed: ' + key) graph_dir, bundle_dir = Path(spec['graph_dir']), Path(spec['apl_bundle_dir']) require(graph_dir.is_absolute() and bundle_dir.is_absolute(), 'Static input paths must be absolute') paths = [graph_dir / (key + '.npy') for key in GRAPH_FIELDS] paths += [bundle_dir / key for key in ('input_matrix.npy', 'output_matrix.npy', 'kc_globals.npy', 'apl_globals.npy')] used.update(paths) # Caches for parsed/derived immutable graph data are keyed by FRESH content # SHA, not merely a filesystem timestamp. Re-read hashes on every call. token = tuple(_fingerprint(p) + (file_hash(p),) for p in paths) arrays = _static_arrays(token) graph = {key: arrays[key + '.npy'] for key in GRAPH_FIELDS} bundle = {key: arrays[key] for key in ('input_matrix.npy', 'output_matrix.npy', 'kc_globals.npy', 'apl_globals.npy')} _validate_static(graph, bundle, token) requests = _npz(case_dir / 'requests.npz', used) require(set(requests) == {'tick', 'neuron_idx'}, 'Unexpected request arrays') ticks, nodes = requests['tick'], requests['neuron_idx'] require(ticks.dtype == nodes.dtype == np.int32 and ticks.ndim == 1 and ticks.shape == nodes.shape and np.all((ticks >= 0) & (ticks < STEPS)) and np.all((nodes >= 0) & (nodes < N)), 'Invalid sparse requests') keys = ticks.astype(np.int64) * N + nodes require(np.all(keys[1:] > keys[:-1]), 'Requests must be sorted unique; no silently deduplicated requests') coeff_path = Path(spec['coefficients_path']) require(coeff_path.is_absolute(), 'Coefficient path must be absolute') coeff = _json(coeff_path, used) for key in ('gd', 'c0', 'cg', 'cv', 'threshold', 'reset', 'seed_volt'): require(type(coeff[key]) in (int, float) and math.isfinite(coeff[key]), 'Invalid author coefficient: ' + key) require(coeff['threshold'] == model['threshold_mv'] * .001 and coeff['reset'] == model['reset_potential_mv'] * .001 and coeff['seed_volt'] > coeff['threshold'], 'Author coefficient units/threshold mismatch') input_hashes = {'spec.json': file_hash(case_dir / 'spec.json'), 'requests.npz': file_hash(case_dir / 'requests.npz'), 'base_weights.npy': file_hash(graph_dir / 'weights.npy'), 'coefficients.json': file_hash(coeff_path)} if (case_dir / 'arrays.npz').exists(): used.add(case_dir / 'arrays.npz') input_hashes['arrays.npz'] = file_hash(case_dir / 'arrays.npz') return dict(spec=spec, graph=graph, bundle=bundle, token=token, input_hashes=input_hashes, requested=list(zip(map(int, ticks), map(int, nodes))), graph_dir=graph_dir, bundle_dir=bundle_dir) _VALIDATED_STATIC = set() def _validate_static(graph, bundle, token): if token in _VALIDATED_STATIC: return for key, dtype, shape in (('nodes', np.int32, (N,)), ('ptr', np.int64, (N + 1,)), ('edge_id', np.int64, (E,)), ('src', np.int32, (E,)), ('dst', np.int32, (E,)), ('signed_raw', np.int64, (E,)), ('weights', np.float64, (E,))): require(graph[key].dtype == dtype and graph[key].shape == shape, 'Canonical graph schema changed: ' + key) require(np.array_equal(graph['nodes'], np.arange(N, dtype=np.int32)), 'Global neuron identity changed') ptr = graph['ptr'] require(ptr[0] == 0 and ptr[-1] == E and np.all(np.diff(ptr) >= 0), 'Invalid canonical CSR') for start in range(0, E, 1 << 20): stop = min(E, start + (1 << 20)) expected_ids = np.arange(start, stop, dtype=np.int64) require(np.array_equal(graph['edge_id'][start:stop], expected_ids), 'Original edge identity changed') require(np.array_equal(graph['src'][start:stop], np.searchsorted(ptr[1:], expected_ids, side='right')), 'CSR source order changed') require(np.all((graph['dst'][start:stop] >= 0) & (graph['dst'][start:stop] < N)), 'Invalid edge targets') original = graph['weights'][start:stop] expected = graph['signed_raw'][start:stop] * (.275 * .001) require(np.isfinite(original).all() and raw_hash(original) == raw_hash(expected), 'Original signed SI weights changed') for name, dtype, shape in (('kc_globals.npy', np.int32, (K,)), ('apl_globals.npy', np.int32, (2,)), ('input_matrix.npy', np.float32, (2, N)), ('output_matrix.npy', np.float32, (2, K))): a = bundle[name] require(a.dtype == dtype and a.shape == shape and np.isfinite(a).all(), 'Invalid APL bundle ' + name) if dtype == np.int32: require(np.all((a >= 0) & (a < N)) and np.all(a[1:] > a[:-1]), 'Invalid APL/KC IDs') else: require(np.all(a >= 0), 'Negative normalized APL matrix') require(not np.intersect1d(bundle['kc_globals.npy'], bundle['apl_globals.npy']).size, 'APL/KC overlap') _VALIDATED_STATIC.add(token) def _effective_hash(case, ids=None, delta=None): """Independent static bridge, cached per immutable graph/delta identity.""" key = (case['token'], None if ids is None else raw_hash(ids), None if delta is None else raw_hash(delta)) if key in _WEIGHT_CACHE: return _WEIGHT_CACHE[key] graph, apl = case['graph'], case['bundle']['apl_globals.npy'] baseline, effective = hashlib.sha256(), hashlib.sha256() masked = 0 for start in range(0, len(graph['edge_id']), 1 << 20): stop = min(len(graph['edge_id']), start + (1 << 20)) value = graph['weights'][start:stop].copy() fast = np.isin(graph['src'][start:stop], apl) masked += int(fast.sum()) value[fast] = np.float64(0) baseline.update(value.astype(' 0), 'Static overlay changes candidate sign') effective.update(value.astype(' keys[:-1]), 'Duplicate or unordered actual events') require(np.array_equal(np.bincount(local, minlength=n), state['counts']), 'Event counts do not match per-neuron counts') require([(r['tick'], r['neuron_idx']) for r in run['requests']] == requested, 'Request input identity differs') bounds = np.searchsorted(state['step'], np.arange(steps + 1)) rq_bounds = np.searchsorted([r['tick'] for r in run['requests']], np.arange(steps + 1)) last = np.full(n, -1_000_000_000, np.int64) failures = {} expected_due_total = expected_accepted_total = 0 for tick in range(steps): fired = local[bounds[tick]:bounds[tick + 1]] if np.any(tick - last[fired] < 22): failures.setdefault('refractory_spike_violation', tick) for row in run['requests'][rq_bounds[tick]:rq_bounds[tick + 1]]: target = int(np.searchsorted(nodes, row['neuron_idx'])) require(target < n and nodes[target] == row['neuron_idx'], 'Request outside canonical graph') accepted = tick - last[target] >= 22 if row['accepted'] != int(accepted) or row['rejected'] != int(not accepted): failures.setdefault('request_refractory_gate', tick) if bool(np.any(fired == target)) != bool(accepted): failures.setdefault('request_actual_spike', tick) last[fired] = tick ref = np.maximum(22 - (tick - last), 0).astype(np.int32) if helper.raw_hash(ref, '= 18 else np.empty(0, np.int64) pieces = [np.arange(ptr[source], ptr[source + 1], dtype=np.int64) for source in sources] rows = np.concatenate(pieces) if pieces else np.empty(0, np.int64) accepted = (ref[graph['dst'][rows]] == 0).astype(np.uint8) expected = helper._queue_digest(tick, graph['edge_id'][rows], accepted) expected_due_total += len(rows) expected_accepted_total += int(accepted.sum()) if expected != run['queues'][tick]: failures.setdefault('full_queue_edge_order_and_acceptance', tick) if not np.array_equal(ref, state['ref']): failures['final_ref_from_events'] = steps - 1 summary = run['summary'] if summary.get('arriving_edges') != expected_due_total or summary.get('accepted_arriving_edges') != expected_accepted_total: failures['queue_summary_counts'] = 'mismatch' checks[role + '.full_event_queue_request_accounting'] = not failures if failures: differences[role + '.independent_accounting'] = failures def _overlay(run, case, used, zero_required=False): folder = run['directory'] audit = _json(folder / 'overlay-audit.json', used) require(audit['schema'] == 'phase4am-overlay-audit-v1' and audit['complete'] is True, 'Incomplete overlay audit') source = audit['input'] inputs = {} for label in ('overlay', 'manifest', 'mask', 'base_candidate'): filename, sha = source[label + '_file'], source[label + '_sha256'] if filename is None: require(label == 'base_candidate' and sha is None, 'Required overlay input absent') inputs[label] = None continue path = Path(filename) require(path.is_absolute(), 'Overlay provenance input must be absolute') used.add(path) require(file_hash(path) == sha, 'Overlay input hash mismatch: ' + label) inputs[label] = path manifest = _json(inputs['manifest'], used) require(manifest['schema'] == 'phase4am-overlay-v1' and manifest['overlay_sha256'] == source['overlay_sha256'] and manifest['mask_sha256'] == source['mask_sha256'] and Path(manifest['mask_path']).resolve() == inputs['mask'].resolve(), 'Overlay manifest linkage mismatch') require(manifest['base_candidate_sha256'] == source['base_candidate_sha256'] and (manifest['base_candidate_path'] is None if inputs['base_candidate'] is None else Path(manifest['base_candidate_path']).resolve() == inputs['base_candidate'].resolve()), 'Candidate floor provenance mismatch') require(Path(manifest['aj_model_dir']).resolve() == Path(__file__).resolve().parent.parent / 'apl-timing-lab-v1', 'Overlay is not bound to the sealed AJ model') require(audit['copied_overlay_file'] == 'overlay-input.npz' and audit['copied_manifest_file'] == 'overlay-manifest.json', 'Unexpected copied overlay filenames') for label, name in (('overlay', 'overlay-input.npz'), ('manifest', 'overlay-manifest.json')): used.add(folder / name) require(file_hash(folder / name) == source[label + '_sha256'], 'Copied input mismatch') arrays = _npz(inputs['overlay'], used) require(set(arrays) in ({'edge_id', 'plastic_delta_mv'}, {'edge_id', 'plastic_delta_mv', 'base_candidate_mv'}), 'Overlay NPZ schema changed') ids, delta = arrays['edge_id'], arrays['plastic_delta_mv'] require(ids.dtype == np.int64 and ids.shape == (CANDIDATES,) and np.all(ids[1:] > ids[:-1]) and np.all((ids >= 0) & (ids < len(case['graph']['edge_id']))), 'Invalid original plastic edge IDs') mask = np.load(inputs['mask'], allow_pickle=False) require(mask.dtype == np.int64 and mask.shape == ids.shape and np.array_equal(mask, ids), 'Frozen plastic mask identity mismatch') require(delta.dtype == np.float32 and delta.shape == ids.shape and np.isfinite(delta).all() and np.all(delta <= 0), 'Invalid LTD delta') audit_arrays = dict(arrays) name = manifest['overlay_name'] require(name in ('zero', 'static25') and audit['overlay_name'] == name, 'Unknown overlay intervention') if zero_required: require(name == 'zero', 'Zero-regression cannot use a nonzero intervention') if name == 'zero': require(not np.any(delta != 0), 'Zero overlay contains nonzero delta') else: require(inputs['base_candidate'] is not None, 'Static25 requires its frozen float32 mV floor') if inputs['base_candidate'] is not None: base = np.load(inputs['base_candidate'], allow_pickle=False) require(base.dtype == np.float32 and base.shape == ids.shape and np.isfinite(base).all() and np.all(base > 0), 'Invalid old float32 base') floor = np.multiply(base, np.float32(-.25)) require(np.all(delta >= floor), 'Delta exceeds the existing depression bound') if 'base_candidate_mv' in arrays: require(arrays['base_candidate_mv'].dtype == np.float32 and raw_hash(arrays['base_candidate_mv']) == raw_hash(base), 'Embedded old base differs') if name == 'static25': require(raw_hash(delta) == raw_hash(floor), 'Static25 is not the declared old float32 floor') audit_arrays['base_candidate_mv'] = base else: require('base_candidate_mv' not in arrays, 'Embedded unanchored old base is forbidden') expected_arrays = {key: dict(dtype=str(value.dtype), shape=list(value.shape), raw_sha256=raw_hash(value)) for key, value in audit_arrays.items()} require(audit['arrays'] == expected_arrays, 'Overlay array audit differs from actual bytes') require(np.isin(case['graph']['src'][ids], case['bundle']['kc_globals.npy']).all() and np.all(case['graph']['weights'][ids] > 0), 'Plastic edge source/sign changed') baseline_sha, effective_sha, apl_count = _effective_hash(case, ids, delta) graph = case['graph'] for key, value in {'candidate_count': CANDIDATES, 'nonzero_delta_count': int(np.count_nonzero(delta)), 'mapped_candidate_count': CANDIDATES, 'missing_candidate_count': 0, 'installed_nonzero_count': int(np.count_nonzero(delta)), 'delta_dtype': 'float32', 'delta_units': 'mV', 'state_dtype': 'float64', 'bridge': BRIDGE, 'installation_schedule': SCHEDULE, 'weights_updated_during_run': False, 'learning': False, 'zero_delta_no_write': True, 'frozen_mask_exact': True, 'bounds_pass': True, 'apl_overlap_count': 0, 'apl_fast_edges_zeroed': apl_count, 'base_graph_files_modified': False, 'untouched_weights_bitwise_preserved': True, 'base_weights_file_sha256': file_hash(case['graph_dir'] / 'weights.npy'), 'base_weights_raw_sha256': _base_raw_hash(case), 'effective_weights_raw_sha256': effective_sha, 'expected_effective_weights_raw_sha256': effective_sha}.items(): require(type(audit.get(key)) is type(value) and audit[key] == value, 'Overlay audit mismatch: ' + key) require(run['summary']['effective_weights_raw_sha256'] == effective_sha, 'Installed effective-weight hash differs from independent bridge') if zero_required: require(effective_sha == baseline_sha, 'Zero overlay changed the baseline effective weights') require(audit['inherited_aj_source_provenance'] == run['summary']['source_provenance'] and audit['inherited_source_audit_scope'] == 'AJ source provenance only; AM overlay semantics are recorded separately' and audit['static25_is_exact_fraction_of_float64_base_claimed'] is False and audit['arrival_weight_sampling'] == 'arrival time; delta fixed for entire trial', 'Overlay semantic scope mismatch') return audit def _expected_ast(source_path, adapter_path): """Independently derive just the declared Expr insertion; no adapter import.""" tree = ast.parse(Path(source_path).read_bytes()) original = [node for node in tree.body if isinstance(node, ast.FunctionDef) and node.name == 'run_gpu'] require(len(original) == 1, 'Pinned AJ run_gpu not unique') original = original[0] adapted = copy.deepcopy(original) tries = [node for node in adapted.body if isinstance(node, ast.Try)] require(len(tries) == 1, 'Pinned run_gpu try not unique') statements = tries[0].body dump = lambda node: ast.dump(node, annotate_fields=True, include_attributes=False) anchor = dump(ast.parse('effective_hash = hashlib.sha256()').body[0]) indices = [i for i, node in enumerate(statements) if dump(node) == anchor] require(len(indices) == 1, 'Pinned hook anchor not unique') index = indices[0] previous = ast.parse('if bool(np.any(apl_out_mask)):\n weights[upload(apl_out_mask, torch.bool)] = 0.0').body[0] require(index > 0 and dump(statements[index - 1]) == dump(previous), 'Hook is not immediately after APL zeroing') statements.insert(index, ast.parse(HOOK_CODE).body[0]) loops = lambda node: [item for item in ast.walk(node) if isinstance(item, ast.For) and isinstance(item.target, ast.Name) and item.target.id == 'tick'] before, after = loops(original), loops(adapted) require(len(before) == len(after) == 1 and dump(before[0]) == dump(after[0]), 'Hook changed loop AST') sha = lambda node: hashlib.sha256(dump(node).encode('utf-8')).hexdigest() return dict(original_run_ast_sha256=sha(original), adapted_run_ast_sha256=sha(adapted), loop_ast_sha256=sha(before[0]), entire_tick_loop_ast_identical=True, only_ast_change=HOOK_CODE, inserted_ast_statements=1, hook_after_apl_zero_before_effective_hash=True, derived_namespace_file=str(adapter_path.absolute()), original_module_file=str(Path(source_path).absolute()), original_module_globals_patched=False, fake_original_file_used=False) def _adapter_receipt(run, used): folder = run['directory'] require(not (folder / 'adapter-error.json').exists(), 'Adapter recorded an error') receipt = _json(folder / 'adapter-provenance.json', used) require(receipt['schema'] == 'phase4am-adapter-provenance-v1' and receipt['complete'] is True, 'Completed inherited AJ summary is insufficient without completed AM receipt') model = Path(__file__).resolve().parent for label, filename in (('adapter', 'adapter.py'), ('overlay_module', 'overlay.py')): path = Path(receipt[label + '_file']) require(path.is_absolute() and path.resolve() == model / filename, 'Unexpected new wrapper source path') used.add(path) require(file_hash(path) == receipt[label + '_sha256'], 'Wrapper source hash changed') source_rows = {} for relative, sha in ADAPTER_PINS.items(): path = model.parent / relative used.add(path) require(file_hash(path) == sha, 'Frozen source changed: ' + relative) source_rows[relative] = {'path': str(path.absolute()), 'sha256': sha} require(receipt['sealed_sources'] == source_rows, 'Wrapper sealed-source inventory differs') require(receipt['ast'] == _expected_ast(model.parent / 'apl-timing-lab-v1/gpu_timing.py', model / 'adapter.py'), 'Wrapper AST does not match independently reconstructed single pre-loop hook') for key, value in dict(installation_calls=1, weights_updated_during_run=False, learning=False, apl_delay_steps=18, original_module_globals_patched=False, delta_constant_for_entire_trial=True, inherited_source_audit_describes_AM_semantics=False).items(): require(type(receipt.get(key)) is type(value) and receipt[key] == value, 'Wrapper receipt mismatch: ' + key) require(receipt['scope'] == 'constant sparse overlay installation only; no within-trial plasticity or learning', 'Wrapper scope changed') require(receipt['overlay_audit_sha256'] == file_hash(folder / 'overlay-audit.json') and receipt['inherited_summary_sha256'] == file_hash(folder / 'summary.json') and receipt['effective_weights_raw_sha256'] == run['summary']['effective_weights_raw_sha256'], 'Wrapper receipt not bound to output') return {key: value for key, value in receipt.items() if key != 'inherited_summary_sha256'} def _provenance(run, case, helper, used): summary, component = run['summary'], run['component'] require(summary['input_sha256'] == case['input_hashes'], 'Actual case/weight/coefficient input hash differs') require(summary['all_finite'] is True and summary['counts_match_sparse_events'] is True and summary['learning'] is False and summary['state_units'] == 'SI volts', 'Invalid finite/state/learning declaration') require(summary['sealed_ae_backend_sha256'] == SEALED['ae_backend'], 'Frozen backend changed') build = summary['build'] require(build['sources'] == {'author_ext.cpp': CPP_SHA, 'author_ext.cu': CUDA_SHA} and build['cuda_flags'] == ['-O2', '--fmad=false', '--ftz=false', '--prec-div=true', '--prec-sqrt=true'] and build['arch_list'] == '8.9', 'Build arithmetic/source contract changed') source = _json(run['directory'] / 'source-audit.json', used) require(source == summary['source_provenance'] and source['sealed_source_sha256'] == SEALED and source['candidate_sha256'] == AJ_SHA and source['module_globals_patched'] is False, 'Inherited AJ source audit changed') diff = run['directory'] / 'sealed-gpu-source.diff' used.add(diff) require(file_hash(diff) == source['source_diff_sha256'], 'Inherited source diff hash mismatch') bundle = case['bundle'] require(component['files_sha256'] == {name: file_hash(case['bundle_dir'] / name) for name in bundle} and component['array_sha256'] == {name: raw_hash(value) for name, value in bundle.items()}, 'Actual APL bundle bytes changed') require(component['ok'] is True and component['protocol'] == 'phase4ag-apl-v1' and component['n_neurons'] == N and component['n_apl'] == 2 and component['n_kc'] == K and component['dt_ms'] == .1, 'APL component dimensions/clock changed') for key, value in (('decay_f32_bits', np.float32(math.exp(-.1 / 20.))), ('gain_f32_bits', np.float32(.01))): require(component[key] == f'{int(value.view(np.uint32)):08x}', 'APL constant changed: ' + key) env = component['environment'] require(env['cuda_matmul_allow_tf32'] is False and env['float32_matmul_precision'] == 'highest' and env['precision_configuration_changed_by_component'] is False and '4090' in env['device_name'], 'GPU precision environment changed') require(summary['apl_schedule'] == 'end, after threshold/reset and guarded arrivals, unconditional all KC' and summary['apl_si_conversion'] == 'applied h32 -> float64 -> multiply float64 0.001 -> separate float64 subtraction', 'APL scheduling or SI conversion changed') for key in PERFORMANCE: require(type(summary[key]) in (int, float) and math.isfinite(summary[key]) and summary[key] >= 0, 'Invalid performance field: ' + key) def _summary_pair(left, right, checks, differences): a = {k: v for k, v in left.items() if k not in PERFORMANCE} b = {k: v for k, v in right.items() if k not in PERFORMANCE} checks['summary.nonperformance_exact'] = a == b if a != b: differences['summary'] = {key: {'left': a.get(key), 'right': b.get(key)} for key in sorted(set(a) | set(b)) if a.get(key) != b.get(key) or (key in a) != (key in b)} def compare_runs(case_dir, left, right, output_path=None, mode='zero'): """Zero-vs-sealed-AK or AM repeat equality; failures return a failed report. ``output_path=None`` is read-only. A provided report is created exclusively, outside both run directories and the input case. Parent protocol must bind the case and old manifests; this comparator reports exactly the bytes read. """ case_dir, left, right = (Path(p).resolve() for p in (case_dir, left, right)) if output_path is not None: output_path = Path(output_path).resolve() require(not output_path.exists(), 'Refusing existing comparison output') require(not any(output_path.is_relative_to(p) for p in (case_dir, left, right)), 'Comparison must not write into input evidence') checks, differences, used = {}, {}, {Path(__file__).resolve()} report = dict(schema='phase4am-comparison-v1', mode=mode, case_dir=str(case_dir), left=str(left), right=str(right), pass_all=False, learning_achieved=False, candidate_generated=False, tolerance=None, scope='Exact declared trajectory and static overlay integrity; no physiological or learning PASS', explicit_exclusions=sorted(PERFORMANCE), independent_cpu_wholebrain_oracle_claim=False) try: require(mode in ('zero', 'repeat', 'self'), 'Unknown comparison mode') require((left == right) == (mode == 'self'), 'Only explicit single-run validation may use one directory') helper = _helper(used) case = _load_case(case_dir, used) spec, graph = case['spec'], case['graph'] n, edges, steps = len(graph['nodes']), len(graph['edge_id']), spec['steps'] sides = ((left, 'left_gpu'),) if mode == 'self' else ((left, 'left_gpu'), (right, 'right_gpu')) runs = [helper._load_run(path, role, n, edges, steps, False, spec['name'], 18, used, checks) for path, role in sides] for role, run in zip(('left_gpu', 'right_gpu'), runs): _provenance(run, case, helper, used) require(all(np.isfinite(a).all() for a in run['state'].values()), 'Nonfinite final state/events') _self_consistency(run, graph, case['requested'], steps, helper, role, checks, differences) helper._timing_sequence_checks(run['apl']['inhibition'], run['apl']['applied'], run['pending'], 18, role, checks, differences) helper._timing_metadata_checks(run, role, 18, steps, checks) require(not (run['directory'] / 'first-failure-state.npz').exists(), 'Recorded first numerical failure exists') if mode != 'self': helper._pair_outputs(*runs, checks, differences, n, steps, False) require(runs[0]['timing'] == runs[1]['timing'], 'APL timing metadata differs') _summary_pair(runs[0]['summary'], runs[1]['summary'], checks, differences) baseline_sha, _, apl_count = _effective_hash(case) for run in runs: require(run['summary']['apl_fast_edges_zeroed'] == apl_count and run['summary']['kc_targets_present'] == K, 'Fast APL or KC coverage changed') if mode == 'zero': require(not (left / 'overlay-audit.json').exists(), 'Zero reference must be the unwrapped sealed AK run') require(runs[0]['summary']['effective_weights_raw_sha256'] == baseline_sha, 'Sealed reference effective weights changed') audit = _overlay(runs[1], case, used, zero_required=True) _adapter_receipt(runs[1], used) report['overlay_name'] = audit['overlay_name'] elif mode == 'repeat': a, b = [_overlay(run, case, used) for run in runs] require(a == b, 'Repeated overlay provenance/identity differs') receipts = [_adapter_receipt(run, used) for run in runs] require(receipts[0] == receipts[1], 'Repeated wrapper provenance differs beyond bound walltime-bearing summary') report['overlay_name'] = a['overlay_name'] else: report['overlay_name'] = _overlay(runs[0], case, used)['overlay_name'] _adapter_receipt(runs[0], used) report['scope'] = 'Single-run event/queue/input/static-overlay self-consistency; no repeat, equivalence, physiology or learning PASS' checks['input_overlay_and_source_provenance'] = True report.update(nodes=n, edges=edges, steps=steps, apl_delay_steps=18, full_queue_reconstructed=True, total_spikes=len(runs[0]['state']['step'])) except Exception as error: report['error'] = {'type': type(error).__name__, 'message': str(error)} manifest = [] try: for path in sorted(used): manifest.append(dict(path=str(path.resolve()), bytes=path.stat().st_size, sha256=file_hash(path))) except Exception as error: report['read_manifest_error'] = {'type': type(error).__name__, 'message': str(error)} report.update(checks={key: bool(value) for key, value in checks.items()}, differences=differences, read_manifest=manifest, failed_checks=sorted(key for key, value in checks.items() if not value)) report['pass_all'] = bool(checks) and all(checks.values()) and 'error' not in report and 'read_manifest_error' not in report if output_path is not None: output_path.parent.mkdir(parents=True, exist_ok=True) with output_path.open('x', encoding='utf-8') as target: json.dump(report, target, indent=2, sort_keys=True, allow_nan=False) target.write('\n') return report def validate_run(case_dir, output_dir, output_path=None): """Single-run static-overlay integrity only; not numerical equivalence.""" return compare_runs(case_dir, output_dir, output_dir, output_path, mode='self') if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--case', required=True) parser.add_argument('--left', required=True) parser.add_argument('--right', required=True) parser.add_argument('--output', required=True) parser.add_argument('--mode', choices=('zero', 'repeat', 'self'), required=True) args = parser.parse_args() result = compare_runs(args.case, args.left, args.right, args.output, args.mode) print(json.dumps({'pass_all': result['pass_all'], 'failed_checks': result['failed_checks'], 'error': result.get('error')}, allow_nan=False)) raise SystemExit(0 if result['pass_all'] else 1)