(motir-core) `board-at-scale` test 4 fails on EVERY first attempt — test 3 persists `groupBy=Assignee` on the shared board and CI's `retries: 1` re-runs `beforeAll`, hiding it
Found while running MOTIR-2198 (the seeder position class fix). An out-of-scope finding logged rather than absorbed (notes.html #27) — it is pre-existing on origin/main and causally independent of that card's diff.
The failure
tests/e2e/board-at-scale.spec.ts:361 — "the over-cap banner "Refine filter" CTA opens the board filter (Story 6.15.3/6.15.4)" — fails on the first attempt of every full-file run:
Error: expect(locator).toBeVisible() failed
Locator: getByTestId('board')
Timeout: 30000ms — element(s) not found
at gotoLoadedBoard (tests/e2e/_helpers/board.ts:93)
at signInBoardSeedOwnerAndOpenBoard (tests/e2e/_helpers/board.ts:105)
The accessibility snapshot in the failure artifact shows the board DID render — as a swimlane board (Group by → Assignee pressed), so board never exists and swimlane-board does.
Why
The predecessor test (:335, "shows the over-cap "refine your filter" banner past the cap — flat AND swimlane") ends with setGroupBy(page, 'Assignee'), which PATCHes /api/board and persists the group-by on the board row. The at-scale spec calls resetDatabase() + reseeds once, in beforeAll — not per test — and every test in the describe signs in as the SAME big-seed tenant owner and opens the SAME board. So the persisted Assignee leaks forward into the next test, which waits on the flat-board testid.
Why main is green anyway — and why that is the worse half
playwright.config.ts:157 sets retries: process.env['CI'] ? 1 : 0. A Playwright retry runs in a fresh worker, which re-runs test.beforeAll → resetDatabase() + reseed → the board's group-by is back to its default and the test passes. So CI has been green on a test that deterministically fails first, and the retry budget that exists for genuine flakes is being spent every run on a deterministic defect.
Verified, not reasoned
Both runs against a local prod build (own port 3410, own DB, BOARD_ISSUE_CAP_OVERRIDE=40 DONE_AGE_WINDOW_DAYS_OVERRIDE=7), --grep "board-at-scale":
| spec source | result |
|---|---|
| MOTIR-2198's branch | 6 passed, 1 failed — :361 |
origin/main, byte-for-byte | 6 passed, 1 failed — the same test, the same locator |
And the same test passes in isolation (--grep "Refine filter. CTA opens the board filter" → 1 passed, 4.6s), which is the ordering leak stated as an experiment.
Acceptance criteria
tests/e2e/board-at-scale.spec.tspasses on a first attempt with--grep "board-at-scale"and no retries — demonstrated by a local run whose output is quoted in the PR body.- The fix restores the board's group-by rather than relying on test order: either the swimlane test sets it back to
Nonebefore it ends, orsignInBoardSeedOwnerAndOpenBoard(or a per-test hook) asserts/normalises the group-by it is about to depend on. Prefer the one that survives a test being added between them. - No test in the file depends on a sibling's persisted board state — a comment states the shared-tenant contract, since
beforeAll-only seeding is deliberate (the big seed is expensive) and will keep inviting this. - A grep of the other
beforeAll-seeded E2E specs for the same shape (a persisted setting written by one test and read by the next) reports what it found, even if the answer is nothing.
Context refs
tests/e2e/board-at-scale.spec.ts—setGroupBy(:208), the swimlane test (:335), the CTA test (:361), thebeforeAll(:272).tests/e2e/_helpers/board.ts—gotoLoadedBoard/signInBoardSeedOwnerAndOpenBoard.playwright.config.ts:157— theretries: 1that masks it;:155fullyParallel: false.