import copy import hashlib import json import unittest from unittest.mock import patch import seed_registry as m class Seeds(unittest.TestCase): def test_order_independent(self): a, b = m.SeedRegistry(461), m.SeedRegistry(461) keys = [("mode", "PAM15", str(replicate), str(epoch)) for replicate in range(5) for epoch in range(50)] for key in keys: a.add("training", key) for key in reversed(keys): b.add("training", key) self.assertEqual(a.manifest(), b.manifest()) self.assertEqual(a.manifest()["independent_count"], 250) self.assertTrue(m.validate_manifest(a.manifest())) def test_splits_disjoint_and_no_sequential_overlap(self): r = m.SeedRegistry(461) for split in ("training", "evaluation", "design"): for replicate in range(5): for epoch in range(100): r.add(split, ("shared-name", str(replicate), str(epoch))) out = r.manifest() seeds = [x["seed"] for x in out["independent_streams"]] self.assertEqual(len(set(seeds)), 1500) self.assertEqual(out["training_evaluation_seed_overlap"], 0) self.assertTrue(all(0 <= s < 2**63 for s in seeds)) def test_alias_explicit_not_independent(self): r = m.SeedRegistry(461) seed = r.add("training", ("paired", "0")) self.assertEqual(seed, r.alias("training", ("frozen", "0"), "training", ("paired", "0"), reason="Same prescheduled CS inputs, different learning policy")) out = r.manifest() self.assertEqual(out["independent_count"], 1) self.assertEqual(out["alias_count"], 1) self.assertFalse(out["aliases_count_as_independent_replicates"]) self.assertTrue(m.validate_manifest(out)) def test_no_cross_split_alias(self): r = m.SeedRegistry(1) r.add("training", ("a",)) with self.assertRaisesRegex(ValueError, "Cross-split"): r.alias("evaluation", ("a",), "training", ("a",), reason="Not permitted") def test_no_alias_chain(self): r = m.SeedRegistry(1) r.add("training", ("a",)) r.alias("training", ("b",), "training", ("a",), reason="Control") with self.assertRaisesRegex(ValueError, "not another alias"): r.alias("training", ("c",), "training", ("b",), reason="Invalid chain") def test_no_silent_duplicate(self): r = m.SeedRegistry(1) r.add("training", ("a",)) with self.assertRaisesRegex(ValueError, "Duplicate"): r.add("training", ("a",)) with self.assertRaisesRegex(ValueError, "Duplicate"): r.alias("training", ("a",), "training", ("a",), reason="Invalid") r.alias("training", ("b",), "training", ("a",), reason="Control") with self.assertRaisesRegex(ValueError, "Duplicate"): r.add("training", ("b",)) def test_collision_fails_without_resampling(self): r = m.SeedRegistry(1) with patch.object(m, "seed_for", return_value=(123, "a" * 64)): r.add("training", ("a",)) with self.assertRaisesRegex(ValueError, "Seed collision"): r.add("evaluation", ("b",)) self.assertEqual(len(r._streams), 1) def test_mutations_detected(self): r = m.SeedRegistry(1) r.add("training", ("a",)) original = r.manifest() for mutate in (lambda x: x["independent_streams"][0].update(seed=7), lambda x: x.update(training_evaluation_seed_overlap=1), lambda x: x.update(independent_count=2), lambda x: x.update(payload_sha256="a" * 64), lambda x: x.update(training_executed=True)): corrupt = copy.deepcopy(original) mutate(corrupt) with self.assertRaises(ValueError): m.validate_manifest(corrupt) def test_manifest_copy_not_mutable_alias(self): r = m.SeedRegistry(1) r.add("training", ("a",)) out = r.manifest() out["independent_streams"][0]["key"][0] = "changed" self.assertEqual(r.manifest()["independent_streams"][0]["key"], ["a"]) self.assertTrue(m.validate_manifest(json.loads(json.dumps(r.manifest())))) def test_json_numeric_boolean_type_changes_rejected_even_when_rehashed(self): r = m.SeedRegistry(1) r.add("training", ("a",)) for field, replacement in (("training_executed", 0), ("independent_count", 1.0)): for rehash in (False, True): corrupt = r.manifest() corrupt[field] = replacement if rehash: payload = {key: value for key, value in corrupt.items() if key != "payload_sha256"} corrupt["payload_sha256"] = hashlib.sha256(m._canonical(payload).encode("utf-8")).hexdigest() with self.subTest(field=field, rehash=rehash), self.assertRaises(ValueError): m.validate_manifest(corrupt) def test_reject_invalid_values(self): for master in (True, -1, 2**63, 1.0, "1"): with self.assertRaises(ValueError): m.SeedRegistry(master) for key in ([], "a", [""], [" a"], ["a "]): with self.assertRaises(ValueError): m.seed_for(1, "training", key) with self.assertRaises(ValueError): m.seed_for(1, "unknown", ["a"]) if __name__ == "__main__": unittest.main()