3.7 KiB
| title | status | type | priority | created_at | updated_at |
|---|---|---|---|---|---|
| Scope nbd next and nbd ready by dependency subtree | completed | feature | normal | 2026-03-10T23:30:30Z | 2026-03-10T23:30:30Z |
Summary
Add an optional positional <id> 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
# 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:
id: Option<String>, // 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:
- Resolve the prefix to a full ID using
resolve_id. - Build a
TicketGraphfrom all tickets (the full list, not filtered). - 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). - Convert the subtree IDs into a
HashSet. - 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. Verifynbd next Preturns A (the highest-priority ready dep of P), not P itself or any unrelated ticket.test_ready_scoped_by_id: same setup; verifynbd ready Preturns [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; verifynbd next Preturns no ticket ({"next": null}in JSON mode).test_ready_scoped_with_filter: verify--filterstill narrows within the scoped set.
4. Relevant files
| File | Change |
|---|---|
src/main.rs:135-156 |
Commands::Ready and Commands::Next — add id: Option<String> |
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
cargo fmt && cargo check && cargo clippy && cargo test