Fix Prisma schema detection bugs
Census breaks on first Prisma schema match per root, starving scan-engine's best-match scorer. Three bugs share one disease: census assumes every Prisma project has exactly one `schema.prisma` at a hardcoded path. This breaks dual-candidate roots, multi-file schemas (`prismaSchemaFolder`, GA since Prisma 5.15), and provider detection in split-file layouts.
verdict PASSscore 13 / 13findings 5 (1 risk · 1 debt · 3 obs)duration 28mrejection cycles 0shipped Apr 24, 2026surface cli
Pipeline timeline
Intent to proven code in 28m across Think, Plan, Build, and Verify.
Think9m
Plan9m
Build14m
Verify5m
Assertion ledger
13 claims, each independently verified. Showing 8 — show all →
| ID | Says | Matcher | |
|---|---|---|---|
| A001 | When two schema files exist in the same project, the scanner picks the one with more data models | verified | ok |
| A002 | The scanner identifies the correct file path when multiple schema candidates compete | verified | ok |
| A003 | Dual schema candidates are both considered — the weaker one doesn't block the stronger | verified | ok |
| A004 | A multi-file Prisma schema without a traditional anchor file is still detected | verified | ok |
| A005 | Model counting works across multiple schema files in a directory | verified | ok |
| A006 | The database provider is detected even in a multi-file schema layout | verified | ok |
| A007 | No false alarm fires when a multi-file schema is successfully detected | verified | ok |
| A008 | The database provider is found even when it lives in a supporting file, not the main schema | verified | ok |
Findings 5 total
riskpackages/cli/src/engine/scan-engine.ts→ closed
First-provider-wins with no conflict detection: `scan-engine.ts:313` and `scan-engine.ts:337` — both directory and sibling handlers use `if (!provider)` to take the first datasource block found. If a `.prisma` directory contains conflicting provider declarations (theoretically invalid Prisma, but possible in a broken project), the scanner silently picks whichever file `readdir` returns first. File system ordering is non-deterministic on some platforms. Acceptable because Prisma itself rejects multiple datasource blocks, but the scanner's behavior would be platform-dependent on malformed input.
obspackages/cli/src/engine/census.ts→ closed
Census directory check is non-recursive: `census.ts:219` — `readdirSync(prismaDir)` only checks top-level entries. The second fallback glob `/prisma/*.prisma` in `scan-engine.ts:289` is also one level deep. A `prisma/subdir/models.prisma` layout would be missed by both paths. No known Prisma project uses nested subdirectories within the Prisma folder, but this is a documented gap.
obspackages/cli/tests/engine/scanProject.test.ts→ closed
SQL-only edge case tests indirect path: `scanProject.test.ts:210` — The test creates `prisma/migrations/001_init.sql`. Census's `readdirSync('prisma/')` sees `['migrations']` — a directory name, not a `.sql` file. The test passes because no direct `.prisma` files exist in `prisma/`, not because it explicitly filters `.sql` files. A more direct test would place `.sql` files directly in `prisma/` (e.g., `prisma/seed.sql`). The current test still validates the contract (A010, A011) correctly, but tests the directory-name-filter path, not the extension-filter path.
debtpackages/cli/tests/engine/scanProject.test.ts→ closed
A009 uses weak matcher when specific value is known: `scanProject.test.ts:199` — `toBeGreaterThan(0)` when the test fixture has exactly 2 models. The contract specifies `greater: 0`, so the test matches the contract. But `toBe(2)` would catch regressions that `toBeGreaterThan(0)` wouldn't (e.g., if sibling counting broke and only returned 1 model).
obs→ closed
A002 uses `contains` matcher, allows ambiguous match: Contract A002 says `target: schemas.prisma.path, matcher: contains, value: "schema.prisma"`. Both candidates (`prisma/schema.prisma` and `schema.prisma`) contain `"schema.prisma"`. The test passes regardless of which candidate wins — it can't distinguish them. The modelCount assertion (A001) indirectly proves the right candidate won, but A002 alone doesn't verify path correctness. A more precise value like `"prisma/schema.prisma"` would be unambiguous.
Integrity seal
scopesha256:2ef27097fdc2c...
contractsha256:a57a2d44cb2d1...
plansha256:6f4b7eb636d25...
specsha256:792be65bc3b49...
build-reportsha256:a43dffe54a336...
verify-reportsha256:fe777fda9bb27...
audit cmd$ ana proof audit fix-prisma-schema-detection → all hashes match