diff --git a/nbd/.nbd/tickets/06ca62.md b/nbd/.nbd/tickets/06ca62.md new file mode 100644 index 0000000..abf52f0 --- /dev/null +++ b/nbd/.nbd/tickets/06ca62.md @@ -0,0 +1,57 @@ ++++ +title = "Fix nbd graph : show ancestry path through ticket, not just subtree" +priority = 6 +status = "todo" +ticket_type = "bug" +dependencies = ["668150"] ++++ +## Problem + +Currently `nbd graph ` renders the subtree **below** the given ticket via dependent edges (tickets blocked by it). After the graph orientation fix (see ticket 668150), `nbd graph ` will render the dependency subtree **below** the given ticket. + +But the desired behavior for `nbd graph B` (where A depends on B, C, and D) is more specific: + +> `nbd graph B` should graph up to the root level, down to B, and the rest of the way down from B, but not include siblings like C and D. + +## Desired behavior + +``` +A [todo] High-level goal +└── B [todo] Implement feature B + └── E [todo] Write unit tests for B +``` + +- A is shown because it depends on B (ancestor) +- C and D are NOT shown (they are sibling dependencies of A, not on the path to B) +- E is shown because B depends on E (B's own dependency subtree) + +## Algorithm + +1. **Ancestors of B**: traverse the `dependents` edges upward (who depends on B, and who depends on those, etc.) — collecting all ancestor tickets +2. **Filtered ancestor tree**: when rendering ancestors, only show the branch that leads toward B — i.e., at each ancestor, only the child that is on the path to B is shown (not siblings like C and D) +3. **B's dependency subtree**: show B and all its dependencies recursively (as per the corrected subtree logic from ticket 668150) + +## Implementation approach + +In `src/graph.rs`: +- Add `ancestors(target_id: &str) -> Vec<&str>`: collect all IDs that transitively depend on `target_id` (follow `dependents` edges upward) +- Add `ancestry_path_subtree(target_id: &str) -> ???`: returns the combined view — ancestor tree filtered to the path, plus target's dependency subtree + +In `src/display.rs`: +- New or updated `format_subtree()` to render the ancestry+subtree combined view +- The ancestry portion must filter children to only show the branch toward the target (not all dependents of each ancestor) + +In `src/main.rs`: +- Update `cmd_graph()` to use the new combined view when an ID is provided + +## Edge cases + +- If B has no dependents (it is itself a root), just show B's dependency subtree (no ancestor section) +- If B appears in multiple dependency chains, show all paths to it +- Cycle detection still applies (mark revisited nodes with `*`) + +## Tests + +Add integration tests in `tests/integration.rs`: +- Create tickets A, B, C, D, E with A depending on B/C/D, and B depending on E +- Assert `nbd graph B` output contains A and E but not C and D \ No newline at end of file diff --git a/nbd/.nbd/tickets/668150.md b/nbd/.nbd/tickets/668150.md new file mode 100644 index 0000000..902f33f --- /dev/null +++ b/nbd/.nbd/tickets/668150.md @@ -0,0 +1,45 @@ ++++ +title = "Fix graph orientation: show goals at root, prerequisites as leaves" +priority = 7 +status = "todo" +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. \ No newline at end of file