Run Quality Gates
Five sequential gates that catch the failures that would otherwise blow up in a Vercel build or in production. Fail-fast: the first failing gate stops the run.
Default stance
Run the full suite before any PR. Use --quick only for tight local iteration where you'll re-run before opening the PR. The build gate is the most expensive (30-60s) and the most likely to catch what the other four miss — TypeScript errors, import path issues, Next.js route conflicts. Skipping it locally is fine; skipping it before a PR is how broken builds reach staging.
The pre-commit hook already enforces a slightly different superset (db:check, env:check, lint, knip, test). The build gate isn't in pre-commit because it's slow — it lives here.
Use this skill when
Opening a PR, before promotion, after schema changes to lib/schema.ts, after touching lib/env/*, or after a refactor that crosses multiple files.
Run
./scripts/gates.sh # full suite
./scripts/gates.sh --quick # skips next build for fast local iteration
Gates in order
bun run db:check— Drizzle schema ↔ migration file sync. Catches schema drift before it reaches production.bun run env:check— No rawprocess.env.Xaccess outsidelib/env/*. All env reads must go through typed accessors.bun run lint— ESLint.bun run test— Vitest unit tests intests/unit/.bun run build— Full Next.js production build. Catches type errors, route conflicts, and import issues that lint misses.
When a gate fails
db:check— Schema drift. Runbunx drizzle-kit generateto sync, commit the new migration, retry. Seedb-health.env:check— A rawprocess.env.Xsomewhere. Move it to the appropriatelib/env/*.tsmodule with a typed accessor. The check exists because raw access bypasses the per-environment validation that catches "we forgot to set this in Vercel."lint— Fix orbun run lint --fixfor auto-fixable cases.test— Read the failure.bun run test:watchfor interactive mode.build— Almost always a type error. Check the build output for the file and line; the error message is usually accurate.
Hard rules
- Don't bypass gates to "ship faster." Every gate that's failed in this repo's history was catching something real.
- Don't disable a gate to make it pass. If a gate is wrong, fix the gate; don't skip it.
- Don't commit with a failing pre-commit hook via
--no-verifyunless explicitly told to. Hook failures are signal.
Where things live
| File | Purpose |
|---|---|
scripts/gates.sh | Entrypoint — runs all 5 in order |
scripts/release-gates.sh | Stricter superset for release readiness |
scripts/check-env-fallbacks.mjs | Implementation of env:check |
scripts/ban-db-push.mjs | Refuses to run if db:push is in scripts |
lib/env/*.ts | Typed env accessors (where all process.env access lives) |
tests/unit/ | Where new fast tests go |
Auxiliary content
- references/original-guide.md — full canonical guide
- references/graph.md — when to hand off to
db-health,promote-deployment - scripts/run-gates.sh — skill-local copy of the entrypoint
- assets/gate-result-template.md — template for reporting gate results in PR comments or handoffs