volt: Q68 -- topo_levels materialises a one-shot edges iterable (generator/map/iter all returned every node in level 0 and a one-shot cycle was reported as ordered), and the suite resolves its sibling instead of the host copy
edges = list(edges) above validation. The redundant ready-queue pre-sort is deleted (level is re-sorted one line later; 3000 random DAGs, 0 level-set diffs with it removed). The flattened-invariant assert is a raise, so -O cannot strip it. test_topo_levels resolves topo_levels from Path(__file__).parent, raises ImportError if the import resolves elsewhere, and its 17 cells are TestCase methods so unittest discover collects them (module-level functions were invisible to the gate). test_rendezvous_hash no longer sys.exit()s at import; its trials are a TestCase.
Measured at be363f5+worktree: bash wizard-work/beam/CHECK rc 0, Ran 136 tests, ALL PASS (242 checks) -- at be363f5 the same gate is rc 1 with zero cells run (ImportError: test_topo_sort imported from /root/.hermes/wizard-outputs/beam). Mutant grading and control cells: wizard-work/volt/q68-2026-10-25.md.
This commit is contained in:
1 parent
be363f5d1c
commit
5a43291c28
3 files changed
+158
-58
No files matched your search
@@ -103,5 +103,16 @@ def gen():
|
||||
ok &= check("generator", rendezvous("key", gen()) in nodes)
|
||||
ok &= check("dedup", rendezvous("key", ["a","a","b"]) in ("a","b"))
|
||||
|
||||
print("ALL" if ok else "SOME FAILED")
|
||||
sys.exit(0 if ok else 1)
|
||||
import unittest
|
||||
|
||||
|
||||
class Trials(unittest.TestCase):
|
||||
def test_all_trials(self):
|
||||
# runs under `unittest discover`, where a module-level sys.exit() at
|
||||
# import time would turn the whole gate leg into an ImportError.
|
||||
self.assertTrue(ok, "rendezvous trials failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("ALL" if ok else "SOME FAILED")
|
||||
sys.exit(0 if ok else 1)
|
||||
@@ -1,63 +1,145 @@
|
||||
"""Cells for `topo_levels`, collectable by the lane's `CHECK`.
|
||||
|
||||
`python3 -m unittest discover -p 'test_*.py'` collects this file only because
|
||||
the cells are `unittest.TestCase` methods; the previous module-level functions
|
||||
were invisible to the gate (Q68's third fault, the `retry_jitter` shape).
|
||||
|
||||
The module under test is resolved from this file's directory and the import is
|
||||
verified to land on the sibling file: a copy under
|
||||
`/root/.hermes/wizard-outputs/beam` is never imported (Q62's host-pin class).
|
||||
The check is a `raise`, not an `assert`, so it keeps grading under `-O`.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, "/root/.hermes/wizard-outputs/beam")
|
||||
from topo_levels import topo_levels, flatten, CycleError
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
def test_basic():
|
||||
nodes = ["a","b","c","d"]
|
||||
edges = [("a","c"),("b","c"),("c","d")]
|
||||
levels = topo_levels(nodes, edges)
|
||||
assert levels == [["a","b"],["c"],["d"]], levels
|
||||
HERE = Path(__file__).resolve().parent
|
||||
if str(HERE) not in sys.path:
|
||||
sys.path.insert(0, str(HERE))
|
||||
|
||||
def test_disconnected():
|
||||
nodes = [1,2,3]
|
||||
assert topo_levels(nodes, []) == [[1,2,3]]
|
||||
import topo_levels # noqa: E402
|
||||
from topo_levels import CycleError, flatten # noqa: E402
|
||||
|
||||
def test_cycle():
|
||||
nodes = ["a","b","c"]
|
||||
edges = [("a","b"),("b","c"),("c","a")]
|
||||
try:
|
||||
topo_levels(nodes, edges)
|
||||
except CycleError as e:
|
||||
assert set(e.remaining) == {"a","b","c"}
|
||||
else:
|
||||
raise AssertionError("expected CycleError")
|
||||
EXPECTED_MODULE = HERE / "topo_levels.py"
|
||||
_RESOLVED = Path(topo_levels.__file__).resolve()
|
||||
if _RESOLVED != EXPECTED_MODULE:
|
||||
raise ImportError(
|
||||
f"topo_levels resolved to {str(_RESOLVED)!r}, expected {str(EXPECTED_MODULE)!r}"
|
||||
)
|
||||
|
||||
def test_unknown_node():
|
||||
try:
|
||||
topo_levels(["a"], [("a","z")])
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("expected KeyError")
|
||||
|
||||
def test_single_node_no_edges():
|
||||
assert topo_levels(["x"], []) == [["x"]]
|
||||
class TestTopoLevels(unittest.TestCase):
|
||||
# ---- the import itself is graded, not assumed -------------------------
|
||||
def test_import_is_sibling(self):
|
||||
self.assertEqual(Path(topo_levels.__file__).resolve(), EXPECTED_MODULE)
|
||||
|
||||
def test_diamond():
|
||||
nodes = ["a","b","c","d"]
|
||||
edges = [("a","b"),("a","c"),("b","d"),("c","d")]
|
||||
levels = topo_levels(nodes, edges)
|
||||
assert levels == [["a"],["b","c"],["d"]], levels
|
||||
# ---- level shape ------------------------------------------------------
|
||||
def test_basic(self):
|
||||
levels = topo_levels.topo_levels(
|
||||
["a", "b", "c", "d"], [("a", "c"), ("b", "c"), ("c", "d")]
|
||||
)
|
||||
self.assertEqual(levels, [["a", "b"], ["c"], ["d"]])
|
||||
|
||||
def test_determinism():
|
||||
nodes = list("zyxwv")
|
||||
edges = [("z","w"),("y","w")]
|
||||
r1 = topo_levels(nodes, edges)
|
||||
r2 = topo_levels(list(reversed(nodes)), edges)
|
||||
assert r1 == r2, (r1, r2)
|
||||
def test_disconnected(self):
|
||||
self.assertEqual(topo_levels.topo_levels([1, 2, 3], []), [[1, 2, 3]])
|
||||
|
||||
def test_single_node_no_edges(self):
|
||||
self.assertEqual(topo_levels.topo_levels(["x"], []), [["x"]])
|
||||
|
||||
def test_diamond(self):
|
||||
levels = topo_levels.topo_levels(
|
||||
["a", "b", "c", "d"], [("a", "b"), ("a", "c"), ("b", "d"), ("c", "d")]
|
||||
)
|
||||
self.assertEqual(levels, [["a"], ["b", "c"], ["d"]])
|
||||
|
||||
def test_determinism_under_input_permutation(self):
|
||||
nodes = list("zyxwv")
|
||||
edges = [("z", "w"), ("y", "w")]
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(nodes, edges),
|
||||
topo_levels.topo_levels(list(reversed(nodes)), edges),
|
||||
)
|
||||
|
||||
def test_level_interior_is_sorted_by_key(self):
|
||||
# adjacency arrival order ('c' before 'a') differs from sorted order;
|
||||
# a level emitted in arrival order ([['p'], ['c', 'a']]) must fail.
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(["p", "c", "a"], [("p", "c"), ("p", "a")]),
|
||||
[["p"], ["a", "c"]],
|
||||
)
|
||||
|
||||
def test_duplicate_nodes_deduped(self):
|
||||
# without dedupe this returns [['a', 'a', 'b']].
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(["a", "a", "b"], [("a", "b")]), [["a"], ["b"]]
|
||||
)
|
||||
|
||||
# ---- one-shot iterables (edges is annotated Iterable) ------------------
|
||||
def test_generator_edges_materialised(self):
|
||||
edges = [("a", "c"), ("b", "c")]
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(["a", "b", "c"], (e for e in edges)),
|
||||
[["a", "b"], ["c"]],
|
||||
)
|
||||
|
||||
def test_iter_edges_materialised(self):
|
||||
edges = [("a", "c"), ("b", "c")]
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(["a", "b", "c"], iter(edges)), [["a", "b"], ["c"]]
|
||||
)
|
||||
|
||||
def test_map_edges_materialised(self):
|
||||
edges = [("a", "c"), ("b", "c")]
|
||||
self.assertEqual(
|
||||
topo_levels.topo_levels(["a", "b", "c"], map(tuple, edges)),
|
||||
[["a", "b"], ["c"]],
|
||||
)
|
||||
|
||||
def test_generator_cycle_still_raises(self):
|
||||
cycle = [("a", "b"), ("b", "c"), ("c", "a")]
|
||||
with self.assertRaises(CycleError):
|
||||
topo_levels.topo_levels(["a", "b", "c"], (e for e in cycle))
|
||||
|
||||
# ---- cycles -----------------------------------------------------------
|
||||
def test_cycle_remaining_is_exact(self):
|
||||
# 'd' is acyclic: `remaining = list(node_set)` would add it here.
|
||||
with self.assertRaises(CycleError) as ctx:
|
||||
topo_levels.topo_levels(
|
||||
["a", "b", "c", "d"], [("a", "b"), ("b", "c"), ("c", "a")]
|
||||
)
|
||||
self.assertEqual(ctx.exception.remaining, ["a", "b", "c"])
|
||||
|
||||
# ---- unknown nodes: the message, not just the exception type -----------
|
||||
def test_unknown_prerequisite_message(self):
|
||||
with self.assertRaises(KeyError) as ctx:
|
||||
topo_levels.topo_levels(["a"], [("z", "a")])
|
||||
self.assertEqual(ctx.exception.args[0], "edge references unknown node: 'z'")
|
||||
|
||||
def test_unknown_dependent_message(self):
|
||||
with self.assertRaises(KeyError) as ctx:
|
||||
topo_levels.topo_levels(["a"], [("a", "z")])
|
||||
self.assertEqual(ctx.exception.args[0], "edge references unknown node: 'z'")
|
||||
|
||||
# ---- flatten ----------------------------------------------------------
|
||||
def test_flatten_roundtrip(self):
|
||||
nodes = ["a", "b", "c", "d", "e"]
|
||||
edges = [("a", "c"), ("b", "c"), ("c", "d"), ("c", "e")]
|
||||
levels = topo_levels.topo_levels(nodes, edges)
|
||||
flat = flatten(levels)
|
||||
self.assertEqual(sorted(flat), sorted(nodes))
|
||||
pos = {n: i for i, n in enumerate(flat)}
|
||||
for u, v in edges:
|
||||
self.assertLess(pos[u], pos[v])
|
||||
|
||||
def test_flatten_keeps_level_order(self):
|
||||
# reversing a level inside flatten gives ['b', 'a', 'c'].
|
||||
self.assertEqual(
|
||||
flatten(topo_levels.topo_levels(["a", "b"], [])),
|
||||
["a", "b"],
|
||||
)
|
||||
|
||||
def test_flatten_roundtrip():
|
||||
nodes = ["a","b","c","d","e"]
|
||||
edges = [("a","c"),("b","c"),("c","d"),("c","e")]
|
||||
levels = topo_levels(nodes, edges)
|
||||
flat = flatten(levels)
|
||||
assert sorted(flat) == sorted(nodes)
|
||||
# every edge prerequisite before dependent
|
||||
pos = {n:i for i,n in enumerate(flat)}
|
||||
for u,v in edges:
|
||||
assert pos[u] < pos[v]
|
||||
|
||||
if __name__ == "__main__":
|
||||
for name in [n for n in globals() if n.startswith("test_")]:
|
||||
globals()[name]()
|
||||
print("ALL TESTS PASSED")
|
||||
unittest.main(verbosity=2)
|
||||
@@ -29,6 +29,7 @@ def topo_levels(
|
||||
"""
|
||||
node_set = list(dict.fromkeys(nodes)) # preserve insertion order, dedupe
|
||||
index = {n: i for i, n in enumerate(node_set)}
|
||||
edges = list(edges) # materialise once: `edges` may be a one-shot iterable
|
||||
|
||||
# validate edges reference known nodes
|
||||
for a, b in edges:
|
||||
@@ -43,8 +44,9 @@ def topo_levels(
|
||||
adj[a].append(b)
|
||||
indeg[b] += 1
|
||||
|
||||
# deterministic: process ready queue sorted by key
|
||||
ready = sorted([n for n in node_set if indeg[n] == 0], key=_key)
|
||||
# deterministic: the only ordering point is `level` below; pre-sorting the
|
||||
# ready queue here would re-sort at the next line and change nothing.
|
||||
ready = [n for n in node_set if indeg[n] == 0]
|
||||
levels: List[List[Any]] = []
|
||||
processed = 0
|
||||
# Kahn in waves
|
||||
@@ -66,11 +68,16 @@ def topo_levels(
|
||||
remaining = [n for n in node_set if indeg[n] > 0]
|
||||
raise CycleError(sorted(remaining, key=_key))
|
||||
|
||||
# flatten check: every node appears exactly once
|
||||
# flatten check: every node appears exactly once (a raise, not an assert,
|
||||
# so the invariant is not stripped under -O)
|
||||
seen = []
|
||||
for lvl in levels:
|
||||
seen.extend(lvl)
|
||||
assert len(seen) == len(node_set) == len(set(seen)), "internal invariant violated"
|
||||
if not (len(seen) == len(node_set) == len(set(seen))):
|
||||
raise RuntimeError(
|
||||
f"internal invariant violated: {len(seen)} emitted, "
|
||||
f"{len(node_set)} unique nodes, {len(set(seen))} distinct"
|
||||
)
|
||||
return levels
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user