Seal AO interface failure and verified isolated postprocessing diagnosis
This commit is contained in:
@@ -0,0 +1,478 @@
|
||||
"""Unregistered fixed-weight continuation of the reporting-only AN executor.
|
||||
|
||||
run_continued(case, out, build, overlay, manifest, checkpoint_dir, mode='light')
|
||||
also accepts mode='reference'. Inputs/events/counts use segment-local ticks;
|
||||
summary and receipts expose global_tick_offset/global_next_tick. No training,
|
||||
weight update, early stopping, or implicit extra tail is performed.
|
||||
|
||||
The caller must externally pin spec.parent_checkpoint_manifest_sha256. A fresh
|
||||
parent's original runtime receipt did NOT bind state.npz: seal_checkpoint adds
|
||||
that binding, after checking the available original receipts and current bytes.
|
||||
It cannot retroactively prove that an unsealed state file was never modified.
|
||||
Full graph/APL/coefficient/preregistered-input authority remains the coordinator's
|
||||
responsibility, as in runtime_light. No executable/venv path is resolved here.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import copy
|
||||
import hashlib
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
LIGHT_SHA = '522b8c31ea938890fe15364fccd25ccc5bded54101754909f255532e7ad01aae'
|
||||
N = 166700
|
||||
E = 25582938
|
||||
MANIFEST = 'checkpoint-manifest.json'
|
||||
RECEIPT = 'continuation-receipt.json'
|
||||
RESTORE = '_continuation.restore(v, g, ref, counts, ring, apl_ring, apl, upload)'
|
||||
CLOCK_OLD = 'tick >= 18'
|
||||
CLOCK_NEW = 'tick + _continuation.global_offset >= 18'
|
||||
|
||||
|
||||
def _light():
|
||||
path = Path(__file__).resolve().parent / 'runtime_light.py'
|
||||
raw = path.read_bytes()
|
||||
if hashlib.sha256(raw).hexdigest() != LIGHT_SHA:
|
||||
raise ValueError('Fresh runtime source pin changed')
|
||||
name = 'phase4an_continuation_pinned_light'
|
||||
existing = sys.modules.get(name)
|
||||
if existing is not None:
|
||||
if getattr(existing, '__continuation_pin__', None) != LIGHT_SHA or Path(existing.__file__).resolve() != path:
|
||||
raise ValueError('Unverified runtime module binding')
|
||||
return existing
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[name] = module
|
||||
try:
|
||||
exec(compile(raw, str(path), 'exec'), module.__dict__)
|
||||
except BaseException:
|
||||
sys.modules.pop(name, None)
|
||||
raise
|
||||
module.__continuation_pin__ = LIGHT_SHA
|
||||
return module
|
||||
|
||||
|
||||
R = _light() # Pure NumPy/stdlib; this does not import Torch or run a brain.
|
||||
|
||||
|
||||
def rotate_spike_ring(raw_ring, phase_tick):
|
||||
"""Parent's local next-write slot becomes the child's local slot zero."""
|
||||
R.require(isinstance(raw_ring, np.ndarray) and raw_ring.dtype == np.uint8 and
|
||||
raw_ring.ndim == 2 and raw_ring.shape[0] == 19, 'Invalid spike ring dtype/shape')
|
||||
R.require(type(phase_tick) is int and phase_tick >= 0 and np.all(raw_ring <= 1), 'Invalid ring phase/content')
|
||||
return raw_ring[(np.arange(19) + phase_tick % 19) % 19].copy()
|
||||
|
||||
|
||||
def _tree_hashes(directory):
|
||||
"""Exact regular-file inventory, no symlink/reparse escapes, no self-hash."""
|
||||
directory = Path(directory).resolve(strict=True)
|
||||
R.require(directory.is_dir(), 'Checkpoint must be a directory')
|
||||
result = {}
|
||||
for path in sorted(directory.rglob('*')):
|
||||
R.require(not path.is_symlink() and path.resolve().is_relative_to(directory), 'Checkpoint contains a linked/escaping path')
|
||||
if path.is_dir():
|
||||
continue
|
||||
R.require(path.is_file(), 'Checkpoint contains a nonregular entry')
|
||||
relative = path.relative_to(directory).as_posix()
|
||||
if relative == MANIFEST:
|
||||
continue
|
||||
R.require('error' not in path.name.lower() and 'failure' not in path.name.lower(), 'Parent has failure/error evidence')
|
||||
result[relative] = R.digest(path)
|
||||
return result
|
||||
|
||||
|
||||
def _npz(path, keys):
|
||||
with np.load(path, allow_pickle=False) as archive:
|
||||
R.require(len(archive.files) == len(keys) and set(archive.files) == set(keys), 'Unexpected checkpoint array keys: ' + str(path))
|
||||
return {name: archive[name].copy() for name in keys}
|
||||
|
||||
|
||||
def validate_state(state, terminal, steps, *, fresh):
|
||||
"""Validate local events/counts and the slots written by this segment."""
|
||||
R.require(type(steps) is int and 0 < steps <= np.iinfo(np.int32).max, 'Invalid segment length')
|
||||
for name in ('v', 'g'):
|
||||
value = state[name]
|
||||
R.require(value.dtype == np.float64 and value.shape == (N,) and np.isfinite(value).all(), 'Invalid parent ' + name)
|
||||
for name in ('ref', 'counts'):
|
||||
value = state[name]
|
||||
R.require(value.dtype == np.int32 and value.shape == (N,) and np.all(value >= 0), 'Invalid parent ' + name)
|
||||
R.require(np.all(state['ref'] <= 22), 'Parent refractory counter exceeds frozen 22-step contract')
|
||||
tick, neuron = state['step'], state['neuron_idx']
|
||||
R.require(tick.dtype == neuron.dtype == np.int32 and tick.ndim == neuron.ndim == 1 and tick.shape == neuron.shape,
|
||||
'Invalid sparse event dtype/shape')
|
||||
R.require(np.all((tick >= 0) & (tick < steps)) and np.all((neuron >= 0) & (neuron < N)), 'Parent event outside segment')
|
||||
key = tick.astype(np.int64) * N + neuron
|
||||
R.require(len(key) < 2 or np.all(key[1:] > key[:-1]), 'Parent events must be sorted and unique')
|
||||
R.require(np.array_equal(np.bincount(neuron, minlength=N), state['counts']), 'Parent counts are not segment-local event counts')
|
||||
ring = terminal['spike_ring']
|
||||
R.require(ring.dtype == np.uint8 and ring.shape == (19, N) and np.all(ring <= 1), 'Invalid parent spike ring')
|
||||
for name, shape in (('apl_state', (2,)), ('apl_pending', (18, 4064))):
|
||||
value = terminal[name]
|
||||
R.require(value.dtype == np.float32 and value.shape == shape and np.isfinite(value).all(), 'Invalid terminal ' + name)
|
||||
phase = terminal['next_tick']
|
||||
R.require(phase.dtype == np.int64 and phase.shape == () and phase.item() == steps, 'Terminal local phase does not match segment length')
|
||||
for local_tick in range(max(0, steps - 19), steps):
|
||||
start, stop = np.searchsorted(tick, (local_tick, local_tick + 1))
|
||||
expected = np.zeros(N, dtype=np.uint8)
|
||||
expected[neuron[start:stop]] = 1
|
||||
R.require(np.array_equal(ring[local_tick % 19], expected), 'Spike ring does not match emitted segment events')
|
||||
if fresh and steps < 19:
|
||||
R.require(not np.any(ring[steps:]), 'Fresh parent has nonzero uninitialized spike slots')
|
||||
return state, terminal
|
||||
|
||||
|
||||
def _verify_receipt_hashes(directory, receipt):
|
||||
for key, name in (('summary_sha256', 'summary.json'), ('finite_audit_sha256', 'finite-audit.json'),
|
||||
('terminal_queues_sha256', 'terminal-queues.npz'), ('overlay_audit_sha256', 'overlay-audit.json')):
|
||||
R.require(receipt.get(key) == R.digest(directory / name), 'Parent receipt hash mismatch: ' + name)
|
||||
inputs = receipt.get('input_sha256')
|
||||
R.require(isinstance(inputs, dict) and inputs, 'Parent receipt lacks immutable input bindings')
|
||||
for name, sha in inputs.items():
|
||||
R.require(Path(name).is_absolute() and R._sha(sha) and R.digest(name) == sha, 'Parent input/source bytes changed: ' + name)
|
||||
|
||||
|
||||
def _validate_record(directory, seen):
|
||||
summary = R._read_json(directory / 'summary.json')
|
||||
finite = R._read_json(directory / 'finite-audit.json')
|
||||
provenance = R._read_json(directory / 'runtime-provenance.json')
|
||||
steps = summary.get('steps')
|
||||
R.require(summary.get('complete') is True and summary.get('pass_all') is True and summary.get('all_finite') is True and
|
||||
summary.get('completed_ticks') == steps and summary.get('nodes') == N and summary.get('edges') == E and
|
||||
summary.get('precision') == 'float64' and summary.get('apl_precision') == 'float32' and
|
||||
summary.get('within_trial_weight_updates') is False, 'Parent is not a complete fixed-weight fullgraph trial')
|
||||
R.require(finite.get('all_finite') is True and finite.get('first_failure_tick') == -1 and
|
||||
finite.get('finite_observed_ticks') == steps, 'Parent finite coverage failed')
|
||||
R.require(provenance.get('complete') is True and provenance.get('weights_updated_during_run') is False and
|
||||
provenance.get('old_globals_patched') is False, 'Invalid parent runtime receipt')
|
||||
_verify_receipt_hashes(directory, provenance)
|
||||
fresh = provenance.get('schema') == 'phase4an-reporting-adapter-v1'
|
||||
if fresh:
|
||||
R.require(provenance.get('source_sha256') == LIGHT_SHA and R.digest(provenance['source_file']) == LIGHT_SHA and
|
||||
summary.get('checkpoint_continuation_used') is False, 'Fresh parent source/continuation scope mismatch')
|
||||
offset = 0
|
||||
else:
|
||||
R.require(provenance.get('schema') == 'phase4an-continuation-runtime-v1' and
|
||||
provenance.get('source_sha256') == R.digest(__file__) and
|
||||
R.digest(provenance['source_file']) == R.digest(__file__) and
|
||||
summary.get('checkpoint_continuation_used') is True, 'Unrecognized continued parent source')
|
||||
receipt = R._read_json(directory / RECEIPT)
|
||||
R.require(receipt.get('schema') == 'phase4an-continuation-receipt-v1' and receipt.get('complete') is True,
|
||||
'Invalid continuation receipt')
|
||||
R.require(receipt.get('weights_updated_during_run') is False and receipt.get('segment_steps') == steps and
|
||||
receipt.get('counts_scope') == 'segment_only_not_lifetime' and
|
||||
provenance.get('state_sha256') == R.digest(directory / 'state.npz'), 'Continued state/scope receipt mismatch')
|
||||
expected_payload = _tree_hashes(directory)
|
||||
expected_payload.pop(RECEIPT, None)
|
||||
R.require(receipt.get('payload_sha256') == expected_payload, 'Continuation receipt does not bind the exact payload')
|
||||
parent_pin = receipt.get('parent_checkpoint_manifest_sha256')
|
||||
case_spec = _parent_spec({'summary': summary, 'provenance': provenance})
|
||||
R.require(R._sha(parent_pin) and provenance.get('parent_checkpoint_manifest_sha256') == parent_pin and
|
||||
summary.get('parent_checkpoint_manifest_sha256') == parent_pin and
|
||||
case_spec.get('parent_checkpoint_manifest_sha256') == parent_pin,
|
||||
'Parent checkpoint pin disagrees across case/summary/provenance/continuation receipts')
|
||||
R.require(Path(receipt['parent_checkpoint_dir']).is_absolute(), 'Parent checkpoint directory is not absolute')
|
||||
parent = load_checkpoint(receipt['parent_checkpoint_dir'], parent_pin, _seen=seen)
|
||||
offset = parent['global_next_tick']
|
||||
R.require(receipt.get('global_tick_offset') == offset and receipt.get('global_next_tick') == offset + steps and
|
||||
summary.get('global_tick_offset') == offset and summary.get('global_next_tick') == offset + steps and
|
||||
provenance.get('global_tick_offset') == offset and provenance.get('global_next_tick') == offset + steps,
|
||||
'Continuation global clock chain mismatch')
|
||||
R.require(summary.get('effective_weights_raw_sha256') == parent['summary'].get('effective_weights_raw_sha256'),
|
||||
'Retention effective weights changed between parent and child')
|
||||
state = _npz(directory / 'state.npz', ('step', 'neuron_idx', 'counts', 'v', 'g', 'ref'))
|
||||
terminal = _npz(directory / 'terminal-queues.npz', ('spike_ring', 'apl_state', 'apl_pending', 'next_tick'))
|
||||
validate_state(state, terminal, steps, fresh=fresh)
|
||||
initial_padding = max(18 - (offset + steps), 0)
|
||||
R.require(np.all(terminal['apl_pending'][:initial_padding].view(np.uint32) == 0),
|
||||
'Unconsumed original APL padding is not positive zero')
|
||||
if not fresh:
|
||||
if steps < 19:
|
||||
restored = rotate_spike_ring(parent['terminal']['spike_ring'], int(parent['terminal']['next_tick']))
|
||||
R.require(np.array_equal(terminal['spike_ring'][steps:], restored[steps:]), 'Unwritten carried spike slots changed')
|
||||
if steps < 18:
|
||||
carried = parent['terminal']['apl_pending'][steps:]
|
||||
R.require(np.array_equal(terminal['apl_pending'][:18 - steps].view(np.uint32), carried.view(np.uint32)),
|
||||
'Unconsumed carried APL slots changed')
|
||||
overlay = R._read_json(directory / 'overlay-audit.json')
|
||||
R.require(overlay.get('complete') is True and overlay.get('weights_updated_during_run') is False and
|
||||
overlay.get('effective_weights_raw_sha256') == summary.get('effective_weights_raw_sha256') and
|
||||
overlay.get('mask_sha256') == R.MASK_SHA and overlay.get('am_helper_sha256') == R.AM_OVERLAY_SHA,
|
||||
'Parent effective overlay receipt mismatch')
|
||||
overlay_manifest = R._read_json(directory / 'overlay-manifest.json')
|
||||
R.require(R.digest(directory / 'overlay-input.npz') == overlay_manifest.get('overlay_sha256') and
|
||||
R.digest(directory / 'overlay-manifest.json') in provenance['input_sha256'].values() and
|
||||
overlay_manifest.get('mask_sha256') == R.MASK_SHA and
|
||||
overlay_manifest.get('base_candidate_sha256') == overlay.get('base_candidate_sha256'),
|
||||
'Parent copied overlay inputs do not match their original receipt')
|
||||
timing = R._read_json(directory / 'apl-timing-audit.json')
|
||||
with (directory / 'apl-pending-tail.float32.npy').open('rb') as stream:
|
||||
pending = np.load(stream, allow_pickle=False)
|
||||
R.require(pending.dtype == np.float32 and pending.shape == (18, 4064) and
|
||||
pending.tobytes() == terminal['apl_pending'].tobytes(), 'Parent terminal/pending output mismatch')
|
||||
R.require(timing.get('pending_raw_sha256') == R._raw(pending) and timing.get('apl_delay_steps') == 18 and
|
||||
timing.get('brain_tail_advanced') is False and
|
||||
timing.get('final_apl_state_u32_bits') == terminal['apl_state'].view(np.uint32).tolist(), 'Parent APL terminal audit mismatch')
|
||||
return {'directory': directory, 'summary': summary, 'provenance': provenance, 'overlay': overlay,
|
||||
'state': state, 'terminal': terminal, 'steps': steps, 'global_tick_offset': offset,
|
||||
'global_next_tick': offset + steps, 'fresh': fresh,
|
||||
'ancestry_directories': [directory] if fresh else [directory, *parent['ancestry_directories']]}
|
||||
|
||||
|
||||
def seal_checkpoint(checkpoint_dir):
|
||||
"""Exclusive file-hash seal, not a brain run or proof of pre-seal integrity.
|
||||
|
||||
The returned manifest SHA must be externally pinned into the next case spec.
|
||||
No existing receipt is overwritten. Fresh state.npz is newly bound here.
|
||||
"""
|
||||
directory = Path(checkpoint_dir).resolve(strict=True)
|
||||
R.require(not (directory / MANIFEST).exists(), 'Checkpoint is already sealed')
|
||||
before = _tree_hashes(directory)
|
||||
record = _validate_record(directory, {directory})
|
||||
R.require(before == _tree_hashes(directory), 'Checkpoint changed while sealing')
|
||||
value = {'schema': 'phase4an-checkpoint-v1', 'complete': True, 'files_sha256': before,
|
||||
'segment_steps': record['steps'], 'global_tick_offset': record['global_tick_offset'],
|
||||
'global_next_tick': record['global_next_tick'], 'counts_scope': 'segment_only',
|
||||
'state_binding_origin': 'checkpoint seal; fresh runtime receipt did not hash state.npz',
|
||||
'pre_seal_state_integrity_independently_proven': False}
|
||||
R._save(directory / MANIFEST, value)
|
||||
return {'path': str(directory / MANIFEST), 'sha256': R.digest(directory / MANIFEST), **value}
|
||||
|
||||
|
||||
def load_checkpoint(checkpoint_dir, expected_sha, *, _seen=None):
|
||||
directory = Path(checkpoint_dir).resolve(strict=True)
|
||||
R.require(R._sha(expected_sha) and R.digest(directory / MANIFEST) == expected_sha, 'Parent checkpoint manifest differs from external pin')
|
||||
seen = set() if _seen is None else set(_seen)
|
||||
R.require(directory not in seen, 'Checkpoint ancestry cycle')
|
||||
seen.add(directory)
|
||||
manifest = R._read_json(directory / MANIFEST)
|
||||
R.require(manifest.get('schema') == 'phase4an-checkpoint-v1' and manifest.get('complete') is True and
|
||||
manifest.get('counts_scope') == 'segment_only' and manifest.get('files_sha256') == _tree_hashes(directory),
|
||||
'Checkpoint file inventory/hash mismatch')
|
||||
record = _validate_record(directory, seen)
|
||||
R.require(manifest.get('segment_steps') == record['steps'] and manifest.get('global_tick_offset') == record['global_tick_offset'] and
|
||||
manifest.get('global_next_tick') == record['global_next_tick'], 'Checkpoint clock metadata mismatch')
|
||||
R.require(manifest['files_sha256'] == _tree_hashes(directory) and R.digest(directory / MANIFEST) == expected_sha,
|
||||
'Checkpoint changed while loading')
|
||||
record.update(manifest=manifest, manifest_sha256=expected_sha)
|
||||
return record
|
||||
|
||||
|
||||
def derive_continued(source_bytes, mode):
|
||||
"""One explicit arrival-admission edit plus one pre-loop restore hook."""
|
||||
tree, inherited = R.derive_ast(source_bytes, mode)
|
||||
original = copy.deepcopy(tree)
|
||||
function = tree.body[-1]
|
||||
body = next(node for node in function.body if isinstance(node, ast.Try)).body
|
||||
candidates = [i for i, node in enumerate(body) if isinstance(node, ast.Assign) and
|
||||
len(node.targets) == 1 and isinstance(node.targets[0], ast.Name) and node.targets[0].id == 'apl_ring']
|
||||
R.require(len(candidates) == 1, 'Expected one APL ring initialization')
|
||||
body.insert(candidates[0] + 1, ast.parse(RESTORE).body[0])
|
||||
clocks = [node for node in ast.walk(function) if isinstance(node, ast.If) and ast.unparse(node.test) == CLOCK_OLD]
|
||||
R.require(len(clocks) == 1, 'Expected exact original local arrival-admission condition')
|
||||
clocks[0].test = ast.parse(CLOCK_NEW, mode='eval').body
|
||||
tree = ast.fix_missing_locations(tree)
|
||||
# Independently reverse exactly the two edits, then require the ENTIRE AST.
|
||||
rollback = copy.deepcopy(tree)
|
||||
reverse_body = next(node for node in rollback.body[-1].body if isinstance(node, ast.Try)).body
|
||||
restores = [i for i, node in enumerate(reverse_body) if ast.unparse(node) == RESTORE]
|
||||
reverse_clocks = [node for node in ast.walk(rollback) if isinstance(node, ast.If) and ast.unparse(node.test) == CLOCK_NEW]
|
||||
R.require(len(restores) == len(reverse_clocks) == 1, 'Ambiguous continuation edit rollback')
|
||||
del reverse_body[restores[0]]
|
||||
reverse_clocks[0].test = ast.parse(CLOCK_OLD, mode='eval').body
|
||||
R.require(R._dump(rollback) == R._dump(original), 'Additional unlisted continuation AST edit')
|
||||
audit = {'base': inherited, 'restore_hook': RESTORE, 'clock_admission_old': CLOCK_OLD,
|
||||
'clock_admission_new': CLOCK_NEW, 'full_AST_rollback_identical': True,
|
||||
'kernels_sorting_and_local_ring_math_unchanged': True,
|
||||
'derived_module_ast_sha256': hashlib.sha256(R._dump(tree).encode()).hexdigest()}
|
||||
return tree, audit
|
||||
|
||||
|
||||
def audit_carried_sequence(generated, applied, pending, initial_pending):
|
||||
"""Bitwise FIFO accounting with a carried queue, never a new brain step."""
|
||||
for name, value in (('generated', generated), ('applied', applied), ('pending', pending), ('initial', initial_pending)):
|
||||
R.require(isinstance(value, np.ndarray) and value.dtype == np.float32 and value.ndim == 2 and
|
||||
np.isfinite(value).all() and np.all(value >= 0), 'Invalid continued APL trace: ' + name)
|
||||
R.require(generated.shape == applied.shape and pending.shape == initial_pending.shape == (18, generated.shape[1]),
|
||||
'Continued APL sequence shapes differ')
|
||||
steps = len(generated)
|
||||
for tick in range(steps + 18):
|
||||
actual = applied[tick] if tick < steps else pending[tick - steps]
|
||||
expected = initial_pending[tick] if tick < 18 else generated[tick - 18]
|
||||
R.require(np.array_equal(actual.view(np.uint32), expected.view(np.uint32)),
|
||||
'Carried FIFO bitwise accounting failed at local application tick ' + str(tick))
|
||||
return {'pass_all': True, 'apl_delay_steps': 18, 'steps': steps, 'sample_bits_preserved': True,
|
||||
'initial_queue_from_parent': True, 'initial_queue_raw_sha256': R._raw(initial_pending),
|
||||
'full_sequence_bitwise_audit_performed': True, 'brain_tail_advanced': False}
|
||||
|
||||
|
||||
class ContinuedRuntime(R._Runtime):
|
||||
def __init__(self, *args, parent, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.parent = parent
|
||||
self.global_offset = parent['global_next_tick']
|
||||
self.restorations = 0
|
||||
|
||||
def install(self, *args, **kwargs):
|
||||
super().install(*args, **kwargs)
|
||||
R.require(self.effective_sha == self.parent['summary']['effective_weights_raw_sha256'], 'Retention changed effective weights')
|
||||
|
||||
def restore(self, v, g, ref, counts, ring, apl_ring, apl, upload):
|
||||
R.require(self.installations == 1 and self.restorations == 0, 'Restore must occur once after fixed-weight installation')
|
||||
R.require(not bool(counts.any().item()), 'Segment counts must start at zero')
|
||||
state, terminal = self.parent['state'], self.parent['terminal']
|
||||
for target, value, dtype in ((v, state['v'], self.torch.float64), (g, state['g'], self.torch.float64),
|
||||
(ref, state['ref'], self.torch.int32),
|
||||
(ring, rotate_spike_ring(terminal['spike_ring'], int(terminal['next_tick'])), self.torch.uint8),
|
||||
(apl_ring, terminal['apl_pending'], self.torch.float32),
|
||||
(apl.state, terminal['apl_state'], self.torch.float32)):
|
||||
target.copy_(upload(value, dtype))
|
||||
self.restorations += 1
|
||||
|
||||
def finish(self, *args, **kwargs):
|
||||
R.require(self.restorations == 1, 'Continuation was not restored')
|
||||
return super().finish(*args, **kwargs)
|
||||
|
||||
def audit_sequence(self, generated, applied, pending, delay):
|
||||
R.require(delay == 18, 'Continuation changed D18')
|
||||
return audit_carried_sequence(generated, applied, pending, self.parent['terminal']['apl_pending'])
|
||||
|
||||
def _timing_metadata(self, value):
|
||||
result = dict(value)
|
||||
next_tick, steps = self.global_offset + self.spec['steps'], self.spec['steps']
|
||||
result.pop('initial_padding_positive_zero', None)
|
||||
result.update(initial_queue_from_parent=True, initial_queue_raw_sha256=R._raw(self.parent['terminal']['apl_pending']),
|
||||
global_tick_offset=self.global_offset, global_next_tick=next_tick, tick_coordinate='global',
|
||||
segment_steps=steps, segment_generated_rows_applied=max(steps - 18, 0),
|
||||
applied_parent_pending_rows=min(steps, 18),
|
||||
applied_initial_zero_rows=min(steps, max(18 - self.global_offset, 0)),
|
||||
applied_parent_generated_rows=min(steps, 18) - min(steps, max(18 - self.global_offset, 0)),
|
||||
pending_segment_generated_rows=min(steps, 18),
|
||||
pending_parent_generated_rows=max(18 - steps, 0) - max(18 - next_tick, 0),
|
||||
pending_generated_count=min(next_tick, 18), pending_initial_zero_prefix=max(18 - next_tick, 0),
|
||||
pending_application_tick_start=next_tick, pending_application_tick_stop_exclusive=next_tick + 18,
|
||||
pending_generated_tick_start=max(0, next_tick - 18), pending_generated_tick_stop_exclusive=next_tick,
|
||||
brain_tail_advanced_scope='no extra brain ticks beyond this explicit segment')
|
||||
if self.mode == 'light':
|
||||
result.update(generated_trace=None, applied_trace=None, full_sequence_bitwise_audit_performed=False,
|
||||
scope='Original D18 ring math retained with restored queue; histories not recorded')
|
||||
return result
|
||||
|
||||
def timing(self, steps, pending):
|
||||
return self._timing_metadata(super().timing(steps, pending))
|
||||
|
||||
def summary(self, value):
|
||||
result = super().summary(value)
|
||||
result.update(checkpoint_continuation_used=True, global_tick_offset=self.global_offset,
|
||||
global_next_tick=self.global_offset + self.spec['steps'], event_tick_scope='segment_local',
|
||||
counts_scope='segment_only_not_lifetime', parent_checkpoint_manifest_sha256=self.parent['manifest_sha256'])
|
||||
result.update(pending_generated_count=min(result['global_next_tick'], 18),
|
||||
pending_initial_zero_prefix=max(18 - result['global_next_tick'], 0))
|
||||
if 'apl_timing' in result:
|
||||
result['apl_timing'] = self._timing_metadata(result['apl_timing'])
|
||||
return result
|
||||
|
||||
def write_json(self, path, value):
|
||||
if Path(path).name == 'apl-timing-audit.json':
|
||||
value = self._timing_metadata(value)
|
||||
return super().write_json(path, value)
|
||||
|
||||
|
||||
def compile_continued(aj, runtime, mode):
|
||||
tree, audit = derive_continued(Path(aj.__file__).read_bytes(), mode)
|
||||
namespace = dict(aj.__dict__)
|
||||
namespace.update(__name__=__name__ + '.derived_' + mode, __file__=str(Path(__file__).resolve()),
|
||||
_runtime=runtime, _continuation=runtime, write_json=runtime.write_json,
|
||||
audit_sequence=runtime.audit_sequence)
|
||||
audit['diagnostic_namespace_binding'] = 'audit_sequence checks parent_pending + generated, not an assumed zero-initial queue'
|
||||
exec(compile(tree, str(Path(__file__).resolve()) + '::continued-AJ-AST-' + mode, 'exec'), namespace)
|
||||
return namespace['run_gpu'], audit
|
||||
|
||||
|
||||
def _parent_spec(parent):
|
||||
expected = parent['summary']['input_sha256']['spec.json']
|
||||
paths = [Path(path) for path, sha in parent['provenance']['input_sha256'].items()
|
||||
if Path(path).name == 'spec.json' and sha == expected]
|
||||
R.require(len(paths) == 1, 'Ambiguous original parent case spec')
|
||||
return R._read_json(paths[0])
|
||||
|
||||
|
||||
def run_continued(case_dir, out_dir, build_root, overlay_file, overlay_manifest, checkpoint_dir, *, mode='light'):
|
||||
R.require(sys.dont_write_bytecode, 'Use python -B; frozen sources must not receive bytecode writes')
|
||||
R.require(mode in ('light', 'reference'), 'Invalid diagnostic mode')
|
||||
case_dir, out_dir, build_root = R.execution_paths(case_dir, out_dir, build_root, (checkpoint_dir,))
|
||||
spec = R._read_json(case_dir / 'spec.json')
|
||||
parent_sha = spec.get('parent_checkpoint_manifest_sha256')
|
||||
fresh_admission = dict(spec)
|
||||
fresh_admission.pop('parent_checkpoint_manifest_sha256', None)
|
||||
R.validate_spec(fresh_admission, case_dir)
|
||||
parent = load_checkpoint(checkpoint_dir, parent_sha)
|
||||
# A continuation may never create output or a build cache inside ANY
|
||||
# immutable ancestor, not only its immediate checkpoint parent. This check
|
||||
# precedes overlay imports, Torch imports, compilation and output creation.
|
||||
case_dir, out_dir, build_root = R.execution_paths(case_dir, out_dir, build_root, parent['ancestry_directories'])
|
||||
if 'global_tick_offset' in spec:
|
||||
R.require(type(spec['global_tick_offset']) is int and spec['global_tick_offset'] == parent['global_next_tick'],
|
||||
'Declared global offset disagrees with checkpoint chain')
|
||||
R.require(parent['global_next_tick'] + spec['steps'] <= np.iinfo(np.int64).max, 'Absolute tick overflow')
|
||||
helper, plan, meta, inputs = R.load_overlay(overlay_file, overlay_manifest)
|
||||
R.require(R.digest(overlay_file) == R.digest(parent['directory'] / 'overlay-input.npz') and
|
||||
R.digest(overlay_manifest) == R.digest(parent['directory'] / 'overlay-manifest.json'), 'Retention overlay snapshot/manifest changed')
|
||||
previous = _parent_spec(parent)
|
||||
for key in ('dt_ms', 'model', 'apl', 'apl_delay_steps'):
|
||||
R.require(spec[key] == previous[key], 'Continuation changes frozen dynamics: ' + key)
|
||||
for key in ('graph_dir', 'apl_bundle_dir'):
|
||||
R.require(Path(spec[key]).resolve(strict=True) == Path(previous[key]).resolve(strict=True), 'Continuation changes input directory: ' + key)
|
||||
R.require(R.digest(spec['coefficients_path']) == parent['summary']['input_sha256']['coefficients.json'], 'Continuation coefficients changed')
|
||||
R.require(R.digest(Path(spec['graph_dir']) / 'weights.npy') == parent['summary']['input_sha256']['base_weights.npy'], 'Continuation base weights changed')
|
||||
aj_dir = Path(meta['aj_model_dir']).resolve(strict=True)
|
||||
protected = (aj_dir.parent, Path(meta['am_overlay_path']).resolve().parent, spec['graph_dir'], spec['apl_bundle_dir'],
|
||||
*parent['ancestry_directories'],
|
||||
*(Path(path).resolve(strict=True).parent for path in
|
||||
(overlay_file, overlay_manifest, meta['mask_path'], meta['base_candidate_path'], spec['coefficients_path'])))
|
||||
case_dir, out_dir, build_root = R.execution_paths(case_dir, out_dir, build_root, protected)
|
||||
for path in (case_dir / 'spec.json', case_dir / 'requests.npz', Path(spec['graph_dir']) / 'weights.npy',
|
||||
Path(spec['coefficients_path']), Path(checkpoint_dir).resolve() / MANIFEST, Path(R.__file__).resolve()):
|
||||
inputs[str(path)] = R.digest(path)
|
||||
source_sha = R.digest(__file__)
|
||||
R._load('timing_queue', aj_dir / 'timing_queue.py', R.PINS['apl-timing-lab-v1/timing_queue.py'])
|
||||
aj = R._load('phase4an_continued_sealed_aj_gpu', aj_dir / 'gpu_timing.py', R.AJ_SHA)
|
||||
runtime = ContinuedRuntime(mode, spec, helper, plan, meta, inputs, aj.torch, overlay_file, overlay_manifest, parent=parent)
|
||||
function, ast_audit = compile_continued(aj, runtime, mode)
|
||||
try:
|
||||
inherited = function(case_dir, out_dir, build_root)
|
||||
R.require(runtime.finished and runtime.restorations == 1 and runtime.installations == 1 and inherited['complete'], 'Incomplete continuation')
|
||||
R.require(inherited['effective_weights_raw_sha256'] == runtime.effective_sha, 'Effective weight identity changed')
|
||||
R.require(source_sha == R.digest(__file__) and all(R.digest(path) == sha for path, sha in inputs.items()), 'Source/input changed during continuation')
|
||||
load_checkpoint(checkpoint_dir, parent_sha)
|
||||
summary = R._read_json(out_dir / 'summary.json')
|
||||
R.require(summary == runtime.summary(inherited), 'Stored continuation summary mismatch')
|
||||
provenance = {'schema': 'phase4an-continuation-runtime-v1', 'complete': True, 'mode': mode,
|
||||
'source_file': str(Path(__file__).resolve()), 'source_sha256': source_sha, 'fresh_runtime_sha256': LIGHT_SHA,
|
||||
'ast': ast_audit, 'input_sha256': inputs, 'old_globals_patched': False, 'weights_updated_during_run': False,
|
||||
'learning_pass_claimed': False, 'global_tick_offset': runtime.global_offset,
|
||||
'global_next_tick': runtime.global_offset + spec['steps'],
|
||||
'parent_checkpoint_manifest_sha256': parent_sha}
|
||||
for key, name in (('summary_sha256', 'summary.json'), ('finite_audit_sha256', 'finite-audit.json'),
|
||||
('terminal_queues_sha256', 'terminal-queues.npz'), ('overlay_audit_sha256', 'overlay-audit.json'),
|
||||
('state_sha256', 'state.npz')):
|
||||
provenance[key] = R.digest(out_dir / name)
|
||||
R._save(out_dir / 'runtime-provenance.json', provenance)
|
||||
receipt = {'schema': 'phase4an-continuation-receipt-v1', 'complete': True,
|
||||
'parent_checkpoint_dir': str(parent['directory']), 'parent_checkpoint_manifest_sha256': parent_sha,
|
||||
'global_tick_offset': runtime.global_offset, 'global_next_tick': runtime.global_offset + spec['steps'],
|
||||
'segment_steps': spec['steps'], 'counts_scope': 'segment_only_not_lifetime',
|
||||
'payload_sha256': _tree_hashes(out_dir), 'weights_updated_during_run': False,
|
||||
'clock_admission_edit': CLOCK_NEW, 'checkpoint_continuation_verified_by_GPU_comparison': False}
|
||||
R._save(out_dir / RECEIPT, receipt)
|
||||
sealed = seal_checkpoint(out_dir)
|
||||
return dict(summary, checkpoint_manifest_sha256=sealed['sha256'])
|
||||
except Exception as error:
|
||||
if out_dir.is_dir() and not (out_dir / 'continuation-error.json').exists():
|
||||
R._save(out_dir / 'continuation-error.json', {'complete': False, 'type': type(error).__name__,
|
||||
'message': str(error), 'learning_update_forbidden': True})
|
||||
raise
|
||||
Reference in New Issue
Block a user