You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The audit (verified against 6765f49, 2026-07-22) found 970 backend tests, all against per-module MagicMock DB stubs; zero browser tests; and CI that never starts a database or applies a migration. The persistence layer is therefore structurally untested — a misspelled column, a NOT NULL violation, a wrong .eq() chain, a broken upsert conflict target, or an encrypt-on-write / decrypt-on-read mismatch would all pass today, because the mock agrees with whatever the caller asserts. Negative-authz tests have the same problem: RLS does not exist (zero ROW LEVEL SECURITY statements in backend/db/migrations/; the backend connects with the service-role key via db/connection.py:10, bypassing it), all access control lives in services/auth_guard.py, and every IDOR test runs against mocks — so a guard that is correct in mock-land but wrong about PostgREST filter semantics passes. Meanwhile the local Supabase stack is running and used by no test (open PR #377 starts closing that gap for the subcutaneous lane).
What this chapter is
The lane split is by how each suite is run and trusted, not by subject matter. Chapter 1 asserts conformance to a spec we wrote, finds regressions, requires determinism, runs on every PR, gates merge, tolerates zero flake, and outputs pass/fail. Two lanes:
1. CI container runtime — Supabase CLI on a Docker runner, or plain postgres + db.migrate? The latter is simpler and kills the Podman/Docker divergence, but loses PostgREST, which the backend actually talks to. Leaning: full Supabase CLI, since PostgREST semantics are half the point.
2. CI Postgres version — match local (PG17) or prod (PG15)? Leaning: PG15 to match prod, plus a separate issue to close the local skew.
Problem
The audit (verified against
6765f49, 2026-07-22) found 970 backend tests, all against per-moduleMagicMockDB stubs; zero browser tests; and CI that never starts a database or applies a migration. The persistence layer is therefore structurally untested — a misspelled column, a NOT NULL violation, a wrong.eq()chain, a broken upsert conflict target, or an encrypt-on-write / decrypt-on-read mismatch would all pass today, because the mock agrees with whatever the caller asserts. Negative-authz tests have the same problem: RLS does not exist (zeroROW LEVEL SECURITYstatements inbackend/db/migrations/; the backend connects with the service-role key viadb/connection.py:10, bypassing it), all access control lives inservices/auth_guard.py, and every IDOR test runs against mocks — so a guard that is correct in mock-land but wrong about PostgREST filter semantics passes. Meanwhile the local Supabase stack is running and used by no test (open PR #377 starts closing that gap for the subcutaneous lane).What this chapter is
The lane split is by how each suite is run and trusted, not by subject matter. Chapter 1 asserts conformance to a spec we wrote, finds regressions, requires determinism, runs on every PR, gates merge, tolerates zero flake, and outputs pass/fail. Two lanes:
plus a plumbing lane that unblocks both (#378–#384).
Success criteria
Non-goals
Dependency graph
Regenerated from the per-issue Dependencies sections:
Critical path to a first green browser test:#380 → #384 → #385 → #386, with #381/#382/#383 landing in parallel.
Open decisions
postgres+db.migrate? The latter is simpler and kills the Podman/Docker divergence, but loses PostgREST, which the backend actually talks to. Leaning: full Supabase CLI, since PostgREST semantics are half the point.main?Leaning:main-only for two weeks, then promote once test(e2e): browser-lane stability gate — 20 consecutive green runs #388 has held.db.seed_staging, or a separate smallerdb.seed_e2e? Leaning: separate, so changing demo data can't break tests. PR Local-Supabase follow-ups: rich seed + integration suite (#363, #362; #365 reverted) #377'sdb.seed_local_rich(built for feat(seed): rich local dataset for E2E testing #363) is a strong candidate base.Risks
data-testidconvention decaysChildren
Plumbing
Browser
Subcutaneous
Supersedes #362 and #363 (absorbed; PR #377 implements slices of #396/#397 and the rich seed).