From 3c0665314aeb24119bc91ed3258bee355321d013 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Mon, 2 Mar 2026 10:43:14 -0800 Subject: [PATCH] =?UTF-8?q?tickets(nbd):=20triage=20TODO.md=20=E2=86=92=20?= =?UTF-8?q?818598=20scope=20next/ready=20by=20subtree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 818598: Scope nbd next and nbd ready by dependency subtree Co-Authored-By: Claude Sonnet 4.6 --- nbd/.nbd/tickets/818598.md | 102 +++++++++++++++++++++++++++++++++++++ nbd/TODO.md | 3 -- 2 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 nbd/.nbd/tickets/818598.md diff --git a/nbd/.nbd/tickets/818598.md b/nbd/.nbd/tickets/818598.md new file mode 100644 index 0000000..266fb3d --- /dev/null +++ b/nbd/.nbd/tickets/818598.md @@ -0,0 +1,102 @@ ++++ +title = "Scope nbd next and nbd ready by dependency subtree" +priority = 5 +status = "todo" +ticket_type = "feature" +dependencies = [] ++++ +## Summary + +Add an optional positional `` argument to `nbd next` and `nbd ready` that scopes +the results to the dependency subtree of the given ticket. + +## Motivation + +When a project has many tickets, you often want to focus on tickets that directly +unblock a specific goal ticket. Currently `nbd next` and `nbd ready` operate over +the entire ticket store, with no way to narrow by project/feature scope except +through `--filter` expressions that don't understand the dependency graph. + +## Desired behaviour + +```sh +# Highest-priority ready ticket that is a dependency of abc123 (directly or transitively) +nbd next abc123 +nbd next abc123 --json + +# All ready tickets that are dependencies of abc123 (directly or transitively) +nbd ready abc123 +nbd ready abc123 --json + +# Both commands still accept --filter alongside the scoping ID +nbd next abc123 --filter type=bug +nbd ready abc123 --filter priority=8 +``` + +The root ticket itself (abc123) is *not* included in the results — only its +dependencies (the tickets it is waiting on). + +## Implementation plan + +### 1. CLI changes (`src/main.rs`) + +In `Commands::Next` and `Commands::Ready`, add an optional positional argument: + +```rust +id: Option, // Optional ticket ID or prefix to scope results +``` + +Update `dispatch` to pass the new argument to `cmd_next` and `cmd_ready`. + +Update the CLI doc-comments for both subcommands to mention the scoping +behaviour. + +### 2. Logic changes (`src/main.rs`) + +In `cmd_next` and `cmd_ready`, after loading all tickets, if `scope_id` is +`Some`: + +1. Resolve the prefix to a full ID using `resolve_id`. +2. Build a `TicketGraph` from all tickets (the full list, not filtered). +3. Call `graph.subtree(&resolved_id)` to get the set of all dependency IDs + reachable from the root (this already excludes the root itself when it is + not in its own dependency list). +4. Convert the subtree IDs into a `HashSet`. +5. Restrict the ready/next candidate pool to tickets whose ID is in that set + *and* whose ID is not the scoping ticket itself (the root should never be + returned as a "what to do next" result when it is the scope target). + +`TicketGraph::subtree` is already implemented in `src/graph.rs` and handles +cycles correctly via a visited set. + +### 3. Test coverage (`tests/integration.rs`) + +Add integration tests (using `tempdir`): + +- **`test_next_scoped_by_id`**: create a project ticket P with deps [A, B], + where A has dep [C]. Mark C as done. Verify `nbd next P` returns A (the + highest-priority ready dep of P), not P itself or any unrelated ticket. +- **`test_ready_scoped_by_id`**: same setup; verify `nbd ready P` returns + [A] (B is blocked because... actually B has no deps so it's also ready). + Adjust setup so exactly the expected set is returned. +- **`test_next_scoped_no_ready`**: all deps of P are done; verify `nbd next P` + returns no ticket (`{"next": null}` in JSON mode). +- **`test_ready_scoped_with_filter`**: verify `--filter` still narrows within + the scoped set. + +### 4. Relevant files + +| File | Change | +|---|---| +| `src/main.rs:135-156` | `Commands::Ready` and `Commands::Next` — add `id: Option` | +| `src/main.rs:308-310` | `dispatch` arms for `Next` and `Ready` — pass new arg | +| `src/main.rs:473-511` | `cmd_ready` — add subtree scoping logic | +| `src/main.rs:522-566` | `cmd_next` — add subtree scoping logic | +| `src/graph.rs:165-172` | `TicketGraph::subtree` — already correct, no change needed | +| `tests/integration.rs` | Add 4 new scoped-by-id tests | + +### 5. Validation + +```sh +cargo fmt && cargo check && cargo clippy && cargo test +``` \ No newline at end of file diff --git a/nbd/TODO.md b/nbd/TODO.md index 5d7dd09..10bd3fb 100644 --- a/nbd/TODO.md +++ b/nbd/TODO.md @@ -1,5 +1,2 @@ # Work to be ticketed -should be able to pass a ticket ID to `nbd next` and `nbd ready` that scopes it to the dependency tree of that ticket. -For example `nbd next abc123` should show the highest priority (next) ticket that is a dependency of that project. -`nbd ready abc123` would show all tickets that are ready which unblock that project.