feat(work-items): container-scoped frontier and sub-item enumeration verb#709
Conversation
…verb The work-item-tracker seam reserves work-map containers as a first-class use case but had no read-side to operate one within scope (#498): the frontier was repo-global only, an unassigned/unblocked container surfaced as its own frontier item, and no verb enumerated a container's children. - Add list-sub-items <parent-id> [--state] — a new seam + adapter verb returning a container's direct children (both adapters). GitHub resolves via native subIssues intersected with list-items; local-markdown matches stored parent. - Add list-frontier --parent <container-id> — a container-scoped frontier. - Exclude container (work-map) items from every frontier unconditionally. Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 3m 26s —— View job PR Review: feat(work-items): container-scoped frontier and sub-item enumeration verb
Overall this is a high-quality, well-structured change. The design is clearly reasoned, the test coverage is broad (unit → end-to-end → conformance → e2e-probe), and the CONTRACT and CHANGELOG are kept in sync. A few findings below — one worth fixing before merge, the rest minor. Finding 1 —
|
The comment-hygiene lane flagged six comments citing the source issue by number. Reword each to state the container-frontier invariant it explains (a container never surfaces as its own frontier item) without the ticket citation — version control owns the history. Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 50s —— View job PR Re-review (after
|
… dropping it A container-scoped frontier (list-frontier --parent) is addressed by the container's qualified id, which already carries the repo, so --repo cannot re-target it. The scoped path never threaded list_args, so a caller passing both flags had --repo silently discarded with no error — a silently-wrong-output class defect. Reject the combination at parse time (exit 2, usage error) with a clear stderr message, matching the seam's fail-loud convention for invalid arg combinations. Document the incompatibility under list-frontier in CONTRACT.md and cover the guard with a test asserting the non-zero exit and message. Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 19s —— View job PR Re-review (after
|
|
Post-green review pass complete (rule 8). Bot review classification:
Fixed on-branch, no inline threads to resolve, CI fully green (18/18), 20/20 dispatcher tests passing including 2 new guard cases. Flipping to ready for review; handing off to the babysit lane for merge. |
|
Claude finished @kyle-sexton's task in 2m 21s —— View job Final review pass — PR #709
This is a complete, clean review pass over all 16 changed files. Three prior review cycles already identified and resolved the one actionable finding (silent Core dispatcher (
|
Summary
The work-item-tracker seam reserves
work-mapcontainers as a first-class use case, but its read side was repo-global only — there was no way to operate one container within scope (#498). Concretely:list-frontierhad no container scoping, its rows drop parent linkage (GitHub's list surface omits it), an unassigned/unblocked container surfaced as its own frontier item, and no verb enumerated a container's children (needed for a closed-children invariant check). Surfaced by the #416 wayfind-routing planning pass.Fix
list-sub-items <parent-id> [--state open|closed|all]— new seam + adapter verb. Returns a container's direct children as full normalized item objects (same{items:[…]}envelope aslist-items), each re-parented to the container. Raw enumeration — closed and nested-container children are kept (the closed-children invariant check and sub-map traversal need them).--statedefaults toall. Both adapters implement it: GitHub resolves children via the nativesubIssueslink and intersects withlist-itemsoutput (its list surface omits parent linkage, so the child set can't be derived from rows); the offlinelocal-markdownadapter matches on the storedparentfrontmatter.list-frontier --parent <container-id>— container-scoped frontier. Core readslist-sub-itemsfor that container instead of the repo-globallist-items, then applies the identical filter. The scoped verb is chosen before the capability gate, so an adapter withlist-itemsbut notlist-sub-itemsdegrades explicitly (exit 6) rather than passing the gate then failing mid-call.list-frontiernow excludes any item carrying the container label (work-map) unconditionally — global and--parent-scoped, and under--autonomous. Justification: the CONTRACT already states containers are never claimable by workers, so this is a correctness fix, not a policy toggle — deliberately not behind a flag.Design notes for the reviewer:
WIT_CONTAINER_LABEL, defaultwork-map) matching the CONTRACT term — not a new binding key. Per-repo remapping is deferred to the existingconfig.role_labelsconvention, keyed off the first consumer that needs a non-work-mapmarker.--parentscoping path, not by enriching globallist-itemsrows — GitHub's bulk list surface genuinely omitsparent, andget-itemremains authoritative for a single item's parentage (unchanged CONTRACT stance).list-sub-itemsstays a raw enumeration (nested sub-maps and closed children must survive it).Version
0.15.0→0.16.0(additive); CHANGELOG entry added.Verification
All commands run in the worktree on the rebased branch (tip of
origin/main+ this commit).New behavioral test —
local-markdown list-sub-itemsend-to-end through the core CLI (offline, CI-runnable):Core frontier filter unit test (container exclusion added):
Abstract conformance suite through the core CLI (exercises
list-sub-items+list-frontier --parentfor the adapter — CI runs this offline binding):Full
work-itemsplugin test suite + shellcheck (0.11.0, repo.shellcheckrc) over all changed/new shell files — both clean:The GitHub
subIssues+intersect path runs only under the on-demande2e-probe(needs a live sandbox repo), which was not executed here; itssubIssuesnode shape (id/number/title/url/state/repository.nameWithOwner— noassignees/labels/blockedBy, hence the intersect-with-list-itemsdesign) was verified against gh's own source (cli/cli api/queries_issue.go,LinkedIssuestruct). e2e-probe was extended with container-exclusion andlist-sub-items/--parentassertions for when it is next run against a sandbox.Closes #498
Related
planning:wayfindthrough the seam (the consumer that surfaced this gap); related but distinct, unblocked by this change.