4.5 KiB
deporder — deterministic build-order planner for task DAGs
Lane: Codeforge (hard coding / agentic reasoning). Author: null.
Location of record: /root/.hermes/wizard-outputs/null/deporder/.
What it is
A stdlib-only Python module + CLI that turns a task/dependency spec (JSON) into a build plan:
topological_order— serial order, lexicographically smallest ready task firstwaves— maximal parallelism batches (wave k = longest dependency chain has k edges)critical_path— weighted longest path (the makespan floor), with a unique, lexicographically canonical pathschedule— greedy list scheduling on N identical workers, with precedence and capacity guaranteesfind_cycle— reports one cycle as a real pathx -> y -> ... -> x
Every ordering decision is deterministic: ties break on lexicographically smallest name, so two runs over the same spec — and runs over specs whose keys were inserted in a different order — produce byte-identical output.
CLI
python3 deporder.py plan examples/pipeline.json [--workers N]
Exit codes: 0 ok · 2 dependency cycle · 3 unknown dependency · 4 malformed spec.
Success prints the plan as JSON on stdout; failures print one diagnostic line on
stderr and nothing on stdout.
Run the tests
python3 test_deporder.py # 42 tests, stdlib unittest, no pytest needed
python3 mutate_teeth.py # mutation harness: do the tests bite?
Evidence (measured on this box, Python 3.14.7)
| Claim | How measured | Result |
|---|---|---|
| 42 tests pass | python3 test_deporder.py |
Ran 42 tests in 1.902s — OK (exit 0) |
| Differential vs naive reference | 200 random DAGs × (order, waves, critical path) compared against O(V·E) fixpoint / O(V²) reference implementations inside the suite | all equal |
| Schedule invariants | 150 random DAGs × 1–4 workers: each task placed once, precedence end[d] ≤ start[n], ≤ N tasks in flight (event sweep), per-worker non-overlap, makespan ≥ critical path |
all hold |
| 1 worker == serial | makespan == Σest |
exact |
| ≥N workers == critical path | makespan == critical_path |
exact |
| Scale | 20 000 nodes / 39 987 edges: order + waves + critical path + 8-worker schedule | 0.92 s (budget in-suite: 10 s) |
| Determinism | shuffled spec key insertion order → identical json.dumps(sort_keys=True) |
identical |
| Tests have teeth | python3 mutate_teeth.py: 11 literal source mutations |
10/10 required mutants caught, 1 documented equivalent, harness exit 0 |
| CLI contract | exit 0 on examples/pipeline.json; exit 2 + dependency cycle: draft -> review -> publish -> draft; exit 3 + unknown dependencies: app -> missing_module |
as specified |
Bugs this suite actually caught while building it
All three were found by running things, not by reading the code:
- Scheduler stall (infinite loop). The clock-advance step took
min(free_time, completion_time)even when a worker was already free atnowwith nothing ready —nowstopped moving andschedule()never returned. Caught byPlanTestshanging. Fixed by advancing only to strictly-future events and raisingRuntimeErroron stall (unreachable for a DAG). - O(V²) critical path.
min(n for n in dist if dist[n] == max(dist.values()))recomputed the max inside the generator: a 20k-node plan took 15.98 s. Hoistingmax()gave 0.85 s (≈19× faster) with identical results. - Dead branch found by the mutation harness. The first version of the fix
above also consulted future worker-release times when choosing the next event.
The mutation that deleted that branch survived — it was unreachable, since
workers are only ever released by completions already drained at
now. The branch was removed rather than left as decoration.
Mutation harness (mutate_teeth.py)
Each mutation is a literal source edit applied to a copy of deporder.py in a
temp dir; the mutation is caught if the suite exits non-zero on the mutant.
Mutations tagged equivalent are expected to survive — they document a
genuinely redundant guard rather than a hole in the tests.
See the harness output in EVIDENCE.txt (verbatim run log).
Files
deporder.py implementation (module + CLI)
test_deporder.py 42-test stdlib suite (unit + differential + CLI + perf)
mutate_teeth.py mutation harness
examples/pipeline.json worked example (makespan 14.0 vs 18.0 serial, 3 workers)
EVIDENCE.txt verbatim transcripts of the runs quoted above