+++ title = "Fix graph orientation: show goals at root, prerequisites as leaves" priority = 7 status = "done" ticket_type = "bug" dependencies = [] +++ ## Problem The dependency graph is inverted. Currently: - **Roots** = tickets with no dependencies (foundation/leaf-level work) - **Children** = dependents of the root (tickets blocked by it) This means the graph reads bottom-up: you see "what blocks what" rather than "what needs what". ## Desired behavior If ticket A depends on B, C, and D: - `nbd graph` should show A at the top with B, C, D indented as children (leaves) - Roots = tickets with **no dependents** (nobody depends on them — these are the top-level goals) - Children = the **dependencies** of the current node (prerequisites) This makes the graph read naturally: goals at the top, work to be done first at the bottom. ## Files to change ### `src/graph.rs` - `roots()`: change predicate from `node.dependencies.is_empty()` to `node.dependents.is_empty()` - `subtree()` + `dfs_subtree()`: currently traverses `dependents` edges; should traverse `dependencies` edges so subtree(A) returns A + what A depends on (recursively) - `to_json_value()` and `to_subtree_json_value()`: edge direction in JSON output should be `{"from": dependent_id, "to": dependency_id}` (A→B means A depends on B), or reconsider the `from`/`to` labels in light of the new orientation - Update all doc comments to reflect the new semantics ### `src/display.rs` - `render_node()`: iterate `node.dependencies` as children (not `node.dependents`) - Update doc comments for `format_graph()` and `format_subtree()` ### `src/graph.rs` module-level doc comment The edge semantics paragraph should be updated: "A is a dependency of B" means A appears as a child in the tree of B. ### Tests Update any graph-related tests in `src/tests.rs` and `tests/integration.rs` that assert the current (inverted) traversal order.