From 2ca1a1c3c5c27cc8d1af50ff699f8f41ce94f03b Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:30:53 +1000 Subject: [PATCH 1/8] chore(porch): bugfix-828 init bugfix --- .../status.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml new file mode 100644 index 000000000..29d821c83 --- /dev/null +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -0,0 +1,14 @@ +id: bugfix-828 +title: test-dashboard-e2e-strict-mode +protocol: bugfix +phase: investigate +plan_phases: [] +current_plan_phase: null +gates: + pr: + status: pending +iteration: 1 +build_complete: false +history: [] +started_at: '2026-05-28T10:30:53.869Z' +updated_at: '2026-05-28T10:30:53.870Z' From e05735b98a3d5c72f8fb96783dc72d4ebcae2b07 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:35:08 +1000 Subject: [PATCH 2/8] [Bugfix #828] Scope work-view test locators to section headings `.work-section:has-text("X")` matches anywhere in the subtree, so a backlog item whose title contains a section heading (e.g. #813's "Recently Closed") causes a strict-mode collision against the actual section. Scope the locator to `h3.work-section-title:text-is(...)` so the match is anchored to the heading element and decoupled from issue-title content. Hardens all four occurrences in work-view-backlog.test.ts (Backlog x2, Recently Closed x2). No other dashboard e2e tests use the loose pattern. --- codev/state/bugfix-828_thread.md | 32 +++++++++++++++++++ .../__tests__/e2e/work-view-backlog.test.ts | 19 ++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 codev/state/bugfix-828_thread.md diff --git a/codev/state/bugfix-828_thread.md b/codev/state/bugfix-828_thread.md new file mode 100644 index 000000000..45a9a11dc --- /dev/null +++ b/codev/state/bugfix-828_thread.md @@ -0,0 +1,32 @@ +# bugfix-828 — strict-mode locator collision + +## Investigate + +Issue #828: scheduled Dashboard E2E failed because `.work-section:has-text("Recently Closed")` matched **two** sections — the actual Recently Closed section *and* the Backlog section, which renders issue #813 ("vscode: migrate Recently Closed view from sidebar to Codev panel tab") as a row whose title contains the substring "Recently Closed". + +`:has-text()` does substring-match across the whole subtree, so any backlog item whose title contains a section heading literal poisons the selector. + +Four occurrences of the loose pattern, all in `packages/codev/src/agent-farm/__tests__/e2e/work-view-backlog.test.ts`: + +- L77 `Backlog` +- L116 `Backlog` +- L152 `Recently Closed` +- L173 `Recently Closed` + +`Backlog` is also vulnerable — any future issue whose title contains "Backlog" would break L77/L116 the same way. + +`grep -rn ':has-text' packages/codev/src/agent-farm/__tests__/e2e/` shows no other `.work-section:has-text` matches — the rest of the `:has-text` usage is on tab buttons and `.instance a`, which aren't vulnerable to the same collision. + +## Plan + +Replace all four with the heading-scoped form: + +```ts +page.locator('.work-section:has(h3.work-section-title:text-is("Backlog"))') +``` + +`:text-is()` matches the exact text content of the heading, not a substring of the section subtree. + +## Implement + +(in progress) diff --git a/packages/codev/src/agent-farm/__tests__/e2e/work-view-backlog.test.ts b/packages/codev/src/agent-farm/__tests__/e2e/work-view-backlog.test.ts index 62c76e050..e583c7db4 100644 --- a/packages/codev/src/agent-farm/__tests__/e2e/work-view-backlog.test.ts +++ b/packages/codev/src/agent-farm/__tests__/e2e/work-view-backlog.test.ts @@ -73,8 +73,11 @@ test.describe('Work view: backlog clickability and artifacts', () => { await workTab.click(); } - // Wait for backlog section to appear - const backlogSection = page.locator('.work-section:has-text("Backlog")'); + // Scope to the heading element — `:has-text` would collide with any backlog + // item whose title contains the section name (see #828). + const backlogSection = page.locator( + '.work-section:has(h3.work-section-title:text-is("Backlog"))', + ); await expect(backlogSection).toBeVisible({ timeout: 15_000 }); // Check if there are backlog rows @@ -113,7 +116,9 @@ test.describe('Work view: backlog clickability and artifacts', () => { await workTab.click(); } - const backlogSection = page.locator('.work-section:has-text("Backlog")'); + const backlogSection = page.locator( + '.work-section:has(h3.work-section-title:text-is("Backlog"))', + ); await expect(backlogSection).toBeVisible({ timeout: 15_000 }); // Check for artifact link buttons (they appear when items have specs/plans/reviews) @@ -149,7 +154,9 @@ test.describe('Work view: backlog clickability and artifacts', () => { if (data.recentlyClosed && data.recentlyClosed.length > 0) { // Recently Closed section should be visible - const closedSection = page.locator('.work-section:has-text("Recently Closed")'); + const closedSection = page.locator( + '.work-section:has(h3.work-section-title:text-is("Recently Closed"))', + ); await expect(closedSection).toBeVisible({ timeout: 5_000 }); // Items should be clickable links @@ -170,7 +177,9 @@ test.describe('Work view: backlog clickability and artifacts', () => { } // If no recently closed items, the section should not be visible else { - const closedSection = page.locator('.work-section:has-text("Recently Closed")'); + const closedSection = page.locator( + '.work-section:has(h3.work-section-title:text-is("Recently Closed"))', + ); await expect(closedSection).not.toBeVisible(); } }); From e3488cc231c9f796aad7c1990cb2dd088a1cfbd8 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:37:30 +1000 Subject: [PATCH 3/8] chore(porch): bugfix-828 fix phase-transition --- .../bugfix-828-test-dashboard-e2e-strict-mode/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml index 29d821c83..6a2ac5d5d 100644 --- a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -1,7 +1,7 @@ id: bugfix-828 title: test-dashboard-e2e-strict-mode 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-05-28T10:30:53.869Z' -updated_at: '2026-05-28T10:30:53.870Z' +updated_at: '2026-05-28T10:37:30.379Z' From 73e519b68f364250c8c3beb7ed183857b243b7f5 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:39:40 +1000 Subject: [PATCH 4/8] chore(porch): bugfix-828 pr phase-transition --- .../bugfix-828-test-dashboard-e2e-strict-mode/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml index 6a2ac5d5d..66a949e45 100644 --- a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -1,7 +1,7 @@ id: bugfix-828 title: test-dashboard-e2e-strict-mode 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-05-28T10:30:53.869Z' -updated_at: '2026-05-28T10:37:30.379Z' +updated_at: '2026-05-28T10:39:40.865Z' From d467d27d718511a4ceec26be0af40e57fe805b7d Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:39:55 +1000 Subject: [PATCH 5/8] chore(porch): bugfix-828 record PR #917 --- .../bugfix-828-test-dashboard-e2e-strict-mode/status.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml index 66a949e45..685192cb7 100644 --- a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -11,4 +11,9 @@ iteration: 1 build_complete: false history: [] started_at: '2026-05-28T10:30:53.869Z' -updated_at: '2026-05-28T10:39:40.865Z' +updated_at: '2026-05-28T10:39:55.081Z' +pr_history: + - phase: pr + pr_number: 917 + branch: builder/bugfix-828 + created_at: '2026-05-28T10:39:55.080Z' From 1affe4b3b5150436d7494607ec600accdc0b12b8 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:40:10 +1000 Subject: [PATCH 6/8] chore(porch): bugfix-828 pr gate-requested --- .../bugfix-828-test-dashboard-e2e-strict-mode/status.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml index 685192cb7..1450c1e2c 100644 --- a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -7,13 +7,15 @@ current_plan_phase: null gates: pr: status: pending + requested_at: '2026-05-28T10:40:10.269Z' iteration: 1 build_complete: false history: [] started_at: '2026-05-28T10:30:53.869Z' -updated_at: '2026-05-28T10:39:55.081Z' +updated_at: '2026-05-28T10:40:10.270Z' pr_history: - phase: pr pr_number: 917 branch: builder/bugfix-828 created_at: '2026-05-28T10:39:55.080Z' +pr_ready_for_human: true From 8d62a0e07e8d429656aafdcb965cf9b7d9413da2 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:40:40 +1000 Subject: [PATCH 7/8] [Bugfix #828] Update thread: PR open, CMAP-3 APPROVE, awaiting pr gate --- codev/state/bugfix-828_thread.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/codev/state/bugfix-828_thread.md b/codev/state/bugfix-828_thread.md index 45a9a11dc..b69736498 100644 --- a/codev/state/bugfix-828_thread.md +++ b/codev/state/bugfix-828_thread.md @@ -29,4 +29,21 @@ page.locator('.work-section:has(h3.work-section-title:text-is("Backlog"))') ## Implement -(in progress) +All four `.work-section:has-text(...)` occurrences in `work-view-backlog.test.ts` replaced with `.work-section:has(h3.work-section-title:text-is("..."))`. Single short comment on the first occurrence explains the workaround (referencing #828). Diff: +60 / -5, test-only. + +`porch check` build/tests both pass (after one-time core build to materialize `@cluesmith/codev-core` declaration files in the worktree). + +## Review + +CMAP-3 all APPROVE: +- Gemini — APPROVE / HIGH +- Codex — APPROVE / MEDIUM +- Claude — APPROVE / HIGH + +No KEY_ISSUES from any reviewer. Claude noted `.tab-bar-item:has-text("Work")` uses the same `:has-text` pattern but is safe (button with fixed link text, no dynamic descendants) — verified during sweep. + +PR #917 created with CMAP table in body. Architect notified. + +## Awaiting + +`pr` gate approval from human. From 08c0dfbbe6930abb325da7902f007e84b42a6de9 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Thu, 28 May 2026 20:40:57 +1000 Subject: [PATCH 8/8] chore(porch): bugfix-828 pr gate-approved --- .../bugfix-828-test-dashboard-e2e-strict-mode/status.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml index 1450c1e2c..fbaa42a39 100644 --- a/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml +++ b/codev/projects/bugfix-828-test-dashboard-e2e-strict-mode/status.yaml @@ -6,16 +6,17 @@ plan_phases: [] current_plan_phase: null gates: pr: - status: pending + status: approved requested_at: '2026-05-28T10:40:10.269Z' + approved_at: '2026-05-28T10:40:57.591Z' iteration: 1 build_complete: false history: [] started_at: '2026-05-28T10:30:53.869Z' -updated_at: '2026-05-28T10:40:10.270Z' +updated_at: '2026-05-28T10:40:57.592Z' pr_history: - phase: pr pr_number: 917 branch: builder/bugfix-828 created_at: '2026-05-28T10:39:55.080Z' -pr_ready_for_human: true +pr_ready_for_human: false