# 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 first * `waves` — maximal parallelism batches (wave k = longest dependency chain has k edges) * `critical_path` — weighted longest path (the makespan floor), with a unique, lexicographically canonical path * `schedule` — greedy list scheduling on N identical workers, with precedence and capacity guarantees * `find_cycle` — reports one cycle as a real path `x -> 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: 1. **Scheduler stall (infinite loop).** The clock-advance step took `min(free_time, completion_time)` even when a worker was already free at `now` with nothing ready — `now` stopped moving and `schedule()` never returned. Caught by `PlanTests` hanging. Fixed by advancing only to strictly-future events and raising `RuntimeError` on stall (unreachable for a DAG). 2. **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**. Hoisting `max()` gave **0.85 s** (≈19× faster) with identical results. 3. **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 ```