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.
Think5m
Plan5m
Build7m
Verify61m
Assertion ledger
20 claims, each independently verified. Showing 8 — show all →
| ID | Says | Matcher | |
|---|---|---|---|
| A001 | Drizzle config file discovery finds the schema path from the config | verified | ok |
| A002 | Config-driven discovery works with defineConfig wrapper syntax | verified | ok |
| A003 | Config discovery works across config file extensions | verified | ok |
| A004 | The database dialect from config becomes the detected provider | verified | ok |
| A005 | Schema files are found by glob when no config file exists | verified | ok |
| A006 | Glob fallback locates the correct schema file path | verified | ok |
| A007 | Table definitions in schema files are counted as models | verified | ok |
| A008 | A schema file with no table definitions reports zero models | verified | ok |
Findings 6 total
obspackages/cli/src/engine/census.ts→ closed
`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.ts→ closed
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.ts→ closed
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.ts→ closed
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.ts→ closed
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