vscode: group backlog tree by area/* label (PIR #811)#886
Conversation
Architect ReviewMedium-risk PR. 580/29 across 9 files, but 3 are bookkeeping artifacts (plan/review/state) — real production change is ~234 LOC across Verified
Important design pivot worth calling outThe original issue body proposed a hardcoded rule: This aligns with the framework-neutrality discipline established by #819 (which also stripped a hardcoded "codev.backlog.priorityAreas": ["cross-cutting"]This is better than what the issue spec'd. It preserves user-configurability across the whole Implication for sibling PIR #818 (builders area grouping)
Recommend Option A — matches the existing per-view setting convention in this extension. I'll flag this at pir-818's plan-approval review. VerdictApproved. Per PIR protocol, the Architect review |
Architect Re-Review (iter-2)The revision did exactly what was requested. Verified:
The codex iter-2 REQUEST_CHANGES was on review-file documentation placeholders ( CMAP standing after iter-2 + placeholder fix:
Effective: 2 APPROVE on code, 1 documentation finding addressed. VerdictApproved. The simpler design is meaningfully better than the original — one fewer setting to learn/document/maintain, no migration concern if/when the surface needs to change, and the Per PIR protocol, the Architect review (iter-2) |
…habetical-only, single-Uncategorized flatten)
PIR Review: vscode — group backlog tree by area
Fixes #811
Summary
The vscode Backlog tree is now grouped by
area/*label. Group ordering is pure alphabetical specific areas followed byUncategorizedlast; a single-Uncategorizedgroup collapses to flat rendering so repos that haven't adoptedarea/*labels see no visual regression. No configurable mechanism — the framework stays policy-free about specific label names and about group rank (extending #819's discipline to the view layer).Files Changed
Computed via
git diff --stat origin/main...HEAD:codev/plans/811-vscode-group-backlog-by-area.md(+73 / -0)codev/projects/811-vscode-group-backlog-by-area-a/status.yaml(+29 / -0) — porch-managedcodev/reviews/811-vscode-group-backlog-by-area-a.md(+93 / -0) — this filecodev/state/pir-811_thread.md(+68 / -0)packages/vscode/src/extension.ts(+13 / -4) — wire workspaceState + expand/collapse listenerspackages/vscode/src/test/backlog.test.ts(+59 / -6) — 6 newgroupBacklogByAreatestspackages/vscode/src/views/backlog-tree-item.ts(+22 / -0) —BacklogGroupTreeItemclasspackages/vscode/src/views/backlog.ts(+154 / -19) — puregroupBacklogByAreahelper + two-levelBacklogProvider+ single-Uncategorized flatten optimizationTotal: 8 files, +511 / -29.
Commits
Test Results
pnpm --filter codev-vscode test: ✓ 90 pass (6 newgroupBacklogByAreacases + 84 pre-existing)pnpm build(full workspace): ✓ greenpnpm --filter codev-vscode check-types: ✓ greenpnpm --filter codev-vscode lint: ✓ green (ESLint via the test pretest pipeline)dev-approvalgate): the human inspected the running implementation in the worktree dev server and approved.Architecture Updates
No changes to
codev/resources/arch.md. This PR adds:groupBacklogByArea) over an existing wire shape (OverviewBacklogItem.area, added by core: parseAreaLabels helper + flow areas[] through BacklogItem and BuilderOverview #819) — no new module boundaries, no new wire fields, no new caching layers.TreeDataProviderfor the backlog view — a localized refactor ofBacklogProvider, not a new tree-architecture pattern.None warrant arch-doc entries — they reuse established patterns. The framework-neutrality discipline (do not bake repo-specific label names or per-repo rank policy into framework code) was already established in
codev/resources/arch.md/ lessons via #819 and remains the implicit rule this PR follows.Lessons Learned Updates
No additions to
codev/resources/lessons-learned.md. Two design moves worth recording are already covered by existing project memory:Framework code stays policy-free about label values and about per-repo rank policy. The first iteration hardcoded
'cross-cutting'as a privileged top group; the human atdev-approvalflagged it as the same anti-pattern core: parseAreaLabels helper + flow areas[] through BacklogItem and BuilderOverview #819 corrected at the parser. Switching to acodev.backlog.priorityAreassetting solved the hardcoded-label problem but introduced a new one: a configurable mechanism for what turned out to be the wrong shape (rank ≠ coordination). The architect's reconsideration during the review phase dropped the mechanism entirely. Net: alphabetical specifics +Uncategorizedlast is the simplest rule and matchesparseArea's policy-free posture. Same principle asfeedback_framework_neutral_on_label_semantics; no new lesson.Trust the wire contract; don't add defensive coercions for things the contract guarantees. First iteration had
item.area || UNCATEGORIZED_AREAas a defensive fallback even though the wire contract (required-with-default, set byparseAreaserver-side) guaranteesareais always a populated string. Dropped the fallback and the corresponding empty-string test case. System-prompt rule applied to the view boundary — not a new lesson.A follow-up issue was filed during this PIR:
vscode: capitalize area group header labels in backlog and builders trees. The lowercasearea/*label convention renders headers asvscode (12)next toUncategorized (8); visual inconsistency this PIR did not address (it would touch the rendering layer and the same fix should land in vscode: group builders in the tree by area (area/* label namespace, identical to backlog) #818's builders-tree grouping).Things to Look At During PR Review
Three design revisions before settling, visible in the commit history. First iteration hardcoded
'cross-cutting'as a privileged top group. Second iteration replaced that with a per-repo VSCode settingcodev.backlog.priorityAreas. Third iteration (this commit) dropped the configurable entirely per architect reconsideration — pure alphabetical, no priority mechanism, no setting. The final shape is the smallest possible: a render-layer grouping over an existing wire field, with one optimization (single-Uncategorized flatten) for the no-area-labels case.Single-Uncategorized flatten optimization (
packages/vscode/src/views/backlog.ts:120-125). When the grouped output is exactly one group AND that group isUncategorized, the view skips the header and returns rows directly. This is the zero-cost migration property the issue body promised. Trigger is specifically "1 group AND Uncategorized" — a single-vscoderepo with all items in one specific area still gets a header for clarity (the header carries the categorization signal; anUncategorizedheader carries none).Group identity (
BacklogGroupTreeItem.id = 'backlog-group:<areaName>'). VSCode reuses the same TreeItem instance acrossonDidChangeTreeDatarefreshes whenidmatches, which keeps the user's expand/collapse state visually stable across theOverviewCacheSSE tick. Without the stableid, every refresh would reset the visible expansion (the persisted state inworkspaceStatewould still be honored, but the tree would flash collapsed-then-expanded on each tick).pnpm --filter @cluesmith/codev testshowed 17 unrelated flakes on first run (cron-cli and other agent-farm tests) that all passed on retry. The diff is 100% underpackages/vscode/so the failures cannot be caused by this PIR. Mentioning for transparency, not as a flaky-test skip — no tests were quarantined.How to Test Locally
For reviewers pulling the branch:
pir-811→ Review Diff (auto-detects the repo's default branch). Orgit diff main...HEAD.afx dev pir-811from a shell.vscode (N),tower (N), etc., ordered alphabetically withUncategorizedlast.area/*labels lives underUncategorizedat the bottom.codev.viewBacklogIssue. Right-click → context menu actions (spawn, open in browser, copy issue number) still work.area/*labels at all, the view renders flat (noUncategorized (N)header) — single-Uncategorized flatten optimization.BacklogList(web): no wire changes, no breakage; still renders as a flat list.Flaky Tests
None skipped or quarantined.