From 33babb123d3073e56f8597976a85f57d7c201ec7 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:46:12 +0700 Subject: [PATCH 1/7] chore(porch): bugfix-1170 init bugfix --- .../status.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml diff --git a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml new file mode 100644 index 000000000..beedc2f55 --- /dev/null +++ b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml @@ -0,0 +1,14 @@ +id: bugfix-1170 +title: vscode-agents-tree-group-heade +protocol: bugfix +phase: investigate +plan_phases: [] +current_plan_phase: null +gates: + pr: + status: pending +iteration: 1 +build_complete: false +history: [] +started_at: '2026-07-13T03:46:12.160Z' +updated_at: '2026-07-13T03:46:12.161Z' From 0c09f0a8a1c30c3f15086a457c81341f7819ce29 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:47:28 +0700 Subject: [PATCH 2/7] chore(porch): bugfix-1170 fix phase-transition --- .../bugfix-1170-vscode-agents-tree-group-heade/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml index beedc2f55..faefa3c0e 100644 --- a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml +++ b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml @@ -1,7 +1,7 @@ id: bugfix-1170 title: vscode-agents-tree-group-heade protocol: bugfix -phase: investigate +phase: fix plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-07-13T03:46:12.160Z' -updated_at: '2026-07-13T03:46:12.161Z' +updated_at: '2026-07-13T03:47:28.349Z' From 19724181f26cfa3dc82c41731e20882c563d0493 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:53:54 +0700 Subject: [PATCH 3/7] [Bugfix #1170] Fix: group-header contextValue no longer matches builder menu regexes Flip AreaGroupTreeItem contextValue from `${kind}-group` to `group-${kind}` so a builder group header is `group-builder` (was `builder-group`), which no longer matches the `/^(builder|blocked-builder|awaiting-builder)-/` when-clause regexes gating the seven builder-scoped Agents-tree context-menu entries. The menu no longer surfaces dead entries on group headers. [Bugfix #1170] Test: pin that group-header contextValue is rejected by the seven builder-scoped menu regexes, derived from the real AreaGroupTreeItem. --- codev/state/bugfix-1170_thread.md | 23 ++++ .../group-header-context-value.test.ts | 108 ++++++++++++++++++ .../vscode/src/views/area-group-tree-item.ts | 2 +- 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 codev/state/bugfix-1170_thread.md create mode 100644 packages/vscode/src/__tests__/group-header-context-value.test.ts diff --git a/codev/state/bugfix-1170_thread.md b/codev/state/bugfix-1170_thread.md new file mode 100644 index 000000000..31d524488 --- /dev/null +++ b/codev/state/bugfix-1170_thread.md @@ -0,0 +1,23 @@ +# bugfix-1170 — vscode Agents tree group-header contextValue collision + +## Investigate + +**Bug**: Right-clicking an Agents-tree group header (architect/phase/area axis) surfaces 7 +builder-scoped context-menu entries that no-op on a group header. + +**Root cause (confirmed)**: `packages/vscode/src/views/area-group-tree-item.ts:34` sets +`this.contextValue = `${kind}-group``. `BuilderGroupTreeItem` calls `super(groupName, 'builder', ...)` +(builder-tree-item.ts:54), so kind='builder' → contextValue `builder-group`. The 7 offending menu +entries in package.json (lines 537–587) gate on `/^(builder|blocked-builder|awaiting-builder)-/`, +which matches `builder-group`. The 3 protocol-scoped entries (viewSpec/Plan/ReviewFile) already +require a protocol suffix, so they're unaffected. + +**Fix**: line 34 → `this.contextValue = `group-${kind}``. Yields `group-builder` / `group-backlog`, +neither matches the offending regexes. No package.json change. `id` (line 33) stays `${kind}-group` +(unrelated — drives expansion persistence). + +**Tests**: grep found NO existing assertion on the literal `builder-group` string, so nothing to +update. The regression home is `packages/vscode/src/__tests__/menu-when-clauses.test.ts` — add a +block asserting the 7 builder-scoped regexes reject `group-builder` / `group-backlog`. + +Scope: 1-line src change + new regression test. Comfortably within BUGFIX. diff --git a/packages/vscode/src/__tests__/group-header-context-value.test.ts b/packages/vscode/src/__tests__/group-header-context-value.test.ts new file mode 100644 index 000000000..eeac6dd83 --- /dev/null +++ b/packages/vscode/src/__tests__/group-header-context-value.test.ts @@ -0,0 +1,108 @@ +/** + * Group-header rows must NOT surface builder-scoped context-menu entries (#1170). + * + * Agents-tree group headers (architect / phase / area axis, plus the Backlog + * view) are `AreaGroupTreeItem`s. Their `contextValue` is what VSCode matches + * the `view/item/context` menu `when` regexes against. The seven builder-scoped + * commands gate on the state-family prefix `/^(builder|blocked-builder| + * awaiting-builder)-/`. + * + * The bug: the header contextValue was built as `${kind}-group`, so a builder + * group header got `builder-group` — which matches `^builder-` and surfaced all + * seven entries. Each silently no-ops on a header (the handlers narrow via + * `instanceof BuilderTreeItem`), so the menu was pure noise. The fix flips the + * template to `group-${kind}` (`group-builder`), moving the family token off the + * front so none of the regexes match. + * + * This test derives the contextValue from the REAL `AreaGroupTreeItem` and feeds + * it to the actual package.json regexes. Reverting the source to `${kind}-group` + * makes the header value `builder-group` again, matches the regexes, and fails + * these assertions — which a hardcoded string wouldn't catch. + */ + +import { describe, it, expect, vi } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +vi.mock('vscode', () => { + class TreeItem { + id?: string; + contextValue?: string; + constructor(public label: string, public collapsibleState?: number) {} + } + return { + TreeItem, + TreeItemCollapsibleState: { None: 0, Collapsed: 1, Expanded: 2 }, + }; +}); + +// Import AFTER the mock is registered. +const vscode = await import('vscode'); +const { AreaGroupTreeItem } = await import('../views/area-group-tree-item.js'); + +const PKG = JSON.parse( + readFileSync(resolve(__dirname, '../../package.json'), 'utf8'), +); +const viewItemMenuEntries: Array<{ command: string; when: string }> = + PKG.contributes.menus['view/item/context']; + +/** + * The seven builder-scoped commands whose `when` gates on the state-family + * prefix regex. Two (run/stopWorktreeDev) append `&& codev.hasDevCommand`, so + * the regex isn't at the tail of the clause — extract it tolerantly. + */ +const BUILDER_SCOPED = [ + 'codev.openBuilderById', + 'codev.viewDiff', + 'codev.openWorktreeWindow', + 'codev.openWorktreeFolder', + 'codev.runWorktreeSetup', + 'codev.runWorktreeDev', + 'codev.stopWorktreeDev', +] as const; + +function viewItemRegex(command: string): RegExp { + const entry = viewItemMenuEntries.find( + e => e.command === command && e.when.includes('view == codev.agents')); + if (!entry) { + throw new Error(`No agents view/item/context entry for ${command}`); + } + const m = entry.when.match(/viewItem =~ \/(.+?)\/(?:\s|$)/); + if (!m) { + throw new Error(`No viewItem regex in when clause: ${entry.when}`); + } + return new RegExp(m[1]); +} + +/** contextValue of a group header for the given kind, from the real class. */ +function headerContextValue(kind: 'builder' | 'backlog'): string { + const header = new AreaGroupTreeItem( + 'area/tower', kind, 2, vscode.TreeItemCollapsibleState.Expanded); + return header.contextValue!; +} + +describe('group-header rows reject builder-scoped menu entries (#1170)', () => { + it('AreaGroupTreeItem puts the group token first (group-)', () => { + expect(headerContextValue('builder')).toBe('group-builder'); + expect(headerContextValue('backlog')).toBe('group-backlog'); + }); + + for (const command of BUILDER_SCOPED) { + const regex = viewItemRegex(command); + + it(`${command} is hidden for a builder group header`, () => { + expect(regex.test(headerContextValue('builder')), + `${command} menu for builder group header`).toBe(false); + }); + + it(`${command} is hidden for a backlog group header`, () => { + expect(regex.test(headerContextValue('backlog')), + `${command} menu for backlog group header`).toBe(false); + }); + + it(`${command} still shows for a builder row (guards against over-tightening)`, () => { + expect(regex.test('builder-bugfix'), + `${command} for builder-bugfix`).toBe(true); + }); + } +}); diff --git a/packages/vscode/src/views/area-group-tree-item.ts b/packages/vscode/src/views/area-group-tree-item.ts index bc643fda6..c6c656761 100644 --- a/packages/vscode/src/views/area-group-tree-item.ts +++ b/packages/vscode/src/views/area-group-tree-item.ts @@ -31,6 +31,6 @@ export class AreaGroupTreeItem extends vscode.TreeItem { ) { super(`${uppercaseAreaName(groupName)} (${count})`, collapsibleState); this.id = `${kind}-group:${groupName}`; - this.contextValue = `${kind}-group`; + this.contextValue = `group-${kind}`; } } From a601f36542529eb56b6c7c321b3c024e0adaa4e9 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:54:24 +0700 Subject: [PATCH 4/7] chore(porch): bugfix-1170 pr phase-transition --- .../bugfix-1170-vscode-agents-tree-group-heade/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml index faefa3c0e..3aed7d991 100644 --- a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml +++ b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml @@ -1,7 +1,7 @@ id: bugfix-1170 title: vscode-agents-tree-group-heade protocol: bugfix -phase: fix +phase: pr plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-07-13T03:46:12.160Z' -updated_at: '2026-07-13T03:47:28.349Z' +updated_at: '2026-07-13T03:54:24.485Z' From 7a4ab13ef77952f9ea8c54cfa6a10a2f7f3fdfa9 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:59:15 +0700 Subject: [PATCH 5/7] [Bugfix #1170] Thread: fix + PR + CMAP notes --- codev/state/bugfix-1170_thread.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/codev/state/bugfix-1170_thread.md b/codev/state/bugfix-1170_thread.md index 31d524488..3dde30cb7 100644 --- a/codev/state/bugfix-1170_thread.md +++ b/codev/state/bugfix-1170_thread.md @@ -21,3 +21,23 @@ update. The regression home is `packages/vscode/src/__tests__/menu-when-clauses. block asserting the 7 builder-scoped regexes reject `group-builder` / `group-backlog`. Scope: 1-line src change + new regression test. Comfortably within BUGFIX. + +## Fix + +- `area-group-tree-item.ts:34`: `${kind}-group` → `group-${kind}`. Build + tests green + (`porch check`: build 6.2s, tests 21s; 566 tests pass). +- Regression test `group-header-context-value.test.ts` derives contextValue from the real + `AreaGroupTreeItem` and feeds it to the actual package.json menu regexes. Verified it fails + without the fix (8 failures) and passes with it. +- Note: unit tests need `@cluesmith/codev-core` + `@cluesmith/codev-types` built first, else + suites fail at import resolution (pre-existing, unrelated). `porch check` runs the build. + +## PR + +- PR #1172 opened, `Fixes #1170`. +- CMAP (all three APPROVE, HIGH confidence, zero issues): gemini=APPROVE, codex=APPROVE + (couldn't re-run vitest in its sandbox, approved on inspection), claude=APPROVE. +- Consult snag: `consult --type pr` auto-detect failed from the worktree ("Multiple projects + found" — it scanned the full `codev/projects/`). Adding `--issue 1170` disambiguated. Worth + a look for other bugfix builders. +- Requested `pr` gate via `porch done`. Awaiting human approval to merge. From 82f58421c53d105b6fe7c779bf307f517f4da09a Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 10:59:15 +0700 Subject: [PATCH 6/7] chore(porch): bugfix-1170 pr gate-requested --- .../bugfix-1170-vscode-agents-tree-group-heade/status.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml index 3aed7d991..42a48f88d 100644 --- a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml +++ b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml @@ -7,8 +7,10 @@ current_plan_phase: null gates: pr: status: pending + requested_at: '2026-07-13T03:59:15.458Z' iteration: 1 build_complete: false history: [] started_at: '2026-07-13T03:46:12.160Z' -updated_at: '2026-07-13T03:54:24.485Z' +updated_at: '2026-07-13T03:59:15.459Z' +pr_ready_for_human: true From e629b029d216d6a7ef004b6f2f35f74b17900a00 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Mon, 13 Jul 2026 13:03:29 +0700 Subject: [PATCH 7/7] chore(porch): bugfix-1170 pr gate-approved --- .../bugfix-1170-vscode-agents-tree-group-heade/status.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml index 42a48f88d..3bbdb484e 100644 --- a/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml +++ b/codev/projects/bugfix-1170-vscode-agents-tree-group-heade/status.yaml @@ -6,11 +6,12 @@ plan_phases: [] current_plan_phase: null gates: pr: - status: pending + status: approved requested_at: '2026-07-13T03:59:15.458Z' + approved_at: '2026-07-13T06:03:29.092Z' iteration: 1 build_complete: false history: [] started_at: '2026-07-13T03:46:12.160Z' -updated_at: '2026-07-13T03:59:15.459Z' -pr_ready_for_human: true +updated_at: '2026-07-13T06:03:29.092Z' +pr_ready_for_human: false