Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and `merge --ff-only` refuses while tracked paths are dirty. Discard is not available here (workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed. - `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new prose — the commit exists so the trunk merge can proceed. - `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat owns (AGENTS.md § Live-sync tiers). `ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the inert all-zero AWS example id — and they appear inside the two skill pages that teach that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal dies with this landing. No `--no-verify` was used: the gate ran and its verdict is recorded here. Refs #61
42 lines
2.3 KiB
Markdown
42 lines
2.3 KiB
Markdown
---
|
|
name: parallel-suite-shared-db-flake
|
|
description: "Diagnose test suites that pass isolated but fail only under concurrent/uncached runs against a shared database: cross-file teardown wipes, FK-cascaded sessions, wildcard LIKE deletes."
|
|
---
|
|
|
|
# Flaky only under concurrency on a shared DB
|
|
|
|
Symptom: a suite passes `vitest run <file>` alone, fails under `turbo run test --force`
|
|
(or any concurrent uncached runner) with impossible errors — 401 where 404 was
|
|
expected, rows vanishing mid-test, sessions dying between two awaited requests.
|
|
|
|
## Procedure
|
|
|
|
1. **Reproduce the concurrency, not the file.** Isolated runs prove nothing.
|
|
`bun x turbo run test --force --output-logs=errors-only` (or run the two suspect
|
|
files simultaneously). Never conclude "flake" from one green isolated run.
|
|
2. **Map the impossible state to a vanished row.** 401/auth failures where the
|
|
session was created milliseconds earlier = the session/user row was DELETED
|
|
under the test, not expired. Look for writers, not readers.
|
|
3. **Grep every suite's teardown for shared-namespace deletes:**
|
|
`grep -rn "TRUNCATE\|DELETE FROM\|LIKE" <pkg>/src/*.test.*`
|
|
The classic killer: two test files sign users up under the same domain
|
|
(`%@studio.test`) and each `afterAll` runs a wildcard `DELETE ... LIKE '%@...'`.
|
|
With parallel files on one DB, whichever file finishes first cascades away the
|
|
other's live rows (user FK cascades kill sessions mid-flight).
|
|
4. **Fix = scope, never coordinate.** Each suite deletes only rows it created:
|
|
per-file email/id prefixes (`auth*` vs `rel*`), or track created keys and
|
|
`WHERE email = ANY(...)`. Timing tricks (sleeps, retry) hide the collision.
|
|
5. **Prove stability:** 3 consecutive `--force` uncached runs green, then the
|
|
full gate. Cache makes everything look green; only uncached concurrent runs
|
|
re-exercise the collision window.
|
|
|
|
## Gotchas
|
|
|
|
- Error signatures lie: `expected 401 to be 404` reads as an auth bug but is a
|
|
deleted-row cascade.
|
|
- Supertest `cookieOf`-style helpers that THROW on missing cookies prove signup
|
|
succeeded — so the session died after creation; keep hunting for the deleter.
|
|
- Shared dev DBs (one Postgres for all workspaces/worktrees) make every wildcard
|
|
teardown a cross-suite weapon. Suite teardowns on a shared box MUST scope to
|
|
rows the suite created.
|