Verification — production deploy now ships migrations and fails loudly otherwise
Implementation commit: 5f4087b2b2504a099c73c32536babfebf61f87ea on branch
feature/fix-migrations-in-dist.
Build-time evidence
npm run build happy path
$ rm -rf dist && npm run build
> colibri@0.0.1 build
> tsc
> colibri@0.0.1 postbuild
> node scripts/copy-migrations.mjs
copy-migrations: copied 6 migration(s) ...src/db/migrations -> ...dist/db/migrations
dist/db/migrations/ contents
$ ls dist/db/migrations/
001_init.sql
002_tasks.sql
003_thought_records.sql
004_skills.sql
005_retention.sql
006_eta.sql
All 6 expected migrations present.
Byte-identical copy
$ diff -r src/db/migrations dist/db/migrations
$ echo $?
0
No diff — src and dist migration directories are byte-identical.
Runtime evidence
Lint
$ npm run lint
> colibri@0.0.1 lint
> eslint src
$ echo $?
0
Clean.
Full test suite
$ npm test
...
Test Suites: 1 failed, 29 passed, 30 total
Tests: 1 failed, 1357 passed, 1358 total
1357 of 1358 passing. Net +1 test vs the pre-task baseline (1357 = 1356 prior + new prod-mode test). The single failure is the pre-existing flake startup — subprocess smoke › tsx src/server.ts boots and logs [Startup] Phase 1 documented in MEMORY.md (“predates Wave H; all 4 R77 executors hit it once, always green on rerun”).
Verified flake on isolated rerun:
$ npm test -- --testPathPattern='startup'
...
Test Suites: 1 passed, 1 total
Tests: 40 passed, 40 total
40/40 on the startup file in isolation — the flake is environmental, not a regression of this task.
New test in isolation
$ npm test -- --testPathPattern='db-init' --testNamePattern='NODE_ENV=production'
...
Test Suites: 1 passed, 1 total
Tests: 29 skipped, 1 passed, 30 total
The new test 'throws under NODE_ENV=production when migrations directory is missing' passes deterministically.
Coverage on src/db/index.ts
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
index.ts | 100 | 95.65 | 100 | 100 | 299
Statement / function / line coverage stays at 100%. Branch coverage moved from 95% (pre-task) to 95.65% — the new prod-mode guard is exercised on both arms (migrations.length === 0 true + false in covered tests; NODE_ENV === 'production' true in the new test, false in the existing missing-directory test).
Contract assertions verified
Build-time
| Assertion | Expected | Actual | Pass? |
|---|---|---|---|
npm run build exit code on a clean tree |
0 | 0 | ✓ |
ls dist/db/migrations/*.sql \| wc -l |
6 | 6 | ✓ |
diff -r src/db/migrations dist/db/migrations |
empty | empty | ✓ |
Build fails when src/db/migrations/ is missing |
non-zero | (verified by reading scripts/copy-migrations.mjs:24-27) |
✓ |
Build fails when source dir contains zero .sql |
non-zero | (verified by reading scripts/copy-migrations.mjs:30-33) |
✓ |
Runtime guard
| Step | Expected | Actual | Pass? |
|---|---|---|---|
process.env.NODE_ENV = 'production' + empty migrations + initDb(p) |
throws | throws via the new test | ✓ |
Error contains migrations directory not found |
required | regex matches /migrations directory not found.../is |
✓ |
Error contains dist/db/migrations |
required | included in regex | ✓ |
Error contains npm run build |
required | included in regex | ✓ |
getDb() after failed init throws Database not initialized |
required | second expect in the new test |
✓ |
| Existing test at db-init.test.ts:428 still green | required | covered in full suite (1357/1358) | ✓ |
tsx dev path unaffected |
required | NODE_ENV !== 'production' guard predicate, no tsx run touched |
✓ |
Header comment update
| Assertion | Expected | Actual | Pass? |
|---|---|---|---|
Known limitation substring removed |
true | confirmed via grep -n "Known limitation" src/db/index.ts returns nothing |
✓ |
New paragraph mentions scripts/copy-migrations.mjs and the runtime guard |
true | lines 41-47 of the post-impl file include both | ✓ |
Manual cross-check
$ grep -nF "Known limitation" src/db/index.ts
$ grep -nF "scripts/copy-migrations.mjs" src/db/index.ts
42: * so `scripts/copy-migrations.mjs` runs as `npm postbuild` and copies
$ grep -nF "migrations directory not found" src/db/index.ts
269: 'Database boot aborted: migrations directory not found or empty ' +
Header comment + runtime guard both wired correctly.
Files changed in this task
| File | Status | LOC delta |
|---|---|---|
scripts/copy-migrations.mjs |
new | +37 |
package.json |
modified (added postbuild) |
+1 |
src/db/index.ts |
modified (header comment + runtime guard) | +14 / -7 |
src/__tests__/db-init.test.ts |
modified (new test) | +24 |
docs/audits/fix-migrations-in-dist-audit.md |
new | +106 |
docs/contracts/fix-migrations-in-dist-contract.md |
new | +81 |
docs/packets/fix-migrations-in-dist-packet.md |
new | +179 |
docs/verification/fix-migrations-in-dist-verification.md |
new | (this file) |
Five-step chain commits on branch feature/fix-migrations-in-dist:
dd116ec4— audit(fix-migrations-in-dist): inventory surfacec26821d9— contract(fix-migrations-in-dist): behavioral contract8adf31a1— packet(fix-migrations-in-dist): execution plan5f4087b2— feat(fix-migrations-in-dist): copy SQL migrations into dist + prod boot guard- (this verification commit)
Acceptance criteria — round-trip
| # | Criterion | Status |
|---|---|---|
| 1 | npm run build produces dist/db/migrations/*.sql with all 6 migrations |
✓ |
| 2 | Runtime guard fails boot loudly under prod when migrations are empty (mentions “migrations directory not found” + build step) | ✓ |
| 3 | tsx dev path unaffected; tests still run |
✓ |
| 4 | New test asserts the prod-mode failure with the expected message | ✓ |
| 5 | All existing tests still pass: build && lint && test |
✓ (1357/1358; the 1 fail is the pre-existing startup-subprocess flake) |
| 6 | Header comment in src/db/index.ts:41-44 reflects the resolved limitation |
✓ |
All six acceptance criteria satisfied. No blockers.