scripts/evaluate_rgbd_stream_write.py
#!/usr/bin/env python3
"""Core B V1: evaluate the final write rule of every seed on DEV, all states sealed first."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import torch
from mcss.mechanism_pilot.geometry_carrier_experiment import read, verify_data, verify_lock
from mcss.mechanism_pilot.rgbd_stream_evaluation import evaluate_streams
from mcss.mechanism_pilot.rgbd_stream_write import (
CONTROLS,
POLICIES,
load_frozen_carrier,
load_write_rule,
)
from mcss.mechanism_pilot.small_training import sha, write_json
def evaluate(root, device):
root = Path(root).resolve()
manifest, config = verify_lock(root)
verify_data(root)
torch.set_num_threads(config["num_threads"])
carriers = read(root / "carrier_lock.json")["carriers"]
rows, summaries = [], []
for seed in config["seeds"]:
run = root / "checkpoints" / f"write_{seed}"
summary = read(run / "summary.json")
if summary["status"] != "COMPLETE" or summary["steps"] != config["steps"]:
raise PermissionError("Every seed must finish its frozen write-rule budget")
for name, key in (
("rule_step000000.pt", "initial_rule_sha256"),
("rule_final.pt", "final_rule_sha256"),
):
if sha(run / name) != summary[key]:
raise PermissionError(f"Write rule changed: {run / name}")
lock = carriers[str(seed)]
carrier, _ = load_frozen_carrier(lock["path"], device)
trained, payload = load_write_rule(run / "rule_final.pt", device)
untrained, _ = load_write_rule(run / "rule_step000000.pt", device)
if payload["lock_sha256"] != sha(root / "preregistration.json"):
raise PermissionError("Write rule not from the frozen training")
out = root / "raw" / "dev_stream" / f"seed_{seed}"
seed_rows = evaluate_streams(
carrier, {"trained": trained, "untrained": untrained}, manifest, root, out, seed, device
)
for row in seed_rows:
row["prediction_path"] = str((out / row["prediction_path"]).relative_to(root))
rows.extend(seed_rows)
summaries.append(summary)
streams = {s["data_stream_sha256"] for s in summaries}
names = (*POLICIES, *CONTROLS)
records = {r["scene_id"]: r for r in manifest["scenes"] if r["split"] == "DEV"}
expected = {
(seed, sid, role, qid, name)
for seed in config["seeds"]
for sid, record in records.items()
for role in ("A", "B")
for qid in record["roles"]["primary_query"]
for name in names
}
actual = {(r["seed"], r["scene_id"], r["role"], r["query_id"], r["policy"]) for r in rows}
if actual != expected or len(actual) != len(rows):
raise AssertionError("Incomplete Core B DEV matrix")
state_ok = all(
len(
{
r["used_state_hash"]
for r in rows
if (r["seed"], r["scene_id"], r["role"], r["policy"]) == key
}
)
== 1
for key in {(r["seed"], r["scene_id"], r["role"], r["policy"]) for r in rows}
)
write_json(root / "raw/dev_stream_query_results.json", rows)
write_json(
root / "audit/dev_state_use.json",
{
"status": "PASS" if state_ok else "FAIL",
"one_sealed_state_per_seed_scene_role_policy": state_ok,
"queries_per_state": 2,
"query_after_state_seal": True,
"distinct_seed_data_streams": len(streams),
},
)
write_json(
root / "training_curves.json",
{
str(seed): [
json.loads(line)
for line in (root / "checkpoints" / f"write_{seed}" / "training.jsonl")
.read_text()
.splitlines()
]
for seed in config["seeds"]
},
)
if not state_ok:
raise AssertionError("State reuse audit failed")
print("CORE_B_DEV_EVALUATION_PASS", len(rows), flush=True)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--root", required=True)
parser.add_argument("--device", default="cpu")
args = parser.parse_args()
evaluate(args.root, args.device)