116 lines
5.3 KiB
Python
116 lines
5.3 KiB
Python
"""New branch only. Old files are hash-anchored read-only inputs."""
|
|
import hashlib
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.dont_write_bytecode = True
|
|
ROOT = Path('/data/digital-drosophila')
|
|
MODEL = Path(__file__).resolve().parent
|
|
EXP = ROOT / 'experiments/phase4am-wholebrain-plastic-interface'
|
|
AK = ROOT / 'experiments/phase4ak-apl-timing-validation'
|
|
AL = ROOT / 'experiments/phase4al-mb-credit-transfer'
|
|
AL_MODEL = ROOT / 'models/male-cns-lif/mb-credit-transfer-audit-v1'
|
|
AJ_MODEL = ROOT / 'models/male-cns-lif/apl-timing-lab-v1'
|
|
AG = ROOT / 'experiments/phase4ag-author-apl-r2'
|
|
H = ROOT / 'experiments/phase4h-dopamine-plasticity'
|
|
META = ROOT / 'datasets/male-cns-v1.0/processed/neuron-only/neuron-index/unified-metadata.parquet'
|
|
CFG = json.loads((MODEL / 'config.json').read_text(encoding='utf-8'))
|
|
PINS = {
|
|
'models/male-cns-lif/mb-credit-transfer-audit-v1/context.py': '1626873baa224fab5d427a1fab1d6f840f14814152914ac4c2d6aa7a4f0bb1f6',
|
|
'models/male-cns-lif/mb-credit-transfer-audit-v1/manifest.json': '72e4b4e2c53c258939ca355f31eeba2cd6381e126a61efeea651d8bac8df5328',
|
|
'experiments/phase4al-mb-credit-transfer/manifest.json': 'a22de7d85cbfe760070ff55f5666e74475a3335c63bbd37b41241a94be7e3eea',
|
|
'experiments/phase4al-mb-credit-transfer/audit/final-status.json': 'ec846137531d3bea357f57364857b5de5ca2381a01aac3ebb1b7ade79059209e',
|
|
'models/male-cns-lif/apl-timing-lab-v1/gpu_timing.py': 'af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b',
|
|
'models/male-cns-lif/apl-timing-lab-v1/compare_timing.py': '9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734',
|
|
'models/male-cns-lif/phase4c.py': '5ec83a132deb8ba20e62dab485537c2414016fe2fece546198d61c0668d75b6b',
|
|
'models/male-cns-lif/mb-physiology-v1/phase4j.py': 'abb4574da85f00bd9ef61024c65993ef81d42651ff8d8d63c15dd69c6222471e',
|
|
'experiments/phase4h-dopamine-plasticity/plastic-mask/plastic-edge-candidates.parquet': 'e5075ee3e5a0edf3a4d197453847163cc295b254f21c67203159bba204b12a76',
|
|
'experiments/phase4h-dopamine-plasticity/plastic-mask/plastic-edge-ids.int64.npy': '8b0fb6eb2e6c31da4d17dc20d890aa3f367e514f05642de5bad6b42a1611c05b',
|
|
'experiments/phase4h-dopamine-plasticity/plastic-mask/plastic-edge-mask.bool.npy': 'e8b7a439f07eae6e36729d6577a2c5e4a4c7aa4b15e97fc5266d7278db9e150e',
|
|
'datasets/male-cns-v1.0/processed/neuron-only/neuron-index/unified-metadata.parquet': '922af16846a065c3dbfca7c11146b83ca217fcbd7392edc745f444a04eae8c63'
|
|
}
|
|
|
|
|
|
def digest(path):
|
|
h = hashlib.sha256()
|
|
with Path(path).open('rb') as f:
|
|
for block in iter(lambda: f.read(8 << 20), b''):
|
|
h.update(block)
|
|
return h.hexdigest()
|
|
|
|
|
|
def read(path):
|
|
return json.loads(Path(path).read_text(encoding='utf-8'))
|
|
|
|
|
|
def save(path, value):
|
|
path = Path(path); path.parent.mkdir(parents=True, exist_ok=True)
|
|
with path.open('x', encoding='utf-8') as f:
|
|
json.dump(value, f, indent=2, ensure_ascii=False, allow_nan=False)
|
|
f.write('\n')
|
|
|
|
|
|
def write_npz(path, **values):
|
|
import numpy as np
|
|
with Path(path).open('xb') as f:
|
|
np.savez_compressed(f, **values)
|
|
|
|
|
|
def load_module(name, path, expected_hash):
|
|
data = Path(path).read_bytes()
|
|
assert hashlib.sha256(data).hexdigest() == expected_hash, str(path)
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = module
|
|
exec(compile(data, str(path), 'exec'), module.__dict__)
|
|
return module
|
|
|
|
|
|
def sources():
|
|
return {p.relative_to(MODEL).as_posix(): digest(p) for p in sorted(MODEL.rglob('*'))
|
|
if p.is_file() and '__pycache__' not in p.parts and p.name not in ('manifest.json', 'checksums.sha256')}
|
|
|
|
|
|
def integrity():
|
|
old = load_module('sealed_al_context_am', AL_MODEL / 'context.py',
|
|
PINS['models/male-cns-lif/mb-credit-transfer-audit-v1/context.py'])
|
|
result = old.integrity()
|
|
sys.path.insert(0, str(ROOT / 'models/male-cns-lif/terminal-scope-diagnostic-v1'))
|
|
from diagnostic import manifest_check
|
|
for path in (AL_MODEL, AL):
|
|
result[path.relative_to(ROOT).as_posix()] = manifest_check(path, digest)
|
|
assert all(row['pass'] for row in result.values())
|
|
return result
|
|
|
|
|
|
def check(full=False):
|
|
reg = read(EXP / 'protocol/preregistered.json')
|
|
assert reg['sources'] == sources() and reg['config'] == CFG
|
|
for row in reg['inputs'] if full else []:
|
|
assert digest(ROOT / row['path']) == row['sha256'], row['path']
|
|
for row in read(EXP / 'protocol/prepared-hashes.json'):
|
|
assert digest(EXP / row['path']) == row['sha256'], row['path']
|
|
return reg
|
|
|
|
|
|
def bit_equal(a, b):
|
|
return a.dtype == b.dtype and a.shape == b.shape and a.tobytes() == b.tobytes()
|
|
|
|
|
|
def budget():
|
|
size = sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file())
|
|
assert size < CFG['output_budget_bytes'], 'Output budget exceeded; stop and preserve all partials'
|
|
return size
|
|
|
|
|
|
def seal(root):
|
|
rows = [dict(path=p.relative_to(root).as_posix(), bytes=p.stat().st_size, sha256=digest(p))
|
|
for p in sorted(root.rglob('*')) if p.is_file() and '__pycache__' not in p.parts]
|
|
save(root / 'manifest.json', dict(root=str(root), files=rows))
|
|
with (root / 'checksums.sha256').open('x', encoding='utf-8') as f:
|
|
for row in rows:
|
|
f.write(row['sha256'] + ' ' + row['path'] + '\n')
|
|
f.write(digest(root / 'manifest.json') + ' manifest.json\n')
|