You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Builders tree currently groups by area/* label (via #818, which mirrored the Backlog tree's grouping from #811). One mental model across both views was deliberate at the time. But the two views serve different triage modes:
Backlog = "what should I pick up next?" → optimising by domain (area) is right. You scan to the area you want to work on today, then pick from that list.
Builders = "what's blocking me right now? where do I need to act?" → optimising by domain misses the question. What you actually want is "show me the builders that need plan-approval", "show me the builders that need a PR merge", "show me the builders just sitting at implement". Those are phase-shaped questions, not area-shaped.
Phase is the action-driven axis for builders. The current area-grouping forces a reverse scan: open every area group, read each row's [<phase>] prefix, mentally collect the ones at a given phase. That's the opposite of how human triage actually works.
Recommended: explicit lifecycle ordering, lifecycle-first then any custom protocol phases appended after VERIFIED. Empty groups hide rather than show. Plan should pin the exact order and the empty-group policy.
2. Empty phase groups
If no builder is at SPECIFY, do we render the empty group header, hide it, or render it collapsed?
Render empty = always-visible structure, predictable; clutter when sparse.
Hide = clean look; user has to mentally model "which phases exist".
Render collapsed = compromise; still visible but doesn't take vertical space.
Recommended: hide entirely. Builder counts are typically <15; sparse groups are noise.
No prefix; row label stays #<id> <title> — area context only visible via tooltip
Recommended: [vscode] (lowercase, no area/ prefix). UPPERCASE was useful for group headers (matching VSCode's own panel-header convention) but on per-row prefixes it competes visually with the issue number and title for attention.
4. Active vs idle vs blocked distinction across phases
Pre-#810, blocked builders showed bell warning-yellow. Now they show gate-specific icons (book/checklist/play/git-pull-request/verified). The state-color still distinguishes: active = green circle-filled, idle = blue comment-discussion, blocked = warning-yellow per-gate icon.
Under phase-grouping, you'd typically have:
IMPLEMENT group: mostly green (active) + maybe blue (idle) rows
PLAN group: same (active during planning) — UNLESS the gate is pending in which case the icon would be checklist warning-yellow. But the builder is in the plan PHASE up until the gate is requested, so blocked-on-plan-approval is technically "still phase: plan" with b.blocked set.
This needs clarification:
Do blocked builders appear under their pre-block phase group (PLAN with a checklist icon)?
Or under a synthetic BLOCKED group?
Or split: rows blocked at gate Y appear in PHASE-WHERE-Y-FIRES (e.g., plan-approval → still PLAN group; dev-approval → still IMPLEMENT group)?
Recommended: blocked builders stay in their semantic phase group. PLAN group can contain green-active rows (working on plan) AND warning-yellow blocked-on-plan-approval rows. The icon tells you the state; the group tells you the phase. Don't introduce a synthetic BLOCKED group — it'd compete with the state-color signal already conveyed by icon color.
5. Cross-cutting issue rows
Backlog items with area/cross-cutting show under CROSS-CUTTING today. With phase-grouping, a builder on a cross-cutting issue gets prefixed [cross-cutting] — fine, but verbose. Worth considering [shared] or similar shorthand. Or accept the verbose form for clarity.
Recommended: keep [cross-cutting] verbatim. Shorthand invites confusion ("is [shared] the same as [cross-cutting]?").
6. Persistence of group collapse state
The existing AreaGroupExpansionStore persists area/* group expansion to workspace state. Under phase-grouping:
Keep the persistence shape but key by phase name? Different storage keys?
Reset to all-expanded since "Pull Requests" group state has no meaning anymore?
Recommended: introduce a parallel PhaseGroupExpansionStore keyed by phase name; old BuilderGroupExpansion (area-based) entries become stale and harmless. Issue #913 is also tracking ephemeral-vs-persistent group state for builders — coordinate this work with that.
Implementation surface
packages/vscode/src/views/builders.ts — grouping logic that currently calls groupByArea becomes groupByPhase (new helper or inline). Row label construction (makeBuilderRow / builder-row.ts) gets the prefix swapped from [<phase>] to [<area>].
A toggle between area-grouping and phase-grouping (could be a follow-up if the swap turns out to be controversial; this issue commits to the swap).
Why PIR
Two real design surface areas justify the plan-approval gate:
Phase ordering and empty-group policy — the recommendations above are reasonable defaults but worth pinning before code lands; a wrong call here is a re-do, not a tweak.
And the visual result needs running-app verification before PR — multiple builders across phases, scanning the new tree, confirming the phase-first triage actually feels better in practice. PR-diff-alone is insufficient.
Problem
The Builders tree currently groups by
area/*label (via #818, which mirrored the Backlog tree's grouping from #811). One mental model across both views was deliberate at the time. But the two views serve different triage modes:Phase is the action-driven axis for builders. The current area-grouping forces a reverse scan: open every area group, read each row's
[<phase>]prefix, mentally collect the ones at a given phase. That's the opposite of how human triage actually works.Proposed change — swap the axes
Group by phase. Move area into the row prefix.
Visual comparison
Today (area as group, phase as prefix):
Proposed (phase as group, area as prefix):
Now "all builders at PR-review" is one group expand; "what's in implement vs blocked at plan" is pre-attentive.
What stays the same
book/checklist/play/git-pull-request/verified), warning-yellow color uniform across blocked states, the active/idle/blocked tri-state colors.[new]prefix on freshly-created backlog rows (only applies to Backlog tree, no overlap with this issue).#<id> <title>core stays; only the prefix and the group axis change.area/*grouping (vscode: group backlog by area (area/* label namespace, predictable across views) #811, vscode: capitalize area group header labels in backlog and builders trees #885/vscode: UPPERCASE area group header labels in backlog and builders trees (supersedes #885's Capitalized form) #895 UPPERCASE headers): unchanged, since "by domain" is the right axis for Backlog.Design calls (locked at plan-approval)
These are real choices that benefit from a plan-phase gate rather than being decided ad-hoc during implementation:
1. Phase group order
Alphabetical (
IMPLEMENT, PLAN, PR, REVIEW, SPECIFY, VERIFIED) is nonsensical for builder triage. Phases have a natural lifecycle order:(Plus protocol-specific phases like AIR's two-phase shape, BUGFIX's
investigate/fix, MAINTAIN's distinct flow.)Recommended: explicit lifecycle ordering, lifecycle-first then any custom protocol phases appended after
VERIFIED. Empty groups hide rather than show. Plan should pin the exact order and the empty-group policy.2. Empty phase groups
If no builder is at
SPECIFY, do we render the empty group header, hide it, or render it collapsed?Recommended: hide entirely. Builder counts are typically <15; sparse groups are noise.
3. What does the
[<area>]prefix look like?Options:
[vscode]— direct label echo, lowercase[VSCODE]— matches the UPPERCASE convention from vscode: capitalize area group header labels in backlog and builders trees #885/vscode: UPPERCASE area group header labels in backlog and builders trees (supersedes #885's Capitalized form) #895[area/vscode]— verbose, redundant#<id> <title>— area context only visible via tooltipRecommended:
[vscode](lowercase, noarea/prefix). UPPERCASE was useful for group headers (matching VSCode's own panel-header convention) but on per-row prefixes it competes visually with the issue number and title for attention.4. Active vs idle vs blocked distinction across phases
Pre-#810, blocked builders showed
bellwarning-yellow. Now they show gate-specific icons (book/checklist/play/git-pull-request/verified). The state-color still distinguishes: active = greencircle-filled, idle = bluecomment-discussion, blocked = warning-yellow per-gate icon.Under phase-grouping, you'd typically have:
IMPLEMENTgroup: mostly green (active) + maybe blue (idle) rowsPLANgroup: same (active during planning) — UNLESS the gate is pending in which case the icon would bechecklistwarning-yellow. But the builder is in the plan PHASE up until the gate is requested, so blocked-on-plan-approval is technically "still phase: plan" withb.blockedset.This needs clarification:
BLOCKEDgroup?PHASE-WHERE-Y-FIRES(e.g., plan-approval → still PLAN group; dev-approval → still IMPLEMENT group)?Recommended: blocked builders stay in their semantic phase group. PLAN group can contain green-active rows (working on plan) AND warning-yellow blocked-on-plan-approval rows. The icon tells you the state; the group tells you the phase. Don't introduce a synthetic
BLOCKEDgroup — it'd compete with the state-color signal already conveyed by icon color.5. Cross-cutting issue rows
Backlog items with
area/cross-cuttingshow underCROSS-CUTTINGtoday. With phase-grouping, a builder on a cross-cutting issue gets prefixed[cross-cutting]— fine, but verbose. Worth considering[shared]or similar shorthand. Or accept the verbose form for clarity.Recommended: keep
[cross-cutting]verbatim. Shorthand invites confusion ("is[shared]the same as[cross-cutting]?").6. Persistence of group collapse state
The existing
AreaGroupExpansionStorepersistsarea/*group expansion to workspace state. Under phase-grouping:Recommended: introduce a parallel
PhaseGroupExpansionStorekeyed by phase name; oldBuilderGroupExpansion(area-based) entries become stale and harmless. Issue #913 is also tracking ephemeral-vs-persistent group state for builders — coordinate this work with that.Implementation surface
packages/vscode/src/views/builders.ts— grouping logic that currently callsgroupByAreabecomesgroupByPhase(new helper or inline). Row label construction (makeBuilderRow/builder-row.ts) gets the prefix swapped from[<phase>]to[<area>].packages/vscode/src/views/builder-row.ts(thebuilderRowLabelhelper from vscode: builder row legibility — phase prefix + gate-specific icons for at-a-glance protocol/state visibility #810) — thephasePrefixbecomesareaPrefix; phase is implicit from the group containment.BuilderGroupTreeItemshape stays the same; just receives a phase name instead of an area name.backlog.ts,groupByArea) — unchanged.Acceptance
phase, not theirarea/*label.SPECIFY → PLAN → IMPLEMENT → REVIEW → PR → VERIFIED; protocol-specific phases (e.g.INVESTIGATE,FIX) appended afterVERIFIED.[<area>] #<id> <title>instead of#<id> [<phase>] <title>.area/*grouping is unaffected.<count>inIMPLEMENT (3)reflects actual children).Out of scope
[new]prefix on freshly-created backlog rows from vscode: mark recently-created backlog rows (created within last 24h) #930 — no overlap (Backlog-only).Why PIR
Two real design surface areas justify the plan-approval gate:
And the visual result needs running-app verification before PR — multiple builders across phases, scanning the new tree, confirming the phase-first triage actually feels better in practice. PR-diff-alone is insufficient.
Related
[new]prefix on Backlog rows — no overlap, just adjacent.