feat: add transactional module migration runner
CI / verify (pull_request) Successful in 19s
CI / infrastructure-smoke (pull_request) Successful in 20s

This commit is contained in:
ekklesia
2026-07-21 08:52:41 -05:00
parent dc37e59035
commit 0b282865cb
22 changed files with 2589 additions and 47 deletions
+27 -1
View File
@@ -20,10 +20,12 @@ pnpm lint # Biome recommended rules
pnpm boundaries # architectural directions, UI ownership, and cycles
pnpm modules:validate # installed module manifests, compatibility, and dependency graph
pnpm migrations:validate # offline module migration inventory and exact checksums
pnpm migrations:plan # read-only comparison with PostgreSQL applied history
pnpm migrations:apply # locked, transactional application of the pending batch
pnpm typecheck # strict TypeScript
pnpm test # Vitest
pnpm build # Turborepo package build graph
pnpm verify # every code gate above
pnpm verify # every code-only gate; never plan or apply
```
The lint, typecheck, and test commands run both repository-root checks and every matching
@@ -41,6 +43,30 @@ checks every declared stable Drizzle migration directory. It reports dependency-
inventories and exact SHA-256 checksums without importing module code, connecting to PostgreSQL, or
executing SQL. Modules with no migration history are valid.
Migration planning and application require `DATABASE_URL`. Keep it in the uncommitted `.env`
created from `.env.example`:
```bash
cp .env.example .env
pnpm migrations:plan
pnpm migrations:apply
```
Planning completes discovery and validation, reads Core's applied history, and prints a
deterministic applied/pending/approval-blocked inventory. It is read-only and can become stale if
another process applies migrations afterward. Applying is an explicit mutating operation: it
acquires the bounded Core advisory lock, rereads history, checks every destructive approval, and
executes the complete pending aggregate in one transaction. A later failure rolls back all schema
and history changes from that invocation; migrations committed by earlier invocations remain.
The default command composition supplies no destructive approvals. There is no `--force`, wildcard,
or source-controlled approval escape hatch; deployments must later compose a trusted external
provider that supplies an exact module ID, migration identity, and checksum triple.
The migration runner currently has comprehensive unit coverage through its narrow database port.
Live PostgreSQL tests for real DDL rollback, advisory-lock contention, history-table behavior, and
driver cleanup are deliberately deferred and are not part of `pnpm verify` or CI yet.
CI runs `pnpm ci:verify`, which adds Compose configuration validation to `pnpm verify`. A separate
CI job runs the live infrastructure smoke test so code-only local verification does not require
Docker. The explicit suffix avoids pnpm's built-in `ci` install command.