Estimate: 30m · Depends on: 6.1.4, 6.1.5
The story-closing verification (Principle #18; the 5.x split — the epic-wide journey stays Story 6.7).
Vitest (integration, real Postgres): the compile-correctness matrix — every (field-type × operator) cell against seeded data with known expected sets, under BOTH combinators, incl. relative date windows (frozen clock), empty/negation semantics, multi-CF join composition, and the tree-read parity cases (flat and tree match sets identical per AST); the injection fuzz suite (meta-chars, quote-smuggling, operator/field-id forgery, oversized ASTs → 422s; query-log assert: zero unparameterized user strings); the serialization properties (AST↔URL round-trip for generated ASTs; malformed-param recovery; facet-upgrade losslessness); the stale-referent matrix (deleted field/option/label/component each).
Playwright E2E (tests/e2e/filter-builder.spec.ts): the recipe journey — build the multi-row mixed filter (incl. a CF row + a label row + negation + a relative date), assert results + count, flip the combinator, round-trip the URL in a fresh context, upgrade from facets, hit zero-results + Clear all, and verify the Tree shows the same set with muted ancestors. a11y: the strict axe sweep over the open builder (every editor kind open once) + the applied state.
pnpm test:coverage keeps all 6.1 files ≥90%.tests/integration/ + tests/e2e/ conventions; the harness/selector memories