Work plan: batch a dependency graph
work_planTurn a dependency graph into parallelizable task batches, respecting dependencies, priority, and optional write-path conflicts while validating malformed graphs, missing dependencies, and cycles.
Instructions
Work plan: turn a dependency graph you hand it into the batches that may run in parallel — pure computation over nodes: no file opened, no path taken, nothing mutated. Use it when the graph is in your hands (tasks with depends_on); use shiftwork_plan when the graph is a shift-work checkpoint on disk, which it reads for you under the same batching rules. Batch k holds every node whose dependencies all sit in batches below k; sequence is the batches flattened; width is the largest batch — the fan-out an orchestrator must afford. Inside a batch: priority descending, then the order the nodes were given; both halves are contract, so two implementations answer byte-identically. Empty nodes is an ANSWER (no batches, width 0), not a refusal. Four refusals, in this order, one sentence each: nodes[<i>].<field> must be ... (an id that is not a string, depends_on not a list of strings, priority not an integer — named by position, never coerced), duplicate node id <id>, node <id> depends on <dep>, which no node declares, and the graph has a cycle: <a> -> <b> -> <a>. depends_on encodes logical order, not file contention; give a node touches (repo-relative paths it will WRITE) and no batch ever holds two nodes sharing a path: inside a level, in the same order, a node whose path an admitted node already claims is held for the next batch, and the answer then carries held: [{id, batch, by, path}] (absent when no node declares touches). A path that is empty, absolute, holds a backslash or a ./../empty segment is the fifth refusal, checked with the shape: node <id> touches <json>, which is not a plain relative path.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| nodes | Yes | The graph: one object per task, {id, depends_on?, priority?, touches?}. The order given is the tie-break inside a batch after priority. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| held | No | Present only when a node declares `touches`: one {id, batch, by, path} per hold, the node held out of batch `batch` because `by`, admitted there, already writes `path`. | |
| width | No | The largest batch length: the widest fan-out. | |
| reason | No | With result `error`: one sentence saying why the call was refused. | |
| result | Yes | `plan` on success; `error` with `reason` for one of the four refusals. | |
| batches | No | Node ids by wave: batch k holds every node whose dependencies all sit in batches below k. | |
| sequence | No | The batches flattened in order. |