Skip to Content
Getting StartedVerify and CI

Verify and CI

bun run verify is the single pre-push command in this repo, and this page explains why it exists, what it actually gates, how CI mirrors it, and the one thing it deliberately does not cover: the real-Postgres integration lane. If you internalize one page in this section, make it this one.

The motivation is iteration cost. A CI round-trip through GitHub Actions is ~10 minutes; verify runs the same gate sequence locally in ~3–8 minutes and catches most failures in seconds. The repo’s stance (from CLAUDE.md): always run bun run verify from the root before pushing any branch that will trigger CI, and never treat a per-package check as a substitute — per-package runs miss cross-package type inference, the AppShell bundle budget, the fixture-key registry, the schema-audit error-class pattern, and tests that depend on workspace-built artifacts.

What verify runs

The verify script in the root package.json chains build, workspace typecheck, roughly forty gate scripts from scripts/check-*.ts, and the full test suite:

StageExamples
Build + typecheckturbo run build, turbo run typecheck
Package structurecheck:boundaries, check:integration-contract, check:barrel-hygiene
Auth / authzcheck:auth-method-lockstep, check:authz-endpoint-coverage, check:authz-authority-inventory, check:canonical-identity
Fund accountingcheck:fund-accounting-write-cutover, check:account-code-semantics
Portaldisplay-only imports, canonical links, route health, trip-wire (boot+render smoke), bundle audit, a11y baseline, dev_local reachability, demo-fixture imports
Data safetydata-safety:fixtures, xlsx:safety, check:no-pii-logs-adjacent gates
Schemaschema:audit, schema:active-ci (active migration catalog + pglite schema contracts)
Testsbun run test — the full Vitest suite (~2,000 test files) on pglite

Copy-pasteable, from the repo root:

bun run verify # ~3-8 minutes; run before every push

How CI mirrors it

.github/workflows/ci.yml runs on every PR and push to staging and main (docs/markdown paths are excluded), split into three parallel jobs:

The ci and gates jobs together cover roughly what verify covers (the gates job also runs the migration-immutability check, which needs full git history). The ci test phase caps TURBO_CONCURRENCY=4 and OPSDNA_TEST_MAX_WORKERS=4 so pglite (WASM Postgres) suites don’t oversubscribe the runner. Playwright e2e is not a merge gate — portal:trip-wire smoke-tests portal boot+render; the Playwright harness runs locally via bun run portal:e2e only.

verify ≠ the postgres integration lane

bun run verify runs its tests on pglite, an in-process WASM Postgres. pglite silently passes things real Postgres rejects: EXECUTE grants, FORCE ROW LEVEL SECURITY, and cross-cutting catalog invariants like the identity-spine rule (every *_identity_id column must be uuid after migration 0311). Those live only in the separate postgres integration CI job, which runs against a real postgres:18 container — deliberately matching prod RDS PG 18, because postgres:16 gave false confidence. A green verify with a red postgres integration job is the classic tell that a schema change slipped the pglite lane.

When your change touches schema — a migration, a new *_identity_id column, RLS, grants — also run the lane locally against a real Postgres on :55432:

DATABASE_URL=postgres://opsdna:opsdna@localhost:55432/opsdna_dev \ bun run --cwd packages/persistence test:integration

Or target a single file:

bun x vitest run \ --config packages/persistence/vitest.integration.postgres.config.ts \ path/to/your.test.ts
Last updated on