"""One pre-loop overlay hook in the SHA-pinned AJ function; no old global patch. run_gpu_overlay(case_dir, out_dir, build_root, overlay_file, overlay_manifest) retains AJ's output/summary schema. overlay-audit.json and adapter-provenance.json are mandatory additional evidence. The inherited source-audit.json describes the unchanged AJ source only, NOT the complete Phase 4AM adapter semantics. Delta is fixed during the whole trial; this interface never trains or updates eligibility. The original CUDA arrival operator still samples current weights at arrival, and no emission-time weight snapshot is introduced. """ from __future__ import annotations import ast import copy import hashlib import importlib.util import json from pathlib import Path import sys import numpy as np import overlay AJ_SHA256 = 'af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b' PINS = { 'apl-timing-lab-v1/gpu_timing.py': AJ_SHA256, 'apl-timing-lab-v1/timing_queue.py': '54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e', 'author-apl-lab-v2/gpu_apl.py': '69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a', 'author-apl-lab-v2/legacy_apl_worker.py': '21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291', 'author-runtime-lab-v1/gpu_backend.py': '03758d07572f4b44d272059d9308fac534268ad201b57bdd77d69fee95e67278', 'author-runtime-lab-v1/author_ext.cpp': '208a937d17bbb041b9bf6b25b89264ee566830b60609e58491b44583d8541f15', 'author-runtime-lab-v1/author_ext.cu': '669f166e18ce9a3f63fc723db8b0a8b74f7fa4757194b1bd65b4cf6008a7787e', 'author-fullgraph-lab-v1/oracle_full.py': 'd72003d98f0f1624b12126eff50bd361c43d888f4a64d90ba9247a58976f1961', } HOOK_NAME = '_phase4am_install_overlay' HOOK_CODE = HOOK_NAME + '(weights, graph, apl_out_mask, upload, out_dir, source_provenance)' _LOADED = {} def _save(path, value): with Path(path).open('x', encoding='utf-8') as stream: json.dump(value, stream, ensure_ascii=False, sort_keys=True, indent=2, allow_nan=False) stream.write('\n') def verify_sources(aj_model_dir): directory = Path(aj_model_dir).absolute() overlay.require(directory.name == 'apl-timing-lab-v1', 'AJ must be loaded from its actual original model directory') paths = {key: directory.parent / key for key in PINS} for key, path in paths.items(): overlay.require(overlay.file_hash(path) == PINS[key], 'Sealed source SHA mismatch: ' + str(path)) return {key: {'path': str(paths[key]), 'sha256': value} for key, value in PINS.items()} def _load_checked(name, path, expected): path = Path(path).absolute() data = path.read_bytes() overlay.require(hashlib.sha256(data).hexdigest() == expected, 'Source changed before loading: ' + str(path)) if name in sys.modules: existing = sys.modules[name] overlay.require(_LOADED.get(name) == (path, expected, existing), 'Refusing an existing unverified module binding: ' + name) return existing spec = importlib.util.spec_from_file_location(name, path) overlay.require(spec is not None and spec.loader is not None, 'No source loader') module = importlib.util.module_from_spec(spec) sys.modules[name] = module try: # Execute precisely the checked source bytes; do not write frozen pyc. exec(compile(data, str(path), 'exec'), module.__dict__) except BaseException: sys.modules.pop(name, None) raise _LOADED[name] = (path, expected, module) return module def _dump(node): return ast.dump(node, annotate_fields=True, include_attributes=False) def derive_ast(source_bytes): """Pure AST adapter: one inserted Expr, every other original node unchanged.""" overlay.require(hashlib.sha256(source_bytes).hexdigest() == AJ_SHA256, 'Cannot derive from unpinned AJ source') module = ast.parse(source_bytes) matches = [node for node in module.body if isinstance(node, ast.FunctionDef) and node.name == 'run_gpu'] overlay.require(len(matches) == 1, 'Expected exactly one sealed AJ run_gpu') original = matches[0] adapted = copy.deepcopy(original) tries = [node for node in adapted.body if isinstance(node, ast.Try)] overlay.require(len(tries) == 1, 'Unexpected run_gpu try structure') statements = tries[0].body anchor = ast.parse('effective_hash = hashlib.sha256()').body[0] positions = [i for i, node in enumerate(statements) if _dump(node) == _dump(anchor)] overlay.require(len(positions) == 1, 'Effective-weight hash insertion anchor is not unique') position = positions[0] previous = ast.parse('if bool(np.any(apl_out_mask)):\n weights[upload(apl_out_mask, torch.bool)] = 0.0').body[0] overlay.require(position > 0 and _dump(statements[position - 1]) == _dump(previous), 'Overlay hook must immediately follow frozen fast-APL zeroing') hook = ast.copy_location(ast.parse(HOOK_CODE).body[0], statements[position]) statements.insert(position, hook) tick_loops = lambda tree: [node for node in ast.walk(tree) if isinstance(node, ast.For) and isinstance(node.target, ast.Name) and node.target.id == 'tick'] old_loops, new_loops = tick_loops(original), tick_loops(adapted) overlay.require(len(old_loops) == len(new_loops) == 1 and _dump(old_loops[0]) == _dump(new_loops[0]), 'Entire simulation loop AST must remain identical') restored = copy.deepcopy(adapted) restored_try = next(node for node in restored.body if isinstance(node, ast.Try)) restored_try.body.pop(position) overlay.require(_dump(restored) == _dump(original), 'Adapter changed more than its single pre-loop hook') ast.fix_missing_locations(adapted) sha = lambda value: hashlib.sha256(value.encode('utf-8')).hexdigest() audit = {'original_run_ast_sha256': sha(_dump(original)), 'adapted_run_ast_sha256': sha(_dump(adapted)), 'loop_ast_sha256': sha(_dump(old_loops[0])), 'entire_tick_loop_ast_identical': True, 'only_ast_change': HOOK_CODE, 'inserted_ast_statements': 1, 'hook_after_apl_zero_before_effective_hash': True} return adapted, audit def compile_derived(aj_module, install_hook): """Compile only the derived function into a NEW namespace, never old globals.""" source_path = Path(aj_module.__file__).absolute() function_ast, audit = derive_ast(source_path.read_bytes()) namespace = dict(aj_module.__dict__) # Real adapter location, not AJ's __file__ masquerading as a new module. namespace.update(__name__=__name__ + '.derived_run', __file__=str(Path(__file__).absolute())) overlay.require(HOOK_NAME not in namespace, 'Hook name collides with sealed globals') namespace[HOOK_NAME] = install_hook tree = ast.fix_missing_locations(ast.Module(body=[function_ast], type_ignores=[])) exec(compile(tree, str(Path(__file__).absolute()) + '::AST-derived-AJ-run_gpu', 'exec'), namespace) audit.update(derived_namespace_file=namespace['__file__'], original_module_file=str(source_path), original_module_globals_patched=False, fake_original_file_used=False) return namespace['run_gpu'], audit def _copy_input(source, destination, expected): with Path(source).open('rb') as incoming, Path(destination).open('xb') as outgoing: for block in iter(lambda: incoming.read(8 << 20), b''): outgoing.write(block) overlay.require(overlay.file_hash(destination) == expected, 'Copied input hash mismatch') def run_gpu_overlay(case_dir, out_dir, build_root, overlay_file, overlay_manifest): """Fresh D18 constant-weight interface run; no learning/update inside trial. This is the ONLY GPU entry point; importing/testing the module is CPU-only. Output is exclusive. The caller still owns preregistration, case/graph and frozen-mask authority, resource checks, budgets, and scientific gate choice. Success requires the added complete adapter-provenance.json, not merely an inherited AJ summary that may precede a failed final wrapper verification. """ case_dir, out_dir = Path(case_dir).absolute(), Path(out_dir).absolute() overlay.require(not out_dir.exists(), 'Refusing an existing output directory') overlay.require(sys.dont_write_bytecode, 'Invoke with python -B so inherited loaders cannot write frozen __pycache__') own_sources = {'adapter': overlay.file_hash(__file__), 'overlay': overlay.file_hash(overlay.__file__)} plan = overlay.load_overlay(overlay_file, overlay_manifest) spec = json.loads((case_dir / 'spec.json').read_text(encoding='utf-8')) overlay.require(type(spec.get('apl_delay_steps')) is int and spec['apl_delay_steps'] == 18, 'Phase 4AM interface requires fixed D18') overlay.require(spec.get('training', False) is False and spec.get('learning', False) is False, 'This interface does not authorize a learning run') aj_dir = Path(plan['metadata']['aj_model_dir']) sources = verify_sources(aj_dir) _load_checked('timing_queue', aj_dir / 'timing_queue.py', PINS['apl-timing-lab-v1/timing_queue.py']) aj = _load_checked('phase4am_sealed_aj_gpu', aj_dir / 'gpu_timing.py', AJ_SHA256) base_file = Path(spec['graph_dir']) / 'weights.npy' base_file_sha = overlay.file_hash(base_file) calls = [] def install(weights, graph, apl_out_mask, upload, output, inherited_provenance): overlay.require(not calls, 'Plastic overlay hook must run exactly once') mapping = overlay.map_installation(graph['weights'], graph['edge_id'], apl_out_mask, plan) if len(graph['nodes']) == 166700: overlay.require(int(apl_out_mask.sum()) == 5845, 'Frozen fullgraph fast-APL mask changed') torch = aj.torch overlay.require(weights.dtype == torch.float64 and weights.ndim == 1 and weights.numel() == len(graph['edge_id']), 'Runtime weight tensor must retain float64 SI edge order') rows = mapping['rows'] if len(rows): local = upload(rows, torch.int64) # Separate eager f64 multiply and addition, never base->f32 roundtrip. delta32 = plan['plastic_delta_mv'][plan['plastic_delta_mv'] != np.float32(0)] delta_si = upload(delta32, torch.float64) * 0.001 weights[local] = weights[local] + delta_si actual = weights[local].cpu().numpy().copy() overlay.require(overlay.bit_equal(actual, mapping['expected_si']), 'GPU installation differs from independent CPU SI arithmetic') # With zero delta no indexing assignment or +0 arithmetic happens. base_raw_sha, expected_sha = overlay.expected_hashes(graph['weights'], apl_out_mask, mapping) actual_hash = hashlib.sha256() for start in range(0, weights.numel(), 1 << 20): actual_hash.update(weights[start:start + (1 << 20)].cpu().numpy().astype('