Estimate: 28m · Depends on: 6.15.3
The story-closing verification (Principle #18).
Vitest (integration, real Postgres): the filtered board read — the predicate applied per column, the truncated/cap computed over the FILTERED set (a filter under the cap clears truncated), the unfiltered path unchanged, the 6.4-permission + workspace scope, and the Scrum compose (the filter ANDs with the 4.5 sprint scope, never widening it). An unauthorized/invalid saved-filter id → the typed error.
Playwright E2E (tests/e2e/board-filter.spec.ts): on a seeded board, open the toolbar Filter → apply a quick filter (kind Bug) → assert only matching cards across columns (wait on the board re-projection response, not the optimistic UI) → toggle a Work type facet (e.g. Design) and assert the board re-projects to that work type (the 6.15.5 facet) → apply a saved filter → Clear restores the full board → the over-cap banner CTA opens the filter; assert the URL carries the filter and survives reload. a11y: strict axe sweep over the filter affordance (closed / open builder incl. the Work type group / saved-filter picker / active chips / filtered-empty).
waitForResponse before the action, per CLAUDE.md); the axe sweep reports zero violations.pnpm test:coverage keeps all 6.15 files ≥ 90%.tests/e2e/board-crud.spec.ts / board-scrum.spec.ts (the board E2E setup + selector patterns to build on) + tests/helpers/db.ts (the large-seed fixture for the cap case)