Adds a CI-enforced lint check that rejects any Liquibase migration whose CREATE TABLE statements do not declare a PRIMARY KEY. Mirrors the existing lint-two-phase-column-drop pattern (custom TS script + baseline file + GitHub Actions workflow).
PrimaryKeyOnTable quality check)Hermes Liquibase changesets are executeCommand shells that run bun against a per-migration up.ts. Liquibase quality checks inspect changeset elements like <createTable> — but our changesets only ever call out to a bun script. Liquibase never sees the CREATE TABLE SQL, so its built-in PK check is blind here. The lint runs against the migration files directly.
For every vN_*/ directory under packages/db/liquibase/migrations/:
up.ts — SQL extracted from executeQuery(client, …), prisma.$executeRaw\…`, and prisma.$executeRawUnsafe(…)`.up.sql — sibling SQL file, if present..sql file referenced from up.ts via readFileSync(join(currentDir, …)) — covers v0_baseline loading the Prisma baseline migration end-to-end."id" SERIAL PRIMARY KEYPRIMARY KEY ("id"[, …])CONSTRAINT foo_pkey PRIMARY KEY ("id"[, …])ALTER TABLE foo ADD [CONSTRAINT x] PRIMARY KEY (…)CREATE TEMP / TEMPORARY / UNLOGGED TABLECREATE TABLE … AS SELECT (query-derived; PG can't put a PK at create time)CREATE TABLE … PARTITION OF (inherits the parent's PK)packages/db/liquibase/migrations/.lint-missing-primary-key-baseline.json grandfathers documented exemptions. The single entry today is v5_add_malleable_code_table / malleable_api_code — the PK was retroactively added in v67_malleable_api_code_primary_key via ALTER TABLE … ADD PRIMARY KEY, which we cannot retro-edit into v5 since the migration has shipped. New migrations should never be added to the baseline.
packages/db/scripts/lint-missing-primary-key.ts — the lint script (parser + CLI).packages/db/scripts/lint-missing-primary-key.test.ts — 21 vitest tests covering SQL extraction, CREATE TABLE parsing (incl. nested parens, quoted/qualified names, multi-column PK), exempt forms, and ALTER TABLE … ADD PRIMARY KEY detection.packages/db/liquibase/migrations/.lint-missing-primary-key-baseline.json — baseline with the documented v5 exemption.packages/db/package.json — adds lint:missing-primary-key script and includes the new test file in pnpm test..github/workflows/lint-missing-primary-key.yaml — required PR check on changes to packages/db/liquibase/migrations/**, packages/db/prisma/migrations/**, or the lint script itself.Unit tests (parser logic):
$ cd packages/db && pnpm test
✓ src/wrap_prisma/prisma_error_handler.test.ts (5 tests) 8ms
✓ scripts/lint-missing-primary-key.test.ts (21 tests) 11ms
Test Files 2 passed (2)
Tests 26 passed (26)
End-to-end on the real corpus (86 migrations) with the baseline present:
$ pnpm run lint:missing-primary-key
✓ All CREATE TABLE statements in Liquibase migrations declare a PRIMARY KEY.
End-to-end with an empty baseline — proves the lint actually rejects a real violation:
$ # baseline temporarily emptied
$ pnpm run lint:missing-primary-key
✗ Found 1 CREATE TABLE statement(s) without a PRIMARY KEY:
liquibase/migrations/v5_add_malleable_code_table/up.ts:2
Migration: v5_add_malleable_code_table
Table: malleable_api_code
CREATE TABLE "malleable_api_code" in migration "v5_add_malleable_code_table"
does not declare a PRIMARY KEY. …
ELIFECYCLE Command failed with exit code 1.
--update-baseline is idempotent against the current state:
$ pnpm tsx scripts/lint-missing-primary-key.ts --update-baseline
✓ Updated baseline with 0 new entries.
Type-check: zero new TS errors in the new files (verified tsc --noEmit -p tsconfig.json).
Triggered by: srujan@composio.dev | Source: slack Session: https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-963891822a36
Based on git blame analysis of 5 file(s):
| Contributor | Contribution | Files |
|---|---|---|
| Zen | 97% | 5 |
| Rahul Tarak | 1% |
| 1 |
| Utkarsh Dixit | 0% | 1 |
| sarahsimionescu | 0% | 1 |
| Himanshu Dixit | 0% | 1 |
Recommend Zen as the primary reviewer — they authored the majority of the changes and edited the affected files most recently (today). As a secondary reviewer, Rahul Tarak is a good fit since they last edited packages/db about a month ago and can vet package-related changes.
🤖 Based on git blame with recency weighting (recent edits count more).
:white_check_mark: All modified and coverable lines are covered by tests.
| Flag | Coverage Δ | |
|---|---|---|
| e2e-tests | ? | |
| self-hosted-tests | 5.64% <ø> (ø) | |
| thermos-service-isolation-tests | ? | |
| thermos-unit-tests | ? | |
| unit-tests | ? |
Flags with carried forward coverage won't be shown. Click here to find out more. see 1085 files with indirect coverage changes