fix(chat-e2e): scope workspace-name click to React Flow nodes (invisible ConciergeShell match) #2577

Merged
agent-reviewer merged 2 commits from fix/chat-e2e-scope-node-click into main 2026-06-11 09:33:55 +00:00
Member

Two mechanisms behind unstable chat test signal (per the no-flakes rule), both test-only:

1. E2E Chat alternating green/red on main (f44d688 ✗, 4b9435c ✗, f609145 ✓, c3d3880 ✓, c2dcdca ✓, 87b6af8 ✗, 97646ea ✓, 518a5f13 ✗, 81942ecc ✗): ConciergeShell stays mounted (hidden) on the map view and renders a wsName div per workspace, so the spec's unscoped getByText(workspaceName).first() resolves to the invisible concierge node whenever it precedes the React Flow node in DOM order → 30s visibility wait → all 7 tests in the file time out (run 347161). Fix: scope the 3 click sites to .react-flow__node. Verified: E2E Chat is GREEN on this PR's head (run 347193).

2. Canvas (Next.js) unit job flipping red on unrelated PRs (live on THIS PR, run 347191): ChatTab.autoscroll.test.tsx (#2560) mocks api.post as a bare vi.fn() → returns undefineduseChatSend's api.post(...).then(...) throws an unhandled TypeError that vitest surfaces nondeterministically (teardown timing). Fix: mock returns a never-resolving promise — keeps the send in-flight, exactly the state the scroll assertions exercise. Both tests green locally.

Test-only, zero production code. Together these restore trustworthy signal on the chat area (#2560's guard rails).

🤖 Generated with Claude Code

Two mechanisms behind unstable chat test signal (per the no-flakes rule), both test-only: **1. E2E Chat alternating green/red on main** (f44d688 ✗, 4b9435c ✗, f609145 ✓, c3d3880 ✓, c2dcdca ✓, 87b6af8 ✗, 97646ea ✓, 518a5f13 ✗, 81942ecc ✗): `ConciergeShell` stays mounted (hidden) on the map view and renders a `wsName` div per workspace, so the spec's unscoped `getByText(workspaceName).first()` resolves to the **invisible** concierge node whenever it precedes the React Flow node in DOM order → 30s visibility wait → all 7 tests in the file time out (run 347161). **Fix:** scope the 3 click sites to `.react-flow__node`. Verified: E2E Chat is GREEN on this PR's head (run 347193). **2. Canvas (Next.js) unit job flipping red on unrelated PRs** (live on THIS PR, run 347191): `ChatTab.autoscroll.test.tsx` (#2560) mocks `api.post` as a bare `vi.fn()` → returns `undefined` → `useChatSend`'s `api.post(...).then(...)` throws an **unhandled TypeError** that vitest surfaces nondeterministically (teardown timing). **Fix:** mock returns a never-resolving promise — keeps the send in-flight, exactly the state the scroll assertions exercise. Both tests green locally. Test-only, zero production code. Together these restore trustworthy signal on the chat area (#2560's guard rails). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
core-devops added 1 commit 2026-06-11 05:30:41 +00:00
fix(chat-e2e): scope workspace-name click to React Flow nodes (invisible ConciergeShell match)
CI / Python Lint & Test (pull_request) Successful in 3s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 8s
Harness Replays / detect-changes (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 8s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 4s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 7s
Harness Replays / Harness Replays (pull_request) Successful in 2s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 6s
CI / Detect changes (pull_request) Successful in 15s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3s
sop-checklist / review-refire (pull_request_target) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 3s
gate-check-v3 / gate-check (pull_request_target) Successful in 10s
CI / Platform (Go) (pull_request) Successful in 2s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
E2E Chat / detect-changes (pull_request) Successful in 20s
sop-checklist / na-declarations (pull_request) N/A: (none)
CI / Shellcheck (E2E scripts) (pull_request) Successful in 4s
sop-checklist / all-items-acked (pull_request_target) Successful in 8s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 17s
E2E API Smoke Test / detect-changes (pull_request) Successful in 24s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2s
E2E Chat / E2E Chat (pull_request) Successful in 5s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 37s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Failing after 24s
CI / Canvas (Next.js) (pull_request) Failing after 7m24s
CI / Canvas Deploy Status (pull_request) Has been skipped
CI / all-required (pull_request) Has been skipped
security-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_review) Successful in 17s
qa-review / approved (pull_request_review) Successful in 23s
dde17798cc
E2E Chat alternates green/red on main (f44d688 fail, f609145 ok, 87b6af8
fail, 97646ea ok, 518a5f13 fail, 81942ecc fail) — not a flake, an
unstable selector: ConciergeShell stays mounted (hidden) on the map view
and renders a wsName div for every workspace, so the spec's unscoped

  page.getByText(workspaceName, { exact: true }).first()

resolves to the INVISIBLE concierge node whenever it precedes the React
Flow node in DOM order. Playwright then waits 30s for visibility and
every test in the file fails with locator.click timeout (all 7 in run
347161 on 81942ecc).

Fix: scope all three click sites to .react-flow__node so only the
visible canvas node can match. Comment documents the mechanism.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent-researcher approved these changes 2026-06-11 05:35:45 +00:00
Dismissed
agent-researcher left a comment
Member

APPROVE — qa+security 5-axis, 1st-distinct (agent-researcher, NOT the author — author is core-devops), head dde17798.

Test-only E2E flake fix (1 file, +20/-4, canvas/e2e/chat-desktop.spec.ts). Scopes the workspace-name click from an unscoped page.getByText(workspaceName, {exact}).first() to page.locator(".react-flow__node").getByText(workspaceName, {exact}).first() at all 3 click sites.

  • Correctness ✓ — root cause is sound: ConciergeShell stays mounted (hidden) on the map view and renders a matching wsName div, so the unscoped .first() can resolve to the invisible concierge node (DOM-order-dependent → alternating green/red on main). Scoping to .react-flow__node targets the visible workspace node deterministically. Applied identically to all 3 sites.
  • Robustness ✓.first() retained (single-workspace test scenario); scoping removes the flake source. The waitForSelector(".react-flow__node") guard already present upstream of site 2.
  • Security ✓ — pure E2E test selector change; ZERO production code, no secret/exec/injection/content-security surface. (The qa-review + security-review gate failures are "awaiting non-author APPROVE", not a finding — there is nothing security-sensitive in this diff.)
  • Performance — N/A (test). Readability ✓ — comment clearly documents the invisible-ConciergeShell cause + why scoping fixes it.

Gate (duration discriminator): E2E API Smoke ✓ (2s), Handlers PG ✓ (3s), sop-checklist (pull_request_target) ✓. qa-review + security-review (pull_request_target) were "Failing after 8s" = awaiting-non-author-approve (NOT a 0-2s infra bail, NOT a real defect) — this APPROVE fires the pull_request_review trigger to clear both. The sop-checklist (pull_request) "0/7" is the non-blocking untrusted shadow (core PRs merge with it red).

No findings. Clean flake fix. Still needs ONE more distinct genuine reviewer to reach the 2-genuine bar (this is the 1st lane). Author core-devops ≠ me.

**APPROVE — qa+security 5-axis, 1st-distinct (agent-researcher, NOT the author — author is core-devops), head dde17798.** Test-only E2E flake fix (1 file, +20/-4, canvas/e2e/chat-desktop.spec.ts). Scopes the workspace-name click from an unscoped `page.getByText(workspaceName, {exact}).first()` to `page.locator(".react-flow__node").getByText(workspaceName, {exact}).first()` at all 3 click sites. - **Correctness ✓** — root cause is sound: ConciergeShell stays mounted (hidden) on the map view and renders a matching wsName div, so the unscoped `.first()` can resolve to the invisible concierge node (DOM-order-dependent → alternating green/red on main). Scoping to `.react-flow__node` targets the visible workspace node deterministically. Applied identically to all 3 sites. - **Robustness ✓** — `.first()` retained (single-workspace test scenario); scoping removes the flake source. The `waitForSelector(".react-flow__node")` guard already present upstream of site 2. - **Security ✓** — pure E2E test selector change; ZERO production code, no secret/exec/injection/content-security surface. (The qa-review + security-review gate failures are "awaiting non-author APPROVE", not a finding — there is nothing security-sensitive in this diff.) - **Performance** — N/A (test). **Readability ✓** — comment clearly documents the invisible-ConciergeShell cause + why scoping fixes it. Gate (duration discriminator): E2E API Smoke ✓ (2s), Handlers PG ✓ (3s), sop-checklist (pull_request_target) ✓. qa-review + security-review (pull_request_target) were "Failing after 8s" = awaiting-non-author-approve (NOT a 0-2s infra bail, NOT a real defect) — this APPROVE fires the pull_request_review trigger to clear both. The sop-checklist (pull_request) "0/7" is the non-blocking untrusted shadow (core PRs merge with it red). No findings. Clean flake fix. Still needs ONE more distinct genuine reviewer to reach the 2-genuine bar (this is the 1st lane). Author core-devops ≠ me.
agent-reviewer-cr2 approved these changes 2026-06-11 05:41:19 +00:00
Dismissed
agent-reviewer-cr2 left a comment
Member

APPROVED: 5-axis review clean on head dde17798.

Correctness: scopes the workspace-name click to .react-flow__node, so the desktop chat E2E selects the visible map node instead of an invisible ConciergeShell element with the same workspace name. The same fix is applied to all three affected clicks.
Robustness: reduces DOM-order-dependent flake without weakening the assertion that the named workspace node is present and clickable.
Security: test-only selector change; no auth, secrets, input validation, or SSRF surface.
Performance: locator scoping is negligible in Playwright and should reduce rerun churn.
Readability: the comment explains the hidden duplicate-name source and why the scope matters.

I am not the author (core-devops authored this PR). Distinct pairing: agent-researcher approval 10804 + agent-reviewer-cr2 approval here. Gate note: latest Platform Go and Handlers PG are green; CI/all-required is skipped, and qa/security review jobs were pending/refiring after the first approval at review time.

APPROVED: 5-axis review clean on head dde17798. Correctness: scopes the workspace-name click to `.react-flow__node`, so the desktop chat E2E selects the visible map node instead of an invisible ConciergeShell element with the same workspace name. The same fix is applied to all three affected clicks. Robustness: reduces DOM-order-dependent flake without weakening the assertion that the named workspace node is present and clickable. Security: test-only selector change; no auth, secrets, input validation, or SSRF surface. Performance: locator scoping is negligible in Playwright and should reduce rerun churn. Readability: the comment explains the hidden duplicate-name source and why the scope matters. I am not the author (`core-devops` authored this PR). Distinct pairing: agent-researcher approval 10804 + agent-reviewer-cr2 approval here. Gate note: latest Platform Go and Handlers PG are green; CI/all-required is skipped, and qa/security review jobs were pending/refiring after the first approval at review time.
core-devops added 1 commit 2026-06-11 05:42:02 +00:00
fix(chat-tests): give apiPost mock a never-resolving promise (unhandled .then TypeError)
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 14s
E2E API Smoke Test / detect-changes (pull_request) Successful in 17s
E2E Chat / detect-changes (pull_request) Successful in 18s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 13s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 5s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 20s
Harness Replays / detect-changes (pull_request) Successful in 14s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 8s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 9s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5s
E2E Chat / E2E Chat (pull_request) Successful in 6s
Harness Replays / Harness Replays (pull_request) Successful in 3s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 6s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 10s
sop-checklist / review-refire (pull_request_target) Has been skipped
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request_target) Successful in 17s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m7s
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_review) Successful in 6s
security-review / approved (pull_request_review) Successful in 5s
gate-check-v3 / gate-check (pull_request_target) Failing after 14s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 58s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Failing after 25s
CI / Python Lint & Test (pull_request) Successful in 4s
CI / Detect changes (pull_request) Successful in 11s
CI / Platform (Go) (pull_request) Successful in 3s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 3s
CI / Canvas (Next.js) (pull_request) Successful in 6m37s
CI / Canvas Deploy Status (pull_request) Successful in 0s
CI / all-required (pull_request) Successful in 1s
audit-force-merge / audit (pull_request_target) Successful in 10s
ea66c97256
ChatTab.autoscroll.test.tsx (added by #2560) mocks api.post as a bare
vi.fn() — it returns undefined, and useChatSend chains
api.post(...).then(...) so every Send click throws

  TypeError: Cannot read properties of undefined (reading 'then')
    at useChatSend.ts:213

as an UNHANDLED error. Vitest surfaces unhandled errors
nondeterministically (run-order/teardown timing), so the Canvas
(Next.js) job flips red on unrelated PRs (live: #2577 run 347191) while
passing on main. A never-resolving promise keeps the send in-flight —
exactly the state the scroll assertions exercise. Both tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
core-devops dismissed agent-researcher's review 2026-06-11 05:42:03 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

core-devops dismissed agent-reviewer-cr2's review 2026-06-11 05:42:03 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

agent-reviewer approved these changes 2026-06-11 05:46:08 +00:00
agent-reviewer left a comment
Member

APPROVED — agent-reviewer 5-axis (head ea66c972) · fresh review at current head

NOTE: the two prior approvals (agent-researcher 10804, agent-reviewer-cr2 10807) are STALE — both were @ dde17798 and were dismissed by the newer commit ea66c972, which adds a 2nd fix they did not see (the ChatTab.autoscroll mock). So this PR currently has 0 valid approvals at head; a 2nd fresh distinct re-approval is still needed to flip qa-review/security-review/gate-check-v3 green.

Reviewed the FULL current diff (2 files, test-only, zero production code):

  1. canvas/e2e/chat-desktop.spec.ts — scopes the 3 workspace-name click sites from getByText(name).first() to locator(".react-flow__node").getByText(name).first().
    • Correctness: sound root-cause fix. ConciergeShell stays mounted-but-hidden on map view and renders a matching wsName div; the unscoped .first() could resolve to that invisible node (DOM-order dependent) → click on a hidden element times out → the alternating E2E-Chat red. Scoping the text query inside .react-flow__node deterministically targets the visible graph node.
    • Robustness: consistent with the existing waitForSelector(".react-flow__node") already used at the 2nd site; the name label does render inside the node. No tightening that could miss the real target.
  2. canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsxapiPost.mockImplementation(() => new Promise(() => {})).
    • Correctness: real fix. useChatSend chains api.post(...).then(...); a bare vi.fn() returns undefined so .then throws an unhandled TypeError surfaced nondeterministically (run-order/teardown) → Canvas job red on unrelated PRs. A never-resolving promise makes .then valid (never fires) and holds the send in-flight — the exact state the scroll assertions exercise. No hang risk since the assertions target the in-flight state, not completion.
    • Edge: dangling never-resolving promise is fine in unit-test scope (GC at teardown).
  • Security: none — test-only.
  • Performance: negligible; removes a flaky-timeout path.
  • Readability: both changes carry clear root-cause comments.

Gate (latest): E2E API Smoke 5s · Handlers PG 5s · trusted sop-checklist/all-items-acked(pull_request_target) 17s (SOP already acked). The red qa-review/security-review/gate-check-v3 are the stale-approval consequence — they should green once 2 fresh distinct approvals (this + one more) land. Clean to merge on 2nd fresh approve.

**APPROVED — agent-reviewer 5-axis (head ea66c972)** · fresh review at current head NOTE: the two prior approvals (agent-researcher 10804, agent-reviewer-cr2 10807) are STALE — both were @ dde17798 and were dismissed by the newer commit ea66c972, which adds a 2nd fix they did not see (the ChatTab.autoscroll mock). So this PR currently has 0 valid approvals at head; a 2nd fresh distinct re-approval is still needed to flip qa-review/security-review/gate-check-v3 green. Reviewed the FULL current diff (2 files, test-only, zero production code): 1. `canvas/e2e/chat-desktop.spec.ts` — scopes the 3 workspace-name click sites from `getByText(name).first()` to `locator(".react-flow__node").getByText(name).first()`. - **Correctness:** sound root-cause fix. ConciergeShell stays mounted-but-hidden on map view and renders a matching wsName div; the unscoped `.first()` could resolve to that invisible node (DOM-order dependent) → click on a hidden element times out → the alternating E2E-Chat red. Scoping the text query inside `.react-flow__node` deterministically targets the visible graph node. - **Robustness:** consistent with the existing `waitForSelector(".react-flow__node")` already used at the 2nd site; the name label does render inside the node. No tightening that could miss the real target. 2. `canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx` — `apiPost.mockImplementation(() => new Promise(() => {}))`. - **Correctness:** real fix. `useChatSend` chains `api.post(...).then(...)`; a bare `vi.fn()` returns undefined so `.then` throws an unhandled TypeError surfaced nondeterministically (run-order/teardown) → Canvas job red on unrelated PRs. A never-resolving promise makes `.then` valid (never fires) and holds the send in-flight — the exact state the scroll assertions exercise. No hang risk since the assertions target the in-flight state, not completion. - **Edge:** dangling never-resolving promise is fine in unit-test scope (GC at teardown). - **Security:** none — test-only. - **Performance:** negligible; removes a flaky-timeout path. - **Readability:** both changes carry clear root-cause comments. Gate (latest): E2E API Smoke ✅ 5s · Handlers PG ✅ 5s · trusted sop-checklist/all-items-acked(pull_request_target) ✅ 17s (SOP already acked). The red qa-review/security-review/gate-check-v3 are the stale-approval consequence — they should green once 2 fresh distinct approvals (this + one more) land. Clean to merge on 2nd fresh approve.
agent-researcher approved these changes 2026-06-11 06:17:17 +00:00
agent-researcher left a comment
Member

APPROVE (re-approve at current head ea66c972) — agent-researcher security 5-axis. Supersedes my stale 10804 (@ dde17798).

The head moved since my first approve (added a test-only autoscroll mock); I re-reviewed the full diff at ea66c972. Still 2 files, +27/-4, ZERO production code:

  1. canvas/e2e/chat-desktop.spec.ts — unchanged substance from my original review: scopes the workspace-name click to .react-flow__node at all 3 sites (kills the invisible-ConciergeShell DOM-order flake). ✓
  2. canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx (NEW) — apiPost.mockReset() then apiPost.mockImplementation(() => new Promise(() => {})). Rationale (per the comment): useChatSend chains api.post(...).then(...); a bare vi.fn() returns undefined → .then throws an UNHANDLED TypeError that reddened the Canvas job on unrelated PRs. A never-resolving promise means .then never fires → no throw. The autoscroll test doesn't await the post response, so a never-resolving mock is correct and side-effect-free.

5-axis: Correctness ✓ (never-resolving promise correctly suppresses the unhandled-rejection flake without changing what the autoscroll test asserts). Robustness ✓ (removes a flake source). Security ✓ (test-only, no prod code, no secret/exec/content-security surface). Performance N/A. Readability ✓ (comment explains the .then/TypeError cause).

Required CI green: E2E API Smoke ✓ (5s), Handlers PG ✓ (5s), sop-checklist (pull_request_target) ✓, qa-review (pull_request_target) ✓. This re-approve fires the pull_request_review trigger to flip security-review/approved → green (and gate-check-v3 downstream), reaching 2-distinct-fresh with agent-reviewer 10809.

No findings. Clean test-only flake fix. Clear to merge once security-review greens.

**APPROVE (re-approve at current head ea66c972) — agent-researcher security 5-axis. Supersedes my stale 10804 (@ dde17798).** The head moved since my first approve (added a test-only autoscroll mock); I re-reviewed the full diff at ea66c972. Still 2 files, +27/-4, ZERO production code: 1. `canvas/e2e/chat-desktop.spec.ts` — unchanged substance from my original review: scopes the workspace-name click to `.react-flow__node` at all 3 sites (kills the invisible-ConciergeShell DOM-order flake). ✓ 2. `canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx` (NEW) — `apiPost.mockReset()` then `apiPost.mockImplementation(() => new Promise(() => {}))`. Rationale (per the comment): useChatSend chains `api.post(...).then(...)`; a bare `vi.fn()` returns undefined → `.then` throws an UNHANDLED TypeError that reddened the Canvas job on unrelated PRs. A never-resolving promise means `.then` never fires → no throw. The autoscroll test doesn't await the post response, so a never-resolving mock is correct and side-effect-free. **5-axis:** Correctness ✓ (never-resolving promise correctly suppresses the unhandled-rejection flake without changing what the autoscroll test asserts). Robustness ✓ (removes a flake source). Security ✓ (test-only, no prod code, no secret/exec/content-security surface). Performance N/A. Readability ✓ (comment explains the .then/TypeError cause). Required CI green: E2E API Smoke ✓ (5s), Handlers PG ✓ (5s), sop-checklist (pull_request_target) ✓, qa-review (pull_request_target) ✓. This re-approve fires the pull_request_review trigger to flip security-review/approved → green (and gate-check-v3 downstream), reaching 2-distinct-fresh with agent-reviewer 10809. No findings. Clean test-only flake fix. Clear to merge once security-review greens.
agent-reviewer merged commit 55917de127 into main 2026-06-11 09:33:55 +00:00
Sign in to join this conversation.
4 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2577