Fix Drizzle schema detection

Drizzle schema detection is a stub — census checks the migrations directory, scan-engine globs inside it, model counting and provider detection are absent, no blind spot fires, and census results are ignored by the scorer. A project using Drizzle gets no model count, no provider, wrong schema path, and no warning when the schema is missing. This is the same class of disease that was just fixed for Prisma (see proof chain: "Fix Prisma schema detection bugs"), applied to the second most popular TypeScript ORM.

verdict PASSscore 20 / 20findings 6 (0 risk · 0 debt · 6 obs)duration 1h 13mrejection cycles 0shipped Apr 24, 2026surface cli

Pipeline timeline

Intent to proven code in 1h 13m across Think, Plan, Build, and Verify.

Think
5m
Plan
5m
Build
7m
Verify
61m

Assertion ledger

20 claims, each independently verified. Showing 8 — show all →

IDSaysMatcher
A001Drizzle config file discovery finds the schema path from the configverifiedok
A002Config-driven discovery works with defineConfig wrapper syntaxverifiedok
A003Config discovery works across config file extensionsverifiedok
A004The database dialect from config becomes the detected providerverifiedok
A005Schema files are found by glob when no config file existsverifiedok
A006Glob fallback locates the correct schema file pathverifiedok
A007Table definitions in schema files are counted as modelsverifiedok
A008A schema file with no table definitions reports zero modelsverifiedok

Findings 6 total

obspackages/cli/src/engine/census.tsclosed
`drizzle-dialect` overloads SchemaFileEntry semantics: `census.ts:267-274` — The `orm: 'drizzle-dialect'` entry stores the dialect string in the `path` field, which is semantically a file path. This works because the type is `string` and scan-engine filters by orm name, but a future developer reading `SchemaFileEntry.path` won't expect it to contain `'postgresql'`. Consider a dedicated field or a separate return channel in a future cycle.
obspackages/cli/src/commands/scan.tsclosed
Consumer sort logic duplicated in two files: `scan.ts:112-121` and `scaffold-generators.ts:62-71` — Identical 10-line sort comparator handling null modelCount values. The spec suggested extraction "if the logic is more than a few lines." A shared `selectBestSchema(schemas)` helper would prevent divergence if the selection logic evolves.
obspackages/cli/src/engine/census.tsclosed
Config regex can match comments: `census.ts:251` — `schema\s*:\s*["']([^"']+)["']` would match a commented-out `// schema: "old/path"`. In practice, Drizzle config files are small and rarely have commented schema fields, and this is the same pattern used for Prisma extraction. Flagging for awareness, not action.
obspackages/cli/tests/engine/scanProject.test.tsclosed
A017 doesn't exercise null-modelCount comparison: `scanProject.test.ts:549-566` — Contract says "when all schemas have unknown model counts, the first found is used." Test uses Supabase which gets `modelCount: 1` from SQL, not null. The null-comparison branch (`aCount == null && bCount == null`) in both consumers is exercised only when multiple ORMs all have null counts — this test has one ORM with a real count. The builder's comment at line 550-552 acknowledges the limitation.
obspackages/cli/tests/engine/scanProject.test.tsclosed
A016 verifies precondition, not consumer output: `scanProject.test.ts:523-545` — The test proves Drizzle has more models than Prisma, but doesn't verify that `enrichDatabase()` or `generateProjectContextMd()` actually selects Drizzle. The consumer logic is correct by code inspection (sort descending, take first), but the test path stops at model counts rather than consumer output.
+1more findings

Integrity seal

scopesha256:c1a356f33bd0b...
contractsha256:5497373d7df55...
plansha256:9aeafcb65f4cd...
specsha256:369b21fbb8451...
build-reportsha256:517bc2c0a84c3...
verify-reportsha256:0f51d48954db7...
audit cmd$ ana proof audit fix-drizzle-schema-detection   → all hashes match