"""Temporary synthetic seals only; never publish/register any real evidence.""" import hashlib import json from pathlib import Path import tempfile import unittest from unittest import mock import publish_phase4al as publication HELPER = Path(__file__).resolve().parents[1] / 'pn-recruitment-audit-v1/publication.py' if not HELPER.is_file(): HELPER = publication.ROOT / publication.HELPER_RELATIVE def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() def write(path, value): path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(value, indent=2), encoding='utf-8') def seal(root): rows = [dict(path=path.relative_to(root).as_posix(), bytes=path.stat().st_size, sha256=sha(path)) for path in sorted(root.rglob('*')) if path.is_file() and path.name not in ('manifest.json', 'checksums.sha256') and '__pycache__' not in path.parts] write(root / 'manifest.json', dict(root=str(root), files=rows)) lines = [row['sha256'] + ' ' + row['path'] for row in rows] lines.append(sha(root / 'manifest.json') + ' manifest.json') (root / 'checksums.sha256').write_text('\n'.join(lines) + '\n', encoding='utf-8') class PublicationTests(unittest.TestCase): def setUp(self): temporary = tempfile.TemporaryDirectory(prefix='phase4al-publication-synthetic-') self.addCleanup(temporary.cleanup) self.root = Path(temporary.name).resolve() self.model = self.root / publication.MODEL_RELATIVE self.experiment = self.root / publication.EXPERIMENT_RELATIVE self.registry = self.root / publication.REGISTRY_RELATIVE self.model.mkdir(parents=True) self.experiment.mkdir(parents=True) (self.model / 'module.py').write_text('# synthetic, not a model\n', encoding='utf-8') self.config = 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) write(self.model / 'config.json', self.config) self.science = dict(arithmetic_and_coverage_pass=True, primary_trials=120, exact_repeats=24, pairs=60, candidate_generated=False, learning_achieved=False, conditioning_executed=False, scientific_overall_PASS_threshold_defined=False, blocks={c + '/' + m: dict(trials=30, pairs=15, pairs_with_both_specific_KC_and_edge_sets=0, conditional25_event_changed_trials=0, conditional25_count_or_first_latency_changed_trials=0) for c in publication.COHORTS for m in publication.MODES}) write(self.experiment / 'audit/scientific-summary.json', self.science) self.status = dict(status=publication.FINAL_STATUS, **self.science, old_integrity_pass=True, frozen_five_reference_pass=True, frozen_eligibility_and_mask_unchanged=True, base_weights_unchanged=True, summary_all_144_baseline_raw_states_and_repeat_pair_metrics_reverified=True, scientific_summary_sha256=sha(self.experiment / 'audit/scientific-summary.json')) write(self.experiment / 'audit/final-status.json', self.status) write(self.experiment / 'regression/frozen-five.json', dict(pass_all=True, trials=[dict(trial=str(i), exact={k: True for k in ('step', 'neuron_idx', 'counts', 'v', 'g')}) for i in range(5)])) write(self.experiment / 'regression/old-integrity-after.json', {'synthetic-old-tree': {'pass': True}}) write(self.experiment / 'nested/case/summary.json', {'synthetic': True}) (self.experiment / 'REPORT.md').write_text('Synthetic zero-effect diagnostic.\n', encoding='utf-8') (self.experiment / 'tests.log').write_text('Synthetic log\n', encoding='utf-8') for suffix in ('.npy', '.npz', '.parquet'): (self.experiment / ('bulk' + suffix)).write_bytes(b'synthetic bulk bytes, not scientific data') seal(self.model) seal(self.experiment) def publish(self): return publication.publish(self.root, HELPER) def test_completed_zero_effect_diagnostic_is_not_regraded_as_learning(self): before = {str(p): sha(p) for base in (self.model, self.experiment) for p in base.rglob('*') if p.is_file()} result = self.publish() self.assertTrue(result['publication_complete']) receipt = json.loads((self.registry / 'publication-receipt.json').read_text(encoding='utf-8')) self.assertEqual(receipt['declared_audit_status'], publication.FINAL_STATUS) self.assertFalse(receipt['scientific_overall_PASS_threshold_defined']) self.assertFalse(receipt['learning_achieved']) self.assertTrue(receipt['publication_success_is_not_scientific_pass']) self.assertEqual(receipt['scientific_summary_sha256'], self.status['scientific_summary_sha256']) for suffix in ('.npy', '.npz', '.parquet'): self.assertFalse((self.registry / ('evidence/bulk' + suffix)).exists()) for row in receipt['files']: self.assertEqual(sha(self.registry / row['path']), row['sha256']) self.assertEqual(before, {str(p): sha(p) for base in (self.model, self.experiment) for p in base.rglob('*') if p.is_file()}) def test_changed_config_blocks_before_destination(self): for key, value in (('phase', '4AK'), ('primary_trials', 119), ('candidate_edges', 14231), ('conditional_depression_fraction', .5), ('training', True), ('virtual_gate_tick', 901)): with self.subTest(key=key): write(self.model / 'config.json', dict(self.config, **{key: value})) seal(self.model) with self.assertRaisesRegex(ValueError, 'configuration/design'): self.publish() self.assertFalse(self.registry.exists()) def test_summary_hash_counts_and_scope_must_match(self): for changed in ({'scientific_summary_sha256': '0' * 64}, {'primary_trials': 119}, {'pairs': 59}, {'learning_achieved': True}, {'arithmetic_and_coverage_pass': 'true'}, {'old_integrity_pass': False}, {'base_weights_unchanged': False}): with self.subTest(changed=changed): write(self.experiment / 'audit/final-status.json', dict(self.status, **changed)) seal(self.experiment) with self.assertRaises(ValueError): self.publish() self.assertFalse(self.registry.exists()) def test_missing_or_corrupt_scientific_summary_is_rejected(self): path = self.experiment / 'audit/scientific-summary.json' path.unlink() seal(self.experiment) with self.assertRaisesRegex(ValueError, 'Required finalized evidence absent'): self.publish() self.assertFalse(self.registry.exists()) def test_complete_status_requires_all_four_complete_blocks(self): value = dict(self.science, blocks={}) write(self.experiment / 'audit/scientific-summary.json', value) write(self.experiment / 'audit/final-status.json', dict(self.status, **value, scientific_summary_sha256=sha(self.experiment / 'audit/scientific-summary.json'))) seal(self.experiment) with self.assertRaisesRegex(ValueError, 'cohort-mode blocks'): self.publish() def test_false_reference_exactness_is_not_hidden_by_pass_all(self): write(self.experiment / 'regression/frozen-five.json', dict(pass_all=True, trials=[dict(exact={'step': False})] * 5)) seal(self.experiment) with self.assertRaisesRegex(ValueError, 'five exact trial'): self.publish() self.assertFalse(self.registry.exists()) def test_unknown_or_unfinalized_status_is_not_promoted(self): for status in ('INCOMPLETE-NOT-SEALED', 'PASS-FROZEN-D18-INDEPENDENT-VALIDATION'): write(self.experiment / 'audit/final-status.json', dict(self.status, status=status)) seal(self.experiment) with self.assertRaisesRegex(ValueError, 'Unrecognized Phase 4AL'): self.publish() self.assertFalse(self.registry.exists()) def test_manifest_path_escape_rejected_before_destination(self): path = self.experiment / 'manifest.json' manifest = json.loads(path.read_text(encoding='utf-8')) manifest['files'][0]['path'] = '../escape.json' write(path, manifest) controls = self.experiment / 'checksums.sha256' controls.write_text('\n'.join([r['sha256'] + ' ' + r['path'] for r in manifest['files']] + [sha(path) + ' manifest.json']) + '\n', encoding='utf-8') with self.assertRaisesRegex(ValueError, 'escaping relative path'): self.publish() self.assertFalse(self.registry.exists()) def test_completed_status_without_frozen_reference_is_not_publishable(self): (self.experiment / 'regression/frozen-five.json').unlink() seal(self.experiment) with self.assertRaisesRegex(ValueError, 'frozen-reference report/presence'): self.publish() self.assertFalse(self.registry.exists()) def test_existing_registry_never_overwritten_or_resumed(self): self.registry.mkdir(parents=True) sentinel = self.registry / 'keep.txt' sentinel.write_bytes(b'keep these bytes') with self.assertRaisesRegex(ValueError, 'Registry already exists'): self.publish() self.assertEqual(sentinel.read_bytes(), b'keep these bytes') self.assertEqual(list(self.registry.iterdir()), [sentinel]) def test_missing_integrity_report_blocks_before_destination(self): (self.experiment / 'regression/old-integrity-after.json').unlink() seal(self.experiment) with self.assertRaisesRegex(ValueError, 'Required finalized evidence absent'): self.publish() self.assertFalse(self.registry.exists()) def test_bulk_corruption_blocks_even_though_bulk_is_not_copied(self): path = self.experiment / 'bulk.npy' path.write_bytes(b'x' * path.stat().st_size) with self.assertRaisesRegex(ValueError, 'Payload SHA-256 mismatch'): self.publish() self.assertFalse(self.registry.exists()) def test_unlisted_payload_and_bad_manifest_self_hash_fail(self): extra = self.experiment / 'unlisted.csv' extra.write_text('unlisted\n') with self.assertRaisesRegex(ValueError, 'unlisted/missing'): self.publish() extra.unlink() controls = self.experiment / 'checksums.sha256' lines = controls.read_text().splitlines() lines[-1] = '0' * 64 + ' manifest.json' controls.write_text('\n'.join(lines) + '\n') with self.assertRaisesRegex(ValueError, 'manifest self-checksum'): self.publish() self.assertFalse(self.registry.exists()) def test_large_json_verified_but_not_copied(self): path = self.experiment / 'large.json' path.write_bytes(b' ' * (publication.MAX_EVIDENCE_BYTES + 1)) seal(self.experiment) self.publish() self.assertFalse((self.registry / 'evidence/large.json').exists()) receipt = json.loads((self.registry / 'publication-receipt.json').read_text(encoding='utf-8')) self.assertEqual(next(r for r in receipt['experiment_payload_not_copied'] if r['path'] == 'large.json')['reason'], 'exceeds_4_MiB') def test_interrupted_copy_retained_and_cannot_resume(self): with mock.patch.object(publication, '_copy', side_effect=OSError('synthetic interrupted copy')): with self.assertRaisesRegex(OSError, 'synthetic interrupted copy'): self.publish() self.assertTrue((self.registry / 'publication-failure.json').is_file()) self.assertFalse((self.registry / 'publication-receipt.json').exists()) with self.assertRaisesRegex(ValueError, 'Registry already exists'): self.publish() def test_after_copy_full_verification_detects_bulk_change(self): original = publication._copy changed = False def copy_then_change(helper, source, destination, size, checksum): nonlocal changed original(helper, source, destination, size, checksum) if not changed: changed = True (self.experiment / 'bulk.npy').write_bytes(b'changed after initial seal check') with mock.patch.object(publication, '_copy', side_effect=copy_then_change): with self.assertRaises(ValueError): self.publish() self.assertTrue((self.registry / 'publication-failure.json').is_file()) self.assertFalse((self.registry / 'publication-receipt.json').exists()) def test_helper_pin_checked_without_modifying_old_globals_or_cache(self): helper = publication.load_helpers(HELPER) self.assertEqual(helper.MODEL_RELATIVE, Path('models/male-cns-lif/pn-recruitment-audit-v1')) self.assertEqual(helper.FINAL_STATUS, 'PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT') wrong = self.root / 'wrong-helper.py' wrong.write_bytes(b'raise RuntimeError("must never execute")\n') with self.assertRaisesRegex(ValueError, 'helper hash mismatch'): publication.publish(self.root, wrong) self.assertFalse(self.registry.exists()) if __name__ == '__main__': unittest.main()