zanith

Know before you swap

The doctor scans your codebase and reports exactly which Prisma constructs the compat layer doesn't translate — file and line, before you change anything. Ten seconds of scanning replaces a week of surprises.

Run it

SHELLterminal
zanith compat scan ./src
 
# machine-readable, and a CI gate that fails on unsupported findings:
zanith compat scan ./src --json
zanith compat scan ./src --strict

The scan walks your tree (skipping node_modules, dist, build output), counts every Prisma model-method call site, and matches the remainder against the compat layer's refusal vocabulary. Findings carry two severities:

SeverityMeaning
unsupportedWill throw ZanithCompatError at runtime — a named, deliberate refusal.
reviewHeuristic match that usually means an untranslated construct, but wants a human glance (could be a same-named field).
TXTsample output
Scanned 412 file(s) under ./src
Prisma call sites seen: 1,387 (the call surface itself is translated)
 
Findings: 2 unsupported (throw at runtime), 3 to review (heuristic match)
 
$transaction isolationLevel 1 site(s)
src/payments/ledger.ts:84 await prisma.$transaction(fn, { isolationLevel: 'Serializable' });
 
JSON path filter 1 site(s)
src/search/contracts.ts:31 where: { core_data: { path: ['health'], equals: 'red' } }
 
? nested write "set" (replace memberships) 3 site(s)
src/teams/sync.ts:112 data: { members: { set: [] } }
and 2 more
 
This is a heuristic text scan "review" findings may be same-named fields.
Runtime behavior is the contract: untranslated constructs throw ZanithCompatError, never approximate.

The rule that keeps it honest

The doctor's marker list mirrors the runtime's refusal list, with a standing rule: when the compat layer learns a construct, its marker is deleted in the same commit. The doctor must never claim less than the runtime delivers. Three markers have already died this way — case-insensitive mode, array filters, and many-to-many writes all graduated from "flagged" to "translated".

The adoption loop

The intended workflow, end to end:

TSfour steps, each reversible
# 1. Measure zero changes, zero risk
zanith compat scan ./src
 
# 2. If clean (most codebases are): swap db.ts on a branch
# new PrismaClient(...) new ZanithPrismaClient({ adapter })
 
# 3. Run YOUR test suite. Every divergence is either a named
# ZanithCompatError or a bug we want to hear about.
 
# 4. Ship or revert one file and walk away. Both are fine.

Findings that block you go on the roadmap as named line items — several constructs were built precisely because scans of real codebases said they'd be hit. A request that lands on an existing line item is a vote, not a discovery.