Files
digital-drosophila/tools/phase4al-publication/publish_phase4al.py
T
2026-09-30 13:58:39 +08:00

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()