"""Read-only normal analysis, conditional on independent final integrity. analyze(exp, registration_sha256, *, verified_inventory, final_ledger) consumes an externally authenticated absolute-path -> {bytes, sha256} inventory and the final append-ledger audit. Neither caller Boolean nor digest alone is treated as an OS observation: actual ledger/start/job/parent/worker receipts and every consumed file are rebound to bytes. SHA caching is invocation-local, never mtime-based. The outer verifier still owns complete tree/historical integrity, anatomical/source authority, concurrency exclusion and the final science claim. No writes, sampling, subprocesses, follow-up assays, candidates or new gates. """ from __future__ import annotations from collections import defaultdict import hashlib import io import json from pathlib import Path import types import numpy as np GATES_SHA256 = '8ae9bcb77fe14dbdda164f86ffdbfc1e2976be752766ef526777577223b4dd99' PLAN_SHA256 = 'd1a6b840a547cb10b00df40f4d8b287867d09f355c9777e5f7a8b9489f5555ea' ARM_NAMES = dict(paired='paired', d_zero='D=0', frozen='frozen', random_reward='random reward', unpaired='unpaired', cs_only='CS-only', dan_only='DAN-only') ODORS = {'A': '4-ethylphenol', 'B': '3-hexanone'} POINTS = (0, 1, 2, 5, 10, 20, 50) def require(ok, message): if not ok: raise ValueError(message) def canonical(value): return json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=False, allow_nan=False) def sha(value): return hashlib.sha256(canonical(value).encode()).hexdigest() def _module(name, path, expected): raw = path.read_bytes() require(hashlib.sha256(raw).hexdigest() == expected, 'Analysis dependency pin differs: ' + str(path)) module = types.ModuleType(name) module.__file__ = str(path) exec(compile(raw, str(path), 'exec'), module.__dict__) return module _HERE = Path(__file__).resolve().parent G = _module('_normal_frozen_gates', _HERE.parent / 'conditioning-execution-v1/learning_gates.py', GATES_SHA256) P = _module('_normal_frozen_plan', _HERE / 'normal_plan.py', PLAN_SHA256) M = G.M class Reader: """Actual SHA once per unique path per invocation; not an atomic snapshot.""" def __init__(self, inventory): require(type(inventory) is dict and inventory, 'Externally verified checksum inventory required') self.inventory = inventory self.seen = {} def path(self, path): path = Path(path) require(path.is_absolute() and '..' not in path.parts and not any(p.is_symlink() or (hasattr(p, 'is_junction') and p.is_junction()) for p in (path, *path.parents)), 'Unsafe artifact path') key = str(path) require(key in self.inventory, 'Artifact absent from external checksum authority: ' + key) expected = self.inventory[key] require(type(expected) is dict and set(expected) == {'bytes', 'sha256'} and type(expected['bytes']) is int and expected['bytes'] >= 0 and M._sha(expected['sha256']), 'Invalid checksum authority') return path, expected def check(self, path): path, expected = self.path(path) key = str(path) if key not in self.seen: require(path.is_file(), 'Missing artifact: ' + key) digest = hashlib.sha256() size = 0 with path.open('rb') as stream: for part in iter(lambda: stream.read(8 << 20), b''): digest.update(part); size += len(part) require(dict(bytes=size, sha256=digest.hexdigest()) == expected, 'Actual file checksum differs: ' + key) self.seen[key] = dict(expected) require(self.seen[key] == expected, 'Checksum authority changed during analysis') return expected def raw(self, path): self.check(path) # Parsed data are read from the now-bound file, not retained for every # trajectory. Concurrent mutation remains an outer quiescence obligation. return Path(path).read_bytes() def json(self, path): def unique(items): result = {} for key, value in items: require(key not in result, 'Duplicate JSON field'); result[key] = value return result return json.loads(self.raw(path).decode('utf-8'), object_pairs_hook=unique, parse_constant=lambda _: (_ for _ in ()).throw(ValueError('Nonfinite JSON'))) def arrays(self, path): with np.load(io.BytesIO(self.raw(path)), allow_pickle=False) as archive: return {key: archive[key].copy() for key in archive.files} def task_key(task): return 'task-' + hashlib.sha256(task['task_id'].encode()).hexdigest() def expected_entries(plan): result = ['input-generation'] for task in plan['tasks']: result.extend(task_key(task) + suffix for suffix in (('--brain', '--update', '--verify') if task['kind'] == 'train' else ('--brain',))) return result def audit_case(reader, exp, task, job, *, template, inputs, sampler, populations, population_file, output_cap): """Independent raw CS/US composition and reset/spec checks; no brain call. A scheduled US request is not an accepted spike or a successful behavior. The artificial D scalar remains the original recipe, never an event count. """ exp = Path(exp); case = exp / 'cases' / task_key(task) require(job['case_dir'] == str(case), 'Case path differs from original task') spec = reader.json(case / 'spec.json') removed = ('validation_cohort', 'odor_index', 'expected_external_events', 'training', 'cs_input_seed', 'cs_input_seed_bits', 'seed_scope', 'odor_id', 'odor_name', 'source_panel_row', 'source_panel_split', 'rate_sum_hz', 'target_count', 'expected_CS_requests', 'CS_window', 'outer_epoch_id', 'outer_arm', 'outer_protocol') fixed = {k: v for k, v in template.items() if k not in removed} fixed.update(name=task_key(task), steps=1200, duration_ms=120., max_steps=1200, budget_root=str(exp), output_budget_bytes=output_cap, mode=task['mode'], within_trial_weight_updates=False, outer_protocol='normal-acquisition-v1', outer_task_id=task['task_id'], outer_arm=task['arm']) require(canonical(spec) == canonical(fixed) and spec['seed'] == template['seed'] and spec['dt_ms'] == .1 and spec['apl_delay_steps'] == 18 and spec['precision'] == 'float64' and spec['apl_precision'] == 'float32' and spec['record_history'] is False and spec['kind'] == 'fullgraph', 'Scientific model/reset/clock spec changed') recipe = task['recipe'] cs_recipe = recipe['cs'] if task['kind'] == 'train' else recipe expected = None if cs_recipe is not None: cue = cs_recipe['cue'] seed = cs_recipe['seed'] if task['kind'] == 'train' else cs_recipe['input']['seed'] stream = cs_recipe['source_stream_id'] if task['kind'] == 'train' else cs_recipe['input']['stream_id'] require(type(seed) is int and 0 <= seed < 2**63, 'Original full63 seed required') expected = dict(mode=task['mode'], cue=cue, seed=seed, steps=1200, cs_start_tick=0, cs_stop_tick_exclusive=1000, source_stream_id=stream, table_id=task['mode'] + '--' + cue) csid = None if expected is None else sha(expected) require(inputs['task_inputs'][task['task_id']] == csid, 'Original task/CS descriptor mapping differs') binding = reader.json(case / 'input-binding.json') require(binding['task_id'] == task['task_id'] and binding['CS_descriptor_id'] == csid and binding['DAN_type'] == task['dan_type'] and binding['population_file'] == dict(path=population_file, sha256=reader.check(population_file)['sha256']), 'Case input/population binding differs') empty = dict(tick=np.empty(0, np.int32), neuron_idx=np.empty(0, np.int32)) source = empty if csid is None: require(binding['CS_source'] is None, 'No-CS epoch acquired an odor source') else: npzpath = exp / f'inputs/generated/{csid}.npz'; jsonpath = exp / f'inputs/generated/{csid}.json' generated = reader.json(jsonpath); audit = generated['audit'] require(inputs['descriptors'][csid] == generated['descriptor'] == expected and generated['requests_sha256'] == reader.check(npzpath)['sha256'] and binding['CS_source'] == dict(path=str(npzpath), sha256=reader.check(npzpath)['sha256']) and sampler['inputs'][csid] == dict(requests=binding['CS_source'], audit=dict(path=str(jsonpath), sha256=reader.check(jsonpath)['sha256'])), 'Saved sampler receipt/descriptor differs') require(audit['seed'] == audit['generator_initial_seed'] == seed and audit['seed_bits'] == 63 and audit['seed_conversion'] == 'exact integer; no truncation/modulo/offset' and audit['private_generator'] is True and audit['matrix_draw_calls'] == 1 and audit['uniform_matrix_shape'][0] == 1200 and audit['CS_window'] == [0, 1000], 'Original sampler seed/full-shape/window evidence differs') source = reader.arrays(npzpath) def keys(request): require(set(request) == {'tick', 'neuron_idx'} and all(v.dtype == np.int32 and v.ndim == 1 for v in request.values()) and request['tick'].shape == request['neuron_idx'].shape and np.all((request['tick'] >= 0) & (request['tick'] < 1200)) and np.all((request['neuron_idx'] >= 0) & (request['neuron_idx'] < 166700)), 'Invalid raw request arrays') result = request['tick'].astype(np.int64) * 166700 + request['neuron_idx'] require(np.all(result[1:] > result[:-1]), 'Requests are not sorted unique') return result source_keys = keys(source) require(np.all(source['tick'] < 1000), 'CS escaped original window') cs, us, combined = (reader.arrays(case / name) for name in ('cs_requests.npz', 'us_requests.npz', 'requests.npz')) cs_keys, us_keys, combined_keys = keys(cs), keys(us), keys(combined) require(np.array_equal(source_keys, cs_keys), 'Actual case CS differs from original saved input') requested = task['kind'] == 'train' and recipe['us']['requested'] dan = populations[task['dan_type']] require(dan.dtype == np.int32 and dan.ndim == 1 and np.all(dan[1:] > dan[:-1]), 'Actual DAN mapping differs') require(binding['DAN_membership_sha256'] == hashlib.sha256(dan.tobytes()).hexdigest(), 'DAN membership binding differs') expected_us = 900 * 166700 + dan.astype(np.int64) if requested else np.empty(0, np.int64) require(np.array_equal(us_keys, expected_us) and not np.intersect1d(cs_keys, us_keys).size and np.array_equal(combined_keys, np.union1d(cs_keys, us_keys)), 'Actual scheduled US/CS composition differs') masks = reader.arrays(case / 'source-mask.npz') expected_mask = np.where(np.isin(combined_keys, cs_keys), 1, 2).astype(np.uint8) require(set(masks) == {'source_mask'} and masks['source_mask'].dtype == np.uint8 and np.array_equal(masks['source_mask'], expected_mask) and binding['composition']['policy'] == 'error' and binding['composition']['cross_source_conflict_count'] == 0, 'Raw composition/source-mask differs') class Evidence: def __init__(self, reader, exp, registration_sha, expected, final): require(final.get('schema') == 'normal-append-ledger-v1-final-audit' and final.get('registration_sha256') == registration_sha and final.get('pass_all') is True and final.get('entry_ids') == final.get('expected_entry_ids') == expected and final.get('expected_order_exact') is True, 'Final ledger authority/complete order differs') require(all(final.get(k) == [] for k in ('extra_files', 'missing_files', 'changed_files', 'unsafe_files', 'errors', 'uncommitted_entry_ids')) and final.get('uncommitted_state_unknown') is False, 'Incomplete/failed final ledger audit') self.r, self.exp, self.regsha, self.expected = reader, Path(exp), registration_sha, expected self.index, self.tail, self.final = 0, None, final def process(self, entry_id, kind): self.index += 1 require(self.expected[self.index - 1] == entry_id, 'Analysis process order differs') entry_path = self.exp / f'.append-ledger/entries/{self.index:016d}.json' entry = self.r.json(entry_path) start_path = self.exp / f'.append-ledger/started/{entry_id}.json' start = self.r.json(start_path) job_path = self.exp / f'jobs/{entry_id}.json' process_path = self.exp / 'receipts' / entry_id / 'process.json' require(entry['entry_id'] == start['entry_id'] == entry_id and entry['sequence'] == start['next_sequence'] == self.index and entry['registration_sha256'] == start['registration_sha256'] == self.regsha and entry['prev_entry_sha256'] == start['prev_entry_sha256'] == self.tail and entry['start_sha256'] == self.r.check(start_path)['sha256'] and start['retry_authorized'] is False, 'Ledger/start chain differs') incoming = {row['path']: row for row in entry['consumed_inputs']} outgoing = {row['path']: row for row in entry['new_outputs']} require(len(incoming) == len(entry['consumed_inputs']) and len(outgoing) == len(entry['new_outputs']), 'Duplicate ledger files') for path, row in {**incoming, **outgoing}.items(): _, bound = self.r.path(path) require(all(row[k] == bound[k] for k in ('bytes', 'sha256')), 'Ledger/checksum authority differs') metadata = entry['metadata'] require(metadata['job_file'] == str(job_path) and metadata['process_receipt_file'] == str(process_path) and type(metadata['observed_returncode']) is int and metadata['observed_returncode'] == 0 and str(process_path) in outgoing and str(job_path) in incoming and start['job']['path'] == str(job_path) and start['job']['sha256'] == self.r.check(job_path)['sha256'], 'Process/job not owned by committed ledger entry') process, job = self.r.json(process_path), self.r.json(job_path) require(process['entry_id'] == entry_id and process['registration_sha256'] == job['registration_sha256'] == self.regsha and process['job_sha256'] == self.r.check(job_path)['sha256'] and process['complete'] is True and type(process['exit_code']) is int and process['exit_code'] == 0 and process['timed_out'] is False and process['exit_observed_by_parent'] is True and job['kind'] == kind, 'Actual parent exit/job receipt differs') for path, digest in job['input_sha256'].items(): require(path in incoming and self.r.check(path)['sha256'] == digest, 'Actual consumed job input differs') for label in ('stdout', 'stderr'): path = self.exp / f'logs/{entry_id}.{label}.log' require(str(path) in outgoing and self.r.check(path)['sha256'] == process[label + '_sha256'], 'Parent log differs') if kind in ('brain', 'update'): require(job['receipt_file'] in outgoing and job['receipt_file'] + '.attempt.json' in outgoing, 'Worker/attempt receipt not ledger owned') worker = self.r.json(job['receipt_file']) closure = dict(job['input_sha256']) closure[str(job_path)] = self.r.check(job_path)['sha256'] # The AP worker includes its own exact script source in its closure. script = process['argv'][2] closure[script] = self.r.check(script)['sha256'] for value in job['sources'].values(): require(self.r.check(value['path'])['sha256'] == value['sha256'], 'Worker source differs') closure[value['path']] = value['sha256'] require(worker['schema'] == 'phase4ap-isolated-worker-receipt-v1' and worker['complete'] is True and worker['job_id'] == entry_id and worker['kind'] == kind and worker['registration_sha256'] == self.regsha and worker['job_sha256'] == self.r.check(job_path)['sha256'] and worker['verified_input_sha256'] == closure and worker['attempt_sha256'] == self.r.check(job['receipt_file'] + '.attempt.json')['sha256'], 'Worker/attempt binding differs') declared = {str(Path(p).relative_to(job['output_dir'])): row['sha256'] for p, row in outgoing.items() if Path(p).is_relative_to(job['output_dir'])} require(worker['output_files_sha256'] == declared, 'Worker output coverage differs') self.tail = self.r.check(entry_path)['sha256'] return dict(job=job, outgoing=outgoing, process_sha256=self.r.check(process_path)['sha256'], process_path=str(process_path)) def finish(self): require(self.index == len(self.expected) and self.tail == self.final['head_sha256'], 'Missing process or terminal ledger head differs') def audit_records(reader, exp, reg, regsha, plan, evidence, *, template, inputs, populations): """Bind all 33,920 tasks and actual update chains; retain only small indexes.""" sample = evidence.process('input-generation', 'sample') sampler = reader.json(Path(exp) / 'receipts/input-generation.json') require(sampler['complete'] is True and sampler['registration_sha256'] == regsha and str(Path(exp) / 'receipts/input-generation.json') in sample['outgoing'], 'Sampler receipt not ledger owned') require(sampler['descriptors'] == len(inputs['descriptors']) == 4080 and set(sampler['inputs']) == set(inputs['descriptors']) and sampler['input_inventory_sha256'] == reader.check(Path(exp) / 'protocol/input-inventory.json')['sha256'], 'Actual sampler inventory incomplete') previous, probes, arms, record_hashes = {}, {}, defaultdict(list), [] for task in plan['tasks']: key = task_key(task); result_path = Path(exp) / f'results/{key}.json' record = reader.json(result_path) require(record['schema'] == 'normal-task-result-v1' and record['complete'] is True and record['registration_sha256'] == regsha and canonical(record['task']) == canonical(task), 'Actual result/task differs') branch = task['block_id'], task['arm'] overlay = previous.get(branch, reg['initial_overlay']) require(record['overlay_before'] == overlay, 'Delta ancestry changed or probe fed back') brain = evidence.process(key + '--brain', 'brain') audit_case(reader, exp, task, brain['job'], template=template, inputs=inputs, sampler=sampler, populations=populations, population_file=reg['population_file'], output_cap=reg['budget']['output_cap_bytes']) job = brain['job']; output = Path(exp) / 'runs' / key require(record['brain_process_receipt_path'] == brain['process_path'] and record['checkpoint_dir'] == job['output_dir'] == str(output) and all(job[k] == overlay[k] for k in ('overlay_file', 'overlay_manifest')) and job['diagnostic_mode'] == 'light', 'Brain result/overlay path differs') manifest = reader.json(output / 'checkpoint-manifest.json') require(record['checkpoint_manifest_sha256'] == record['brain_audit']['checkpoint_manifest_sha256'] == reader.check(output / 'checkpoint-manifest.json')['sha256'] and record['brain_audit']['task_id'] == task['task_id'], 'Checkpoint binding differs') for name, digest in manifest['files_sha256'].items(): require(reader.check(output / name)['sha256'] == digest, 'Checkpoint payload differs') record_hashes.append([task['task_id'], reader.check(result_path)['sha256']]) if task['kind'] == 'probe': require(str(result_path) in brain['outgoing'], 'Probe result not ledger owned') probes[(task['block_id'], task['arm'], task['checkpoint'], task['recipe']['cue'])] = record continue update = evidence.process(key + '--update', 'update') cpu = evidence.process(key + '--verify', 'cpu_verify') require(record['update_process_receipt_path'] == update['process_path'] and record['cpu_process_receipt_path'] == cpu['process_path'] and str(result_path) in cpu['outgoing'], 'Training result/parent process ownership differs') authority = reader.json(record['epoch_authority']['path']) require(reader.check(record['epoch_authority']['path'])['sha256'] == record['epoch_authority']['sha256'] == update['job']['authority_sha256'] == cpu['job']['authority_sha256'] and authority['epoch_id'] == task['task_id'] and authority['checkpoint_dir'] == str(output) and authority['checkpoint_manifest_sha256'] == record['checkpoint_manifest_sha256'], 'Original E authority differs') command = dict(steps=1200, compartment=task['compartment_verbatim'], us_tick=task['recipe']['us']['tick'], d_command=task['recipe']['D_command'], frozen=not task['recipe']['update_enabled'], trace_backend='torch') require(authority['command'] == command, 'Original E command changed') valid = reader.json(record['cpu_validation']['path']) after = dict(overlay_file=str(Path(exp) / 'updates' / key / 'delta-after.npz'), overlay_manifest=str(Path(exp) / 'updates' / key / 'overlay-manifest.json')) require(record['update_dir'] == update['job']['output_dir'] == cpu['job']['update_dir'] == str(Path(exp) / 'updates' / key) and record['cpu_validation']['path'] == cpu['job']['receipt_file'] and record['cpu_validation']['path'] in cpu['outgoing'] and record['epoch_authority']['path'] == update['job']['authority_file'] == cpu['job']['authority_file'] and authority['files']['state'] == dict(path=str(output / 'state.npz'), sha256=reader.check(output / 'state.npz')['sha256']) and authority['files']['overlay_before'] == dict(path=overlay['overlay_file'], sha256=reader.check(overlay['overlay_file'])['sha256']) and authority['files']['overlay_manifest_before'] == dict(path=overlay['overlay_manifest'], sha256=reader.check(overlay['overlay_manifest'])['sha256']) and record['after_overlay'] == after and reader.check(record['cpu_validation']['path'])['sha256'] == record['cpu_validation']['sha256'] and valid['complete'] is True and valid['frozen_U_verify_receipt_recomputed'] is True and valid['actual_sealed_events_used'] is True and valid['epoch_authority_sha256'] == record['epoch_authority']['sha256'] and valid['after_overlay_sha256'] == reader.check(after['overlay_file'])['sha256'], 'Independent CPU update validation differs') if task['arm'] in ('d_zero', 'frozen', 'cs_only'): require(not reader.arrays(after['overlay_file'])['plastic_delta_mv'].view(np.uint32).any(), 'Zero control contains nonzero delta') previous[branch] = after arms[branch].append(dict(result=record_hashes[-1], brain=brain['process_sha256'], update=update['process_sha256'], cpu=cpu['process_sha256'], requested=task['recipe']['us']['requested'])) evidence.finish() require(len(probes) == 3920 and len(arms) == 280 and len(record_hashes) == 33920, 'Incomplete actual task inventory') return probes, arms, sha(record_hashes) def build_registry(trial, plan, *, nodes, populations, population_binding_sha, regsha, input_hashes): membership = M.validate_populations(nodes, populations) blocks = {} inputs = {(r['block_id'], r['cue']): r for r in plan['evaluation_inputs']} for block in trial['plan']['blocks']: identity = block['block_id'] source_rows = [r for r in trial['seed_manifest']['independent_streams'] if r['key'][0] == identity and r['key'][1] == 'normal' and r['split'] in ('training', 'design')] sources = [dict(stream_id=P._FROZEN['trial_plan']._stream_id(P.MASTER, r['split'], r['key']), seed=r['seed'], split=r['split']) for r in source_rows] blocks[identity] = dict(mode=block['mode'], dan_type=block['dan_type'], compartment_verbatim=block['compartment_verbatim'], conditioned_cue=ODORS[block['initial_reinforced_cue']], replicate=block['replicate'], training_sources=sources, evaluation_sources={ODORS[c]: {k: inputs[(identity, c)][k] for k in ('stream_id', 'seed', 'split')} for c in ODORS}, evaluation_input_sha256={ODORS[c]: input_hashes[(identity, c)] for c in ODORS}) registry = dict(schema=G.REGISTRY_SCHEMA, protocol_sha256=regsha, population_binding_sha256=population_binding_sha, nodes_raw_sha256=M._hash(nodes), population_membership_sha256=membership['membership_sha256'], blocks=blocks) G.validate_registry(registry, expected_sha256=G.descriptor_sha256(registry)) return registry def compact_metric(metric): return dict(rawS=metric['rawS'], rawB=metric['rawB'], separation=metric['separation'], cues={cue: dict(state_pre=summary['pre_state_raw_sha256'], state_post=summary['post_state_raw_sha256'], populations={name: {k: v for k, v in group.items() if not isinstance(v, list)} for name, group in summary['populations'].items()}) for cue, summary in metric['cues'].items()}) def scientific_reports(probes, arms, *, registry, authority, nodes, populations, load_state): """One cell's terminal vectors at a time; curve outputs contain no raw vectors.""" curves, compact_reports = [], [] def cells(): for mode in M.MODES: for dan in M.DAN_TYPES: for conditioned in M.CUES: rows = [] selected = [(key, b) for key, b in registry['blocks'].items() if (b['mode'], b['dan_type'], b['conditioned_cue']) == (mode, dan, conditioned)] for identity, block in selected: arm_values = {} for name, legacy_name in ARM_NAMES.items(): pre = {ODORS[c]: load_state(probes[(identity, name, 0, c)]) for c in ODORS} terminal = None for point in POINTS: post = pre if point == 0 else {ODORS[c]: load_state(probes[(identity, name, point, c)]) for c in ODORS} metric = M.arm_metrics(pre, post, conditioned_cue=conditioned, nodes=nodes, populations=populations) curves.append(dict(block_id=identity, arm=name, checkpoint=point, metrics=compact_metric(metric))) if point == 50: terminal = metric history = arms[(identity, name)] require(len(history) == (150 if name == 'unpaired' else 100), 'Missing actual training/control epochs') execution = dict(complete=True, recording_verified=True, receipt_sha256=sha(history), assay='normal', epoch_duration_ms=120., cs_duration_ms=100., us_tick=900, completed_epochs=len(history), reinforcement_opportunities=sum(r['requested'] for r in history), terminal_pairings=50) arm_values[legacy_name] = dict(metrics=terminal, execution=execution) rows.append(dict(replicate_id=identity, replicate_unit='independent_training', training_stream_ids=[x['stream_id'] for x in block['training_sources']], evaluation_stream_ids=[block['evaluation_sources'][c]['stream_id'] for c in M.CUES], assay='normal', mode=mode, dan_type=dan, conditioned_cue=conditioned, arms=arm_values)) report = G.evaluate_acquisition(rows, assay='normal', mode=mode, dan_type=dan, conditioned_cue=conditioned, registry=registry, authority=authority) compact_reports.append({k: v for k, v in report.items() if k not in ('acquisition_metric_inputs', 'frozen_acquisition_result')}) yield report cohort = G.summarize_cohort(cells(), registry=registry, authority=authority, required_assays=('normal',)) require(cohort['complete_inventory'], 'Missing normal cells') return dict(cells=compact_reports, cohort=cohort, curves=curves) def legacy_audit(reports, declared_mapping): """G.H_MAPPING source layout; call the unchanged M scalar twice per group.""" require(declared_mapping == G.H_MAPPING, 'Explicit original registered H mapping required') lookup = {(r['mode'], r['dan_type'], r['conditioned_cue']): r for r in reports} require(len(reports) == len(lookup) == 8, 'Exact eight-cell legacy input required') groups = [] for mode in M.MODES: for cue in M.CUES: selected = {d: lookup[(mode, d, cue)] for d in M.DAN_TYPES} outcomes = {} for source in M.DAN_TYPES: gains = {label: [r['population_separation_gains']['MBON'] for r in selected[dan]['replicates']] for dan, label in (('PAM15', 'appetitive-conditioning'), ('PPL103', 'aversive-conditioning'))} for name, label in (('D=0', 'd-zero-control'), ('random reward', 'random-reward-control'), ('frozen', 'frozen-brain-control')): controls = selected[source]['legacy_control_MBON_gains'][name] require(set(controls) == {r['replicate_id'] for r in selected[source]['replicates']}, 'Legacy replicate control source differs') gains[label] = [controls[r['replicate_id']] for r in selected[source]['replicates']] outcomes[source] = M.legacy_h_mean_control_audit(gains) groups.append(dict(mode=mode, conditioned_cue=cue, control_sources=outcomes, both_pass=all(v['predicate_pass'] for v in outcomes.values()))) return dict(schema=G.SCHEMA, status='CONDITIONAL-AUDIT', declared_mapping=declared_mapping, groups=groups, both_pass=all(g['both_pass'] for g in groups), original_H_data_layout_reproduced=False, new_stricter_control_source_mapping=True, **G._scope()) def analyze(exp, registration_sha256, *, verified_inventory, final_ledger): exp, reader = Path(exp), Reader(verified_inventory) regpath = exp / 'protocol/preregistered.json' require(reader.check(regpath)['sha256'] == registration_sha256, 'Registration authority differs') reg = reader.json(regpath) require(reg['schema'] == 'normal-conditioning-registration-v1' and reg['scientific_scope'] == 'normal-acquisition-only' and reg['subsequent_assays_authorized'] is False, 'Wrong scientific authority') for collection in ('source_sha256', 'input_sha256', 'prepared_sha256'): for path, digest in reg[collection].items(): require(reader.check(path)['sha256'] == digest, 'Registered dependency differs') plan = reader.json(exp / 'protocol/normal-plan.json') full = reader.json(reg['original_full_trial_plan']['path']) require(reader.check(reg['original_full_trial_plan']['path'])['sha256'] == reg['original_full_trial_plan']['sha256'] == P.AO_TRIAL_FILE_SHA256, 'Original AO full plan differs') evaluation = P.expand_pinned_evaluation(full) P.validate_normal_plan(plan, full, evaluation) gates = reader.json(exp / 'protocol/gates.json') require(gates['H_mapping'] == G.H_MAPPING and gates['all_eight_cells_required'] is True and gates['same_replicate_conjunction_at_least'] == 3 and gates['training_replicates'] == 5 and gates['terminal_checkpoint'] == 50 and gates['intermediate_checkpoints_cannot_rescue_terminal'] is True, 'Registered scientific policy differs') template = reader.json(exp / 'protocol/case-template.json') nodes_path = Path(template['graph_dir']) / 'nodes.npy' nodes = np.load(io.BytesIO(reader.raw(nodes_path)), allow_pickle=False) require(nodes.dtype == np.int32 and len(nodes) == 166700, 'Full original graph nodes required') require('readout_population_file' in reg, 'Registered full legacy/non-MBON readout populations missing') populations = reader.arrays(reg['readout_population_file']) original = reader.arrays(reg['population_file']) for name in ('MBON', 'MBON01', 'MBON12'): require(np.array_equal(original[name], populations[name]), 'Original anatomical population changed') M.validate_populations(nodes, populations) require('readout_population_binding_file' in reg, 'Registered anatomical binding file missing') population_binding_sha = reader.check(reg['readout_population_binding_file'])['sha256'] evidence = Evidence(reader, exp, registration_sha256, expected_entries(plan), final_ledger) inputs = reader.json(exp / 'protocol/input-inventory.json') probes, arms, inventory_sha = audit_records(reader, exp, reg, registration_sha256, plan, evidence, template=template, inputs=inputs, populations=original) input_hashes, seen_receipts = {}, set() def load_state(record): task = record['task']; key = task_key(task) receipt = record['brain_process_receipt_path'] require(receipt not in seen_receipts, 'Probe execution reused across snapshots') seen_receipts.add(receipt) csid = inputs['task_inputs'][task['task_id']] recipe = task['recipe'] expected_descriptor = dict(mode=task['mode'], cue=recipe['cue'], seed=recipe['input']['seed'], steps=1200, cs_start_tick=0, cs_stop_tick_exclusive=1000, source_stream_id=recipe['input']['stream_id'], table_id=task['mode'] + '--' + recipe['cue']) require(csid == sha(expected_descriptor) and inputs['descriptors'][csid] == expected_descriptor, 'Evaluation seed/stream/clock mapping differs from original plan') source = exp / f'inputs/generated/{csid}.npz' generated = reader.json(exp / f'inputs/generated/{csid}.json') require(generated['descriptor'] == inputs['descriptors'][csid] and generated['requests_sha256'] == reader.check(source)['sha256'], 'Actual evaluation input descriptor differs') case = exp / 'cases' / key binding = reader.json(case / 'input-binding.json') require(binding['CS_source'] == dict(path=str(source), sha256=reader.check(source)['sha256']) and binding['CS_descriptor_id'] == csid and binding['task_id'] == task['task_id'], 'Probe shared input binding differs') requests, cs, us = (reader.arrays(path) for path in (case / 'requests.npz', source, case / 'us_requests.npz')) require(set(requests) == set(cs) == set(us) == {'tick', 'neuron_idx'} and all(not len(v) for v in us.values()) and all(np.array_equal(requests[k], cs[k]) for k in requests), 'Probe includes US or changed CS') state = reader.arrays(Path(record['checkpoint_dir']) / 'state.npz') actual = M.validate_state(state, nodes=nodes, steps=1200) require(actual['hashes'] == record['brain_audit']['state_raw_sha256'], 'Actual probe raw arrays differ') return state for item in plan['evaluation_inputs']: record = probes[(item['block_id'], 'paired', 0, item['cue'])] csid = inputs['task_inputs'][record['task']['task_id']] input_hashes[(item['block_id'], item['cue'])] = reader.check(exp / f'inputs/generated/{csid}.npz')['sha256'] registry = build_registry(full, plan, nodes=nodes, populations=populations, population_binding_sha=population_binding_sha, regsha=registration_sha256, input_hashes=input_hashes) authority = dict(schema=G.AUTHORITY_SCHEMA, registry_sha256=G.descriptor_sha256(registry), verification_receipt_sha256=sha(final_ledger), execution_inventory_sha256=inventory_sha, population_binding_sha256=population_binding_sha) result = scientific_reports(probes, arms, registry=registry, authority=authority, nodes=nodes, populations=populations, load_state=load_state) require(len(seen_receipts) == 3920, 'Not every independently executed probe was analyzed') result['legacy_H'] = legacy_audit(result['cells'], gates['H_mapping']) return dict(schema='normal-scientific-analysis-v1', status='CONDITIONAL-PENDING-OUTER-INTEGRITY', registration_sha256=registration_sha256, normal_plan_sha256=plan['payload_sha256'], registry=registry, authority=authority, analysis=result, analyzed_probe_calls=3920, curve_points=1960, consumed_file_count=len(reader.seen), subsequent_assays_status='NOT-RUN', subsequent_assays_authorized=False, candidate_generated=False, learning_pass_claimed=False, scientific_learning_pass_claimed=False, data_backed_claimed=False, external_full_tree_anatomy_historical_integrity_verified_here=False, retained_raw_evidence='original state and receipt files; terminal raw metric vectors recomputable, not duplicated in report')