Files
2026-09-30 17:09:40 +08:00

196 lines
11 KiB
Python

"""Synthetic planning tests only; no input generation, files or brain runs."""
import copy
from collections import Counter
import unittest
from unittest.mock import patch
import evaluation_plan as m
import trial_plan
def synthetic_config(trial, reversal_points=(0, 50)):
"""An explicit TEST choice, not a proposed production default.
Controls here use a simple fixed epoch fraction; the planner never supplies
this policy. Only paired/reversal checkpoints track actual scheduled USs.
"""
config = dict(schema=m.CONFIG_SCHEMA, probe_steps=1200, cs_start_tick=0,
cs_stop_tick_exclusive=1000, reversal_checkpoints=list(reversal_points),
baseline_execution="execute_each_snapshot", snapshot_binding_policy="explicit_completed_epochs",
snapshot_bindings=[])
for block in trial["plan"]["blocks"]:
for suite in block["suites"]:
points = list(reversal_points) if suite["assay"] == "reversal" else block["evaluation_checkpoints"]
for arm in suite["arms"]:
for point in points:
if point in (0, 50):
completed = 0 if point == 0 else len(arm["epochs"])
elif arm["arm"] in ("paired", "reversal", "no_reversal"):
rewarded = [i + 1 for i, e in enumerate(arm["epochs"]) if e["us"]["requested"]]
completed = rewarded[point - 1]
else:
completed = point * len(arm["epochs"]) // 50
config["snapshot_bindings"].append(dict(block_id=block["block_id"], assay=suite["assay"],
arm=arm["arm"], checkpoint=point, completed_epochs=completed))
return config
class EvaluationPlan(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Existing synthetic master from the trial-plan tests, not a real choice.
cls.trial = trial_plan.build_trial_plan(461)
cls.config = synthetic_config(cls.trial)
cls.plan = m.build_evaluation_plan(cls.trial, cls.config)
def test_public_full_authority_reconstruction(self):
self.assertTrue(m.validate_evaluation_plan(self.plan, self.trial, self.config))
def test_exact_inventory_budget_and_no_execution_claim(self):
b = self.plan["budget"]
self.assertEqual(b["probes_by_assay"], dict(normal=3920, delayed=3920, reversal=320, retention=480))
self.assertEqual(b["evaluation_probes"], 8640)
self.assertEqual(b["snapshot_count"], 4320)
self.assertEqual(b["evaluation_steps"], 10368000)
self.assertEqual(b["planned_scientific_steps_including_evaluation"], 117968000)
self.assertEqual(b["independent_evaluation_inputs"], 80)
for name in ("execution_authorized", "training_executed", "inputs_generated", "candidate_generated",
"learning_pass_claimed", "scientific_gate_added", "external_source_and_snapshot_authority_verified"):
self.assertIs(self.plan[name], False)
def test_full_cells_and_all_control_coverage(self):
cells = {}
for p in self.plan["probes"]:
cells.setdefault((p["mode"], p["dan_type"], p["original_reinforced_cue"]), set()).add(p["training_replicate"])
self.assertEqual(p["odor"], trial_plan.ODORS[p["cue"]])
self.assertFalse(p["weight_updates_enabled"])
self.assertFalse(p["US_requested"])
self.assertFalse(p["feedback_to_training_or_idle"])
self.assertFalse(p["adds_training_replicate"])
self.assertEqual(len(cells), 8)
self.assertTrue(all(v == {1, 2, 3, 4, 5} for v in cells.values()))
first = self.trial["plan"]["blocks"][0]["block_id"]
normal = [p for p in self.plan["probes"] if p["block_id"] == first and p["assay"] == "normal"]
self.assertEqual(Counter(p["arm"] for p in normal), Counter({arm: 14 for arm in trial_plan.ARMS}))
def test_stream_keys_disjoint_and_reused_as_paired_probes(self):
non_eval = {r["seed"] for r in self.trial["seed_manifest"]["independent_streams"] if r["split"] != "evaluation"}
grouped = {}
for p in self.plan["probes"]:
grouped.setdefault((p["block_id"], p["cue"]), set()).add((p["input"]["seed"], p["input"]["stream_id"]))
self.assertEqual(p["input"]["semantic_key"], [p["block_id"], "evaluation", "CS", p["cue"], "00", "base-probe"])
self.assertEqual(p["input"]["seed_bits"], 63)
seeds = {next(iter(values))[0] for values in grouped.values()}
self.assertEqual(len(grouped), 80)
self.assertTrue(all(len(v) == 1 for v in grouped.values()))
self.assertEqual(len(seeds), 80)
self.assertFalse(seeds & non_eval)
self.assertTrue(any(seed > 2**32 for seed in seeds))
def test_reversal_original_baseline_and_orientation(self):
for s in self.plan["snapshots"]:
if s["assay"] == "reversal":
self.assertEqual(s["baseline_snapshot_id"], s["block_id"] + "/normal/paired/checkpoint-00")
if s["checkpoint"] == 0:
self.assertEqual(s["delta_source"], {"kind": "fork", "source": s["block_id"] + "/normal/paired/terminal-delta"})
self.assertEqual(s["neural_state_source"]["kind"], "common_frozen_reset")
def test_retention_same_idle_lineage_independent_forks(self):
grouped = {}
for s in self.plan["snapshots"]:
if s["assay"] != "retention":
continue
src = s["neural_state_source"]
grouped.setdefault((s["block_id"], s["arm"]), []).append(src)
self.assertFalse(src["reset_or_analytic_time_advance"])
self.assertFalse(s["snapshot_mutated_by_planning"])
self.assertEqual(s["baseline_snapshot_id"], s["block_id"] + "/normal/" + s["arm"] + "/checkpoint-00")
self.assertEqual(len(grouped), 80)
for rows in grouped.values():
self.assertEqual([r["elapsed_ticks"] for r in rows], [0, 10000, 100000])
self.assertEqual(len({r["idle_lineage_id"] for r in rows}), 1)
self.assertEqual(rows[0]["kind"], "actual_terminal_checkpoint")
self.assertEqual(rows[1]["kind"], "continuous_idle_checkpoint")
def test_missing_choices_no_hidden_default(self):
for key in m.CONFIG_FIELDS:
bad = copy.deepcopy(self.config)
del bad[key]
with self.subTest(key=key), self.assertRaisesRegex(ValueError, "missing="):
m.build_evaluation_plan(self.trial, bad)
self.assertIn("snapshot_bindings", m.required_choices())
def test_bad_configuration_types_and_unimplemented_reuse(self):
for key, value in (("probe_steps", 1200.0), ("cs_start_tick", False),
("cs_stop_tick_exclusive", True), ("cs_stop_tick_exclusive", 1201),
("reversal_checkpoints", [False, 50]), ("reversal_checkpoints", [50]),
("baseline_execution", "reuse_identical"), ("snapshot_binding_policy", "guess_from_paired")):
bad = copy.deepcopy(self.config)
bad[key] = value
with self.subTest(key=key, value=value), self.assertRaises(ValueError):
m._assemble(self.trial, bad)
def test_binding_coverage_order_types_and_pairing_boundary(self):
changes = (
lambda rows: rows.pop(), lambda rows: rows.reverse(),
lambda rows: rows[0].update(checkpoint=False),
lambda rows: rows[0].update(completed_epochs=False),
lambda rows: rows[1].update(completed_epochs=0),
lambda rows: rows[6].update(completed_epochs=99),
lambda rows: rows[1].update(completed_epochs=100),
lambda rows: rows[0].update(extra="unknown"),
)
for index, change in enumerate(changes):
bad = copy.deepcopy(self.config)
change(bad["snapshot_bindings"])
with self.subTest(index=index), self.assertRaises(ValueError):
m._assemble(self.trial, bad)
def test_explicit_alternative_curve_changes_budget_not_seed_inventory(self):
config = synthetic_config(self.trial, trial_plan.PROBE_CHECKPOINTS)
result = m._assemble(self.trial, config)
self.assertEqual(result["budget"]["evaluation_probes"], 9440)
self.assertEqual(result["budget"]["probes_by_assay"]["reversal"], 1120)
self.assertEqual(result["budget"]["independent_evaluation_inputs"], 80)
config["cs_stop_tick_exclusive"] = 1200
alternate = m._assemble(self.trial, config)
self.assertNotEqual(result["config_sha256"], alternate["config_sha256"])
self.assertTrue(all(p["cs_stop_tick_exclusive"] == 1200 for p in alternate["probes"]))
def test_payload_mutations_rejected_even_when_self_hash_updated(self):
changes = (
lambda p: p["probes"].pop(), lambda p: p["probes"].reverse(),
lambda p: p["probes"][0]["input"].update(seed=1),
lambda p: p["probes"][0].update(training_replicate=True),
lambda p: p["probes"][0].update(adds_training_replicate=True),
lambda p: p.update(execution_authorized=True),
)
# Full trial authority was validated in setUpClass and again above.
# Isolate evaluation reconstruction here, avoiding six repeated rebuilds
# of the large, unchanged 68k-epoch synthetic training schedule.
with patch.object(m.trial_plan, "validate_trial_plan", return_value=True):
for index, change in enumerate(changes):
bad = copy.deepcopy(self.plan)
change(bad)
bad["payload_sha256"] = m._sha({k: v for k, v in bad.items() if k != "payload_sha256"})
with self.subTest(index=index), self.assertRaises(ValueError):
m.validate_evaluation_plan(bad, self.trial, self.config)
def test_parent_authority_failure_propagates(self):
with patch.object(m.trial_plan, "validate_trial_plan", side_effect=ValueError("invalid full parent")):
with self.assertRaisesRegex(ValueError, "invalid full parent"):
m.build_evaluation_plan(self.trial, self.config)
def test_no_mutable_alias_to_caller(self):
result = m._assemble(self.trial, self.config)
result["config"]["snapshot_bindings"][0]["completed_epochs"] = 900
result["snapshots"][0]["delta_source"]["kind"] = "corruption"
result["probes"][0]["input"]["semantic_key"][0] = "corruption"
self.assertEqual(self.config["snapshot_bindings"][0]["completed_epochs"], 0)
self.assertEqual(self.trial["plan"]["blocks"][0]["suites"][0]["arms"][0]["delta_start"]["kind"], "zero")
self.assertEqual(m._assemble(self.trial, self.config), self.plan)
if __name__ == "__main__":
unittest.main()