Skip to content
Merged
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This directory contains the primary documentation for the repository.
- [Integer representation types](./reference/integer-representation-types.md) — choosing `BigInt`, `BigIntNumber`, or `UnboundedInt` by target, storage, application value, and aggregate behavior
- [Aggregate descriptor guide](./reference/aggregate-descriptor-guide.md) — how a target or extension declares aggregate operations and their result codecs (`SqlAggregateDescriptor` on `types.aggregateDescriptors`)
- [PSL editor tooling for tagged literal defaults](./reference/psl-editor-tooling-tagged-literals.md) — what the language server, formatter and highlighting need for `` sql`...` `` and `` json`...` `` defaults, and what is not done yet
- [TypeScript module settings for Prisma 8 projects](./reference/typescript-module-settings.md) — the `tsconfig.json` settings a Prisma 8 project needs, which fit which kind of project, and what `prisma orm init` writes
- [Naming model and result types](./reference/model-and-result-types.md) — `Models`, `Scalars`, `Shape`, and `ResultType` on ORM queries
- [Mongo Pipeline Builder](./reference/Mongo%20Pipeline%20Builder.md) — typed builder for MongoDB aggregation pipelines, reads, writes, and find-and-modify
- [`migration graph --tree` rendering](./reference/migration-graph-rendering.md) — condensed annotated-tree rendering for offline migration topology
Expand Down
35 changes: 35 additions & 0 deletions docs/reference/typescript-module-settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# TypeScript module settings for Prisma 8 projects

Which `tsconfig.json` settings a Prisma 8 project needs, which ones work for which kind of project, and what `prisma orm init` writes. Guides that show a tsconfig for a Prisma 8 project, including the Prisma ORM 7 to 8 upgrade guides, should follow this page.

## What Prisma 8 requires

- **An ESM-capable `module` setting.** The `@prisma/orm-*` packages ship ES modules only; every export is an `.mjs` file.
- **`resolveJsonModule: true`.** The scaffolded `db.ts` imports the emitted `contract.json`.
- **The import attribute, where the file is an ES module.** `db.ts` imports the contract with `with { type: 'json' }`. TypeScript accepts that attribute only when `module` is `esnext`, `node18`, `node20`, `nodenext`, or `preserve`, and only from TypeScript 5.3.
- **The emitted declarations in `include`,** so `contract.d.ts` is part of the program.

Prisma 8 does not require `NodeNext`. Under `"module": "NodeNext"` with `"type": "module"` in `package.json`, TypeScript requires a `.js` extension on every relative import, because Node's ESM loader requires one at runtime. That is Node's rule, and it only matters to projects that compile with `tsc` and run the output with plain `node`.

## Which settings to use

| Project | Settings | Notes |
| --- | --- | --- |
| Already on an ESM-capable `module` | Keep it; add `resolveJsonModule` and the `include` entry | Nothing else changes. |
| CommonJS, staying CommonJS | `"module": "nodenext"` and `resolveJsonModule`; `db.ts` imports the JSON without the `with { type: "json" }` attribute | No `"type": "module"`, no `.js` extensions, no import attribute. The attribute-free import works only because `nodenext` emits `db.ts` as CommonJS here; a file emitted as an ES module needs the attribute. |
| Running through `tsx`, `vite`, `next`, `esbuild`, or another bundler | `"module": "preserve"`, `"moduleResolution": "bundler"`, `resolveJsonModule` | Accepts extensionless imports and the import attribute. Needs TypeScript 5.4 or later, the release that added `preserve`. This is what `prisma orm init` writes. |
| Compiled with `tsc` and run with plain `node` as ES modules | `"module": "NodeNext"` | Every relative import needs its `.js` extension. |

## What `prisma orm init` writes

- It merges `module: 'preserve'`, `moduleResolution: 'bundler'`, and `resolveJsonModule: true` into an existing `tsconfig.json`, and adds `node` to `compilerOptions.types` while keeping the entries already there, so `process.env` typechecks in a project with an explicit `types` list (`packages/1-framework/3-tooling/cli/src/commands/init/templates/tsconfig.ts`). It does this whatever the project's current `module` setting is, and reports only that it updated the file.
- It scaffolds `db.ts` with the `with { type: 'json' }` import (`templates/code-templates.ts`).
- When `package.json` declares a `"type"` other than `"module"`, it keeps the user's value and warns that `db.ts` will not load under it (`commands/init/hygiene-package-scripts.ts`). For a CommonJS project, the attribute-free import from the table above would load, because the file runs as CommonJS; Node requires the attribute when the file runs as an ES module.

## How the CommonJS option was verified

Tested on Node 24.13 with TypeScript 5.9.3 against the workspace build:

- At runtime, a plain `.cjs` file can `require("./contract.json")` and `require("@prisma/orm-postgres/runtime")`, and `postgres({ contractJson, url })` constructs the client. Node's `require(esm)` loads the ESM-only package because it has no top-level `await`.
- For types, a `.cts` file, or a `.ts` file in a package without `"type": "module"`, that imports `@prisma/orm-postgres/runtime` and `./contract.json` typechecks under `"module": "nodenext"` with no import attribute and no `.js` extensions.
- `"module": "node16"` rejects the same file with TS1479, and `"moduleResolution": "node10"` cannot resolve the package at all.
34 changes: 34 additions & 0 deletions drive/calibration/failure-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -644,3 +644,37 @@ Per-repo stop conditions beyond the canonical ones:
- An implementer's claim "predates this dispatch" about a journey is verified by the reviewer with `git log -1 origin/main -- <file>` and by asking whether `dist` was rebuilt after the last source change.

**Reference incident.** remove-dbgenerated slice C dispatch 1 (2026-09-22): `infer-roundtrip-fidelity.prisma7-defaults` failed on a stale `family-sql` dist; the reviewer accepted the "red on main" claim in round 1 and corrected it in dispatch 3 after the implementer rebuilt the package.

### F32. A brief restates an operator ruling in its own words, and the restatement is stricter than the ruling

**Symptom.** An implementer builds work, or asks the operator a round of questions, on a premise the operator never held. The operator's answer to the first question is "this is wrong", and every question built on the premise has to be asked again.

**Detection signal.**

- The brief or design notes state a ruling as a rule ("init must be target-agnostic") without the operator's words, date, or context.
- Several open questions in the brief depend on that one rule.
- The rule forbids something the codebase already does in many places, and the brief treats those places as debt to remove.

**Mitigation.**

- Record a ruling as a quote, with speaker and date, and write the interpretation separately under it.
- In the first question round, restate the interpretation in one sentence and ask the operator to confirm it before asking any question that depends on it.

**Reference incident.** orm-init-prisma7-detection (2026-09-23): the ruling "Our init command cannot be target specific" was recorded as "init must be target-agnostic". The brief planned to stop choosing the target from the Prisma 7 schema's provider and asked whether to remove 17 existing target branches. Will's intent was narrower: init must not be coupled to one database, and choosing among known targets is fine.

### F33. A test double returns what the real dependency never returns, so the test covers a path production cannot reach

**Symptom.** A test passes, and the behaviour it names never happens for a user. The fake that drives the test answers with a value or outcome the real implementation cannot produce.

**Detection signal.**

- A fake implements an interface whose real implementation lives in another package (for example `PromptSurface` from `@prisma/cli-engine`).
- The fake's return values were chosen for the test's convenience, not read from the real implementation.
- A reviewer asks "can the real surface return this?" and nobody has checked.

**Mitigation.**

- When writing a fake for another package's surface, read the real implementation and make the fake return and throw exactly what it does. When the behaviour depends on the real surface's outcomes, drive it through that package's own test harness (for the CLI engine, `createTestCli` with scripted `answers`).
- The reviewer checks each fake's possible outcomes against the real implementation, not only the code under test.

**Reference incident.** prisma/orm#30291 (2026-09-24): a scripted prompt returned `false` from `consent`, and a test showed that a declined consent printed the command to remove packages init had installed. The engine's `consent` with a token never returns `false`: it returns `true` or throws `CLI.CONSENT_REQUIRED`, a token mismatch, or `CLI.PROMPT_CANCELLED`. Real users never saw the command. An independent review found it; the fix attached the command to whatever error follows the install.
1 change: 1 addition & 0 deletions drive/project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ A stacked PR is justified only when its base PR is independently valuable to mer
- Linear Project status: update at slice-merge (`drive-deliver-workflow` does this implicitly via `drive-check-health`).
- Wider-team comms: optional, operator-set. Use `drive-post-update` for the cadence the project needs.
- Cross-team dependencies: surface in the project plan's `Dependencies` section; ping owners explicitly when a dependency is blocking.
- Release dependencies: when users get a feature only through a package release, the plan's `Dependencies` section names that release (package, version, and whether it is published yet), so the plan says when users can use the feature, not only when it merges. (Added 2026-09-24, orm-init-prisma7-detection final retro: the Prisma 7 path of `orm init` merged while the published `@prisma/orm-postgres` still predated the Prisma 7 contract source it needs.)

## ADR cadence

Expand Down
2 changes: 2 additions & 0 deletions drive/qa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Manual QA reads:

A clean pre-QA tree means `pnpm typecheck && pnpm test:packages && pnpm fixtures:check` all green. QA against an unverified tree wastes the runner's time discovering broken assertions that a 1-minute `pnpm test:packages` would have surfaced.

When the QA project installs published builds made from `main` (for example a package's `dev` dist-tag), merge the current `origin/main` into the branch, rebuild every workspace package the run executes (`pnpm build`, or `pnpm --filter <package> build` for each one), and run the rebuilt binary, not one installed earlier. A branch that is behind `main`, run against packages built from a later `main`, fails in ways neither side fails alone. (Added 2026-09-24: a Prisma 7 schema check on a branch based on a week-old `main` refused `@default(false)`, because the branch's CLI lacked a lookup the `dev` target package expected. The same run on the merged branch passed.)

## Sample coherence, not just placement, for content-preamble dispatches

Symptom seen during the drive trial (project `orchestrator-role`): a dispatch added a uniform delegated-execution preamble across 19 atomic skills. Manual-QA dry-run sampled preamble placement (right line, right format, cross-link resolves) — found nothing wrong. Reviewer (CodeRabbit) then surfaced three "critical" findings on stop-condition coherence: the preamble's "STOP. Dispatch on Read/Grep/Glob" rule contradicted skill bodies whose Step 2 explicitly required Read/Grep/Glob investigation as the default first step.
Expand Down
1 change: 1 addition & 0 deletions drive/retro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ When a retro lesson could land in multiple surfaces, the team's preference:

Patterns the team has seen multiple times. Each entry: pattern → severity → mitigation surface (where it landed).

- **2026-09-24 — Final orm-init-prisma7-detection retro:** Record an operator ruling as a quote and confirm its interpretation before asking questions that depend on it (F32). Make a test fake return only what the real surface returns (F33). A spec for a command that edits user files names the project's state after each failure; a plan names the release that ships each dependency to users. Merge `main` before manual QA against published builds made from `main`. Manual QA on a real project and an independent review found five bugs the tests missed.
- **2026-09-23 — Final remove-dbgenerated retro:** A design that the operator has not settled is not implemented on an assumption; slice B's first PR built codec methods that took PSL text, was withdrawn after review, and was rebuilt on ADR 254 with one blocked decision named in the brief and asked before the code that depended on it. Name every unsettled decision in the brief as a stop, and write the answer into the slice spec before re-delegating. Also: order regeneration of committed generated artefacts before the deletion of the form they use (F30), and rebuild `dist` before trusting a journey failure (F31).
- **2026-09-15 — Final editor-project retro:** Editor acceptance must verify the rendered editor, not just HTTP or LSP transport. Record invocation and acceptance separately; verify the applied edit, caret, and visible follow-up suggestions, including required client opt-ins.

Expand Down
1 change: 1 addition & 0 deletions drive/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ In addition to the canonical project-spec / slice-spec templates, this repo expe
- **Contract-impact section** for any spec that touches the contract surface (`packages/0-shared/contract/**`, `packages/1-framework-core/**`). Names the contract entities affected, the new / changed kinds, the migration plan for downstream consumers.
- **Adapter-impact section** for any spec that affects target adapters (`packages/3-targets/**`). Names which adapters are affected (postgres / sqlite / mongo / etc.).
- **ADR pointer** for any architectural shift. Either link an existing ADR or commit to authoring one as part of the project's close-out.
- **Failure-state section** for any spec of a command that edits files it did not write. For each way the command can fail after it starts, name the state the user's project is left in, and require that a failure the command can predict is reported before the first edit. (Added 2026-09-24, orm-init-prisma7-detection final retro: `orm init` renamed the Prisma 7 config and rewrote scripts before finding out Prisma 8 could not read the schema, and the problem surfaced only in manual review after five dispatches.)

## Grounding illustrative snippets before execution

Expand Down
11 changes: 10 additions & 1 deletion packages/1-framework/3-tooling/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,21 @@ Before any consent question or file change, init checks that Prisma 8 can read t

The second question is the consent token; `--confirm <dir>` answers it non-interactively. Under it init:

- renames the Prisma 7 config to `prisma7.config.<same extension>` and points its `prisma/config` import at `@prisma/prisma7/config`;
- renames the Prisma 7 config to `prisma7.config.<same extension>` and points its `prisma/config` import at `@prisma/prisma7/config`; a config that does not import `prisma/config` is renamed with its imports unchanged, and init warns that any other import of the Prisma 7 config helper must be pointed at `@prisma/prisma7/config` by hand;
- rewrites every `package.json` script that invokes `prisma` to invoke `prisma7` (scripts init adds keep `prisma`);
- installs `@prisma/prisma7@7` as a development dependency alongside `prisma@latest`, and `@prisma/client@7` when the project declares a client below the 7 line.

It then writes `prisma.config.ts` with `contract: prisma7Schema("<schema path>")` and `output: "src/prisma"`, `src/prisma/db.ts`, and a `prisma-8.md` that describes the transition loop; no starter schema is written and `prisma/` stays byte-identical. The next steps are the transition routine: set `DATABASE_URL`, `prisma db sign`, move routes one at a time, and re-run `prisma contract emit` then `prisma db sign` after each `prisma7 migrate dev`.

**Design constraints on the Prisma 7 path:**

- There is no separate upgrade command. Init already installs, scaffolds, and emits. A command that automated the whole upgrade guide could not find its inputs reliably in arbitrary projects (computed config values, multi-file schemas, monorepos, CI files that call `prisma migrate`), and the Prisma 7 contract source removes the need for a schema converter.
- From a Prisma 7 config init reads only `schema`. The new config connects with `process.env['DATABASE_URL']!`: copying the Prisma 7 `datasource.url` expression would need a TypeScript rewrite of user code, and matching its resolved value back to an environment variable assumes the URL came from one.
- Init's files go under `src/prisma/`, where a fresh init puts them, so an upgraded project is shaped like a new one. `prisma/` belongs to Prisma 7.
- The Prisma 7-specific edits (renaming the config, changing its import, rewriting scripts that call `prisma`, moving the Prisma 7 packages) all happen under one consent; the file merges a fresh init makes happen as usual. Renaming the config alone would leave scripts calling a `prisma` binary that is now Prisma 8, and `@prisma/client` moves with the Prisma 7 CLI because Prisma 7 requires both at the same version.
- `package.json#type` and `tsconfig.json` are handled as on a fresh init; see [TypeScript module settings for Prisma 8 projects](../../../../docs/reference/typescript-module-settings.md).
- There is no cutover step. The next steps list only what the user runs right after init.

**Exit codes:**
- `0`: set up (and, unless skipped, installed and emitted)
- `2`: precondition — an invalid flag, a refusal on the Prisma 7 path (`CLI.INIT_FLAG_CONFLICT`, `CLI.INIT_PRISMA7_SCHEMA_INVALID`, `CLI.INIT_PRISMA7_CONFIG_COLLISION`, `CLI.INIT_PRISMA7_CONFIG_UNREADABLE`, `CLI.INIT_PRISMA7_TARGET_MISMATCH`, `CLI.INIT_PRISMA7_PROVIDER_UNSUPPORTED`, `CLI.INIT_PRISMA7_SCHEMA_REFUSED`, `CLI.INIT_PRISMA7_SOURCE_UNAVAILABLE`), a consent not granted, or a write that failed; nothing is written before a refusal, and the schema check's install is the only change before one
Expand Down
Loading
Loading