1"""Freeze the confirmatory design: record SHA-256 of every confirmatory bundle, oracle, arm text, gate program, config,2preregistration and analysis interface into protocol/freeze_manifest.json and stamp tasks/registry.csv (frozen_utc)."""3import csv, glob, hashlib, json, os, sys, datetime4REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))5def sha(p): return hashlib.sha256(open(p, "rb").read()).hexdigest()6def main(split="conf"):7 now = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds")8 man = {"frozen_utc": now, "split": split, "bundles": {}, "oracles": {}, "protocol": {}, "configs": {}, "analysis": {}}9 rows = list(csv.DictReader(open(os.path.join(REPO, "tasks", "registry.csv"))))10 for r in rows:11 if r["split"] != split: continue12 t = r["task_id"]; b = os.path.join(REPO, "tasks", "public_bundles", t)13 man["bundles"][t] = {"bundle_json": sha(os.path.join(b, "bundle.json")), "TASK_md": sha(os.path.join(b, "TASK.md")), "gate_spec": sha(os.path.join(b, "gate_spec.json"))}14 o = os.path.expanduser(f"~/wp29-oracles/{t}")15 man["oracles"][t] = {"oracle_json": sha(os.path.join(o, "oracle.json")), "evaluate_py": sha(os.path.join(o, "evaluate.py"))}16 r["frozen_utc"] = now17 for f in sorted(glob.glob(os.path.join(REPO, "protocol", "arms", "*.md"))) + [os.path.join(REPO, "protocol", "preregistration.md"), os.path.join(REPO, "src", "pgar", "runtime_gates.py"), os.path.join(REPO, "src", "pgar", "launcher.py"), os.path.join(REPO, "src", "pgar", "scheduler.py"), os.path.join(REPO, "src", "pgar", "evaluation.py")]:18 man["protocol"][os.path.relpath(f, REPO)] = sha(f)19 for f in sorted(glob.glob(os.path.join(REPO, "configs", "*.yaml"))): man["configs"][os.path.relpath(f, REPO)] = sha(f)20 for f in sorted(glob.glob(os.path.join(REPO, "analysis", "*.py"))): man["analysis"][os.path.relpath(f, REPO)] = sha(f)21 import subprocess22 man["code_commit"] = subprocess.run(["git", "-C", REPO, "rev-parse", "HEAD"], capture_output=True, text=True).stdout.strip()23 out = os.path.join(REPO, "protocol", f"freeze_manifest_{split}.json"); json.dump(man, open(out, "w"), indent=1)24 with open(os.path.join(REPO, "tasks", "registry.csv"), "w", newline="") as fh:25 w = csv.DictWriter(fh, fieldnames=list(rows[0].keys())); w.writeheader(); w.writerows(rows)26 print(f"froze {len(man['bundles'])} {split} tasks at {now} -> {out}")27if __name__ == "__main__":28 main(sys.argv[1] if len(sys.argv) > 1 else "conf")29