254 lines
16 KiB
Python
254 lines
16 KiB
Python
"""Exclusive small-evidence publication after both Phase 4AL seals verify.
|
|
|
|
Publication verifies and copies bytes. It never runs a brain, re-evaluates a
|
|
scientific gate, converts FAIL/INCOMPLETE into PASS, or changes frozen sources.
|
|
The source-pinned Phase 4AI verification/copy helpers are executed unchanged.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path, PurePosixPath
|
|
|
|
|
|
ROOT = Path('/data/digital-drosophila')
|
|
MODEL_RELATIVE = Path('models/male-cns-lif/mb-credit-transfer-audit-v1')
|
|
EXPERIMENT_RELATIVE = Path('experiments/phase4al-mb-credit-transfer')
|
|
REGISTRY_RELATIVE = Path('registry/phase4al-mb-credit-transfer')
|
|
HELPER_RELATIVE = Path('models/male-cns-lif/pn-recruitment-audit-v1/publication.py')
|
|
HELPER_SHA256 = '7a79c499098b74163e7bb16adabcbc54e7069dafa204d0b99c7f4c03d79f8016'
|
|
MAX_EVIDENCE_BYTES = 4 * 1024 ** 2
|
|
EVIDENCE_SUFFIXES = frozenset(('.json', '.csv', '.md', '.log', '.sha256'))
|
|
FINAL_STATUS = 'PASS-CONDITIONAL-CREDIT-TRANSFER-AUDIT-NOT-LEARNING'
|
|
# Finalize currently seals only this completed diagnostic status. A partial
|
|
# run is not promoted; future failure sealing needs an explicit new contract.
|
|
FINAL_STATUSES = frozenset((FINAL_STATUS,))
|
|
REQUIRED_EVIDENCE = ('audit/final-status.json', 'regression/old-integrity-after.json',
|
|
'audit/scientific-summary.json')
|
|
REFERENCE_EVIDENCE = 'regression/frozen-five.json'
|
|
GATE_FIELDS = ('arithmetic_and_coverage_pass', 'old_integrity_pass', 'frozen_five_reference_pass',
|
|
'frozen_eligibility_and_mask_unchanged', 'base_weights_unchanged',
|
|
'summary_all_144_baseline_raw_states_and_repeat_pair_metrics_reverified',
|
|
'scientific_overall_PASS_threshold_defined')
|
|
COUNT_FIELDS = ('primary_trials', 'exact_repeats', 'pairs')
|
|
COHORTS = ('seed_validation', 'novel_to_aj')
|
|
MODES = ('physiological', 'matched_energy')
|
|
|
|
|
|
def require(condition, message):
|
|
if not condition:
|
|
raise ValueError(message)
|
|
|
|
|
|
def load_helpers(path):
|
|
"""Instantiate the unchanged module from its exact pinned source bytes.
|
|
|
|
Using module_from_spec plus the source bytes avoids writing/importing a pyc
|
|
inside the sealed old model, even if the publisher was invoked without -B.
|
|
No old module global is redirected or modified after module initialization.
|
|
"""
|
|
path = Path(path)
|
|
require(path.is_absolute() and path.is_file() and not path.is_symlink(), 'Invalid frozen helper path')
|
|
data = path.read_bytes()
|
|
require(hashlib.sha256(data).hexdigest() == HELPER_SHA256, 'Frozen AI publication helper hash mismatch')
|
|
spec = importlib.util.spec_from_file_location('phase4al_frozen_ai_publication_helpers', path)
|
|
require(spec is not None and spec.loader is not None, 'Unable to define frozen helper module')
|
|
module = importlib.util.module_from_spec(spec)
|
|
exec(compile(data, str(path), 'exec'), module.__dict__)
|
|
require(module._digest(path) == HELPER_SHA256, 'Helper source changed while loading')
|
|
return module
|
|
|
|
|
|
def _copy(helper, source, destination, size, checksum):
|
|
"""Separate local delegation point for interruption-only synthetic tests."""
|
|
helper._copy_verified(source, destination, size, checksum)
|
|
|
|
|
|
def _write_small_json(helper, path, value):
|
|
data = (json.dumps(value, indent=2, ensure_ascii=False, allow_nan=False) + '\n').encode('utf-8')
|
|
require(len(data) <= MAX_EVIDENCE_BYTES, 'Generated registry evidence exceeds 4 MiB: ' + str(path))
|
|
with Path(path).open('xb') as stream:
|
|
stream.write(data)
|
|
require(Path(path).stat().st_size == len(data), 'Generated registry evidence size changed')
|
|
|
|
|
|
def _status_evidence(helper, experiment, rows, model):
|
|
"""Check declaration consistency only, not the scientific gate itself."""
|
|
for relative in REQUIRED_EVIDENCE:
|
|
require(relative in rows, 'Required finalized evidence absent from seal: ' + relative)
|
|
require(rows[relative]['bytes'] <= MAX_EVIDENCE_BYTES, 'Required finalized evidence exceeds 4 MiB')
|
|
status, integrity, science = [helper._json_bytes((experiment / relative).read_bytes())
|
|
for relative in REQUIRED_EVIDENCE]
|
|
config = helper._json_bytes((model / 'config.json').read_bytes())
|
|
expected = dict(phase='4AL', neurons=166700, edges=25582938, candidate_edges=14232,
|
|
primary_trials=120, technical_repeats=24, steps=1000, dt_ms=.1,
|
|
virtual_gate_tick=900, kc_trace_tau_ms=100., trace_cap=1., stable_seed_count=3,
|
|
conditional_depression_fraction=.25, groups=['plastic_KC', 'nonplastic_KC', 'DAN', 'MBON', 'APL', 'other'],
|
|
training=False, candidate_generation=False, no_new_overall_credit_threshold=True)
|
|
require(isinstance(config, dict) and all(type(config.get(k)) is type(v) and config[k] == v
|
|
for k, v in expected.items()), 'Changed Phase 4AL configuration/design contract')
|
|
reference = None
|
|
if REFERENCE_EVIDENCE in rows:
|
|
require(rows[REFERENCE_EVIDENCE]['bytes'] <= MAX_EVIDENCE_BYTES, 'Frozen reference evidence exceeds 4 MiB')
|
|
reference = helper._json_bytes((experiment / REFERENCE_EVIDENCE).read_bytes())
|
|
require(isinstance(reference, dict) and type(reference.get('pass_all')) is bool and
|
|
isinstance(reference.get('trials'), list), 'Invalid frozen reference report')
|
|
if reference['pass_all']:
|
|
require(len(reference['trials']) == 5 and all(isinstance(r, dict) and isinstance(r.get('exact'), dict)
|
|
and set(r['exact']) == {'step', 'neuron_idx', 'counts', 'v', 'g'}
|
|
and all(value is True for value in r['exact'].values()) for r in reference['trials']),
|
|
'Declared frozen-five PASS must contain five exact trial records')
|
|
require(isinstance(status, dict) and status.get('status') in FINAL_STATUSES,
|
|
'Unrecognized Phase 4AL final status')
|
|
for key in GATE_FIELDS:
|
|
require(type(status.get(key)) is bool, 'Missing/non-Boolean finalized result: ' + key)
|
|
for key in COUNT_FIELDS:
|
|
require(type(status.get(key)) is int and status[key] >= 0, 'Missing/invalid finalized count: ' + key)
|
|
for key in ('candidate_generated', 'learning_achieved', 'conditioning_executed',
|
|
'scientific_overall_PASS_threshold_defined'):
|
|
require(status.get(key) is False, 'Unexpected finalized scope claim: ' + key)
|
|
require(isinstance(science, dict) and science and all(k in status and status[k] == value
|
|
and type(status[k]) is type(value) for k, value in science.items()),
|
|
'Final status contradicts its scientific summary')
|
|
require(status.get('scientific_summary_sha256') == rows['audit/scientific-summary.json']['sha256'],
|
|
'Final status scientific-summary SHA mismatch')
|
|
require(isinstance(integrity, dict) and bool(integrity) and all(
|
|
isinstance(row, dict) and type(row.get('pass')) is bool for row in integrity.values()),
|
|
'Missing/invalid frozen-integrity report')
|
|
require(status['old_integrity_pass'] == all(row['pass'] for row in integrity.values()),
|
|
'Final status contradicts its frozen-integrity report')
|
|
reference_pass = bool(reference is not None and reference['pass_all'])
|
|
require(status['frozen_five_reference_pass'] == reference_pass,
|
|
'Final status contradicts its frozen-reference report/presence')
|
|
if status['status'].startswith('PASS-'):
|
|
require(all(status[key] for key in GATE_FIELDS if key != 'scientific_overall_PASS_threshold_defined')
|
|
and reference_pass and status['primary_trials'] == 120 and status['exact_repeats'] == 24
|
|
and status['pairs'] == 60,
|
|
'Declared PASS contradicts finalized gate/coverage flags')
|
|
blocks = status.get('blocks')
|
|
require(isinstance(blocks, dict) and set(blocks) == {c + '/' + m for c in COHORTS for m in MODES},
|
|
'Missing/extra cohort-mode blocks')
|
|
for block in blocks.values():
|
|
require(isinstance(block, dict) and type(block.get('trials')) is int and block['trials'] == 30
|
|
and type(block.get('pairs')) is int and block['pairs'] == 15, 'Incomplete cohort-mode block')
|
|
for key, maximum in (('pairs_with_both_specific_KC_and_edge_sets', 15),
|
|
('conditional25_event_changed_trials', 30),
|
|
('conditional25_count_or_first_latency_changed_trials', 30)):
|
|
require(type(block.get(key)) is int and 0 <= block[key] <= maximum,
|
|
'Invalid diagnostic count: ' + key)
|
|
# Zero observed specificity/functional changes is publishable. This
|
|
# is not a new minimum scientific effect or pair-success criterion.
|
|
return status, reference, integrity
|
|
|
|
|
|
def publish(root=ROOT, helper_path=None):
|
|
"""Publish the fixed AL registry exclusively; root override is for tests.
|
|
|
|
Only sealed small experiment evidence and the two model seal controls are
|
|
copied. Every bulk payload is nevertheless verified before and after copying.
|
|
An interrupted registry is preserved and cannot be overwritten or resumed.
|
|
"""
|
|
root = Path(root)
|
|
require(root.is_absolute() and root.is_dir() and not root.is_symlink(), 'Invalid project root')
|
|
root = root.resolve(strict=True)
|
|
model, experiment, registry = (root / part for part in
|
|
(MODEL_RELATIVE, EXPERIMENT_RELATIVE, REGISTRY_RELATIVE))
|
|
require(not registry.exists() and not registry.is_symlink(), 'Registry already exists; no overwrite/resume')
|
|
helper_path = root / HELPER_RELATIVE if helper_path is None else Path(helper_path)
|
|
helper = load_helpers(helper_path)
|
|
for path in (model, experiment, registry.parent):
|
|
current = root
|
|
for part in path.relative_to(root).parts:
|
|
current = current / part
|
|
require(not current.is_symlink(), 'Symlink in publication root path: ' + str(current))
|
|
verified = {'model': helper.verify_seal(model), 'experiment': helper.verify_seal(experiment)}
|
|
experiment_rows = {row['path']: row for row in verified['experiment']['files']}
|
|
status, reference, integrity = _status_evidence(helper, experiment, experiment_rows, model)
|
|
plans, omitted = [], []
|
|
for row in verified['experiment']['files'] + helper._control_rows(experiment, verified['experiment']):
|
|
if PurePosixPath(row['path']).suffix.lower() in EVIDENCE_SUFFIXES and row['bytes'] <= MAX_EVIDENCE_BYTES:
|
|
plans.append((experiment, row, 'evidence/' + row['path']))
|
|
else:
|
|
omitted.append(dict(path=row['path'], bytes=row['bytes'], sha256=row['sha256'],
|
|
reason='exceeds_4_MiB' if row['bytes'] > MAX_EVIDENCE_BYTES else 'bulk_or_non_evidence_extension'))
|
|
for row in helper._control_rows(model, verified['model']):
|
|
require(row['bytes'] <= MAX_EVIDENCE_BYTES, 'Model seal control exceeds small-evidence limit')
|
|
plans.append((model, row, 'model/' + row['path']))
|
|
destinations = {target for _, _, target in plans}
|
|
required_copies = ['manifest.json', 'checksums.sha256', *REQUIRED_EVIDENCE]
|
|
if reference is not None:
|
|
required_copies.append(REFERENCE_EVIDENCE)
|
|
for relative in required_copies:
|
|
require('evidence/' + relative in destinations, 'Required experiment evidence cannot be copied: ' + relative)
|
|
require(len(destinations) == len(plans), 'Duplicate planned evidence destination')
|
|
registry.parent.mkdir(parents=True, exist_ok=True)
|
|
registry.mkdir(exist_ok=False)
|
|
try:
|
|
records = []
|
|
for source_root, row, relative in plans:
|
|
source = helper._regular_file(source_root.resolve(), row['path'])
|
|
_copy(helper, source, registry / relative, row['bytes'], row['sha256'])
|
|
records.append(dict(source=source.relative_to(root).as_posix(), copy=relative,
|
|
bytes=row['bytes'], sha256=row['sha256']))
|
|
after = {'model': helper.verify_seal(model), 'experiment': helper.verify_seal(experiment)}
|
|
require(after == verified, 'A sealed tree changed during publication')
|
|
require(helper._digest(helper_path) == HELPER_SHA256, 'Frozen helper changed during publication')
|
|
proof = {name: {key: value for key, value in report.items() if key != 'files'}
|
|
for name, report in verified.items()}
|
|
_write_small_json(helper, registry / 'seal-verification.json', proof)
|
|
_write_small_json(helper, registry / 'evidence-index.json', records)
|
|
files = [dict(path=path.relative_to(registry).as_posix(), bytes=path.stat().st_size,
|
|
sha256=helper._digest(path)) for path in sorted(registry.rglob('*')) if path.is_file()]
|
|
receipt = dict(publication_complete=True, registry=registry.relative_to(root).as_posix(),
|
|
project_root=str(root), declared_audit_status=status['status'],
|
|
declared_gate_results={key: status[key] for key in GATE_FIELDS},
|
|
declared_audit_counts={key: status[key] for key in COUNT_FIELDS},
|
|
declared_diagnostic_scope='Read-only credit and fixed 25-percent conditional MBON replay; not learning or whole-brain intervention',
|
|
scientific_overall_PASS_threshold_defined=False,
|
|
scientific_summary_sha256=status['scientific_summary_sha256'],
|
|
frozen_reference_report=dict(present=reference is not None,
|
|
path='evidence/' + REFERENCE_EVIDENCE if reference is not None else None,
|
|
sha256=experiment_rows[REFERENCE_EVIDENCE]['sha256'] if reference is not None else None,
|
|
declared_pass_all=reference['pass_all'] if reference is not None else None,
|
|
reported_trial_count=len(reference['trials']) if reference is not None else None,
|
|
missing_is_not_a_success_or_fabricated_trial_failure=True),
|
|
frozen_integrity_report=dict(path='evidence/regression/old-integrity-after.json',
|
|
sha256=experiment_rows['regression/old-integrity-after.json']['sha256'],
|
|
declared_pass_by_root={name: row['pass'] for name, row in integrity.items()}),
|
|
frozen_helper_source=str(helper_path), frozen_helper_sha256=HELPER_SHA256,
|
|
publisher_sha256=helper._digest(Path(__file__)), helper_globals_redirected=False,
|
|
model_manifest_sha256=verified['model']['manifest_sha256'],
|
|
experiment_manifest_sha256=verified['experiment']['manifest_sha256'],
|
|
source_trees_verified_before_and_after_copy=True,
|
|
copied_evidence_files=len(records), copied_evidence_bytes=sum(row['bytes'] for row in records),
|
|
files=files, experiment_payload_not_copied=omitted,
|
|
model_payload_not_duplicated=True, model_payload_remains_at=MODEL_RELATIVE.as_posix(),
|
|
bulk_remains_at=EXPERIMENT_RELATIVE.as_posix(), complete_bulk_backup=False,
|
|
scientific_gate_executed_by_publisher=False, scientific_gate_certified_by_publication=False,
|
|
publication_success_is_not_scientific_pass=True, candidate_generated=False,
|
|
learning_achieved=False, full_scientific_goal_achieved=False,
|
|
old_heldout_dynamic_results_parsed=False, existing_files_modified=False,
|
|
receipt_self_hash='Not self-referential; returned by publish() and printed by main()',
|
|
limits=dict(max_selected_evidence_file_bytes=MAX_EVIDENCE_BYTES,
|
|
selected_suffixes=sorted(EVIDENCE_SUFFIXES)))
|
|
receipt_path = registry / 'publication-receipt.json'
|
|
_write_small_json(helper, receipt_path, receipt)
|
|
return dict(publication_complete=True, registry=str(registry), declared_audit_status=status['status'],
|
|
copied_evidence_files=len(records), receipt_sha256=helper._digest(receipt_path),
|
|
scientific_gate_executed_by_publisher=False, publication_success_is_not_scientific_pass=True)
|
|
except Exception as error:
|
|
failure = registry / 'publication-failure.json'
|
|
if not failure.exists():
|
|
_write_small_json(helper, failure, dict(publication_complete=False, type=type(error).__name__,
|
|
message=str(error), partial_outputs_preserved=True, existing_files_modified=False))
|
|
raise
|
|
|
|
|
|
def main():
|
|
print(json.dumps(publish(), ensure_ascii=False, allow_nan=False), flush=True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|