From 3cdd07d18b8f8d434ac820a7772313b1e2c3d916 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 14:37:10 +0200 Subject: [PATCH 01/28] docs: add the Prisma ORM 8 docs audit and restructure proposal Personas, reader journeys, the mental model, the proposed information architecture, the change list, the naming rule, the corrections slice plan, two ORM briefs, and the page-by-page audit findings behind #8236, #8237, and #8238. Shared for discussion; not site content. Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/README.md | 17 ++ docs/orm-docs-audit/audit/AREAS.md | 24 ++ docs/orm-docs-audit/audit/INSTRUCTIONS.md | 74 +++++++ docs/orm-docs-audit/audit/builders.md | 70 ++++++ docs/orm-docs-audit/audit/contract.md | 60 +++++ docs/orm-docs-audit/audit/extras.md | 112 ++++++++++ docs/orm-docs-audit/audit/gaps.md | 66 ++++++ docs/orm-docs-audit/audit/migrations-cli.md | 66 ++++++ docs/orm-docs-audit/audit/orm-client.md | 63 ++++++ docs/orm-docs-audit/audit/start-guides.md | 60 +++++ .../brief-db-ref-on-adoption.md | 53 +++++ docs/orm-docs-audit/brief-skills-opt-out.md | 47 ++++ docs/orm-docs-audit/changes.md | 205 ++++++++++++++++++ docs/orm-docs-audit/ia.md | 178 +++++++++++++++ docs/orm-docs-audit/journeys.md | 147 +++++++++++++ docs/orm-docs-audit/mental-model.md | 112 ++++++++++ docs/orm-docs-audit/naming.md | 37 ++++ docs/orm-docs-audit/personas.md | 33 +++ docs/orm-docs-audit/slice-corrections.md | 83 +++++++ 19 files changed, 1507 insertions(+) create mode 100644 docs/orm-docs-audit/README.md create mode 100644 docs/orm-docs-audit/audit/AREAS.md create mode 100644 docs/orm-docs-audit/audit/INSTRUCTIONS.md create mode 100644 docs/orm-docs-audit/audit/builders.md create mode 100644 docs/orm-docs-audit/audit/contract.md create mode 100644 docs/orm-docs-audit/audit/extras.md create mode 100644 docs/orm-docs-audit/audit/gaps.md create mode 100644 docs/orm-docs-audit/audit/migrations-cli.md create mode 100644 docs/orm-docs-audit/audit/orm-client.md create mode 100644 docs/orm-docs-audit/audit/start-guides.md create mode 100644 docs/orm-docs-audit/brief-db-ref-on-adoption.md create mode 100644 docs/orm-docs-audit/brief-skills-opt-out.md create mode 100644 docs/orm-docs-audit/changes.md create mode 100644 docs/orm-docs-audit/ia.md create mode 100644 docs/orm-docs-audit/journeys.md create mode 100644 docs/orm-docs-audit/mental-model.md create mode 100644 docs/orm-docs-audit/naming.md create mode 100644 docs/orm-docs-audit/personas.md create mode 100644 docs/orm-docs-audit/slice-corrections.md diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md new file mode 100644 index 0000000000..792005a9d2 --- /dev/null +++ b/docs/orm-docs-audit/README.md @@ -0,0 +1,17 @@ +# Prisma ORM 8 docs audit + +Working documents behind the Prisma ORM 8 docs corrections (prisma/web #8236, #8237, #8238) and the proposed restructure. Written September 2026 against `@prisma/orm-postgres@8.0.0-rc.9`; source paths refer to the prisma/orm monorepo at that tag (`packages/`, `docs/releases/`, `examples/`, `skills/prisma-8/`) and to prisma/create-prisma. Site paths are relative to `apps/docs/content/docs/`. + +Read in this order: + +1. `personas.md` — who reads the ORM docs: the Newcomer, the Upgrader, the Builder, the Agent. +2. `journeys.md` — ten jobs those readers come to do, with an entry point, a done criterion, the path through today's pages, and a verdict. +3. `mental-model.md` — the standalone explanation of Prisma ORM 8 (contract, emit, signature, plans, migrations and refs) that pages get written from. +4. `ia.md` — the proposed sidebar trees and `/orm` page structure, then the current state and the reasons. +5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B, shipped), new pages (C), ORM changes (D). Leads with the suggested order. +6. `naming.md` — the "Prisma ORM" naming rule. +7. `slice-corrections.md` — how the shipped corrections were sliced, and the decisions taken. +8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md` — two ORM changes handed to other agents. +9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. + +Prose is a draft throughout; the structure and the cited facts are what has been verified. diff --git a/docs/orm-docs-audit/audit/AREAS.md b/docs/orm-docs-audit/audit/AREAS.md new file mode 100644 index 0000000000..361243012b --- /dev/null +++ b/docs/orm-docs-audit/audit/AREAS.md @@ -0,0 +1,24 @@ +# Audit areas and page lists + +Site paths are relative to `apps/docs/content/docs/`. + +## orm-client +orm/index.mdx, orm/core-concepts.mdx, orm/fundamentals/{reading-data,writing-data,relations-and-joins,advanced-queries,transactions}.mdx, orm/reference/{index,orm-client,transactions-and-runtime,error-reference}.mdx + +## builders +orm/reference/{sql-query-builder,pipeline-builder,raw-queries}.mdx, orm/extensions/using-extensions.mdx, orm/middleware/{how-middleware-works,authoring-custom-middleware,built-in-lints,built-in-budgets,built-in-cache}.mdx + +## contract +orm/contract-authoring/{the-data-contract,the-contract-artifact,psl-syntax,typescript-schema-builder,capabilities}.mdx, orm/data-modeling/{index,relational-databases,mongodb}.mdx, cli/{contract-emit,contract-infer}.mdx + +## migrations-cli +orm/migrations/*.mdx (6), cli/{index,global-flags,configuration,error-reference,init,orm-init,skills,dev,git}.mdx, cli/db-{init,update,migrate,sign,verify,schema}.mdx, cli/migration-{new,plan,ref,show,status}.mdx. Platform commands (auth, branch, bucket, deploy, feedback, postgres, project, service, telemetry) out of scope. + +## start-guides +(index)/{index,getting-started}.mdx, (index)/prisma-orm/{index,create-prisma}.mdx, (index)/prisma-orm/quickstart/{postgresql,mongodb}.mdx, (index)/prisma-orm/add-to-existing-project/{postgresql,mongodb}.mdx, (index)/prisma-postgres/quickstart/prisma-orm.mdx, guides/index.mdx, guides/upgrade-prisma-orm/{postgresql,mongodb}.mdx, guides/switch-to-prisma-orm/*.mdx (3), guides/database/*.mdx (3) + +## gaps +Part 1: guides/frameworks/*.mdx (10), guides/deployment/*.mdx (6), guides/runtimes/*.mdx (2), guides/integrations/{github-actions,vercel-deployment,ai-sdk}.mdx. Part 2: reverse audit of skills/prisma-8/ and docs/glossary.md and the public export maps against the whole ORM 8 site. + +## extras +(index)/full-stack-tutorial.mdx, ai/tools/skills.mdx, cli/telemetry.mdx, plus the targeted gap questions from the first session's gaps brief (RLS, expression indexes, Postgres extensions, JSON filtering, Decimal, SQLite, Vite plugin, @@control, soft delete, read replicas, await using, streaming, native provider, docs/reference/*, extension packages). diff --git a/docs/orm-docs-audit/audit/INSTRUCTIONS.md b/docs/orm-docs-audit/audit/INSTRUCTIONS.md new file mode 100644 index 0000000000..fa0b1f3f92 --- /dev/null +++ b/docs/orm-docs-audit/audit/INSTRUCTIONS.md @@ -0,0 +1,74 @@ +# Audit instructions (shared by every area agent) + +You are auditing the Prisma ORM docs site against the Prisma 8 monorepo at rc.9. The goal is a list of things on the site that are wrong, out of date, or missing, with evidence. + +## Where things are + +Work only inside the docs worktree. Do not edit any file except your own output file. Put scratch files in `wip/docs-audit/audit/scratch-/`. + +- Docs site source: `apps/docs/content/docs/` (this worktree is the `prisma/web` repo). Cite site paths relative to that directory, for example `orm/fundamentals/reading-data.mdx:42`. Prisma ORM 8 pages are under `orm/` (not `orm/v6`, `orm/v7`), `(index)/prisma-orm/`, `(index)/getting-started.mdx`, `cli/` (not `cli/v7`), and the ORM parts of `guides/`. +- The monorepo (the truth) is checked out at rc.9 under `wip/prisma-src/`. Inside it: `packages/` for source, `docs/releases/v8.0.0-rc.*.md` and `docs/releases/v0.1[5-7].0.md` for what changed and when, `docs/glossary.md` for terms, `skills/prisma-8/` for the shipped agent skill (`SKILL.md` plus `references/*.md`). The skill is well maintained and a good second source, but it uses `@internal/*` import paths that users must read as `@prisma/orm-postgres/*`; do not report that, it is known. +- The public package: `packages/9-public/@prisma/orm-postgres/package.json` lists the real export paths users import. +- create-prisma source (what the scaffold generates): `wip/create-prisma-src/`. +- Worked examples that compile against rc.9: `wip/prisma-src/examples/`. + +## How to work + +- Read every page in your area in full. Do not skim headings. +- For every API name, method, flag, command, config key, file path, import path, type name, and error code on a page, check it exists in the source with that name and shape. Grep `packages/` and `skills/prisma-8/references/`. Check `docs/releases/` for renames. +- For every code sample, ask: would this typecheck and run on rc.9? You do not need to run it, but you must be able to point at the source that says yes or no. +- Verify before reporting. A finding must cite a file in the monorepo or a release note. If you cannot find evidence either way, report it under "Unverified" with what you looked for. +- Also look the other way: what does the source or skill support in your area that the site never mentions? Report those under "Missing". +- The product is called "Prisma ORM"; do not report pages that say "Prisma 8", that is a known site-wide naming issue. +- Do not report the items already known (list below). Do not report prose style, tone, or the "written for AI" complaint. Do not report `@internal/*` in the skill. + +## Already known, do not re-report + +- `.take()`/`.skip()` should be `.limit()`/`.offset()` (renamed rc.7). +- `createCount`/`updateCount`/`deleteCount` should be `createAndCount` etc. (renamed 0.17). +- The existing-project PostgreSQL page uses `db.orm.User` and `db.sql.user` instead of `db.orm.public.User` / `db.sql.public.user`. +- `@db.*` attributes were removed in 0.17; `psl-syntax.mdx` still shows `String @db.Uuid`. +- `orm/index.mdx` says SQLite is planned; it ships as `@prisma/orm-sqlite`. +- The upgrade guide is pinned to rc.6 / rc.4. +- `db sign` does not set the `db` ref, so `migration plan` after adoption plans from empty. +- No page covers: a Prisma 7 to 8 API mapping, model/result types (`Models`, `Shape<>`, in open PRs), `createMany`/`skipDuplicates`, `firstOrThrow`, atomic increment, case-insensitive filters, editor setup, RLS outside Supabase, functional indexes, pg_trgm, money/Decimal, the skills opt-out on getting-started pages, the npm `latest` tag / release status. +- `DATABASE_URL` from `.env` vs the environment is inconsistent across getting-started pages; `db.connect()` vs `db.runtime()` is used interchangeably; `db.ts` is imported but never shown on getting-started pages; Node version claims differ. + +## Output + +Write your findings to `wip/docs-audit/audit/.md` (the area name is given in your prompt). Use exactly this structure. Markdown, no hard-wrapped lines, plain English, no invented jargon. + +``` +# Audit: + +Pages read: + +## Breaks copy-paste +Things a user copies that fail: wrong name, removed API, wrong flag, wrong path, wrong import. + +- `:` — — evidence: `` + +## Misleading +True-ish statements that lead the user wrong: stale defaults, changed behaviour, wrong claims about what is supported. + +- (same format) + +## Missing +Things the source or skill supports in this area that the site never mentions, or that a user in this area would need and cannot find. + +- — evidence it exists: `` — where on the site it belongs + +## Unverified +Things that looked wrong but you could not confirm either way. + +- `:` — + +## Skill vs site +Places where the shipped skill (`skills/prisma-8/references/`) and the site disagree, beyond the items above. Say which one matches the source. + +- (same format) +``` + +Keep each bullet to the facts. Line numbers are from the site file. When one defect repeats across many lines, give the count and the first line, not every line. + +When finished, return a two-paragraph summary: how many findings in each section, and the three most serious. diff --git a/docs/orm-docs-audit/audit/builders.md b/docs/orm-docs-audit/audit/builders.md new file mode 100644 index 0000000000..f5f76a774e --- /dev/null +++ b/docs/orm-docs-audit/audit/builders.md @@ -0,0 +1,70 @@ +# Audit: builders + +Pages read: `orm/reference/sql-query-builder.mdx`, `orm/reference/pipeline-builder.mdx`, `orm/reference/raw-queries.mdx`, `orm/extensions/using-extensions.mdx`, `orm/middleware/how-middleware-works.mdx`, `orm/middleware/authoring-custom-middleware.mdx`, `orm/middleware/built-in-lints.mdx`, `orm/middleware/built-in-budgets.mdx`, `orm/middleware/built-in-cache.mdx` + +## Breaks copy-paste + +- `orm/reference/sql-query-builder.mdx:147` (and about 30 more on this page: 218, 230, 244, 278, 308, 330, 375, 405, 415, 425, 444, 480, 512, 545, 620, 632, 667, 689, 690, 711, 788, 821, 833, 857, 897, 947, 956, 981, 1003) — `const rows = await runtime.execute(plan)` reads rows from `execute()` — since rc.2 `runtime.execute(plan)` resolves `Promise` (`{ affectedRows }`); rows come from `runtime.query(plan)`, which returns `AsyncIterableResult`. Every row-returning example on the page is wrong at the type level and at runtime — evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `docs/releases/v8.0.0-rc.2.md` ("Runtime row queries and non-returning writes are separate calls"), `examples/prisma-8-demo/src/queries/get-users.ts:5`. +- `orm/reference/sql-query-builder.mdx:977-981` — "Run a plan with `runtime.execute(plan)` … It resolves to an array of rows (`Row[]`)" — `execute()` is the non-returning write call; `query()` is the row call, and it resolves to `AsyncIterableResult` (awaitable to an array, or `for await`) — evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`. +- `orm/reference/raw-queries.mdx:42` (also 57, 74, 90, 112, 126) — `const rows = await runtime.execute(plan)` — same defect; must be `runtime.query(plan)` — evidence: as above, plus `examples/prisma-8-demo/src/queries/raw-sql-demo.ts:36`. +- `orm/extensions/using-extensions.mdx:86` — `await db.runtime().execute(plan)` for a similarity search — the demo this is copied from uses `db.runtime().query(plan)` — evidence: `examples/prisma-8-demo/src/queries/similarity-search.ts:14`. +- `orm/middleware/built-in-cache.mdx:49` — `const users = await db.runtime().execute(plan)` — must be `.query(plan)`; the cache middleware only acts on the query lifecycle (`interceptQuery`), so a cached read through `execute()` would neither return rows nor be cached — evidence: `examples/prisma-8-demo/src/queries/get-users-cached.ts:26`, `packages/3-extensions/middleware-cache/src/cache-middleware.ts:238-243`. +- `orm/reference/pipeline-builder.mdx:117` (and about 50 more on this page, every `db.execute(plan)`), `orm/reference/pipeline-builder.mdx:122-126` — "`db.execute(plan)` is the client-level executor" — the Mongo client has no `execute` method; its surface is `orm`, `query`, `raw`, `contract`, `enums`, `context`, `connect()`, `runtime()`, `close()`. Plans run through `(await db.runtime()).query(plan)`; note `runtime()` returns a Promise on Mongo. The rc.2 note says explicitly "the row-executing `db.execute` facade method is gone" — evidence: `packages/3-extensions/mongo/src/runtime/mongo.ts:28-39`, `docs/releases/v8.0.0-rc.2.md`, `examples/mongo-demo/test/query-builder-writes.test.ts:57`. +- `orm/reference/pipeline-builder.mdx:126` — "`runtime.execute(plan)` is the equivalent lower-level call" — on Mongo `runtime.execute()` also returns `Promise`; the row call is `runtime.query()` — evidence: `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-99`. +- `orm/reference/raw-queries.mdx:146-147` (and every `db.execute(...)` in the MongoDB section: 167, 181, 191, 208, 221, 231, 235, 257-259, 271, 283) — `db.execute(plan)` — does not exist; see above. Write plans (`insertOne`, `deleteMany`, `findOneAndUpdate`) also run through `runtime.query(plan)` and yield their result envelope as the single row — evidence: `examples/mongo-demo/test/query-builder-writes.test.ts:50-60, 84-87`. +- `orm/reference/raw-queries.mdx:121` — ``db.raw`now()`.returns('pg/timestamptz@1')`` — `db.raw` is a lane object with one key; the tag is ``db.raw.sql`...` ``. Calling `db.raw` as a template tag throws — evidence: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:153-166` (`RawLane = { readonly sql: RawTagFor }`), `packages/3-extensions/postgres/src/runtime/postgres.ts:63` (`readonly raw: RawLane`), `examples/prisma-8-demo/src/queries/raw-query-demo.ts:35`. +- `orm/middleware/how-middleware-works.mdx:39-73`, `orm/middleware/authoring-custom-middleware.mdx:152-160` — "There are five hooks": `beforeCompile`, `beforeExecute`, `intercept`, `onRow`, `afterExecute` — there is no `intercept` hook. Since rc.2 the lifecycle is split by operation: row queries run `beforeCompile → beforeQuery → interceptQuery → onRow → afterQuery`; non-returning writes run `beforeCompile → beforeExecute → interceptExecute → afterExecute`. A middleware object with an `intercept` key is an excess-property type error and is never called — evidence: `packages/2-sql/5-runtime/src/middleware/sql-middleware.ts:28-128`, `docs/releases/v8.0.0-rc.2.md` ("Runtime middleware splits the same way, into `beforeQuery` / `interceptQuery` / `afterQuery` and `beforeExecute` / `interceptExecute` / `afterExecute` … There is no operation discriminator, compatibility alias, or generic fallback hook"). +- `orm/middleware/authoring-custom-middleware.mdx:31-46, 107-129` — the query logger implements only `afterExecute` and reads `result.rowCount` — `afterExecute` fires only for `runtime.execute()` (non-returning writes). Every ORM read, every ORM `create` (which returns rows), and every SQL-builder `query()` goes through `afterQuery`, so the logger as written never logs the two queries the page shows at lines 95-99. Also `AfterExecuteResult` has no `rowCount` field (it carries `stats.affectedRows`), so line 41 is a type error. The shipped equivalent uses `afterQuery` — evidence: `packages/1-framework/1-core/framework-components/src/execution/runtime-middleware.ts:114-126` (`AfterQueryResult.rowCount` vs `AfterExecuteResult.stats`), `packages/2-sql/5-runtime/src/middleware/sql-middleware.ts:88-128`, `examples/prisma-8-demo/src/prisma/slow-query-warning.ts:24`. +- `orm/middleware/authoring-custom-middleware.mdx:56-58, 157`, `orm/middleware/how-middleware-works.mdx:53-61` — `beforeExecute(plan)` as the place to validate or block a query — `beforeExecute` runs only on the execute (non-returning write) path. To block reads a middleware needs `beforeQuery`; the built-ins register the same function under both names — evidence: `packages/2-sql/5-runtime/src/middleware/lints.ts:176-181` (`beforeQuery: beforeOperation, beforeExecute: beforeOperation`), `packages/2-sql/5-runtime/src/middleware/budgets.ts:118-137`. +- `orm/middleware/built-in-lints.mdx:68` — "The options type also accepts `unindexedPredicate`" — `LintsOptions.severities` has exactly five keys (`selectStar`, `noLimit`, `deleteWithoutWhere`, `updateWithoutWhere`, `readOnlyMutation`); `unindexedPredicate` is an excess-property type error — evidence: `packages/2-sql/5-runtime/src/middleware/lints.ts:13-23`. + +## Misleading + +- `orm/reference/raw-queries.mdx:19` ("There is no way to run a bare raw SQL string on its own"), `orm/reference/raw-queries.mdx:130` ("`db.raw` is not a way to execute a standalone raw SQL statement") — whole-query raw SQL exists since rc.2: ``db.raw.sql`SELECT ...`.returnsRow({ col: 'pg/text@1', ... }).build()`` produces a plan for `runtime.query()`, and ``db.raw.sql`UPDATE ...`.affectedCount().build()`` produces one for `runtime.execute()`. Row-returning raw queries interpolate into other raw templates as subqueries and CTEs — evidence: `docs/releases/v8.0.0-rc.2.md` ("Whole-query raw SQL replaces the classic `$queryRaw` / `$executeRaw` use case"), `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:120-150`, `examples/prisma-8-demo/src/queries/raw-query-demo.ts`. +- `orm/reference/raw-queries.mdx:95`, `orm/reference/sql-query-builder.mdx:925` — "Bare-scalar interpolation is currently broken … the codec inferer emits unversioned codec ids (`pg/int4`)" — the Postgres raw codec inferer emits versioned ids (`pg/int4@1`, `pg/int8number@1`, `pg/float8@1`, `pg/int8@1`, `pg/text@1`, `pg/bool@1`, `pg/bytea@1`); the source comment says "The ids are versioned because that is how the codec registry keys them" — evidence: `packages/3-targets/6-adapters/postgres/src/core/adapter.ts:112-140`. +- `orm/reference/sql-query-builder.mdx:588-590, 621, 633, 668, 691-692` — "`COUNT()` … `SUM()` / `AVG()` over an integer column decode as JavaScript strings … Call `Number(...)`" — since rc.1 aggregates in both the ORM and the SQL builder resolve through the contract's `AggregateTypes`, and since rc.2 `count()`, integer `sum()`, and integer `avg()` return `number` (throwing `RUNTIME.DECODE_FAILED` outside the safe range); lossless `countBigInt()`, `sumBigInt()`, `avgDecimal()` sit beside them. The string-decoding advice describes pre-rc.1 behaviour — evidence: `docs/releases/v8.0.0-rc.1.md` ("`contract.d.ts` gains an `AggregateTypes` block that both the ORM and the SQL builder resolve result types from"), `docs/releases/v8.0.0-rc.2.md` ("The default aggregates are JavaScript numbers again"), `packages/2-sql/4-lanes/sql-builder/src/expression.ts:145-200`, `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:146-192`. +- `orm/middleware/built-in-budgets.mdx:46, 48` — "`severities.latency` … not read by the middleware in v0.14; latency behavior follows the runtime mode" — it is read: default is `'warn'`, and a latency overrun blocks when `severities.latency === 'error'` or the runtime is in strict mode — evidence: `packages/2-sql/5-runtime/src/middleware/budgets.ts:97, 113-125`. +- `orm/middleware/built-in-budgets.mdx:45, 48, 54, 74`, `orm/middleware/authoring-custom-middleware.mdx:203` — repeated references to "permissive mode" as a reachable state — the `postgres(...)` client never forwards a `mode`, so a Postgres runtime is always `'strict'` (`mode ?? 'strict'`) and every "warn in permissive mode" path is unreachable from the public client. Only `mongo(...)` accepts `mode` — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:86-94, 276-282` (options and `PostgresRuntimeImpl` construction pass only `verifyMarker` and `middleware`), `packages/2-sql/5-runtime/src/sql-runtime.ts:187`, `packages/3-extensions/mongo/src/runtime/mongo.ts:44`. +- `orm/middleware/built-in-cache.mdx:32, 79` — "`beforeExecute` hooks still run before a cache hit … `afterExecute` still fires" — the cache implements `interceptQuery`, `onRow`, `afterQuery`; the hooks that run around a hit are `beforeQuery` and `afterQuery` — evidence: `packages/3-extensions/middleware-cache/src/cache-middleware.ts:238-243`, `examples/prisma-8-demo/src/prisma/db.ts:16-22`. +- `orm/middleware/how-middleware-works.mdx:65, 73, 78`, `orm/middleware/authoring-custom-middleware.mdx:158, 192` — "Return `{ rows }` from `intercept`" and "`afterExecute` receives `result.rowCount`" — `interceptQuery` returns `{ rows }`, `interceptExecute` returns `{ stats }`; `afterQuery` carries `rowCount`/`completed`/`source`/`latencyMs`, `afterExecute` carries `stats.affectedRows`/`completed`/`source`/`latencyMs` — evidence: `packages/1-framework/1-core/framework-components/src/execution/runtime-middleware.ts:93-136`. +- `orm/middleware/built-in-lints.mdx:72-77` — "Raw SQL … `lints` falls back to text heuristics for raw plans … Control the fallback with `fallbackWhenAstMissing`" — a whole-query raw plan from `db.raw.sql` has an AST of kind `'raw-query'`; for it the structural rules are skipped and the text heuristics always run, regardless of `fallbackWhenAstMissing`. That option only matters when `plan.ast` is absent entirely — evidence: `packages/2-sql/5-runtime/src/middleware/lints.ts:100-104, 155-168`. +- `orm/reference/sql-query-builder.mdx:14` — "PostgreSQL is supported today" for the SQL builder — SQLite ships as a public package with its own adapter (including a raw codec inferer) — evidence: `packages/9-public/@prisma/orm-sqlite/package.json`, `packages/3-targets/6-adapters/sqlite/src/core/adapter.ts`. +- `orm/reference/pipeline-builder.mdx:96` — "Passing an unknown root throws synchronously: `Error: Unknown root …`. This is an `Error`, not a `TypeError`" — it is a structured ORM error with code `ORM.MODEL_UNKNOWN`; users should match on the code — evidence: `packages/2-mongo-family/5-query-builders/query-builder/src/state-classes.ts:646`. +- `orm/reference/sql-query-builder.mdx:906-917` — "The complete built-in set is fixed … Aggregate: `count`, `sum`, `avg`, `min`, `max`" — the aggregate helpers are not a fixed list; they are derived from the contract's aggregate map, which on PostgreSQL also carries `countBigInt`, `sumBigInt`, `avgDecimal`, and `count()` has a zero-argument form — evidence: `packages/2-sql/4-lanes/sql-builder/src/expression.ts:183-200`, `packages/3-targets/3-targets/postgres/src/core/aggregates.ts`, `docs/releases/v8.0.0-rc.2.md`. + +## Missing + +- Whole-query raw SQL lane (``db.raw.sql`...`.returnsRow(spec)`` / `.affectedCount()`, raw subqueries and CTEs by interpolating a `RawRowQuery`, and the `.returns` column-ref record added in rc.5) — evidence it exists: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts`, `docs/releases/v8.0.0-rc.2.md`, `docs/releases/v8.0.0-rc.5.md`, `examples/prisma-8-demo/src/queries/raw-query-demo.ts` — belongs on `orm/reference/raw-queries.mdx` (it currently says the opposite). +- `runtime.query(plan)` vs `runtime.execute(plan)` (rows vs `{ affectedRows }`), and `tx.query` / `tx.execute` inside `db.transaction(...)` — evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `packages/3-extensions/postgres/src/runtime/postgres.ts:346-372` — belongs under "Compiling and executing" on `orm/reference/sql-query-builder.mdx`. +- The two middleware lifecycles (`beforeQuery`/`interceptQuery`/`onRow`/`afterQuery` and `beforeExecute`/`interceptExecute`/`afterExecute`), `interceptExecute` returning `{ stats }`, `AfterExecuteResult.stats.affectedRows`, and the `params: SqlParamRefMutator` third argument on both before-hooks — evidence: `packages/2-sql/5-runtime/src/middleware/sql-middleware.ts` — belongs on `orm/middleware/how-middleware-works.mdx` and `orm/middleware/authoring-custom-middleware.mdx`. +- `ctx.signal` (per-operation `AbortSignal`, `RUNTIME.ABORTED { phase }`) on the middleware context — evidence: `packages/1-framework/1-core/framework-components/src/execution/runtime-middleware.ts:53-59` — belongs in "The context object" on `orm/middleware/authoring-custom-middleware.mdx`. +- `MongoMiddleware` (`familyId?: 'mongo'`) from `@prisma/orm-mongo/family-runtime`, and the `mode: 'strict' | 'permissive'` option on `mongo(...)` — evidence: `packages/2-mongo-family/7-runtime/src/mongo-middleware.ts:45-46`, `packages/3-extensions/mongo/src/runtime/mongo.ts:44-48`, `examples/mongo-demo/src/db.ts:2` — belongs on `orm/middleware/authoring-custom-middleware.mdx` step 5. +- `createInMemoryCacheStore` (exported, lets you share one store between clients or set your own `clock`) and the `middleware.cache.hit` / `middleware.cache.miss` / `middleware.cache.store` debug log events — evidence: `packages/3-extensions/middleware-cache/src/exports/index.ts`, `packages/3-extensions/middleware-cache/src/cache-middleware.ts:262, 275, 305` — belongs on `orm/middleware/built-in-cache.mdx`. +- Lossless aggregates `countBigInt()`, `sumBigInt()`, `avgDecimal()` and zero-argument `count()` on `fns` — evidence: `docs/releases/v8.0.0-rc.2.md`, `packages/3-targets/3-targets/postgres/src/core/aggregates.ts` — belongs under "Built-in functions" on `orm/reference/sql-query-builder.mdx`. +- `fns.cosineSimilarity` from pgvector (alongside `cosineDistance`) — evidence: `packages/3-extensions/pgvector/src/types/operation-types.ts:17-32` — belongs on `orm/extensions/using-extensions.mdx` step 5. +- `db.prepare(declaration, (sql, params) => plan)` prepared statements; `limit()`/`offset()` accept a prepared bind site (`PaginationValue`) — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:67-70`, `packages/2-sql/4-lanes/sql-builder/src/types/shared.ts:63-64`, `docs/releases/v8.0.0-rc.2.md` ("Prepared statements split by their declared result") — belongs on `orm/reference/sql-query-builder.mdx`. +- Driver-free static client (`@prisma/orm-postgres/static`, `@prisma/orm-mongo/static`) exposing the SQL builder, `raw`, and `enums` without a connection — evidence: `packages/9-public/@prisma/orm-postgres/package.json` (`./static`), `docs/releases/v0.15.0.md` ("Client-safe static surface") — belongs under "Entry points" on `orm/reference/sql-query-builder.mdx`. +- `raw` is a reserved storage namespace (`ORM.NAMESPACE_RESERVED`) — evidence: `docs/releases/v8.0.0-rc.2.md` — belongs on `orm/reference/raw-queries.mdx`. +- `RUNTIME.MISSING_EXTENSION_PACK` is the error raised when the contract needs an extension the client did not register — evidence: `packages/2-sql/5-runtime/src/sql-context.ts:229-232` — belongs under "Capabilities" on `orm/extensions/using-extensions.mdx:101`, which describes the failure without naming the code. +- `runtime.query()` returns `AsyncIterableResult`, so SQL-builder and raw plans can be streamed with `for await` — evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-313` — belongs under "Streaming vs. collecting" on `orm/reference/sql-query-builder.mdx:1008`, which sends users to the ORM client instead. + +## Unverified + +- `orm/reference/sql-query-builder.mdx:589, 936` — a raw `EXTRACT(...)` annotated `.returns('pg/int4@1')` "still decodes as a string" — I could not find where a raw expression's declared codec is or is not applied on the decode path; given rc.2 made codec ids in raw fragments contract-checked, the claim needs re-testing against rc.9. +- `orm/reference/pipeline-builder.mdx:190-194` — "`_id` equality inside `match()` never matches any document" — the only `f._id.eq(...)` tests in the source check plan shape in the contract-free builder (`packages/2-mongo-family/5-query-builders/query-builder/test/contract-free-collection.test.ts:37-147`); no live test confirms or refutes the claim. +- `orm/reference/pipeline-builder.mdx:128, 346` — a `lookup()` sub-document's `_id` "comes back as a raw driver `ObjectId`" — `docs/releases/v0.15.0.md` says reshaping reads decode through codecs; I found no source for lookup sub-document decoding either way (`pipeline-result-shape.ts` has no lookup handling). +- `orm/reference/pipeline-builder.mdx:937` — pipeline `insertMany` result shown as `{ insertedIds: { '0': …, '1': … } }` — the declared `InsertManyResult.insertedIds` is `ReadonlyArray` (`packages/2-mongo-family/4-query/query-ast/src/result-types.ts:16`); I could not confirm which shape the pipeline builder path yields on rc.9. +- `orm/reference/raw-queries.mdx:245-263` — raw `findOneAndUpdate` "always uses the driver's `'before'` default", so the first upsert call returns an empty result — the wrapper does pass `returnDocument` as `undefined` (`packages/2-mongo-family/5-query-builders/orm/src/raw-collection.ts:81-88`), but I could not find where the wire layer resolves an undefined `returnDocument`. +- `orm/extensions/using-extensions.mdx:76` — "If `db init` reports a contract-space layout violation … run `migration plan` once: it writes the extension's baseline migration under `migrations//`" — I searched `packages/2-sql/3-tooling` and `packages/3-extensions/postgres` for "layout violation" and "contract-space" and found no such message; only `skills/prisma-8/references/contract.md:53` describes the `migrations//` layout. +- `orm/extensions/using-extensions.mdx:116` — "ParadeDB and Supabase are experimental" — neither README nor either public `package.json` carries an experimental marker. The ParadeDB `key_field`-only restriction is confirmed (`packages/3-extensions/paradedb/README.md:9`). +- `orm/reference/sql-query-builder.mdx:917` — "`ilike` is registered by the Postgres adapter for textual columns" as an `fns` helper — I found no `ilike` operation contributed to the SQL builder's function bag in `packages/3-targets/6-adapters/postgres` or `packages/3-targets/3-targets/postgres`; `ilike` exists on the ORM field proxy (`skills/prisma-8/references/queries-postgres.md`). + +## Skill vs site + +- `skills/prisma-8/references/queries-postgres.md:255-300` and `skills/prisma-8/references/queries.md:144, 149` use `db.runtime().execute(plan)` to read rows; `skills/prisma-8/references/queries-mongo.md` uses `(await db.runtime()).execute(plan)`. The site does the same. Both are wrong: the source uses `query()` for rows (`packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-99`, `examples/prisma-8-demo/src/queries/*.ts`, `examples/mongo-demo/test/query-builder-writes.test.ts`). +- `skills/prisma-8/references/queries-postgres.md:392, 415` and `queries.md:143` spell the raw lane ``db.raw.sql`…` ``; the site (`orm/reference/raw-queries.mdx:121`) uses ``db.raw`…` ``. The skill matches the source (`packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:164-166`). +- `skills/prisma-8/references/queries.md:143` says whole-query raw SQL exists with `.returnsRow()` / `.affectedCount()`; the site (`orm/reference/raw-queries.mdx:19, 130`) says there is no way to run a standalone raw statement. The skill matches the source. +- `skills/prisma-8/references/runtime.md` ("What Prisma Next doesn't do yet") says lints and budgets must be imported from `@internal/sql-runtime` because the facade has no middleware subpath; the site imports them from `@prisma/orm-postgres/family-runtime`. The site matches the source: the export map has `./family-runtime` and the demo imports from it (`packages/9-public/@prisma/orm-postgres/package.json`, `examples/prisma-8-demo/src/prisma/db.ts:3`). +- `skills/prisma-8/references/queries-postgres.md:258` shows `db.sql.user.insert({ email })` with a single object; the site (`orm/reference/sql-query-builder.mdx:725`) says `insert()` always takes an array. The site matches the source (`packages/2-sql/4-lanes/sql-builder/src/types/table-proxy.ts:122-123`, `rows: ReadonlyArray<...>`). +- `skills/prisma-8/references/queries.md:146` says there is no streaming surface; the site (`orm/reference/sql-query-builder.mdx:1008`) says streaming exists on the ORM client's `AsyncIterableResult`. The source returns `AsyncIterableResult` from `runtime.query()` on both the ORM and SQL-builder paths, so the site is closer, but neither says a SQL-builder plan can be streamed directly. +- `skills/prisma-8/references/runtime.md` ("Lints take `severities` (with the five keys above)") lists the five real lint severity keys; the site (`orm/middleware/built-in-lints.mdx:68`) adds a sixth, `unindexedPredicate`. The skill matches the source (`packages/2-sql/5-runtime/src/middleware/lints.ts:13-23`). diff --git a/docs/orm-docs-audit/audit/contract.md b/docs/orm-docs-audit/audit/contract.md new file mode 100644 index 0000000000..45a3e3cd08 --- /dev/null +++ b/docs/orm-docs-audit/audit/contract.md @@ -0,0 +1,60 @@ +# Audit: contract + +Pages read: `orm/contract-authoring/the-data-contract.mdx`, `orm/contract-authoring/the-contract-artifact.mdx`, `orm/contract-authoring/psl-syntax.mdx`, `orm/contract-authoring/typescript-schema-builder.mdx`, `orm/contract-authoring/capabilities.mdx`, `orm/data-modeling/index.mdx`, `orm/data-modeling/relational-databases.mdx`, `orm/data-modeling/mongodb.mdx`, `cli/contract-emit.mdx`, `cli/contract-infer.mdx` + +## Breaks copy-paste + +- `orm/contract-authoring/typescript-schema-builder.mdx:66` (also 165, 167, 241, 247) — `defineContract({ extensionPacks: { pgvector } }, ...)` — the option is `extensions: { pgvector }`; `extensionPacks` was renamed in 0.17 and "the old key fails loudly", so the PostgreSQL contract on this page does not build — evidence: `wip/prisma-src/docs/releases/v0.17.0.md` ("`extensionPacks` config key renamed to `extensions` — in ... the TS builder ..."), `wip/prisma-src/packages/3-extensions/postgres/src/contract/define-contract.ts` (`readonly extensions?: Extensions`), `wip/prisma-src/packages/2-sql/2-authoring/contract-ts/README.md` (`extensions: { pgvector }`). The config-side `extensions: [pgvector]` at line 256 is correct. + +## Misleading + +- `orm/contract-authoring/the-contract-artifact.mdx:49` (also 81, 98, 119, 121) — hashes shown as `"sha256:…"` and `StorageHashBase<"sha256:9f49…">` — content hashes are bare hex since 0.17 and "loaders reject the prefixed form"; emitted files carry `StorageHashBase<'8abaa…'>` with no prefix — evidence: `wip/prisma-src/docs/releases/v0.17.0.md` ("Content hashes are bare hex"), `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.d.ts:38-43`, `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.json` (`"profileHash": "3916f…"`). +- `orm/contract-authoring/the-contract-artifact.mdx:100` (also 111) — contract.json top-level key `"extensionPacks": {}` — the emitted key is `extensions` (renamed 0.17, and it is inside the hashed bytes); emitted files also carry `meta` and a `_generated` notice block the page's outline omits — evidence: `wip/prisma-src/docs/releases/v0.17.0.md`, `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.json` (top-level keys: `schemaVersion, targetFamily, target, profileHash, roots, domain, storage, execution, capabilities, extensions, meta, _generated`). +- `orm/data-modeling/relational-databases.mdx:81` — "The mirror field on the other model (`profile Profile?` on `User`) is not supported yet" — a bare optional model-typed field with no `@relation` is accepted as the 1:1 back side (it only requires the FK to be unique, else `PSL_NON_UNIQUE_BACKRELATION`) — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts:78` ("accepts a bare model-typed optional field with no @relation as the 1:1 back side"), `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/psl-relation-resolution.ts:462`, `wip/prisma-src/docs/releases/v0.16.0.md` ("A singular back-relation over a non-unique foreign key is rejected at emit"). +- `orm/data-modeling/relational-databases.mdx:192` — "pass the discriminator value explicitly when you create through a variant ... it is not filled in automatically yet" — creating through the variant-narrowed collection (`db.orm.public.Task.variant('Bug').create({...})`) injects the discriminator automatically; the page never mentions `.variant()` at all and instead points at `db.orm.public.Bug` — evidence: `wip/prisma-src/packages/3-extensions/sql-orm-client/src/collection.ts:406` ("Insert under a variant — discriminator is injected automatically"), `wip/prisma-src/examples/prisma-8-demo/src/orm-client/collections.ts:48`, `wip/prisma-src/skills/prisma-8/references/queries-mongo.md:22`. +- `orm/data-modeling/relational-databases.mdx:463` — "Referential actions ... are covered in the relations reference as it lands" (implies they are not available) — `onDelete`/`onUpdate` with `NoAction`, `Restrict`, `Cascade`, `SetNull` are parsed and lowered today — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/psl-relation-resolution.ts:19-22`, `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/interpreter.ts:1255`, `wip/prisma-src/skills/prisma-8/references/contract.md:92-99`. +- `orm/data-modeling/index.mdx:159` — scalar table lists `Json` as "Arbitrary JSON value" — on PostgreSQL `Json` binds to native `json` since 0.17 and `Jsonb` is the separate scalar for `jsonb` (which is what the TS builder's `field.json()` and value objects use); the table never mentions `Jsonb`, `Decimal`, or `Bytes` — evidence: `wip/prisma-src/docs/releases/v0.17.0.md` ("`Json` re-binds to native `json` storage, with a new `Jsonb` scalar"), `wip/prisma-src/packages/3-targets/6-adapters/postgres/src/exports/control.ts:15` (`valueObjectStorageType: 'Jsonb'`), `wip/prisma-src/packages/3-targets/3-targets/postgres/src/core/authoring.ts:721-727` (`json` preset emits `pg/jsonb@1`). +- `orm/contract-authoring/psl-syntax.mdx:173-181` — the "Named types" section teaches `types { Uuid = String @db.Uuid }` as the way to get a `uuid` column (the `@db.Uuid` part is the known item) — the replacement is that `Uuid` is a built-in type name in type position and needs no alias: `id Uuid @id @default(uuid())`; the page should show an alias over a real type (for example `ShortName = VarChar(35)`) — evidence: `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.prisma` (`id Uuid @id @default(uuid())`), `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("Resolve Postgres native storage types from bare names and constructor calls in type position (`Char`, `VarChar`, `Numeric`, `Uuid`, ...)"). +- `cli/contract-infer.mdx:16` (also 23) — usage and option table present `--db` as required — `--db` falls back to `db.connection` from `prisma.config.ts`; only when neither is set does the command fail — evidence: `wip/prisma-src/packages/1-framework/3-tooling/cli/src/orm/contract/infer.ts` (`const dbConnection = args.flags.db ?? ctx.config.db?.connection`). +- `orm/contract-authoring/typescript-schema-builder.mdx:169` — "The MongoDB builder is simpler: it exports `field`, `model`, and `rel` directly, and its `defineContract` takes a single definition object" — the Mongo builder also exports `index`, `valueObject`, `member`, `enumType`, and `defineContract` has the same factory overload as PostgreSQL — evidence: `wip/prisma-src/packages/3-extensions/mongo/src/exports/contract-builder.ts`, `wip/prisma-src/packages/3-extensions/mongo/src/contract/define-contract.ts` (overload 2, "factory form"). + +## Missing + +- Native PostgreSQL types in type position (`Uuid`, `VarChar(255)`, `Char`, `Numeric`, `Inet`, `SmallInt`, `Real`, `Timestamp`, `Timestamptz`, `Date`, `Time`, `Timetz`, `Json`, `Jsonb`, `BigIntNumber`, `UnboundedInt`) — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md`, `wip/prisma-src/docs/releases/v0.17.0.md` — belongs on `psl-syntax.mdx` (Models and fields / Named types) and the scalar table on `data-modeling/index.mdx`. +- `@@index` options: `expression:`, `where:` (partial), `unique:`, `type:`/`options:`, and `name:` vs `map:` naming; `@@unique([...])` composite uniques — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("`@@index` parameter surface"), `wip/prisma-src/skills/prisma-8/references/contract.md:101-108` — belongs on `psl-syntax.mdx` (Models and fields). The relational page's agent prompt asks for a composite unique, but no page shows the syntax. +- `@@check(expression:, name: | map:)` hand-written CHECK constraints and the `sql.checkConstraint` capability (present in the demo's emitted capabilities but absent from the page's excerpt) — evidence: `wip/prisma-src/skills/prisma-8/references/contract.md:269-290`, `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.json` (`"checkConstraint": true`) — belongs on `psl-syntax.mdx` and `capabilities.mdx`. +- `@noCheck` / `@noCheck(membership)` / `@noCheck(elementNotNull)` to waive generated CHECK constraints on enum and list columns (TS: `.noCheck(...)`) — evidence: `wip/prisma-src/skills/prisma-8/references/contract.md:265`, `wip/prisma-src/packages/2-sql/2-authoring/contract-ts/src/contract-dsl.ts:294` — belongs on `psl-syntax.mdx` (Enums). +- Scalar lists (`String[]`) are supported on PostgreSQL and rejected only on targets without `sql.scalarList` (SQLite); the data-modeling overview shows `tags String[]` but `psl-syntax.mdx` never says lists exist, which database supports them, or that list columns get a generated not-null-element CHECK — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/psl-field-resolution.ts:497-500`, `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.json` (`"scalarList": true`) — belongs on `psl-syntax.mdx`. +- `@@control(managed | tolerated | external | observed)` per-model control policy and `defaultControlPolicy` — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("Model-level control policy"), `wip/prisma-src/skills/prisma-8/references/contract.md:333-346` — belongs on `psl-syntax.mdx` and `the-contract-artifact.mdx`. +- `namespace { ... }` blocks for non-default PostgreSQL schemas, and cross-contract-space relation targets (`supabase:auth.AuthUser`) — evidence: `wip/prisma-src/packages/1-framework/2-authoring/psl-parser/src/parse.ts:502`, `wip/prisma-src/skills/prisma-8/references/contract.md:292-331` — belongs on `psl-syntax.mdx`. The artifact page says everything is "grouped by namespace" without saying how to author one. +- `native_enum` blocks (real `CREATE TYPE ... AS ENUM`) with `@@map` for the Postgres type name, and the TS `nativeEnum(...)` / `pg.enum(handle)` helpers, as the alternative to `@@type`-coded enums — evidence: `wip/prisma-src/packages/3-targets/3-targets/postgres/src/core/authoring.ts` (`keyword: 'native_enum'`), `wip/prisma-src/packages/3-extensions/postgres/src/contract/native-enum.ts` — belongs on `psl-syntax.mdx` (Enums) and `typescript-schema-builder.mdx` (Enums). +- `@@rls`, `policy_select` / `policy_insert` / `policy_update` / `policy_delete` / `policy_all` blocks and `role` blocks in PSL; `rlsEnabled`, `policy*`, `role` handles in the TS builder — evidence: `wip/prisma-src/packages/3-targets/3-targets/postgres/src/core/authoring.ts:121-125`, `wip/prisma-src/packages/3-extensions/postgres/src/exports/contract-builder.ts` — belongs on `psl-syntax.mdx` / `typescript-schema-builder.mdx` (RLS outside Supabase is a known site-wide gap; the authoring syntax is the part that belongs in this area). +- The `@default(...)` generator surface: `uuid(4)`, `uuid(7)`, `cuid(2)`, `ulid()`, `nanoid()`, `nanoid()`, `dbgenerated("...")`, and that `cuid()` is rejected with a hint to use `cuid(2)` — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("Supported `@default(...)` surface") — belongs on `psl-syntax.mdx` (Models and fields). +- Timestamp presets `temporal.createdAt()` / `temporal.updatedAt()` in PSL type position, and that Prisma 7's `@updatedAt` is rejected (`PSL_UNSUPPORTED_FIELD_ATTRIBUTE` with a hint) — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("Supported timestamp authoring surface") — belongs on `psl-syntax.mdx`; the TS page shows `field.temporal.updatedAt()` but the PSL page has no way to express an updated-at field. +- `onDelete` / `onUpdate` on `@relation` and `@relation("Name")` disambiguation when several relations join the same two models — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/psl-relation-resolution.ts:19-22`, `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md` ("Matching may use `@relation("Name")`") — belongs on `relational-databases.mdx` and `psl-syntax.mdx` (Relations). +- Extension types inline in field position (`embedding pgvector.Vector(length: 1536)?`) without a `types {}` alias, and the `PN-CLI-4011`-style "missing extension" failure mode is now a dotted structured code — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md`, `wip/prisma-src/docs/releases/v0.17.0.md` — belongs on `psl-syntax.mdx` (Extension types). +- TS builder field helpers beyond the four listed: `field.int()`, `field.bigint()`, `field.float()`, `field.decimal()`, `field.boolean()`, `field.bytes()`, `field.dateTime()`, `field.id.uuidv7String()`, `field.id.nanoid({ size })`, `field.uuidNative()` / `field.id.uuidv4Native()` / `field.id.uuidv7Native()`, `type.BigIntNumber()`, `type.UnboundedInt()`; and that scalar helpers exist only inside the factory callback (outside it only `field.column`, `field.generated`, `field.namedType`) — evidence: `wip/prisma-src/packages/3-targets/3-targets/postgres/src/core/authoring.ts:679-793`, `wip/prisma-src/packages/2-sql/2-authoring/contract-ts/README.md` ("Helper Notes") — belongs on `typescript-schema-builder.mdx` (Fields). +- TS builder model-level features: `.attributes(({ fields, constraints }) => ({ id, uniques }))` for composite keys and uniques, `constraints.index(...)` under `.sql({ indexes })`, `check(...)` under `.sql({ checks })`, `.noCheck()`, `rel.belongsTo(...).sql({ fk })`, and the root-level `foreignKeyDefaults` / `naming` options — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-ts/README.md` ("Constraint Placement", "Indexes", "Foreign Key Defaults"), `wip/prisma-src/packages/2-sql/2-authoring/contract-ts/src/contract-dsl.ts:1207-1215` — belongs on `typescript-schema-builder.mdx` (Storage mapping). The page shows no way to declare a composite primary key in TypeScript. +- Mongo TS builder: `valueObject(...)` + `field.valueObject(Address)` for embedded documents, `index({...}, { unique })` and `collectionOptions`, `field.vector()`, `enumType`/`member`, and discriminator polymorphism via `base` / `discriminator` / `variants` — evidence: `wip/prisma-src/packages/2-mongo-family/2-authoring/contract-ts/README.md` — belongs on `typescript-schema-builder.mdx`; the MongoDB tab cannot express the embedded `Address` the PSL tab on `psl-syntax.mdx` shows. +- Mongo PSL index syntax beyond `@@index([f])`: sort order per field (`@@index([createdAt(sort: Desc), authorId])`), `@@unique`, `@@textIndex`; and that per-index `collation`, `partialFilterExpression`, `wildcardProjection` need the TS builder — evidence: `wip/prisma-src/examples/mongo-demo/src/contract.prisma`, `wip/prisma-src/packages/2-mongo-family/2-authoring/contract-psl/README.md` — belongs on `mongodb.mdx` / `psl-syntax.mdx` (MongoDB tab). +- `contract infer` is SQL-only (fails with `CONTRACT.INFER_UNSUPPORTED` on MongoDB), its default output is `contract.prisma` next to the emitted `contract.json`, and it captures indexes, `@@check` (as `map:`), `@@rls` and policy blocks, and 1:1 relations from unique indexes — evidence: `wip/prisma-src/packages/1-framework/3-tooling/cli/src/orm/contract/infer.ts`, `wip/prisma-src/packages/1-framework/3-tooling/cli/src/orm/contract/paths.ts`, `wip/prisma-src/docs/releases/v0.17.0.md` ("`contract infer` reaches full fidelity") — belongs on `cli/contract-infer.mdx` (What to review). +- The config `output` option on `ormConfig({ contract, output })` (a directory; `contract.json` and `contract.d.ts` land there instead of next to the source), which `create-prisma` sets to `./src/prisma/generated` for TypeScript authoring — evidence: `wip/prisma-src/packages/3-extensions/postgres/src/config/define-config.ts` (`join(options.output, 'contract.json')`), `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs` — belongs on `typescript-schema-builder.mdx` (Point the config at the contract file) and `cli/contract-emit.mdx`. +- The Vite plugin that re-emits on save (`@prisma/orm-postgres/vite-plugin-contract-emit`) as the alternative to running `contract emit` by hand — evidence: `wip/prisma-src/packages/9-public/@prisma/orm-postgres/package.json` (`./vite-plugin-contract-emit`), `wip/prisma-src/skills/prisma-8/references/contract.md:12` — belongs on `cli/contract-emit.mdx` / `the-contract-artifact.mdx` (Version control). +- `contract emit` prints the three hashes and returns them in `--json` (`storageHash`, `executionHash`, `profileHash`, `outDir`, `files`) — evidence: `wip/prisma-src/packages/1-framework/3-tooling/cli/src/orm/contract/emit.ts` (`EmitDocument`) — belongs on `cli/contract-emit.mdx` (Options / `--json`). +- Querying polymorphic variants with `.variant('Bug')` (narrows reads and injects the discriminator on create), on both SQL and Mongo — evidence: `wip/prisma-src/packages/3-extensions/sql-orm-client/src/collection.ts:395-410`, `wip/prisma-src/skills/prisma-8/references/queries-mongo.md:57` — belongs on `relational-databases.mdx` and `mongodb.mdx` (Polymorphic sections). +- `AddressInput` alongside `AddressOutput`, plus `FieldOutputTypes`, `TypeMaps`, `QueryOperationTypes`, `AggregateTypes` in `contract.d.ts` — evidence: `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.d.ts` — belongs on `the-contract-artifact.mdx` (Inside `contract.d.ts`), which only shows the output type. + +## Unverified + +- `orm/data-modeling/relational-databases.mdx:192` — "Variants appear as their own models in queries (`db.orm.public.Bug` ...)" — the runtime facet enumerates every model in `domain.namespaces[ns].models`, which includes variants, so the property resolves; I could not confirm that creating through it (rather than through `.variant('Bug')`) sets the discriminator, or that the site's `{ title, severity, type: "bug" }` shape is accepted there. Checked `wip/prisma-src/packages/3-extensions/sql-orm-client/src/orm.ts:155-185`, `storage-resolution.ts:42-48`, and the demo, which only ever uses `.variant(...)`. +- `orm/data-modeling/relational-databases.mdx` (whole page) — the default referential action when `onDelete` is omitted; the skill says `Restrict` but I could not find the default in the interpreter or planner. Checked `psl-relation-resolution.ts`, `interpreter.ts:1255-1304`, and grepped the postgres target and sql family for a fallback. +- `orm/contract-authoring/the-contract-artifact.mdx:142-145` — `postgres({ contractJson })` with no `url`; the runtime accepts `url?` and the demo omits it, so a connection presumably comes from `db.connect(...)` or `prisma.config.ts`; how the URL is resolved is outside this area. Checked `wip/prisma-src/packages/3-extensions/postgres/src/runtime/postgres.ts:88,312`. + +## Skill vs site + +- `orm/data-modeling/mongodb.mdx:126-148` and `psl-syntax.mdx:281` show `@@discriminator` / `@@base` in PSL for MongoDB; the skill says these attributes "are SQL-only" and Mongo polymorphism needs the TS builder (`contract.md:221`). The site matches the source: the Mongo attribute registry includes both, and `examples/mongo-demo/src/contract.prisma` uses them — evidence: `wip/prisma-src/packages/2-mongo-family/2-authoring/contract-psl/README.md`, `wip/prisma-src/examples/mongo-demo/src/contract.prisma`. +- `orm/data-modeling/index.mdx:167` shows `tags String[]`; the skill (`contract.md:123`) and the contract-psl README say scalar lists "are rejected by the SQL interpreter". The site matches the source: lists are gated on `sql.scalarList`, which PostgreSQL declares — evidence: `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/src/psl-field-resolution.ts:497`, `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.json`. +- `typescript-schema-builder.mdx:66` uses `extensionPacks`; the skill (`contract.md:51,386`) uses `extensions: { pgvector }`. The skill matches the source — evidence: `wip/prisma-src/packages/3-extensions/postgres/src/contract/define-contract.ts`, `wip/prisma-src/docs/releases/v0.17.0.md`. +- The site's config samples use `definePrismaConfig({ orm: ormConfig({...}) })`; the skill (`contract.md:47,164-170`) still shows the flat `defineConfig({ contract, extensions })` from `@internal/postgres/config` as the whole file. The site matches the source: the flat shape was removed in rc.4 and every example and the create-prisma template use the envelope — evidence: `wip/prisma-src/docs/releases/v8.0.0-rc.4.md` ("The deprecated config fallbacks are gone"), `wip/prisma-src/examples/prisma-8-demo/prisma.config.ts`, `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs`. +- The skill (`contract.md:28,62-66`) routes on `PN-CLI-4002` / `PN-CLI-4003` / `PN-CLI-4011`; those codes were replaced by dotted structured codes in 0.17. Neither the site nor the skill lists the current codes for a failed emit — evidence: `wip/prisma-src/docs/releases/v0.17.0.md` ("Every published error is a structured envelope with a dotted code"). +- `psl-syntax.mdx:302` declares the pgvector type via a `types {}` alias with a positional argument (`pgvector.Vector(1536)`); the skill (`contract.md:179`) writes it inline on the field with a named argument (`pgvector.Vector(length: 1536)`). Both forms are accepted; the demo uses the site's spelling — evidence: `wip/prisma-src/examples/prisma-8-demo/src/prisma/contract.prisma`, `wip/prisma-src/packages/2-sql/2-authoring/contract-psl/README.md`. diff --git a/docs/orm-docs-audit/audit/extras.md b/docs/orm-docs-audit/audit/extras.md new file mode 100644 index 0000000000..1aeeb54ed2 --- /dev/null +++ b/docs/orm-docs-audit/audit/extras.md @@ -0,0 +1,112 @@ +# Audit: extras + +Pages read: `(index)/full-stack-tutorial.mdx`, `ai/tools/skills.mdx`, `cli/telemetry.mdx` (in full). Also consulted for cross-checks: `cli/skills.mdx`, `cli/init.mdx`, `cli/configuration.mdx`, `orm/extensions/using-extensions.mdx`, `orm/data-modeling/index.mdx`, `orm/reference/transactions-and-runtime.mdx`, `orm/fundamentals/reading-data.mdx`, `guides/database/multiple-databases.mdx`. + +Sources used: `wip/create-prisma-src/` (what the `hono` scaffold generates), `wip/prisma-src/packages/1-framework/3-tooling/cli/` (orm init, migration plan, telemetry hooks), `wip/prisma-src/packages/1-framework/3-tooling/cli-telemetry/`, `wip/prisma-src/skills/`, `wip/prisma-src/docs/Telemetry.md`, `wip/prisma-src/docs/reference/*`, and the packages named per finding. The `skills sync` and `telemetry status|enable|disable` command implementations are not in the ORM monorepo (`skills sync` appears only in a test name; `telemetryCommandGroup` is imported from the external `@prisma/cli-engine` package in `packages/1-framework/3-tooling/cli/src/orm/cli.ts:4`), so claims about those commands' exact behaviour are checked against `skills/README.md` and `docs/Telemetry.md` only. + +## Breaks copy-paste + +- `ai/tools/skills.mdx:102` — says `orm init --skip-skills` skips skill installation — no such flag exists. `orm init` takes `--target`, `--authoring`, `--schema-path`, `--write-env`, `--probe-db`, `--strict-probe`, `--skip-install`, `--keep-previous-facade` and does not touch skills at all — evidence: `packages/1-framework/3-tooling/cli/src/orm/init.ts:92-110`; `packages/1-framework/3-tooling/cli/src/commands/init/skill-sources.ts:1-5` ("Skills setup belongs to the family-level `prisma init` command; the only skill work left in `orm init` is deleting the retired directories"); `skills/README.md` ("`prisma orm init` does not touch them"). +- `ai/tools/skills.mdx:111-112` — lists `prisma-next-upgrade` and `prisma-8-extension-upgrade` as installable Prisma 8 skills — both names are retired; only one skill, `prisma-8`, ships, and upgrading is a branch inside it (`references/upgrade-app.md`, `references/upgrade-extension.md`). A user running `npx skills add ... --skill prisma-next-upgrade` gets nothing, and `prisma init` actively deletes directories with those names — evidence: `wip/prisma-src/skills/` contains only `prisma-8/`; `skills/README.md` ("One installable skill"); `packages/1-framework/3-tooling/cli/src/commands/init/skill-sources.ts:24-38` (`RETIRED_SKILL_NAMES` includes `prisma-next-upgrade` and `prisma-8-extension-upgrade`). + +## Misleading + +- `(index)/full-stack-tutorial.mdx:193-203` — shows the scaffold's `User` model with `createdAt DateTime @default(now())` and `updatedAt temporal.updatedAt()`, and tells the user to "add one line" — the `hono` scaffold's contract is written by `prisma orm init` and actually contains `createdAt TimestamptzString @default(now())` and `updatedAt temporal.updatedAtString()`. Both spellings are valid PSL, but the user's file will not match the page, and the two store different runtime types (`Temporal` object vs. string) — evidence: `packages/1-framework/3-tooling/cli/src/commands/init/templates/code-templates.ts:171-193` (`starterSchemaPslPostgres`); `wip/create-prisma-src/src/tasks/prisma-setup/commands.ts:50-63` (create-prisma runs `orm init --schema-path src/prisma/contract.prisma`); `packages/2-sql/2-authoring/contract-psl/README.md:18,70` (both `DateTime @default(now())` and `temporal.updatedAt()` are valid). +- `(index)/full-stack-tutorial.mdx:51` and `:28` — say the scaffold "added the `postinstall` hook that keeps [skills] current" and that `init` repairs it — create-prisma adds a `skills:sync` npm script (`prisma skills sync || exit 0`) and runs `prisma init --yes` once; it does not write a `postinstall` hook. Whether the family-level `prisma init` adds one cannot be checked in the ORM monorepo — evidence: `wip/create-prisma-src/src/tasks/install.ts:56`; `wip/create-prisma-src/src/tasks/prisma-setup/commands.ts:65-72`. +- `ai/tools/skills.mdx:102` — "Projects scaffolded with `create-prisma` or `orm init` install them automatically" — `create-prisma` does (it runs the family-level `prisma init --yes`), `orm init` does not — evidence: `wip/create-prisma-src/src/tasks/prisma-setup/commands.ts:65-72`; `packages/1-framework/3-tooling/cli/src/commands/init/skill-sources.ts:1-5`. +- `ai/tools/skills.mdx:114` — "`orm init` applies this pinning for you" (pinning `npx skills add ...#v`) — `orm init` does not install skills from GitHub at all; the version match comes from the skill shipping inside the installed `@prisma/orm-*` tarball and `prisma skills sync` copying it — evidence: `skills/README.md` (Install and Versioning sections); `packages/9-public/@prisma/orm-postgres/package.json` (`"files": ["dist", "skills"]`, `prepack` runs `sync-package-skills.ts`). +- `ai/tools/skills.mdx:105` and `:19-20` — present `npx skills add prisma/prisma/skills` as the way to add Prisma 8 skills to an existing project — the monorepo README calls that "interoperability, not the recommended path: nothing keeps a copy installed this way up to date", and the recommended path is `prisma init` / `prisma skills sync`, which the page only mentions in passing at line 36 — evidence: `skills/README.md` ("Manual fallback — install from GitHub"). +- `ai/tools/skills.mdx:114` — "The two upgrade skills are intentionally unpinned; the latest revision covers every prior transition" — there are no separate upgrade skills; the per-transition instructions live under `prisma-8/upgrading/app/upgrades/-to-/` inside the single skill, and "The version you upgrade *to* carries the instructions" — evidence: `skills/README.md`; `wip/prisma-src/skills/prisma-8/upgrading/`. +- `guides/database/multiple-databases.mdx` (whole page, e.g. `:63`, `:109`) — sits in the non-versioned `guides/` tree and is the only ORM 8 page matching "multiple databases", but it is a Prisma 7 guide (`@prisma/client@7.10.0`, `schema.prisma`, `PrismaClient`). A Prisma 8 user searching for multi-database or replica guidance lands on v7 instructions with no banner — evidence: `guides/database/multiple-databases.mdx:63,93,109`; ORM 8 has no multi-database routing (`skills/prisma-8/references/runtime.md:323`). +- `cli/telemetry.mdx:9` — "Telemetry is on by default" with no mention that CI environments never send events and never see the first-run notice, so a user reading only this page may add opt-out env vars to CI unnecessarily. Not wrong, but incomplete — evidence: `packages/1-framework/3-tooling/cli/src/orm/telemetry/reporting.ts:75-78`; `docs/Telemetry.md` ("CI environments"). + +## Missing + +Ranked by how likely a user is to need it, most likely first. Items marked (known) are in the instructions' already-known list but are included here because the task asked for evidence for each. + +1. Telemetry: how to opt out without the CLI, and what is sent — `cli/telemetry.mdx` never mentions `DO_NOT_TRACK=1` or `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file (`~/.config/prisma-next/config.json` / `%APPDATA%\prisma-next\config.json`, `enableTelemetry` field), that CI is always silent, the first-run stderr notice, that `telemetry` itself sends nothing, that the preference is per-user not per-project, agent detection via `@vercel/detect-agent` / `AI_AGENT`, or the event fields. Note the field list in `docs/Telemetry.md` is itself stale: the rc.9 sender also reports `exitCode` ("No outcome data" in the doc is no longer true) — evidence: `packages/1-framework/3-tooling/cli-telemetry/src/gating.ts:62-72`, `user-config.ts:23-51`, `payload.ts:101-116`, `enrich.ts:205-223`; `packages/1-framework/3-tooling/cli/src/orm/telemetry/reporting.ts:24-31,75-92`; `docs/Telemetry.md` — belongs on `cli/telemetry.mdx`. +2. Row level security and policies on plain Postgres (known) — supported without Supabase: PSL `policy_select` / `policy_insert` / `policy_update` / `policy_delete` / `policy_all` blocks with `target`, `roles`, `using`, `withCheck`, `permissive = false`, `@@map`; `@@rls` on the model; roles declared as contract entities; TS builder `policySelect` … `policyAll`, `rlsEnabled(Model)`, `role('name')` from `@prisma/orm-postgres/contract-builder`; `contract infer` captures live policies; the planner emits `ENABLE ROW LEVEL SECURITY` and `CREATE POLICY` — evidence: `packages/3-extensions/postgres/src/contract/rls.ts` (role, enablement and policy handles), `packages/3-targets/3-targets/postgres/src/core/postgres-rls-policy.ts`, `postgres-rls-enablement.ts`, `postgres-role.ts`, `migrations/operations/rls.ts`, `psl-infer/infer-policy-blocks.ts`; `skills/prisma-8/references/contract.md:378`; `skills/prisma-8/references/supabase.md` ("Contract: FK into auth.users + RLS policies") — the site only mentions RLS in error codes (`orm/reference/error-reference.mdx:382-392,436`) — belongs in `orm/contract-authoring/` (a "Row level security" page) with a note that the Supabase pack only supplies the roles. +3. Expression (functional) and partial indexes (known) — `@@index(expression: "lower(email)", name: "users_email_lower")`, `@@index([...], where: "...")`, `unique:`, `type:` (btree, hash, gin, gist, spgist, brin) and `options:`, `name:` vs `map:`; TS builder `constraints.index({ expression, ... })` — evidence: `packages/2-sql/1-core/contract/src/ir/sql-index.ts:12-26,45-60`; `packages/3-targets/3-targets/postgres/src/core/index-types.ts`; `skills/prisma-8/references/contract.md:101-108` — the site shows only `@@index([cols])` (`orm/contract-authoring/psl-syntax.mdx:97,137`; `orm/reference/orm-client.mdx:161-162`) — belongs on `orm/contract-authoring/psl-syntax.mdx`. +4. `@@control()` and `defaultControlPolicy` — a model can declare `managed`, `tolerated`, `external`, or `observed` to say whether Prisma owns its DDL; a contract-wide default goes on `prismaContract(path, { defaultControlPolicy })` — evidence: `packages/2-sql/2-authoring/contract-psl/README.md:104`; `packages/2-sql/2-authoring/contract-psl/src/interpreter.ts:341`, `psl-field-resolution.ts:418-422`; `packages/9-public/@prisma/orm-postgres/package.json` export `./contract/apply-specifier-default-control-policy`; `skills/prisma-8/references/contract.md:333-346` — no ORM 8 page contains `@@control` — belongs on `orm/contract-authoring/psl-syntax.mdx` and `orm/migrations/how-migrations-work.mdx`. +5. Vite plugin — `@prisma/orm-postgres/vite-plugin-contract-emit` exports `prismaVitePlugin('prisma.config.ts', { debounceMs, logLevel })`, re-emits the contract on save in `vite dev` (Vite 7 and 8 only; no build-time emit; no Next.js / Webpack / esbuild / Rollup / Turbopack plugin) — evidence: `packages/9-public/@prisma/orm-postgres/package.json` (`"./vite-plugin-contract-emit"`); `packages/1-framework/3-tooling/vite-plugin-contract-emit/`; `skills/prisma-8/references/build.md` — the only site hits for "vite" are TanStack's own Nitro plugin (`guides/frameworks/tanstack-start.mdx:86`) — belongs in `orm/contract-authoring/` or a new "Build tools" page, and in `guides/frameworks/tanstack-start.mdx`. +6. `Decimal` (known) — PSL `Decimal` maps to Postgres `numeric` with optional `precision` (1..1000) and `scale` params; runtime value is a decimal string (`CANONICAL_NUMERIC_TEXT`); `@default` accepts numeric text; aggregates: `sum` over `numeric` returns a decimal `string | null`, `avgDecimal(field)` gives an exact decimal string, `sumBigInt` / `countBigInt` for integers, and `count()` / `sum` over integers throw `RUNTIME.DECODE_FAILED` past 2^53-1 — evidence: `packages/3-targets/3-targets/postgres/src/core/codecs.ts:121-175,547`; `codec-type-map.ts:73`; `default-normalizer.ts:18,221`; `psl-infer/infer-enum-blocks.ts:19`; `skills/prisma-8/references/queries-postgres.md:233-255,386,407` — `orm/data-modeling/index.mdx:152-160` omits `Decimal` from the scalar table and `:182` says to store money as integer minor units; nothing documents `avgDecimal` / `sumBigInt` / the overflow error — belongs on `orm/data-modeling/index.mdx` and `orm/fundamentals/advanced-queries.mdx` (aggregates). +7. SQLite target (known) — `@prisma/orm-sqlite` ships at rc.9 with `sqlite(...)` runtime, `[Symbol.asyncDispose]`, and its own capability limits (no `checkConstraint`, no `scalarList`, no `enums`, no `lateral`, no `avgDecimal`); the skill routes to it throughout — evidence: `packages/9-public/@prisma/orm-sqlite/package.json`; `packages/3-extensions/sqlite/src/runtime/sqlite.ts:85,354`; `skills/prisma-8/references/runtime.md:333`, `queries-postgres.md:255`, `contract.md` (`@@check` on SQLite) — site mentions are only `orm/reference/error-reference.mdx:598`, `cli/skills.mdx:38` and capability examples in `orm/contract-authoring/capabilities.mdx:46-70`; there is no getting-started, quickstart, or runtime section for SQLite — belongs in `(index)/prisma-orm/quickstart/`, `orm/reference/transactions-and-runtime.mdx`, `orm/index.mdx`. +8. Enabling a Postgres extension that has no pack (`pg_trgm`, `citext`, …) (known) — the migration authoring API has a structured `createExtension('')` op (renders `CREATE EXTENSION IF NOT EXISTS`), so a user can add it to a hand-written or edited `migration.ts`; there is no contract-level "requires extension" declaration, and no `pg_trgm` pack ships even though `docs/reference/capabilities.md:97-103` reserves a `pg_trgm` capability namespace — evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/op-factory-call.ts:1443-1465` (`CreateExtensionCall`, `renderTypeScript` → `createExtension("...")`); `migrations/operations/dependencies.ts:7-22`; `packages/3-extensions/` has no `pg_trgm` — the site only mentions `CREATE EXTENSION` for packs that ship their own migration (`orm/extensions/using-extensions.mdx:76`) — belongs on `orm/migrations/editing-a-migration.mdx`. +9. Streaming is cursor-backed on Postgres — the site documents `for await` over `.all()` (`orm/fundamentals/reading-data.mdx:280-313`) but never says the Postgres driver reads through a server-side cursor in batches (`pg-cursor`, `cursorBatchSize`) nor that the serverless client takes `cursor` options; the skill wrongly says "No `.stream()` cursor today" — evidence: `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:24,374-384`, `named-cursor.ts`; `packages/3-extensions/postgres/src/runtime/postgres-serverless.ts:31` (`PostgresServerlessCursorOptions`); `packages/2-sql/5-runtime/src/sql-runtime.ts:387-399` — belongs on `orm/fundamentals/reading-data.mdx` and `orm/reference/transactions-and-runtime.mdx`. +10. `create-prisma` flags used by the tutorial — the tutorial uses `create ... --template hono --provider postgres --yes`, and `--authoring`, `--package-manager`, `--deploy`, `--workspace`, `--force`, `--json`, `--verbose` also exist; the tutorial says "Answer the prompts for contract authoring style and package manager" without naming the flags that skip them — evidence: `wip/create-prisma-src/src/index.ts:39-86` — belongs on `(index)/full-stack-tutorial.mdx:45` (one line) and `(index)/prisma-orm/create-prisma.mdx`. + +## Unverified + +- `(index)/full-stack-tutorial.mdx:213` — "a Composer deploy never sets the `db` ref that `migration plan` chains from by default" — Composer is not in the ORM monorepo, so this cannot be checked. What is verifiable: `--from` accepts "hash, prefix, ref name, migration dir name, `^`, `@empty`, or `./path`" (`packages/1-framework/3-tooling/cli/src/orm/migration/plan.ts:204-208`), so `--from _init` is a valid spelling, and the directory format is `_` (`packages/1-framework/3-tooling/migration/src/io.ts:456-470`). +- `(index)/full-stack-tutorial.mdx:218` — the shown DDL `ALTER TABLE "public"."user" ADD COLUMN "role" text DEFAULT 'member' NOT NULL` — the column is rendered through `renderColumnDdl` → `contractFree.col(name, type, { notNull, default })` (`packages/3-targets/3-targets/postgres/src/core/migrations/column-ddl-rendering.ts:64-78`); I did not trace the final clause ordering inside `contractFree.col`, so the exact text is unconfirmed. Table name `user` is consistent with the known `db.sql.public.user` item. +- `ai/tools/skills.mdx:19,102` and `cli/skills.mdx:9,48-54` disagree with each other and with the monorepo on the agent directory list. `ai/tools/skills.mdx` says Claude Code, Cursor, Codex, Windsurf (matches `skills/README.md` and `packages/1-framework/3-tooling/cli/src/commands/init/skill-sources.ts:44-49`: `.claude`, `.cursor`, `.agents`, `.windsurf`). `cli/skills.mdx:53`, `cli/init.mdx:29`, `cli/configuration.mdx:94` say `claude`, `cursor`, `agents`, `devin` (matches the create-prisma scaffold's `prisma.config.ts`, `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs`: `agents: ["claude", "cursor", "agents", "devin"]`). The `skills sync` implementation is not in the monorepo, so I cannot say which list is current; one of the two pages is wrong. +- `ai/tools/skills.mdx:19,102` — links "prisma/prisma" text to `https://github.com/prisma/orm`, and the install command is `npx skills add prisma/prisma/skills` — `skills/README.md` uses `prisma/prisma/skills`, but `packages/9-public/@prisma/orm-postgres/package.json` `repository.url` is `https://github.com/prisma/orm.git`. Could not determine which GitHub path the `skills` CLI must be given. +- `cli/telemetry.mdx` — the rc.9 first-run notice points users to `https://prisma-next.dev/docs/cli/telemetry` (`packages/1-framework/3-tooling/cli/src/orm/cli.ts:47`; `reporting.ts:24-31`), not to this page's URL. Source-side issue, noted because users will arrive from that link. + +## Skill vs site + +- `skills/prisma-8/references/queries.md:146` says "Streaming large result sets. No `.stream()` cursor today" and recommends holding a `pg.Client` to stream; the site (`orm/fundamentals/reading-data.mdx:280-313`) says `for await` over `.all()` streams without buffering. The source matches the site: `collection.ts:998-1022` exposes the async-iterable read terminal and the Postgres driver iterates via `pg-cursor` (`packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:374-384`). The skill is stale. +- `skills/prisma-8/references/runtime.md:11,135-158,315,322` tells users to import `createTelemetryMiddleware` from `@internal/middleware-telemetry`; no such package exists in the rc.9 tree (only comments and old plan docs mention it). The site's "Three middleware ship with Prisma 8 today" (`orm/middleware/how-middleware-works.mdx:82`: lints, budgets, cache) matches the source (`packages/2-sql/5-runtime/src/middleware/{lints,budgets}.ts`, `packages/3-extensions/middleware-cache/`). The skill is stale; also `runtime.md` never mentions the cache middleware the site documents. +- `skills/prisma-8/references/contract.md:25,29,49` uses `cipherstash.EncryptedString(...)` as a canonical extension example; no cipherstash package exists in the rc.9 tree (`wip/prisma-src/CHANGELOG.md:1040` records `@prisma-next/extension-cipherstash` being dropped in favour of CipherStash's own `@cipherstash/prisma-next`, `README.md:82`). The site does not mention cipherstash, which is correct. +- `skills/prisma-8/references/contract.md:179` writes `pgvector.Vector(length: 1536)`; the site (`orm/extensions/using-extensions.mdx`) and `examples/prisma-8-demo/src/prisma/contract.prisma:4` use positional `pgvector.Vector(1536)`. The examples compile against rc.9, so the site matches. +- `skills/prisma-8/SKILL.md` and `skills/README.md` describe one skill (`prisma-8`) synced from installed packages by `prisma init` / `prisma skills sync`; `ai/tools/skills.mdx:100-114` describes three skills installed by `orm init` from GitHub. The source matches the skill (see Breaks copy-paste and Misleading above). +- `docs/Telemetry.md` says "No outcome data. Phase 1 does not collect success/failure, exit code"; the rc.9 sender includes `exitCode` (`packages/1-framework/3-tooling/cli-telemetry/src/payload.ts:115`, `enrich.ts:222`; `reporting.ts:86-99` fires from `onSettled` with `summary.exitCode`). The monorepo doc is stale; the site says nothing either way. + +## Part 2: targeted gap questions + +Each item: is it supported at rc.9, where the evidence is, and whether the ORM 8 part of the site documents it. Site greps covered `orm/` (not v6/v7), `cli/` (not v7), `(index)/prisma-orm/`, `(index)/getting-started.mdx`, `guides/` (not v7). + +### Supported and undocumented (these are the Missing items above) + +- Row level security outside Supabase — supported (Missing item 2). Site: no page; only error codes. +- Expression and functional indexes — supported (Missing item 3). Site: none. +- Enabling `pg_trgm` and other extensions from a migration — supported via `createExtension()` op in `migration.ts`; not declarable in the contract (Missing item 8). Site: none beyond packs that ship their own migration. +- `Decimal` precision and scale, `@default` on Decimal, aggregate return types — supported (Missing item 6). Site: `Decimal` is not even in the scalar table (`orm/data-modeling/index.mdx:152-160`). +- SQLite target — ships (Missing item 7). Site: `orm/index.mdx:36` still says planned (known); no runtime or quickstart coverage. +- Vite plugin — ships (Missing item 5). Site: none. +- `@@control` policies — supported (Missing item 4). Site: none. +- Streaming — supported and documented; the cursor mechanics are not (Missing item 9). + +### Supported and documented + +- `await using` on the client — `[Symbol.asyncDispose]` on the Postgres, SQLite, Mongo, Supabase and serverless clients (`packages/3-extensions/postgres/src/runtime/postgres.ts:73,381`, `sqlite/src/runtime/sqlite.ts:85,354`, `mongo/src/runtime/mongo.ts:40,237`, `supabase/src/runtime/supabase.ts:111,491`, `postgres-serverless.ts:181`). Site: `orm/reference/transactions-and-runtime.mdx:148-164,328-343` documents it, including the block-scope warning that matches `skills/prisma-8/references/runtime.md:318`. +- Streaming results — `for await` over `.all()` / `.createAll()` / update / delete terminals (`packages/3-extensions/sql-orm-client/src/collection.ts:998-1022,1313-1329,1932-1947,2100-2113`). Site: `orm/fundamentals/reading-data.mdx:280-313`, including the "read once" rule. + +### Not supported at rc.9 + +- Filtering on JSON columns by path or containment — not supported. The `jsonb` codec declares only the `equality` trait, so the ORM `where` shorthand allows whole-value `eq` / `in` on a `Json` field and nothing else; the SQL builder has no JSON path, `->>`, or `@>` functions (`packages/3-targets/3-targets/postgres/src/core/codecs.ts:1417-1421`; no `json` hits in `packages/2-sql/4-lanes/sql-builder/src/` or `packages/3-targets/3-targets/postgres/src/core/ast/`). The only JSON-aware builder pieces are `jsonObject` / `jsonArrayAgg` used internally for includes (`sql-orm-client/src/where-binding.ts:72-75`). Instead: use `db.raw.sql\`...\`` or `fns.raw` in a builder `.select(...)` (`skills/prisma-8/references/queries.md:143`), or `@prisma/orm-extension-arktype-json` for typed storage (not filtering). Site: `orm/data-modeling/index.mdx:159` lists `Json` with no note on filter limits — worth a one-line "Misleading by omission" fix there. +- Soft delete, model validations, lifecycle callbacks — not supported (`skills/prisma-8/references/contract.md:392-394`). Instead: `deletedAt DateTime?` plus explicit filters or a middleware; validate with arktype in app code; use middleware for hooks. Site: no ORM 8 page claims these exist (the `validation` / `callback` grep hits are unrelated uses of the words). +- Custom `Collection` subclasses — not a supported extension point. `Collection` is exported as a type-level surface from `@prisma/orm-postgres/orm-client` (`packages/3-extensions/sql-orm-client/src/exports/index.ts:1`), but the implementation is a `CollectionImpl` class with private `#clone` / `#createSelf` methods (`collection.ts:216,2434-2495`) that cannot be subclassed to add behaviour. Instead: wrap queries in plain functions or write middleware. Site: nothing claims otherwise. +- Read replicas and multi-database routing — not supported (`skills/prisma-8/references/runtime.md:323`; `grep -ri replica packages/` finds only the Mongo replica-set note in `packages/1-framework/3-tooling/cli/src/commands/init/templates/env.ts:44-47` and the cache store). Instead: construct one client per database in separate `db.ts` modules and pick in app code. Site: `guides/database/multiple-databases.mdx` is the only match and is a v7 guide (see Misleading). +- Prisma Composer and a Prisma Postgres native provider — absent from the ORM monorepo. No `@prisma/composer*` code or `prisma+postgres://` handling exists under `packages/` (`grep -ri composer packages/` hits one test; `grep -ri 'prisma+postgres\|accelerate' packages/` hits nothing). Prisma Postgres is reached through the ordinary `pg` driver with a `postgres://` URL (`packages/9-public/@prisma/orm-postgres/package.json` dependencies: `pg`). The scaffold wires Composer's `service.load().database.client` ahead of `DATABASE_URL` (`wip/create-prisma-src/templates/create/_shared/src/prisma/db.ts.hbs`). Instead: nothing needed; the site's Composer coverage lives outside the ORM section and could not be audited against source. +- `pg_trgm` as an extension pack — no pack ships (`packages/3-extensions/`: arktype-json, middleware-cache, paradedb, pgvector, postgis, supabase, plus the postgres / sqlite / mongo façades and sql-orm-client). Instead: `createExtension('pg_trgm')` in a migration plus `@@index(..., type: "gin", ...)` for the index; there are no trigram operators in the builder, so similarity queries go through `db.raw`. + +### Extension packages vs site + +| Package | Public name | Site coverage | +| --- | --- | --- | +| `3-extensions/pgvector` | `@prisma/orm-extension-pgvector` (`/control`, `/pack`, `/runtime`, `/column-types`, `/codec-types`, `/operation-types`) | Worked example throughout `orm/extensions/using-extensions.mdx`; correct | +| `3-extensions/postgis` | `@prisma/orm-extension-postgis` (adds `/geojson`) | Catalog row only (`orm/extensions/using-extensions.mdx:111`) plus error codes; no page for the `Geometry` type or its 7 operations | +| `3-extensions/paradedb` | `@prisma/orm-extension-paradedb` (`/index-types`, `/operation-types`) | Catalog row only (`:112,116`); `key_field`-only caveat matches the README | +| `3-extensions/supabase` | `@prisma/orm-extension-supabase` (`/pack`, `/runtime`, `/contract`; no `/control`) | Catalog row only (`:113`). The page's generic 5-step recipe (import `.../control`, pass to `postgres({ extensions })`) does not work for this package: it is wired via `extensions: [supabasePack]` from `/pack` and the client is built with `supabase()` from `/runtime` (`packages/9-public/@prisma/orm-extension-supabase/package.json`; `skills/prisma-8/references/contract.md:348-367`, `supabase.md`). Report this as Misleading on `orm/extensions/using-extensions.mdx` | +| `3-extensions/arktype-json` | `@prisma/orm-extension-arktype-json` (`arktypeJson(schema)` column factory) | Catalog row only (`:114`); `arktypeJson` never shown | +| `3-extensions/middleware-cache` | `@prisma/orm-extension-middleware-cache` | Dedicated page `orm/middleware/built-in-cache.mdx`; correct | +| lints, budgets (no own package) | `@prisma/orm-postgres/family-runtime` | Dedicated pages `orm/middleware/built-in-lints.mdx`, `built-in-budgets.mdx`; import path matches `packages/0-shared/publish-surface/src/shells.ts:219` | +| cipherstash | none at rc.9 (dropped; see `CHANGELOG.md:1040`) | Correctly absent | +| telemetry middleware | none at rc.9 | Correctly absent (the skill still names it) | + +One more site-side issue from that inventory: every catalog row links to `github.com/prisma/orm/tree/main/packages/3-extensions/#readme`, and those READMEs instruct `pnpm add @internal/extension-`, a private name users cannot install (`packages/3-extensions/pgvector/README.md`, `paradedb/README.md`, `postgis/README.md`). The site's package names are right; its links lead to wrong install commands. + +### Monorepo reference docs vs site + +Written from the sub-agent's report (docs under `wip/prisma-src/docs/`). Only user-facing facts are listed; `mongodb-feature-support-priorities.md`, `mongodb-idioms.md`, `mongodb-primitives-reference.md`, `mongodb-user-journey.md`, `mongodb-user-promise.md`, and `framework-gaps.md` are internal planning or contributor docs and describe intent, not shipped behaviour; treat their claims as unverified unless the source confirms them. + +- `Serverless Deployment Guide.md` — two facades: `postgres()` (long-lived, cursors disabled) and `postgresServerless()` (per-request, cursors enabled by default); `await using runtime = await db.connect({ url })`; Cloudflare Hyperdrive as the tested path (`nodejs_compat`, `wrangler hyperdrive create`, `WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_*`); migrations run on Node against the origin URL, never through Hyperdrive; one runtime per `connect()` and no crossing runtimes inside a transaction; Workers isolate memory is 128 MiB so `limit()` is the memory cap; bundle about 254 KiB gzipped. Production caveat at lines 97 and 274: against real Hyperdrive the default cursor path hangs (`Protocol Error: Unexpected protocol code: C`, SQLSTATE 58000, request killed at 30 s with Cloudflare error 1101), workaround `cursor: { disabled: true }`. None of this is on the site; the only Cloudflare guide is Prisma 7. The guide's own import paths are `@internal/postgres/*`; the public path is `@prisma/orm-postgres/serverless`. +- `Supported Versions.md` — Node 24, Bun 1.2, Deno 2.0, PostgreSQL 15, MongoDB 8.0, TypeScript 5.9 (optional peer), `tsconfig` must set `moduleResolution: "bundler"` and `strict: true`, `prisma orm init --merge-tsconfig`, ESM-only with no CommonJS. Site: Bun guide says 1.1; PostgreSQL floor stated nowhere; ESM-only and `strict` stated nowhere; `--merge-tsconfig` does not exist in `orm/init.ts` at rc.9 (doc is stale there); the upgrade guide presents `module: nodenext` as the example setting; the doc's Node 24 disagrees with the scaffold's `^22.18.0 || >=24.11.0`. +- `reference/integer-representation-types.md` — `BigInt` (default, `bigint`), `BigIntNumber` (`number`, guarded to 2^53-1), Postgres-only `UnboundedInt`; PSL and TS authoring; the aggregate result matrix per column type; SQLite has no `avgDecimal`. Site documents only the runtime errors, never the types as features. +- `reference/aggregate-descriptor-guide.md` — Postgres contributes `count`, `countBigInt`, `sum`, `sumBigInt`, `avg`, `avgDecimal`, `min`, `max`; `min`/`max` output the input's own type (site says numeric-only); the aggregate map lives in `contract.d.ts` only. +- `reference/codec-authoring-guide.md` — two user-facing caveats buried in a contributor doc: `pg/geometry@1` is exempt from the canonical JSON round-trip guarantee (PostGIS users, no warning on the site), and float codecs need `extra_float_digits >= 1` on the session with nothing enforcing it; `NaN` and infinities are rejected by `sql/float@1`, accepted by `pg/numeric@1`. +- `reference/postgres-native-enums.md` — why a contract `enum` is a CHECK constraint (no in-transaction `ADD VALUE`, no remove or reorder, full-table rewrite on retype); externally managed native enums are supported; self-managed native enums get `ADD VALUE` only from `migration plan`. Site states the CHECK fact and nothing else; `orm-client.mdx:478` documents native-enum ordering without ever saying how to get one. +- `reference/capabilities.md` — disagrees with `orm/contract-authoring/capabilities.mdx` on where `lateral` / `returning` / `jsonAgg` live (`sql.*` vs `postgres.*`), on pack key nesting (`pgvector.cosine` vs `postgres.pgvector.cosine`), on the error code (`E_CAPABILITY_MISSING` vs the site's `ORM.CAPABILITY_MISSING`), and on whether capabilities are negotiated at connect time or fixed at emit time. The site's keys (`sql.scalarList`, `postgres.distinctOn`) do not appear in the doc. Unverified which is current; check `packages/3-targets/3-targets/postgres/src` for the real key strings before touching the site page. The handover notes that `docs/architecture docs/subsystems/` is stale; `docs/reference/` may be too. +- `reference/Mongo Pipeline Builder.md` — the doc is older than the site: it shows `mongoQuery()` from an internal path (site: `db.query.from(...)`), bare single-operation updaters (site says they must return an array and names "older internal material" as the source of the mistake), and `build()` executing (site: terminals return a plan). Site is closer to the source; add `merge()`'s `on` / `whenMatched` / `whenNotMatched` keys and the `null` row type on find-and-modify terminals. +- `mongodb-user-promise.md` claims cascade / restrict / setNull referential integrity for MongoDB as the "strongest differentiator"; `grep onDelete packages/2-mongo-family` (non-test) is empty, so it is not implemented at rc.9. Same doc says budgets and lints work on Mongo; the site says `familyId: 'sql'` and that matches the source. diff --git a/docs/orm-docs-audit/audit/gaps.md b/docs/orm-docs-audit/audit/gaps.md new file mode 100644 index 0000000000..dff1ea2ff6 --- /dev/null +++ b/docs/orm-docs-audit/audit/gaps.md @@ -0,0 +1,66 @@ +# Audit: gaps + +Pages read: guides/frameworks/astro.mdx, guides/frameworks/elysia.mdx, guides/frameworks/hono.mdx, guides/frameworks/nestjs.mdx, guides/frameworks/nextjs.mdx, guides/frameworks/nuxt.mdx, guides/frameworks/react-router-7.mdx, guides/frameworks/solid-start.mdx, guides/frameworks/sveltekit.mdx, guides/frameworks/tanstack-start.mdx, guides/deployment/docker.mdx, guides/deployment/cloudflare-workers.mdx, guides/deployment/cloudflare-d1.mdx, guides/deployment/turborepo.mdx, guides/deployment/pnpm-workspaces.mdx, guides/deployment/bun-workspaces.mdx, guides/runtimes/bun.mdx, guides/runtimes/deno.mdx, guides/integrations/github-actions.mdx, guides/integrations/vercel-deployment.mdx, guides/integrations/ai-sdk.mdx. For the reverse audit: `skills/prisma-8/SKILL.md`, every file in `skills/prisma-8/references/`, `docs/glossary.md`, and the `exports` maps of every package under `packages/9-public/@prisma/`. + +Verification sources for the Prisma 8 framework and runtime pages were the create-prisma templates under `wip/create-prisma-src/templates/create/` and its CLI source under `wip/create-prisma-src/src/`, since those pages document what the scaffold generates. + +## Breaks copy-paste + +Ten of the twenty-one pages in this area are Prisma ORM 7 content sitting under a Prisma ORM 8 path. Every install command, config file, schema block, CLI command, and query on them is Prisma 7. None of them has a copy under `guides/v7/` (`guides/v7/` only contains `frameworks/` and `runtimes/`, and neither `react-router-7` nor `solid-start` is in `guides/v7/frameworks/`), so the Prisma 7 content has no v7 home either. One bullet per page; the count is of distinct Prisma 7 constructs on that page. + +- `guides/frameworks/react-router-7.mdx:49` (12 constructs, through line 647) — `npm install prisma@7.10.0 …`, `@prisma/client@7.10.0 @prisma/adapter-pg`, `npx prisma init --output`, `generator client { provider = "prisma-client" }`, `prisma migrate dev`, `prisma generate`, `prisma db seed`, `prisma studio`, `new PrismaClient({ adapter })`, `prisma.user.findMany()`, `findUnique({ where })`, `create({ data })` — Prisma ORM 8 installs `@prisma/orm-postgres` and `prisma`, scaffolds with `prisma orm init` or `create-prisma`, emits with `contract emit`, applies with `db init` / `db update` / `migration plan` + `db migrate`, and queries through `db.orm.public.User.…`; there is no `generate`, `migrate dev`, `db seed`, or `studio` command — evidence: `packages/1-framework/3-tooling/cli/src/orm/{contract,db,migration}/` (the complete command set: `contract emit|infer`, `db init|update|sign|verify|schema`, `migration plan|new|show|status|list|log|graph|check`, `migrate`), `create-prisma-src/src/tasks/install.ts:47-58` (the scripts a scaffold gets), `skills/prisma-8/references/quickstart.md:387-391` (no Studio, no push-style sync), `skills/prisma-8/references/migrations.md:488` (no `db seed` equivalent). +- `guides/frameworks/solid-start.mdx:70` (11 constructs, through line 322: `import { User, Post } from "./generated/prisma/client"`) — same Prisma 7 flow as above — same evidence. +- `guides/deployment/docker.mdx:69` (10 constructs, through line 519) — `prisma@7.10.0`, `@prisma/client@7.10.0`, `prisma init --output`, generator block, `require("./generated/prisma_client/client")`, `"db:deploy": "npx prisma migrate deploy && npx prisma generate"` (line 201), `prisma migrate dev`, `prisma generate`, `npx prisma studio --port 5555` (line 519), and the Alpine `musl` engine note at line 347 — Prisma ORM 8 has no query engine binary to download; the Postgres runtime is the `pg` driver in-process, deployment runs `contract emit` at build time and `db migrate` (or `db init`) at start, and there is no Studio — evidence: `packages/3-extensions/postgres/README.md:8-10` (façade-owned `pg.Pool` / `pg.Client`), `skills/prisma-8/references/build.md:421-435` (`prebuild` emit), `skills/prisma-8/references/migrations.md:487` (run `db migrate` from the deploy pipeline). +- `guides/deployment/cloudflare-workers.mdx:49` (9 constructs, through line 344) — `prisma@7.10.0`, `runtime = "cloudflare"` generator field (line 106), `prisma migrate dev`, `prisma generate`, per-request `new PrismaClient({ adapter })` (line 243), `prisma.user.create({ data })`, `prisma.user.count()` — the Prisma ORM 8 per-request surface is `@prisma/orm-postgres/serverless`: `postgresServerless({ contractJson })` at module scope and `await using runtime = await db.connect({ url })` inside `fetch` — evidence: `packages/9-public/@prisma/orm-postgres/package.json` export `./serverless`, `packages/3-extensions/postgres/README.md:41-60,126-136`. Lines 416 and 418 already link to `/guides/v7/frameworks/hono` and `/orm/v7/...`, confirming the page is v7 content. +- `guides/deployment/cloudflare-d1.mdx:40` (9 constructs, through line 264) — `npx prisma@7.10.0 init --datasource-provider sqlite`, `@prisma/adapter-d1`, `runtime = "cloudflare"`, `prisma migrate diff --from-empty` / `--from-local-d1` (lines 180, 223), `prisma generate`, `new PrismaD1(env.DB)`, `prisma.$disconnect()` — Prisma ORM 8's SQLite target is `@prisma/orm-sqlite` (`sqlite({ contractJson, path })`); there is no D1 driver in the public package set and no `migrate diff` command — evidence: `packages/9-public/@prisma/` directory listing (no `adapter-d1` or D1 driver), `packages/9-public/@prisma/orm-sqlite/package.json` exports, `skills/prisma-8/references/runtime.md:285-296`, CLI command list above. +- `guides/deployment/turborepo.mdx:68` (10 constructs, through line 359) — `prisma@7.10.0`, `@prisma/client@7.10.0`, `prisma init`, generator block, `db:generate`/`db:migrate`/`db:deploy` scripts (`prisma generate`, `prisma migrate dev`, `prisma migrate deploy`), `npx turbo run db:migrate -- --name init`, "In Prisma 7, `migrate dev` no longer runs `prisma generate`" (line 231), `new PrismaClient`, `prisma.user.findFirst()` — Prisma ORM 8's shared package holds `prisma.config.ts`, `src/prisma/contract.prisma`, the emitted `contract.json` / `contract.d.ts`, `db.ts`, and `migrations/app/`; the scripts are `contract:emit`, `db:update`, `migration:plan`, `migrate` — evidence: `skills/prisma-8/references/quickstart.md:127-159` (canonical layout), `create-prisma-src/src/tasks/install.ts:47-58`. +- `guides/deployment/pnpm-workspaces.mdx:43` (10 constructs, through line 305) — `catalogs: prisma: 7.10.0`, `pnpm dlx prisma@7.10.0 init` (line 110), generator block, `prisma generate`/`migrate dev`/`migrate deploy`/`studio` scripts, `new PrismaClient({ adapter })`, `prisma.user.findFirst({ select })` — same as the Turborepo bullet — same evidence. +- `guides/deployment/bun-workspaces.mdx:61` (11 constructs, through line 224) — `prisma@7.10.0`, `@prisma/client@7.10.0`, `prisma init`, generator block, `prisma db seed` script (line 131), `prisma.user.createMany({ data, skipDuplicates: true })` (lines 198-204), `prisma.$disconnect()`, `seed: "bun prisma/seed.ts"` under `migrations` in `prisma.config.ts` (line 224) — Prisma ORM 8 has no `db seed` and no `seed` config key; the bulk insert is `createAll`; a seed is an ordinary script that imports `db` (the scaffolds put it at `src/prisma/seed.ts` and use `upsert` with `conflictOn`) — evidence: `skills/prisma-8/references/migrations.md:488`, `create-prisma-src/templates/create/_shared/src/prisma/seed.ts.hbs`, `skills/prisma-8/references/queries-mongo.md:327` (`createAll`). +- `guides/integrations/github-actions.mdx:46` (9 constructs, through line 445) — `prisma@7.10.0`, `@prisma/client@7.10.0`, `prisma init --output`, generator block, `seed:` in `prisma.config.ts` (line 120), `prisma migrate dev`, `prisma generate`, and the CI steps `npx prisma generate` + `npx prisma db push` (lines 424-427, 442) — the Prisma ORM 8 CI shape is `prisma contract emit`, then `prisma db init --db $URL` for a fresh database (or `migration status --to --db $URL --json` as the check and `db migrate --to --db $URL` to apply); there is no `db push` — evidence: `skills/prisma-8/references/migration-review.md:172-197`, `skills/prisma-8/references/quickstart.md:390`, CLI command list above. +- `guides/integrations/ai-sdk.mdx:56` (10 constructs, through line 392) — `prisma@7.10.0`, `@prisma/client@7.10.0`, `prisma init --output`, generator block, `prisma migrate dev`, `prisma generate`, `new PrismaClient({ adapter })`, `prisma.session.upsert({ where, update, create })` (line 320), `prisma.message.create({ data })` (line 357), `prisma.message.findMany({ orderBy: { createdAt: "asc" } })` (line 392), `npx prisma studio` (line 627) — Prisma ORM 8 spells these `db.orm.public.Session.upsert({ create, update, conflictOn })`, `db.orm.public.Message.create({ … })`, `db.orm.public.Message.orderBy((m) => m.createdAt.asc()).all()` — evidence: `skills/prisma-8/references/queries-postgres.md:196-219,345-377`, `create-prisma-src/templates/create/_shared/src/prisma/seed.ts.hbs` (`conflictOn`). +- All ten pages above: `prisma.config.ts` written as `defineConfig({ schema, migrations: { path }, datasource: { url: env("DATABASE_URL") } })` from `prisma/config` (first at `react-router-7.mdx:125`) — the Prisma ORM 8 config is `definePrismaConfig({ orm: ormConfig({ contract: "./src/prisma/contract.prisma", db: { connection: process.env.DATABASE_URL! } }) })` with `definePrismaConfig` from `prisma/config` and `defineConfig as ormConfig` from `@prisma/orm-postgres/config` — evidence: `create-prisma-src/templates/create/_shared/prisma.config.ts.hbs`, `packages/3-extensions/postgres/src/config/define-config.ts`. +- `guides/runtimes/bun.mdx:161` (also in the agent prompt at line 33) — replace the `build` script with `esbuild src/server.ts --bundle --platform=node --format=esm --outfile=dist/server.mjs` — the minimal scaffold's `build` is `tsdown`, driven by a generated `tsdown.config.ts` whose entry is `{ server: "src/index.ts" }`; `esbuild` is not a dependency the scaffold installs, so `bun run build` fails with a missing `esbuild` binary unless it happens to be hoisted from a transitive dependency; the change that matches the scaffold is editing `entry` in `tsdown.config.ts` to `src/server.ts` — evidence: `create-prisma-src/templates/create/minimal/package.json.hbs` (`"build": "tsdown"`), `create-prisma-src/templates/create/_shared/tsdown.config.ts.hbs`, `create-prisma-src/src/templates/render-create-template.ts:25-30`, `create-prisma-src/src/constants/dependencies.ts` (no `esbuild` entry). + +## Misleading + +- `guides/runtimes/bun.mdx:96` (also lines 99 and 152; `guides/frameworks/hono.mdx:154`; `guides/frameworks/elysia.mdx:125`; `guides/frameworks/nestjs.mdx:138`) — teardown is written as `await db.runtime().close()` — the client's teardown method is `await db.close()` (idempotent, terminal, also wired to `Symbol.asyncDispose`); `runtime().close()` closes the inner `Runtime` without marking the client closed, and every other page on the site (`orm/reference/transactions-and-runtime.mdx:135,145`, `(index)/prisma-orm/add-to-existing-project/mongodb.mdx:115`) uses `db.close()` — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:72,374-383`, `skills/prisma-8/references/runtime.md:66-78,126-133`. +- `guides/runtimes/bun.mdx:11` — "Bun runs TypeScript directly, so there is no build step anywhere in the flow" — the same page requires `bun run build` before `deploy` (lines 156-176), and the scaffold's `dev` script is `tsx watch src/index.ts` for every non-Deno package manager, so `bun run dev` (line 104) starts a watcher that never exits rather than running the script once and printing the two lines shown; `bun src/index.ts` is the one-shot run — evidence: `create-prisma-src/templates/create/minimal/package.json.hbs` (`"dev": "tsx watch src/index.ts"` in the non-Deno branch), `create-prisma-src/src/constants/dependencies.ts:57-63` (`tsx` installed for the minimal template). +- `guides/frameworks/nestjs.mdx:88-92` (repeated in the agent prompt at line 31) — tells the reader to add `@Inject(UsersService)` and `@Inject(PrismaService)` when `GET /users` returns 500 — the scaffold already emits both explicit injection tokens, so the note describes a state the template no longer produces — evidence: `create-prisma-src/templates/create/nest/src/users.controller.ts.hbs:7`, `create-prisma-src/templates/create/nest/src/users.service.ts.hbs:8`. +- `guides/frameworks/astro.mdx:27` — "Node.js 24 or later" (same on `nestjs.mdx:17`, `nextjs.mdx:17`, `nuxt.mdx:27`, `sveltekit.mdx:27`, `tanstack-start.mdx:27`, `hono.mdx:17`; 7 pages) — the scaffolds declare `"engines": { "node": "^22.18.0 || >=24.11.0" }` and create-prisma itself refuses anything below 22.18, so Node 22.18+ works and Node 24.0 to 24.10 does not — evidence: `create-prisma-src/templates/create/minimal/package.json.hbs`, `create-prisma-src/templates/create/hono/package.json.hbs`, `create-prisma-src/src/utils/node-version.ts:17-20`. (The known-issue list mentions differing Node claims on the getting-started pages; these are the framework pages.) +- `guides/runtimes/deno.mdx:142` — "The generated ORM tasks currently use the Deno-compatible Prisma 8 ORM CLI entry point. The consolidated `npm:prisma@latest` CLI still loads Node-only credential storage under Deno" — create-prisma now generates every Deno task against the consolidated CLI (`deno run -A --env-file=.env npm:prisma@latest db init` and so on); the separate entry point is gone — evidence: `create-prisma-src/src/constants/dependencies.ts:26-31` (`PRISMA_DENO_CLI_PACKAGE = PRISMA_PLATFORM_CLI_PACKAGE`, "The former `prisma-next` fallback is frozen"), `create-prisma-src/src/tasks/install.ts:25-45`. +- `guides/runtimes/deno.mdx:93-99` — the sample response shows only `email` and `name` per user — the generated `listUsers` (which the page itself prints at lines 108-127) returns `id`, `email`, `username`, `name`, and `createdAt` — evidence: `create-prisma-src/templates/create/_shared/src/prisma/users.ts.hbs`. +- `guides/frameworks/astro.mdx:78` — "`db:init` applies your schema (`src/prisma/contract.prisma`)" (same on `nestjs.mdx:66`, `nextjs.mdx:65`, `nuxt.mdx:76`, `sveltekit.mdx:75`, `tanstack-start.mdx:74`, `bun.mdx:62`; 7 pages) while the same pages say to "answer the prompts for contract authoring style" — with `--authoring typescript` the source is `src/prisma/contract.ts` and the emitted `contract.json` / `contract.d.ts` land under `src/prisma/generated/`, which no page mentions — evidence: `create-prisma-src/templates/create/_shared/prisma.config.ts.hbs`, `create-prisma-src/templates/create/_shared/src/prisma/db.ts.hbs` (`./generated/contract.json` when `authoring === "typescript"`). +- `guides/frameworks/astro.mdx:39` — "Then run `npx prisma@latest init` in `my-astro-app` so the Prisma agent skills are installed" (same step in every framework and Bun agent prompt; 9 pages) — create-prisma already runs `prisma init --yes` after scaffolding for every package manager except Deno, so the step repeats work the scaffold did; harmless but it suggests the scaffold leaves skills uninstalled — evidence: `create-prisma-src/src/tasks/prisma-setup/commands.ts:56-62`. +- `guides/integrations/vercel-deployment.mdx:18` — the only pointer for deploying your own Prisma ORM app to Vercel goes to `/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel`, and line 629 says the demo templates use "Prisma ORM" without saying which major — under the Prisma 8 guides this sends readers to Prisma 7 instructions; there is no Prisma 8 Vercel deployment path on the site (see Missing). + +## Missing + +- A Prisma ORM 8 deployment guide for any host: Docker, Cloudflare Workers, Vercel, and the three monorepo pages are all Prisma 7 (see above), and nothing under `orm/`, `cli/`, or `(index)/prisma-orm/` mentions Docker, Workers, Lambda, or edge (`grep -i "cloudflare|workers|edge|lambda|docker"` finds nothing there). What a Prisma 8 deploy needs is documented in the source: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, and the per-request façade for edge runtimes — evidence: `skills/prisma-8/references/build.md:421-435`, `skills/prisma-8/references/migrations.md:487`, `packages/3-extensions/postgres/README.md:8-10,41-60` — belongs under `guides/deployment/`. +- `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })`, `await using runtime = await db.connect({ url })`, a fresh `pg.Client` per request, no `orm` / `runtime()` / `transaction()` on that façade, `cursor: { disabled: true }`) — the site never mentions it (`serverless` has zero hits under `orm/`, `cli/`, `(index)/prisma-orm/`) — evidence: `packages/9-public/@prisma/orm-postgres/package.json` export `./serverless`, `packages/3-extensions/postgres/src/exports/serverless.ts`, `packages/3-extensions/postgres/README.md:41-60,126-136` — belongs in `orm/reference/transactions-and-runtime.mdx` and a Prisma 8 Cloudflare Workers guide. +- The Vite plugin `@prisma/orm-postgres/vite-plugin-contract-emit` (`prismaVitePlugin('prisma.config.ts', { debounceMs, logLevel })`, Vite 7 and 8, dev-server only, plus the `"prebuild": "prisma contract emit"` pattern for `vite build`, Next.js, Webpack, esbuild, Rollup, and Turbopack) — zero hits on the site — evidence: `packages/9-public/@prisma/orm-postgres/package.json` export `./vite-plugin-contract-emit`, `packages/1-framework/3-tooling/vite-plugin-contract-emit/README.md`, `skills/prisma-8/references/build.md` — belongs in `orm/contract-authoring/the-contract-artifact.mdx` and the Vite-based framework guides (SvelteKit, Astro, Nuxt, TanStack Start), which currently tell readers to run `npm run contract:emit` by hand. +- The Supabase extension end to end: `@@rls` on a model, `policy_select` / `policy_insert` / `policy_update` / `policy_delete` / `policy_all` blocks with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, the async `supabase({ contractJson, url, jwksUrl | jwtSecret })` factory, role binding with `await db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()` returning a `RoleBoundDb`, the `asServiceRole().supabase` admin root, the session-pooler requirement (never port 6543), the one-time `GRANT` for `auth.*` reads, and the `SUPABASE.JWT_INVALID` / `SUPABASE.CONFIG_INVALID` errors — the site has one table row (`orm/extensions/using-extensions.mdx:113`) and the two error codes; `@@rls`, `policy_`, `asUser`, `jwksUrl`, and `RoleBoundDb` have zero hits — evidence: `packages/9-public/@prisma/orm-extension-supabase/package.json` (exports `./contract`, `./pack`, `./runtime`), `skills/prisma-8/references/supabase.md`, `skills/prisma-8/references/contract.md:309-331,348-367` — belongs as a page under `orm/extensions/` and a guide under `guides/` (the known-issue list covers RLS outside Supabase; this is RLS with Supabase). +- Control policy: `@@control(managed | tolerated | external | observed)` on a model and `defaultControlPolicy` in the config, and what each policy does to planned DDL and `db verify` — zero hits on the site (`control policy` appears only in `guides/integrations/permit-io.mdx`) — evidence: `skills/prisma-8/references/contract.md:333-346`, `skills/prisma-8/references/migrations.md:501-503`, `packages/9-public/@prisma/orm-postgres/package.json` export `./contract/apply-specifier-default-control-policy` — belongs in `orm/contract-authoring/psl-syntax.mdx` and `orm/migrations/how-migrations-work.mdx`. +- Index and check-constraint options: `@@index(expression: …, name: …)`, `@@index([…], where: "…", name: …)`, `unique:`, `type:` / `options:`, `@@check(expression: …, name: | map: …)`, `@noCheck` / `@noCheck(membership)` / `@noCheck(elementNotNull)`, and the naming rule behind `name:` (wire name, `_<8 hex>`) versus `map:` (exact name, body compared byte for byte, warns `PN_EXACT_NAME_BODY_COMPARISON`) — `orm/contract-authoring/psl-syntax.mdx:97,137` shows only `@@index([authorId])`; `@@check`, `@noCheck`, and `wire name` appear only inside `orm/reference/error-reference.mdx` — evidence: `skills/prisma-8/references/contract.md:101-108,265-290`, `packages/2-sql/1-core/contract/src/index-naming.ts:72`, `docs/glossary.md` "Naming Mode" and "Wire Name" — belongs in `orm/contract-authoring/psl-syntax.mdx` (functional and partial indexes are also on the known-missing list; this bullet adds the syntax and the naming rule). +- CLI telemetry opt-out via environment: `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, and `"enableTelemetry": false` in the per-user config — `cli/telemetry.mdx` lists only `telemetry status|enable|disable`; `DO_NOT_TRACK` appears on the site only for create-prisma's own telemetry (`(index)/prisma-orm/create-prisma.mdx:98`) — evidence: `packages/1-framework/3-tooling/cli/src/orm/telemetry/reporting.ts:30-31`, `packages/1-framework/3-tooling/cli-telemetry/src/gating.ts:17-26` — belongs on `cli/telemetry.mdx`. +- The full set of package scripts create-prisma generates: besides `contract:emit`, `db:init`, and `db:update` the scaffold adds `db:verify`, `migration:plan`, `migrate`, `migration:status`, `migration:show`, `skills:sync`, `composer:dev`, `composer:deploy`, `deploy` (build + composer deploy), and `dev:composer` — only `db:init`, `db:update`, `contract:emit`, and one `migration:plan` mention exist on the site — evidence: `create-prisma-src/src/tasks/install.ts:25-70` — belongs on `(index)/prisma-orm/create-prisma.mdx` and in each framework guide's "Where things live". +- The `composer` section of `prisma.config.ts` (`composer: { configPath: "./prisma-composer.config.ts" }`) and the generated Composer files every scaffold ships: `prisma-composer.config.ts` (`defineConfig({ extensions: [prismaCloud(), nodeBuild(), nextjsBuild()], state: prismaState() })`), `src/prisma/composer.ts` (`dataContract(contractJson)`), and the `db.ts` pattern `service.load().database.client ?? postgres({ contractJson, url: process.env.DATABASE_URL })` with `import "temporal-polyfill/global"` — `cli/configuration.mdx` documents only the `orm` and `skills` sections, and no framework page shows the generated `db.ts` — evidence: `create-prisma-src/templates/create/_shared/prisma.config.ts.hbs`, `prisma-composer.config.ts.hbs`, `src/prisma/composer.ts.hbs`, `src/prisma/db.ts.hbs` — belongs on `cli/configuration.mdx` and the framework guides. +- Where the automatic seed lives: `src/prisma/seed.ts` (three users via `upsert({ create, update: {}, conflictOn: { email } })`, memoised) called from `src/prisma/users.ts` before every `listUsers` — the framework pages say "seeded automatically on the app's first query" without naming either file (only `nestjs.mdx:99` and `sveltekit.mdx:89` name `users.ts`; the Deno page names both) — evidence: `create-prisma-src/templates/create/_shared/src/prisma/seed.ts.hbs`, `users.ts.hbs` — belongs in each framework guide's "Where things live". +- PSL scalar names the starter contract and the aggregate types use: `TimestamptzString` (the starter `createdAt` column), `BigIntNumber`, `UnboundedInt` — `TimestamptzString` and `BigIntNumber` appear only in `orm/reference/error-reference.mdx`, `UnboundedInt` nowhere; `psl-syntax.mdx` uses `DateTime` throughout — evidence: `packages/1-framework/3-tooling/cli/src/commands/init/templates/code-templates.ts:180`, `skills/prisma-8/references/queries-postgres.md:405-417` — belongs in `orm/contract-authoring/psl-syntax.mdx` (see Unverified for the `DateTime` question). +- The public packages `@prisma/orm-toolchain` (CLI, emitter, config loader, language server, Vite plugin) and `@prisma/orm-framework` (target-agnostic contract, components, PSL parser and printer) are never named — evidence: `packages/9-public/@prisma/orm-toolchain/package.json`, `packages/9-public/@prisma/orm-framework/package.json` — belongs on `orm/reference/index.mdx` or `cli/index.mdx` wherever the package set is listed. +- A Prisma 8 CI workflow: `prisma migration status --to --db "$URL" --json`, failing the job on any `diagnostics[]` entry with `severity: "warn"`, then `prisma db migrate --to --db "$URL"`; `migration status` exits 0 on warnings, so exit-code checks alone miss `MIGRATION.DIVERGED`, `MIGRATION.MARKER_NOT_IN_HISTORY`, `CONTRACT.AHEAD`, and `MIGRATION.NO_MARKER` — the only CI guide (`guides/integrations/github-actions.mdx`) is Prisma 7 — evidence: `skills/prisma-8/references/migration-review.md:172-197` — belongs in a rewritten `guides/integrations/github-actions.mdx`. + +## Unverified + +- `HostedStateBootstrapError` and the `--name` recovery (every framework page's deploy section, `guides/runtimes/bun.mdx:33,186`, `cli/deploy.mdx:28`) — the Composer / deploy implementation is not in `wip/prisma-src` (`grep -rl HostedStateBootstrapError packages` is empty) and the Composer packages are not in the worktree, so the error name and behaviour could not be checked. +- `guides/runtimes/deno.mdx:29,65` — `npx create-db@latest --env .env --ttl 24h` — the `create-db` source is not in the worktree; flags not checked. +- `guides/runtimes/deno.mdx:17` "Deno 2.0 or later" and `guides/frameworks/elysia.mdx:17` "Bun 1.1 or later" — no engine constraint for Deno or Bun in `create-prisma-src` or `prisma-src`. +- `orm/contract-authoring/psl-syntax.mdx:39` and the framework guides' starter contract — the site writes `createdAt DateTime` while the rc.9 starter contract writes `createdAt TimestamptzString @default(now())` (`code-templates.ts:180`); I could not find the PSL scalar-name table in `packages/2-sql/2-authoring/contract-psl/src` by grep (`'DateTime'` and `TimestamptzString` have no hits there), so whether `DateTime` still parses is not confirmed. Another area owns `psl-syntax.mdx`. +- The scaffold pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` (`create-prisma-src/src/constants/dependencies.ts:9-11`, "Must match @prisma/composer-prisma-cloud's exact peerDependency") while this audit is against rc.9; whether the published `create-prisma@latest` has moved could not be checked offline. Any rc.9-only behaviour the framework pages describe would not hold on a fresh scaffold until it does. + +## Skill vs site + +- Skill `references/debug.md:306-338`, `contract.md:62-66`, `migrations.md:67-75` route on numeric codes `PN-CLI-4001…4020`, `PN-MIG-2001…2005`, `PN-RUN-3001…3030`, `PN-SCHEMA-0001`; no such string exists in rc.9 `packages/` (`grep -rn "PN-MIG-[0-9]\|PN-CLI-[0-9]\|PN-RUN-[0-9]" packages --include='*.ts'` is empty); the site's `orm/reference/error-reference.mdx` uses the dotted `DOMAIN.CODE` form only. Site matches the source; the skill is stale here. +- Skill `references/quickstart.md:125` says the marker is a `pn_meta_marker` row; the source writes `prisma_contract.marker` and so does the site (`orm/migrations/the-migration-graph.mdx`, `orm/reference/error-reference.mdx`) — evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/runner.ts:321-326`. Site matches the source. +- Skill `references/runtime.md:135-158` documents `createTelemetryMiddleware` from `@internal/middleware-telemetry`; no such package exists in `packages/` or `packages/9-public/@prisma/` (grep empty). The site does not mention it, which is correct. +- Skill `references/runtime.md:66-78` and `queries.md:107-127` end scripts with `await db.close()`; the site's Bun, Hono, Elysia, and NestJS guides use `db.runtime().close()` while `orm/reference/transactions-and-runtime.mdx:135,145` uses `db.close()`. The source defines `close()` on the client (`packages/3-extensions/postgres/src/runtime/postgres.ts:72,374`); the skill and the reference page match it, the four guides do not. +- Skill `references/build.md:466` says Next.js has no first-party build integration and needs a `prebuild` emit; the site's `guides/frameworks/nextjs.mdx:117` tells readers to run `npm run contract:emit` by hand after schema changes and never mentions `prebuild`. Both agree there is no plugin; the site omits the workaround the skill gives. diff --git a/docs/orm-docs-audit/audit/migrations-cli.md b/docs/orm-docs-audit/audit/migrations-cli.md new file mode 100644 index 0000000000..f5340752d6 --- /dev/null +++ b/docs/orm-docs-audit/audit/migrations-cli.md @@ -0,0 +1,66 @@ +# Audit: migrations-cli + +Pages read: orm/migrations/how-migrations-work.mdx, orm/migrations/generating-a-migration.mdx, orm/migrations/editing-a-migration.mdx, orm/migrations/applying-a-migration.mdx, orm/migrations/rollbacks-and-recovery.mdx, orm/migrations/the-migration-graph.mdx, cli/index.mdx, cli/global-flags.mdx, cli/configuration.mdx, cli/error-reference.mdx, cli/init.mdx, cli/orm-init.mdx, cli/skills.mdx, cli/dev.mdx, cli/git.mdx, cli/db-init.mdx, cli/db-update.mdx, cli/db-migrate.mdx, cli/db-sign.mdx, cli/db-verify.mdx, cli/db-schema.mdx, cli/migration-new.mdx, cli/migration-plan.mdx, cli/migration-ref.mdx, cli/migration-show.mdx, cli/migration-status.mdx + +Monorepo paths below are relative to `wip/prisma-src/`. `cli/src` means `packages/1-framework/3-tooling/cli/src`. + +## Breaks copy-paste + +- `orm/migrations/how-migrations-work.mdx:56-62` (also `generating-a-migration.mdx:74-80,85-86`, `editing-a-migration.mdx:63-66`) — the migration directory contains `start-contract.json`, `end-contract.json` and `*-contract.d.ts`, and `migration.ts` imports `./end-contract` — since 0.17 every contract snapshot lives once in `migrations/snapshots//contract.json` + `contract.d.ts`, and the rendered `migration.ts` imports `../../snapshots//contract.json` and `../../snapshots//contract` (types). The directory holds only `migration.ts`, `ops.json`, `migration.json` (plus `contract.prisma` in the examples). Copying the page's imports into a real migration fails to resolve — evidence: `docs/releases/v0.17.0.md:47`, `examples/prisma-8-demo/migrations/app/20260810T1108_add_post_engagement_counters/migration.ts:2-10`, `packages/1-framework/3-tooling/migration/src/space-layout.ts:55-66` +- `orm/migrations/the-migration-graph.mdx:130` — `migration ref set prod sha256:f9a41d7...` — hashes are bare hex since 0.17 and loaders reject the `sha256:` form; the ref parser only accepts a 64-hex hash, a 6+ hex prefix, a ref name, a migration dir, or `^`. Same stale prefix on every hash the pages print: `how-migrations-work.mdx:119-123`, `generating-a-migration.mdx:47,144-145`, `applying-a-migration.mdx:32`, `rollbacks-and-recovery.mdx:37-38`, `the-migration-graph.mdx:40` — evidence: `docs/releases/v0.17.0.md:45`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:14-24,56-62`, `examples/prisma-8-demo/migrations/app/20260810T1108_add_post_engagement_counters/migration.json` +- `orm/migrations/the-migration-graph.mdx:187-188` — `ref set prod @db` and `ref list` — the commands are `migration ref set` / `migration ref list` (the bare `ref` group was retired in rc.5), and `migration ref set` is offline: `@db` parses to an empty sentinel hash that is not a graph node, so it fails with `MIGRATION.HASH_NOT_IN_GRAPH` rather than reading the database marker — evidence: `docs/releases/v8.0.0-rc.5.md:9`, `cli/src/orm/cli.ts:104-106`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:46-52`, `cli/src/control-api/operations/ref.ts:104-118` +- `cli/orm-init.mdx:38` — `--skip-skills` — the flag was removed in rc.6 together with the skill install it opted out of; `orm init` no longer installs skills at all. The flag set is `--target`, `--authoring`, `--schema-path`, `--write-env`, `--probe-db`, `--strict-probe`, `--skip-install`, `--keep-previous-facade` — evidence: `docs/releases/v8.0.0-rc.6.md:29`, `cli/src/orm/init.ts:7-26` +- `cli/orm-init.mdx:53` — `CLI.INIT_SKILL_INSTALL_FAILED` — retired with the skill install (rc.6); no such code exists in the tree — evidence: `docs/releases/v8.0.0-rc.6.md:29`, grep of `packages/` for `INIT_SKILL_INSTALL_FAILED` returns nothing +- `orm/migrations/editing-a-migration.mdx:75-80` — `sql({ context: createExecutionContext(...) })` — `SqlOptions.rawCodecInferer` is a required field of `sql()`; the runtime passes `stack.adapter.rawCodecInferer`. As written the block does not typecheck, so `node migration.ts` fails before emitting `ops.json` — evidence: `packages/2-sql/4-lanes/sql-builder/src/runtime/sql.ts:11-19`, `packages/3-extensions/postgres/src/runtime/postgres-serverless.ts:136` +- `orm/migrations/the-migration-graph.mdx:117-118` — `git clone https://github.com/prisma/orm` then `cd prisma` — the clone directory is `orm` — evidence: `packages/9-public/@prisma/orm-postgres/package.json` repository url `https://github.com/prisma/orm.git` + +## Misleading + +- `orm/migrations/generating-a-migration.mdx:164-166`, `cli/migration-plan.mdx:11`, `orm/migrations/the-migration-graph.mdx:137` — "without `--from` or a `db` ref, `migration plan` plans from an empty database: a full CREATE-everything migration" — since rc.8 the command refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` whenever migrations already exist on disk and names three exits (`migration ref set db `, `--from `, or the explicit opt-in `--from @empty`). Only an empty `migrations/app/` still plans from empty silently — evidence: `docs/releases/v8.0.0-rc.8.md:17`, `cli/src/utils/cli-errors.ts:428-475`, `cli/src/orm/migration/plan.ts:206` +- `orm/migrations/how-migrations-work.mdx:20-26`, `orm/migrations/generating-a-migration.mdx:157-161`, `orm/migrations/the-migration-graph.mdx:137`, `cli/index.mdx:70-73,86-92` — the pages present `db migrate --advance-ref db` as the way the `db` ref gets created, and every `db init` / `db update` example passes `--db "$DATABASE_URL"`. In the source `db init` and `db update` advance the `db` ref automatically when run without `--db`; passing `--db` suppresses that unless `--advance-ref` is also given. A user who follows the site's `db init --db ...` then `migration plan` then `db migrate --db ...` loop has no `db` ref, so the second `migration plan` hits `MIGRATION.PLAN_ORIGIN_UNKNOWN` — evidence: `cli/src/control-api/operations/ref-advancement.ts:19-28,116-130`, `skills/prisma-8/references/migrations.md:99-101`, `skills/prisma-8/references/migration-model.md:53-61` +- `orm/migrations/rollbacks-and-recovery.mdx:51,75` — "after a rollback the next `migration plan` fails with `MIGRATION.NO_TARGET` because the planner can no longer infer the latest state" — `migration plan` never infers a latest state: its origin is `--from`, else the `db` ref, else the rc.8 refusal above. `MIGRATION.NO_TARGET` is thrown by `findLeaf`, which `migration new` uses for its default `--from` and `migration ref set` uses for its suggestion text; `migration-plan.ts` does not call it — evidence: `packages/1-framework/3-tooling/migration/src/migration-graph.ts:505-518,544-550`, `cli/src/control-api/operations/migration-new.ts:143`, `cli/src/control-api/operations/ref.ts:115`, grep of `cli/src/control-api/operations/migration-plan.ts` for `findLeaf|findLatestMigration` returns nothing +- `orm/migrations/generating-a-migration.mdx:50,63`, `orm/migrations/applying-a-migration.mdx:34,37,65,68,113,116`, `orm/migrations/rollbacks-and-recovery.mdx:85,88` — the pages reproduce `prisma-cli migrate` / `prisma-cli migration status` hints and explain them as "the binary's own name for itself" — since rc.5 every hint uses the `{bin}` placeholder and the mounted path, so the output reads `prisma db migrate --to ...` / `prisma migration status`. The explanatory sentences are now wrong and the sample output is stale — evidence: `docs/releases/v8.0.0-rc.5.md:9`, `cli/src/orm/migration/status.ts:149`, `cli/src/utils/migrate-failure.ts:13` +- `orm/migrations/applying-a-migration.mdx:111`, `orm/migrations/rollbacks-and-recovery.mdx:83` — `(PN-RUN-3000)` in the failure output — the `PN-*` numeric codes were replaced by dotted codes in 0.17; runner failures surface as `MIGRATION.RUNNER_FAILED`, `MIGRATION.EXECUTION_FAILED`, `MIGRATION.PRECHECK_FAILED` or `MIGRATION.POSTCHECK_FAILED`. `cli/configuration.mdx:146` tells users to branch on the code, so the stale code matters — evidence: `docs/releases/v0.17.0.md:27`, `packages/1-framework/1-core/errors/src/execution.ts:255-275`, grep of `packages/` for `PN-RUN` returns nothing +- `orm/migrations/generating-a-migration.mdx:46` — `from: null` in the plan output — the CLI prints `from: (baseline)` for a null origin — evidence: `cli/src/orm/migration/plan.ts:24-31` +- `orm/migrations/how-migrations-work.mdx:44`, `orm/migrations/applying-a-migration.mdx:26,153` — `✔ Applied 1 migration(s) (3 operation(s)) across 1 contract space(s)` — the summary line is `Applied operation(s) across contract space[s]` (no migration count, no `(s)` on space), or `Database already matches contract ...` when nothing ran — evidence: `cli/src/orm/db/migration-blocks.ts:145-153` +- `orm/migrations/the-migration-graph.mdx:174` — "No baseline. You cannot yet adopt an existing database's history as a starting node without replaying it" — the planner emits an automatic baseline (`null → ref-hash`) plus the delta when the graph is empty and the `db` ref names a stored snapshot, and an explicit `--from @empty` plan at the deployed contract state is the supported retrofit; a baseline is never replayed against a marked database because the runner starts at the marker — evidence: `cli/src/control-api/operations/migration-plan.ts:369,505-545`, `skills/prisma-8/references/migration-model.md:75,139-150` +- `orm/migrations/the-migration-graph.mdx:139-142` — "two reserved tokens (`@contract`, `@db`) work anywhere a command accepts a contract reference" — there is a third, `@empty`, and `@db` is not accepted by the offline commands (`migration ref set`, see above); `migration plan --from` documents `@empty` but not `@db` — evidence: `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:14-24`, `cli/src/orm/migration/plan.ts:206` +- `cli/orm-init.mdx:78` — "the scaffolded `db.ts` reads `DATABASE_URL` from the process environment; your own scripts do not load `.env`, run them with `node --env-file=.env`" — the scaffolded `db.ts` starts with `import 'dotenv/config'`, so any script that imports it loads `.env` — evidence: `cli/src/commands/init/templates/code-templates.ts:324-345` +- `cli/orm-init.mdx:53` — "the `contract:emit` script it adds calls `prisma-cli`" — the script is `prisma contract emit` — evidence: `cli/src/commands/init/hygiene-package-scripts.ts:19` +- `cli/orm-init.mdx:44-49` — the "what it creates" list omits `prisma-next.md`, the quick-reference file the scaffold writes (and replaces on re-run, which is why re-running asks for consent) — evidence: `cli/src/orm/init-scaffold.ts:44-59` +- `cli/migration-plan.mdx:18`, `cli/index.mdx:88`, `cli/migration-new.mdx:16,32`, `orm/migrations/generating-a-migration.mdx:211` — hyphenated `--name add-users-table` / `split-name` / `add-orders-table` — the slug is lower-cased and every non-alphanumeric character becomes `_`, so the directory is `..._add_users_table`. The command runs; the directory name shown to the user differs from the flag — evidence: `packages/1-framework/3-tooling/migration/src/io.ts:456-476` +- `cli/error-reference.mdx:13,19` — "this page lists every code the CLI can emit" — the page carries only the platform and engine namespaces (`AUTH`, `CLI`, `INIT`, `SKILLS`, ...). None of the ORM command codes (`MIGRATION.*`, `CONTRACT.*`, `CONFIG.*`) appear, and the page does not link to `orm/reference/error-reference.mdx` where they belong — evidence: `cli/src/utils/cli-errors.ts` (codes such as `MIGRATION.PLAN_ORIGIN_UNKNOWN`, `MIGRATION.HASH_MISMATCH`, `CONFIG.DB_CONNECTION_REQUIRED`), `packages/1-framework/0-foundation/utils/src/structured-error.ts:90-91` (`docsUrl` base is `.../orm/v8/reference/error-reference`) + +## Missing + +- `--from @empty` and the `MIGRATION.PLAN_ORIGIN_UNKNOWN` refusal — evidence: `cli/src/utils/cli-errors.ts:428-475`, `cli/src/orm/migration/plan.ts:206` — belongs on `cli/migration-plan.mdx` (options and the origin paragraph) and `orm/migrations/generating-a-migration.mdx` +- Automatic `db` ref advancement by `db init` / `db update` when `--db` is omitted, and its suppression when `--db` is passed — evidence: `cli/src/control-api/operations/ref-advancement.ts:19-28` — belongs on `cli/db-init.mdx`, `cli/db-update.mdx`, `cli/migration-ref.mdx`, `orm/migrations/generating-a-migration.mdx#the-db-ref` +- The auto-baseline: on an empty graph with a `db` ref, `migration plan` writes two packages (`_baseline` and the delta) in one run — evidence: `cli/src/control-api/operations/migration-plan.ts:369,505-545` — belongs on `orm/migrations/generating-a-migration.mdx` and `cli/migration-plan.mdx` +- `db update` never plans `data`-class operations, so a change that needs a backfill fails and the user must switch to `migration plan` — evidence: `cli/src/control-api/operations/db-update.ts:17` (`allowedOperationClasses: ['additive', 'widening', 'destructive']`) versus `migrate.ts:283` and `migration-plan.ts:95` which include `'data'` — belongs on `cli/db-update.mdx` and `orm/migrations/rollbacks-and-recovery.mdx:103` +- `migration ref set` refusals: the target must be the `to` hash of an on-disk package (`MIGRATION.HASH_NOT_IN_GRAPH`, `MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE`) and may not be the empty sentinel (`MIGRATION.REF_SET_EMPTY_SENTINEL`) — evidence: `cli/src/control-api/operations/ref.ts:112-124` — belongs on `cli/migration-ref.mdx` +- `migration new` default origin: with no `--from` it takes the single leaf reachable from the empty hash and fails with `MIGRATION.NO_TARGET` (cycles, i.e. after a rollback) or `MIGRATION.AMBIGUOUS_TARGET` (two branch tips); `--from` matches a package's `to` hash by prefix only (not refs or dir names); an identical from/to hash is refused unless `--from` is explicit — evidence: `cli/src/control-api/operations/migration-new.ts:131-155`, `packages/1-framework/3-tooling/migration/src/migration-graph.ts:505-530` — belongs on `cli/migration-new.mdx` and `orm/migrations/rollbacks-and-recovery.mdx` +- The `orm` config keys `migrations.dir` and `formatter` (`indent`, `newline`, used by `contract format`) — evidence: `packages/1-framework/1-core/config/src/config-types.ts:32-37,109-113`, `examples/prisma-8-demo/fixtures/showcase/prisma.config.ts:19-21` — belongs on `cli/configuration.mdx` +- Telemetry opt-out environment variables `PRISMA_NEXT_DISABLE_TELEMETRY=1` and `DO_NOT_TRACK=1` — evidence: `packages/1-framework/3-tooling/cli-telemetry/src` (grep), `skills/prisma-8/references/migrations.md:505-507` — belongs in the `cli/configuration.mdx` environment-variable table (check `cli/telemetry.mdx`, outside this area, for consistency) +- The `node migration.ts` self-emit CLI accepts `--dry-run` and `--config ` — evidence: `cli/src/migration-cli.ts:109-125` — belongs on `orm/migrations/editing-a-migration.mdx` +- The full set of Postgres migration factories on the `Migration` base class (`createIndex`, `dropIndex`, `addForeignKey`, `addUnique`, `addCheckConstraint`, `alterColumnType`, `setDefault`, `dropDefault`, `dropNotNull`, native enum create/drop/add-value, `installExtension`, RLS enable/disable and policy create/drop/rename) plus the free factories `createExtension`, `rawSql`, `foreignKey`, `unique`, `checkExpression`, `fn`, `lit` — evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`, `packages/3-targets/3-targets/postgres/src/exports/migration.ts` — the site shows only `createSchema`, `createTable`, `addColumn`, `setNotNull`, `dataTransform`, `rawSql`; a factory reference belongs beside `orm/migrations/editing-a-migration.mdx` +- `migration status --json` carries `diagnostics[]` (`MIGRATION.MARKER_NOT_IN_HISTORY`, `MIGRATION.MISSING_INVARIANTS`, `CONTRACT.UNREADABLE` verified in `cli/src/orm/migration/status-findings.ts`) with `severity` for CI to branch on; the process exits 0 on warn-level findings — belongs on `cli/migration-status.mdx` +- `orm init` exit codes `4` (scaffold written, install failed) and `5` (installed, contract emit failed) — evidence: `cli/src/orm/init.ts:29-31,114` — belongs on `cli/orm-init.mdx` +- `db migrate` refuses before any DDL with `MIGRATION.MARKER_MISMATCH` when the marker is not a graph node, and with `MIGRATION.PATH_UNREACHABLE` when no path exists — evidence: `cli/src/utils/cli-errors.ts` (both codes), `skills/prisma-8/references/migration-review.md:257-262` — `applying-a-migration.mdx:124` describes the behaviour without the codes; belongs on `cli/db-migrate.mdx` + +## Unverified + +- `cli/global-flags.mdx` (whole page), `cli/init.mdx` (whole page), `cli/skills.mdx` (allowlist including `@prisma/composer`, target directories, the staleness check and its suppression list), `cli/configuration.mdx:13,30,94` (`definePrismaConfig` from `prisma/config`; `defineConfig` from `@prisma/cli-engine` as an alias; the `agents` list) — all implemented in `@prisma/cli-engine` / the `prisma-cli` repo, which is not in the tree (`node_modules/@prisma/cli-engine` has no `dist`). What I could see: the monorepo scaffold imports `definePrismaConfig` from `@prisma/cli-engine` (`cli/src/commands/init/templates/code-templates.ts:304`) and the fixture imports `defineConfig` from `@prisma/cli-engine` (`examples/prisma-8-demo/fixtures/showcase/prisma.config.ts:1`), so both names exist there; `skills/` ship inside `@prisma/orm-postgres`, `@prisma/orm-sqlite`, `@prisma/orm-mongo` (`files` in each `package.json`) +- `cli/dev.mdx`, `cli/git.mdx` — platform commands; not in the monorepo +- `cli/db-migrate.mdx:9`, `orm/migrations/applying-a-migration.mdx:150` — "extensions alphabetically, then the app" — matches the command's own help (`cli/src/orm/migrate.ts:203-206`), but `packages/1-framework/3-tooling/migration/src/plan-all-spaces.ts:66-70` sorts every space id alphabetically, where `app` sorts before `pgvector`; I did not trace the apply-order code far enough to say which is right +- `orm/migrations/the-migration-graph.mdx:120` — `migration graph --config fixtures/showcase/prisma.config.ts --legend` from `examples/prisma-8-demo` — `migrations.dir` in a config is resolved against the working directory, not the config file (`cli/src/orm/migration/paths.ts:11-13`, comment in `cli/src/orm/define-command.ts`), which would point at the demo's own `migrations/` rather than the fixture's; but the fixture's own header comment gives the same invocation, so I could not tell whether it works +- `orm/migrations/editing-a-migration.mdx:95-102` — `db.public.user.update({ displayName: 'Anonymous' }).where(...)` — I verified the `sql()` builder root and the `select(...).where(...).limit(1)` check shape against `data-transform.ts:84-95`, but did not verify the mutation builder's `update(values).where(...)` signature (query-builder area) + +## Skill vs site + +- Transaction scope — `skills/prisma-8/references/migrations.md:48` says each Postgres migration runs in its own `BEGIN ... COMMIT`; `applying-a-migration.mdx:120,146` says the whole `db migrate` run is one transaction. The site matches the source: `execute()` issues one `BEGIN`, loops every space's plan (the concatenated path of edges), then one `COMMIT`/`ROLLBACK` — `packages/3-targets/3-targets/postgres/src/core/migrations/runner.ts:176-215,684-696` +- Destructive consent on `db update` — the skill (`migrations.md:33,146,470`) says pass `-y` to auto-accept; the site (`cli/db-update.mdx:30-36`) says type the database name or pass `--confirm `. The site matches the source: `cli/src/orm/db/update.ts:118-124,218-224`, `cli/src/orm/db/consent.ts`; the engine's `CLI.CONSENT_REQUIRED` entry on `cli/error-reference.mdx:147` also says `--yes` does not grant consent +- Error codes — the skill still uses `PN-MIG-2001`, `PN-MIG-2002/2003/2005`, `PN-RUN-3001`, `PN-RUN-3002` (`migrations.md:21,69-75`); the site uses `PN-RUN-3000`. Both are stale; the source has `MIGRATION.UNFILLED_PLACEHOLDER`, `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`, `CONTRACT.MARKER_MISSING` ("Database not signed"), `CONTRACT.MARKER_MISMATCH` ("Hash mismatch"), `MIGRATION.RUNNER_FAILED` — `packages/1-framework/1-core/errors/src/migration.ts:19-20`, `.../execution.ts:17,34,267`, `docs/releases/v0.17.0.md:27` +- Factory call shape — the skill renders `addColumn('public', 'user', { name, typeSql, defaultSql, nullable })` and `setNotNull('public', 'user', 'name')` as free functions (`migrations.md:231-235,254-270`); the site renders `this.addColumn({ schema, table, column: col(...) })` and `this.setNotNull({ schema, table, column })`. The site matches the source and the rc.9 examples: `postgres-migration.ts:231,364`, `examples/prisma-8-demo/migrations/app/20260810T1108_add_post_engagement_counters/migration.ts:17-21` +- Contract snapshot imports — the skill imports `../../snapshots//contract.json` (`migrations.md:225,253`); the site imports `./end-contract.json`. The skill matches the source (see the first Breaks item) +- `migration show` with no argument — the skill runs `pnpm prisma migration show` bare (`migrations.md:189`); the site says `` is required (`cli/migration-show.mdx:16,23`). The site matches the source: the positional is `positional.string`, not optional — `cli/src/orm/migration/show.ts:3-6` +- `--from` grammar on `migration plan` — the skill lists `@contract | @db | @empty` (`migration-model.md:67`); the site lists neither on `cli/migration-plan.mdx:26` and only `^` on `generating-a-migration.mdx:153`. The parser accepts all three tokens (`contract-ref.ts:14-24`); the command's own brief names only `@empty` (`plan.ts:206`) diff --git a/docs/orm-docs-audit/audit/orm-client.md b/docs/orm-docs-audit/audit/orm-client.md new file mode 100644 index 0000000000..177db445a0 --- /dev/null +++ b/docs/orm-docs-audit/audit/orm-client.md @@ -0,0 +1,63 @@ +# Audit: orm-client + +Pages read: orm/index.mdx, orm/core-concepts.mdx, orm/fundamentals/reading-data.mdx, orm/fundamentals/writing-data.mdx, orm/fundamentals/relations-and-joins.mdx, orm/fundamentals/advanced-queries.mdx, orm/fundamentals/transactions.mdx, orm/reference/index.mdx, orm/reference/orm-client.mdx, orm/reference/transactions-and-runtime.mdx, orm/reference/error-reference.mdx + +## Breaks copy-paste + +- `orm/fundamentals/advanced-queries.mdx:39` (10 occurrences on this page: 39, 61, 75, 101, 123, 138, 177, 200, 218, 230), `orm/core-concepts.mdx:87`, `orm/fundamentals/reading-data.mdx:192`, `orm/fundamentals/relations-and-joins.mdx:73`, `orm/reference/transactions-and-runtime.mdx:96` (and 429-432, 741, 770) — `const rows = await db.runtime().execute(plan)` / `tx.execute(plan)` / `runtime.execute(plan)` used to read rows — since rc.2, `execute(plan)` returns `Promise<{ affectedRows }>` and rows come from `query(plan)`, which returns the `AsyncIterableResult`. Every row-reading example must call `.query(plan)`; only non-returning inserts, updates, and deletes stay on `.execute(plan)` (so `orm/fundamentals/transactions.mdx:60` is correct as written). `transactions-and-runtime.mdx:429-432` also calls `.toArray()` on an `execute` result, which is a stats promise — evidence: `packages/2-sql/4-lanes/relational-core/src/runtime-scope.ts:23-26`, `packages/2-sql/5-runtime/src/sql-runtime.ts:767-790`, `packages/1-framework/1-core/framework-components/src/execution/runtime-middleware.ts:352-358`, `docs/releases/v8.0.0-rc.2.md:72` +- `orm/reference/transactions-and-runtime.mdx:199`, `:279-301` — the MongoDB client exposes `execute()` and `db.execute(plan)` runs a pipeline plan — the row-executing `db.execute` facade method was removed in rc.2; the client exposes `orm`, `query`, `raw`, `contract`, `enums`, `context`, `connect()`, `runtime()`, `close()`. Rows come from `(await db.runtime()).query(plan)` — evidence: `packages/3-extensions/mongo/src/runtime/mongo.ts:28-40, 189-196`, `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-100`, `docs/releases/v8.0.0-rc.2.md:72` +- `orm/fundamentals/advanced-queries.mdx:230` — "`(await db.runtime()).execute(plan)` on MongoDB" — same rename: `(await db.runtime()).query(plan)` for rows — evidence: `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-100` +- `orm/reference/transactions-and-runtime.mdx:581`, `:609-611`, `:662`, `:665-710` — `ps.execute(runtime, { label })` returns rows (`Promise`) — a prepared statement built from a row-returning plan is a `PreparedStatement` whose method is `query(target, params, options?)` returning `AsyncIterableResult`; `execute(target, params)` exists only on `PreparedExecution` (a plan terminated with `.affectedCount()`) and resolves `SqlStatementStats` — evidence: `packages/2-sql/5-runtime/src/prepared/types.ts:55-105`, `docs/releases/v8.0.0-rc.2.md:72` ("Prepared row consumption moves ... to `prepared.query(target, params)`") +- `orm/reference/transactions-and-runtime.mdx:459`, `:467` — `withTransaction`'s `tx` surface is "`execute` (and `executePrepared`) only" — the transaction context is a `RuntimeScope`: `query(plan)` for rows and `execute(plan)` for stats; there is no `executePrepared` method (prepared hooks are symbol-keyed and reached through `prepared.query(tx, params)`) — evidence: `packages/2-sql/4-lanes/relational-core/src/runtime-scope.ts:23-26`, `packages/2-sql/5-runtime/src/sql-runtime.ts:137-141, 786-800` +- `orm/reference/transactions-and-runtime.mdx:653-662` — `await db.prepare(...)` followed by `const runtime = await db.connect()` — `db.prepare` calls `getRuntime()`, which starts the driver connection in the background when a `url` was given; a later `connect()` then throws `DRIVER.ALREADY_CONNECTED` ("Postgres client already connected"). Use `db.runtime()` after any query, `prepare`, or ORM call, and reserve `connect()` for the very first action — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:194-199, 245-250, 297-303, 330-339` +- `orm/fundamentals/writing-data.mdx:182-195` — PostgreSQL `upsert({ create, update })` with no `conflictOn`, and the prose "the record is matched on the model's unique fields (here `email`)" — when `conflictOn` is omitted the conflict target falls back to the table's primary key columns, not the unique fields. Because `create` does not supply `id` (it is generated), the statement never conflicts and either inserts a second row or fails on the `email` unique constraint. Pass `conflictOn: { email: ... }` — evidence: `packages/3-extensions/sql-orm-client/src/collection-contract.ts:511-530`, `packages/3-extensions/sql-orm-client/src/collection.ts:1732-1775` + +## Misleading + +- `orm/fundamentals/reading-data.mdx:280-309`, `:362` (and `orm/index.mdx:29` "streaming results") — `for await` over `.all()` "streams" rows from the database with a "steady, flat memory footprint" for millions of rows, and leaving the loop early means "unprocessed records are never buffered" — the `postgres()` facade constructs its driver with `cursor: { disabled: true }`, which the driver documents as buffered execution: the whole result is fetched before iteration begins. `for await` only changes how the already-buffered rows are handed to your code. Cursor streaming exists in the driver (`batchSize`) and is exposed by the serverless entry point only — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`, `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:39-43, 50-53, 95-101`, `packages/3-extensions/postgres/src/runtime/postgres-serverless.ts:28-42` +- `orm/fundamentals/advanced-queries.mdx:129` — "Prisma 8 does not run standalone raw SQL statements: every query goes through the typed builder" — a whole-query raw lane exists: `db.raw.sql\`SELECT ...\`.returnsRow({ col: 'pg/text@1' }).build()` for typed rows and `.affectedCount()` for mutations, executed through `runtime.query` / `runtime.execute`. `orm/core-concepts.mdx:106` describes the PostgreSQL raw escape hatch only as fragments spliced into builder queries — evidence: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:117-170`, `packages/2-sql/4-lanes/sql-builder/src/runtime/raw-lane.ts:24-33`, `packages/3-extensions/postgres/src/runtime/postgres.ts:61, 284`, `docs/releases/v8.0.0-rc.2.md:120` +- `orm/fundamentals/relations-and-joins.mdx:64-74`, `:217` — "The mirror field on the other model (`profile Profile?` on `User`) is not supported in the contract yet", so users are sent to the SQL builder — a singular back-relation is supported; emit only rejects it when the foreign key is not unique (`PSL_NON_UNIQUE_BACKRELATION`), and `userCollection.include('profile')` type-checks as a to-one include — evidence: `packages/2-sql/2-authoring/contract-psl/src/psl-relation-resolution.ts:448`, `docs/releases/v0.16.0.md:23-40`, `packages/3-extensions/sql-orm-client/test/include-cardinality.test-d.ts:36`, `packages/3-extensions/sql-orm-client/src/collection-contract.ts:640` +- `orm/fundamentals/relations-and-joins.mdx:216` — implicit many-to-many (`through` junction) "not supported by `.include(...)` yet" — the ORM resolves `relation.through` into an include descriptor and the demo app includes the N:M `Post.tags` relation with a refinement callback; nested `create`/`connect`/`disconnect` through the junction also work (and `orm/reference/orm-client.mdx:1088-1098` already documents `disconnect` through the junction, contradicting this page) — evidence: `packages/3-extensions/sql-orm-client/src/collection-contract.ts:356-379`, `packages/3-extensions/sql-orm-client/src/mutation-executor.ts:74, 836-926`, `examples/prisma-8-demo/src/orm-client/get-post-tags.ts:17`, `examples/prisma-8-demo/src/orm-client/create-post-with-tags.ts:30`, `docs/releases/v8.0.0-rc.1.md:64` +- `orm/reference/orm-client.mdx:478`, `:513` — text-backed enum columns sort in declaration order under `orderBy` — changed in rc.9: `ORDER BY` and `DISTINCT ON` on text-backed enums follow the stored values; only native PostgreSQL enums keep database ordering — evidence: `docs/releases/v8.0.0-rc.9.md:7` +- `orm/fundamentals/advanced-queries.mdx:104-111` — "PostgreSQL returns counts as strings; convert with `Number(row.posts)`" — `fns.count()` resolves through the target's `count` aggregate descriptor to a `number` (the int8-as-number codec); `countBigInt()` is the `bigint` form. Site sample output `posts: '2'` is stale — evidence: `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:159-172`, `packages/2-sql/4-lanes/sql-builder/src/runtime/functions.ts:242-253`, `docs/releases/v8.0.0-rc.2.md:32-53` +- `orm/reference/orm-client.mdx:384`, `:393`, `:465-467` — `min()`/`max()` "are typed for numeric fields (`NumericFieldNames`)" — the reducer field set is now derived from the aggregate descriptors: `min`/`max` accept numeric and textual columns and the date/time string and temporal codecs. The plain `pg/timestamptz@1` (`DateTime` decoded to `Date`) column is still absent from that list, so the `min('createdAt')` compile error the page describes is right for that codec, but the "numeric-only" explanation is not — evidence: `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:126-152`, `packages/3-extensions/sql-orm-client/src/types.ts:663-677` +- `orm/reference/orm-client.mdx:726` — "`all()` takes no arguments" — `all(configure?: (meta: MetaBuilder<'read'>) => void)` accepts a callback for query annotations (for example `meta.annotate(cacheAnnotation({ ttl }))`); `first`, `aggregate`, and the write terminals take the same optional trailing `configure` argument — evidence: `packages/3-extensions/sql-orm-client/src/collection.ts:1038, 1060-1083, 1235-1245, 1867-1872`, `examples/prisma-8-demo/src/orm-client/get-users-cached.ts:7-21` +- `orm/reference/transactions-and-runtime.mdx:82`, `:128`, `:155`, `:234`, `:310`, `:325` — closed and double-connect failures are plain `Error: Postgres client is closed` / `Error: Mongo client already connected` — they are structured envelopes with codes `DRIVER.NOT_CONNECTED` and `DRIVER.ALREADY_CONNECTED` (plus `why`/`fix`), matchable with `isStructuredError` per the site's own error-reference intro; and `DRIVER.ALREADY_CONNECTED` is raised by PostgreSQL too, not only MongoDB as `:233` implies — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:224-228, 290-303`, `packages/3-extensions/mongo/src/runtime/mongo.ts:149, 199-202` +- `orm/reference/transactions-and-runtime.mdx:48` — the PostgreSQL client "exposes `.orm`, `.sql`, `.enums`, `connect()`, `runtime()`, `transaction()`, `prepare()`, and `close()`" — it also exposes `.raw` (the raw lane), `.nativeEnums`, `.context`, `.contract`, and `.stack`; the options table (`:35-42`) omits `verifyMarker: 'onFirstUse' | false` and `binding` — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:56-89`, `packages/2-sql/5-runtime/src/runtime-spi.ts:42` +- `orm/reference/transactions-and-runtime.mdx:185-199` — MongoDB options table omits `mode: 'strict' | 'permissive'` and `binding`; the client also exposes `.context` and `.contract` — evidence: `packages/3-extensions/mongo/src/runtime/mongo.ts:28-56, 142` +- `orm/reference/transactions-and-runtime.mdx:359`, `:369` — `tx` exposes `orm`, `sql`, `execute`, `enums` — it also exposes `query` (rows) and `nativeEnums` — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:47-54` +- `orm/fundamentals/reading-data.mdx:114`, `:354` — `.first()` "on PostgreSQL ... fetches at most one row", implying MongoDB does not — the MongoDB collection's `first()` also applies `limit: 1` — evidence: `packages/2-mongo-family/5-query-builders/orm/src/collection.ts:341-343` +- `orm/reference/orm-client.mdx:644-651` — `distinctOn()` Remarks omit that it requires the contract capability `postgres.distinctOn` and throws `... requires capability postgres.distinctOn` without it — evidence: `packages/3-extensions/sql-orm-client/src/collection.ts:957`, `packages/3-extensions/sql-orm-client/src/collection-contract.ts:598-604` +- `orm/reference/error-reference.mdx:9-13`, `:23` (and every ADR link in entries) — links and the generator note point at `github.com/prisma/prisma`, while the rc.9 source and its release notes live in `github.com/prisma/orm` (the site's own `orm/index.mdx:110` says so). The 292 code entries otherwise match the rc.9 source word for word — evidence: `docs/releases/v8.0.0-rc.9.md:7-9` (PR links to `github.com/prisma/orm`), `docs/reference/error-reference.md` (identical body after the repo/name substitutions) + +## Missing + +- Lossless aggregates `countBigInt()`, `sumBigInt(field)`, `avgDecimal(field)` (as `aggregate()` selectors, `include` reducers, and SQL-builder `fns`), and the rule that `count()` / integer `sum()` throw `RUNTIME.DECODE_FAILED` outside the safe-integer range instead of rounding — evidence: `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:159-213`, `docs/releases/v8.0.0-rc.2.md:32-53`, `skills/prisma-8/references/queries-postgres.md:233-251` — belongs in `orm/reference/orm-client.mdx` (`aggregate()` and "Refinements, reducers, and combine") and `orm/fundamentals/reading-data.mdx` "Count records" +- `runtime.query(plan)` vs `runtime.execute(plan)` split (rows vs `{ affectedRows }`), and `RuntimeStatementStats` — evidence: `packages/2-sql/4-lanes/relational-core/src/runtime-scope.ts:23-26`, `docs/releases/v8.0.0-rc.2.md:72` — belongs in `orm/reference/transactions-and-runtime.mdx` "Execution options and results" and `orm/fundamentals/advanced-queries.mdx` "Build and run a plan" +- Whole-query raw SQL: `db.raw.sql\`...\`.returnsRow(spec)` / `.affectedCount()`, `RUNTIME.RAW_COLUMN_MISSING`-style spec mismatches — evidence: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:117-170`, `docs/releases/v8.0.0-rc.2.md:120` — belongs in `orm/fundamentals/advanced-queries.mdx` "Raw SQL fragments" and the `orm/core-concepts.mdx:103-108` table +- `AsyncIterableResult.first()` and `.firstOrThrow()` (throws `RUNTIME.NO_ROWS`) on any read result — evidence: `packages/1-framework/1-core/framework-components/src/execution/async-iterable-result.ts:66-80` — belongs in `orm/reference/orm-client.mdx` "Result types" +- Query annotations: the optional `configure(meta)` callback on every terminal and `meta.annotate(...)`, which is how the built-in cache middleware is opted into per query — evidence: `packages/3-extensions/sql-orm-client/src/collection.ts:1030-1060`, `examples/prisma-8-demo/src/orm-client/get-users-cached.ts` — belongs in `orm/reference/orm-client.mdx` read terminals +- `verifyMarker: 'onFirstUse' | false` on `postgres()`: the startup contract-vs-signature check that `orm/core-concepts.mdx:67` describes without saying how to turn it on or off (it reports `CONTRACT.MARKER_MISSING` / `CONTRACT.MARKER_MISMATCH` as warnings) — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:79`, `packages/2-sql/5-runtime/src/runtime-spi.ts:42`, `packages/2-sql/5-runtime/src/sql-runtime.ts:905-925` — belongs in `orm/reference/transactions-and-runtime.mdx` `postgres(options)` +- The flat accessor form `db.orm.User` / `db.sql.user` for single-namespace contracts (the site only ever shows `db.orm.public.User`); the namespace coordinate is required only when a bare name repeats across namespaces — evidence: `packages/3-extensions/sql-orm-client/src/orm.ts:71-121`, `skills/prisma-8/references/queries.md:39-48` — belongs in `orm/reference/orm-client.mdx` "Setting up the client" +- `db.nativeEnums` (PostgreSQL native enum members at runtime) next to `db.enums` — evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:53, 60`, `docs/releases/v0.15.0.md:75` — belongs in `orm/reference/transactions-and-runtime.mdx` return-type row +- MongoDB `mode: 'strict' | 'permissive'` client option — evidence: `packages/3-extensions/mongo/src/runtime/mongo.ts:44, 142` — belongs in `orm/reference/transactions-and-runtime.mdx` `mongo(options)` +- MongoDB filter classes beyond `MongoFieldFilter`/`MongoOrExpr`: `MongoAndExpr.of([...])`, `MongoNotExpr`, `MongoExistsExpr.exists(field)` / `.notExists(field)` — evidence: `packages/2-mongo-family/4-query/query-ast/src/filter-expressions.ts:68-160`, `packages/2-mongo-family/4-query/query-ast/src/exports/execution.ts:33-37` — belongs in `orm/reference/orm-client.mdx` "Combinators" / "MongoFieldFilter" +- The SQLite facade's lifecycle (`sqlite({ contractJson, path })`, `db.connect({ path })`, `db.transaction`) has no entry on the transactions-and-runtime reference or the transactions fundamentals page (the "SQLite is planned" wording is a known item; this is the missing reference content) — evidence: `packages/9-public/@prisma/orm-sqlite/package.json`, `skills/prisma-8/references/runtime.md:285-296` — belongs in `orm/reference/transactions-and-runtime.mdx` + +## Unverified + +- `orm/reference/orm-client.mdx:334`, `:370`, `:1295` — a looked-up sub-document's `_id` and the upsert update-path `_id` "come back as a raw driver `ObjectId`" — 0.15 changed reshaping reads to decode projected `_id`s and 0.17 made Mongo write results decode through codecs; I did not trace the `$lookup` and `findOneAndUpdate` decode paths far enough to confirm which shape rc.9 returns — checked `docs/releases/v0.15.0.md:103`, `docs/releases/v0.17.0.md:85`, `packages/2-mongo-family/5-query-builders/orm/src/collection.ts:254-320, 535-600` +- `orm/reference/orm-client.mdx:871` — on PostgreSQL, `update()` / `delete()` bypassed without `where()` "narrow to a single row by identity" — the update path does call `#findFirstMatchingRowIdentityWhere()`; I did not read the delete path — checked `packages/3-extensions/sql-orm-client/src/collection.ts:1895-1955` +- `orm/reference/transactions-and-runtime.mdx:724`, `:731` — `scope` documented as a user-settable `RuntimeExecuteOptions` field — the type declares it, but every runtime call site overwrites it (`scope: 'connection'` / `'transaction'`), so a caller-supplied value may have no effect — checked `packages/1-framework/1-core/framework-components/src/execution/runtime-middleware.ts:335-338`, `packages/2-sql/5-runtime/src/sql-runtime.ts:767-880` + +## Skill vs site + +- `and` / `or` / `not` import path — skill (`queries.md:141`, `queries-postgres.md:75, 86, 251`) says the combinators are internal-only and must come from `@internal/sql-orm-client`; site (`orm/fundamentals/reading-data.mdx:167-170`, `orm/reference/orm-client.mdx:1635, 1644`) imports them from `@prisma/orm-postgres/orm-client`. Site matches the source: `packages/9-public/@prisma/orm-postgres/package.json` exports `./orm-client`, and `packages/9-public/@prisma/orm-postgres/test/facade-tarball.test.ts:58, 171` verifies it re-exports `orm`, `Collection`, and the filters +- `.count()` as a collection terminal — skill (`queries-postgres.md:30`) lists `.count()` beside `.all()` / `.first()`; site (`orm/fundamentals/reading-data.mdx:278`) says there is no `.count()` on the chain. Site matches the source: `packages/3-extensions/sql-orm-client/src/collection.ts` has no `count` method; `count()` exists only as an `include` reducer (`:259-300`) and inside `aggregate()` +- SQL-builder `insert` input — skill (`queries-postgres.md:298-299`) writes `db.sql.user.insert({ email })`; site (`orm/fundamentals/advanced-queries.mdx:118-119`) passes an array. Site matches the source: `packages/2-sql/4-lanes/sql-builder/src/runtime/table-proxy-impl.ts:207` (`insert(rows: ReadonlyArray<...>)`) +- Rows from `runtime.execute(plan)` — both the skill (`queries-postgres.md:289, 302, 333, 355`) and the site use `execute` for row reads; the source says `query` (see Breaks copy-paste, first bullet). Neither matches rc.9 +- N:M `.include()` and nested N:M mutations — skill (`queries.md:139-140`) says both are unsupported and that `mutation-executor.ts` throws; site is split (relations page says implicit N:M include is unsupported, orm-client reference shows `disconnect` through the junction). Source supports both (`mutation-executor.ts:836-926`, `examples/prisma-8-demo/src/orm-client/get-post-tags.ts`); the skill's `'N:M nested mutations are not supported yet'` string no longer exists in `packages/3-extensions/sql-orm-client/src/` +- Streaming — skill (`queries.md:146`) says there is no streaming surface; site (`reading-data.mdx:280-309`) says `for await` streams. Source: `AsyncIterableResult` is an async iterable, but the `postgres()` facade disables driver cursors, so the skill is closer to the truth about memory behaviour (`packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`) +- Error codes — skill (`debug.md:12, 78-110`) routes on `PN-CLI-*` / `PN-MIG-*` / `PN-RUN-*` codes; site (`orm/reference/error-reference.mdx`) uses the dotted `NAMESPACE.SUBCODE` scheme. Site matches the source: codes were renamed at 0.16 and `docs/reference/error-reference.md` lists only dotted codes +- Prepared statements — skill (`debug.md:127`) says you "cannot pre-prepare and re-execute a statement by name" and points to TypedSQL (which `queries.md:144` says does not exist); site documents `runtime.prepare` / `db.prepare` (`transactions-and-runtime.mdx:568-663`). Site matches the source (`packages/2-sql/5-runtime/src/sql-runtime.ts:110, 549`), apart from the `query` vs `execute` method name above +- `.first()` on MongoDB — skill (`queries-mongo.md:63`) and site (`orm-client.mdx:775`) agree there is no filter argument; source agrees (`packages/2-mongo-family/5-query-builders/orm/src/collection.ts:110, 341`) diff --git a/docs/orm-docs-audit/audit/start-guides.md b/docs/orm-docs-audit/audit/start-guides.md new file mode 100644 index 0000000000..7c3dfa0291 --- /dev/null +++ b/docs/orm-docs-audit/audit/start-guides.md @@ -0,0 +1,60 @@ +# Audit: start-guides + +Pages read: `(index)/index.mdx`, `(index)/getting-started.mdx`, `(index)/prisma-orm/index.mdx`, `(index)/prisma-orm/create-prisma.mdx`, `(index)/prisma-orm/quickstart/postgresql.mdx`, `(index)/prisma-orm/quickstart/mongodb.mdx`, `(index)/prisma-orm/add-to-existing-project/postgresql.mdx`, `(index)/prisma-orm/add-to-existing-project/mongodb.mdx`, `(index)/prisma-postgres/quickstart/prisma-orm.mdx`, `guides/index.mdx`, `guides/upgrade-prisma-orm/postgresql.mdx`, `guides/upgrade-prisma-orm/mongodb.mdx`, `guides/switch-to-prisma-orm/from-drizzle.mdx`, `guides/switch-to-prisma-orm/from-mongoose.mdx`, `guides/switch-to-prisma-orm/from-sql-orms.mdx`, `guides/database/schema-changes.mdx`, `guides/database/data-migration.mdx`, `guides/database/multiple-databases.mdx`. + +Monorepo paths below are relative to `wip/prisma-src/` unless they start with `wip/create-prisma-src/`. + +## Breaks copy-paste + +- `(index)/prisma-orm/add-to-existing-project/postgresql.mdx:46` (same on `add-to-existing-project/mongodb.mdx:48`) — tells the user to "keep the default schema path, `prisma/contract.prisma`", and every later step assumes that directory: `contract infer --output ./prisma/contract.prisma` (line 63), `prisma/contract.json` and `prisma/contract.d.ts` (line 80), `import { db } from "./prisma/db"` (lines 103, 137; mongodb page lines 109, 138) — `orm init` defaults to `src/prisma/contract.prisma` and writes `db.ts` next to it, so a user who accepts the default gets `src/prisma/`, `contract infer --output ./prisma/contract.prisma` writes a file `prisma.config.ts` never reads, `contract emit` emits the untouched starter contract, and `./prisma/db` does not exist. The site's own agent prompt at `(index)/index.mdx:96` says `src/prisma/` — evidence: `packages/1-framework/1-core/config/src/config-types.ts:45` (`DEFAULT_CONTRACT_SOURCE_DIR = 'src/prisma'`), `packages/1-framework/3-tooling/cli/src/commands/init/templates/code-templates.ts:63-67`, `packages/1-framework/3-tooling/cli/src/orm/init-scaffold.ts:188` +- `(index)/prisma-orm/create-prisma.mdx:94` — "plan and apply the migration with `npx prisma@latest migration plan` and `npx prisma@latest migrate`" — there is no top-level `migrate` command; the apply command is `db migrate`, and the generated `migrate` script runs `prisma db migrate` — evidence: `packages/1-framework/3-tooling/cli/src/orm/cli.ts:97-121` (command tree), `wip/create-prisma-src/src/tasks/install.ts:53` +- `(index)/prisma-orm/add-to-existing-project/postgresql.mdx:148` — `const rows = await db.runtime().execute(plan); console.log(rows);` for a `select` plan — `execute` returns `SqlStatementStats` (`{ affectedRows }`), not rows; rows come from `db.runtime().query(plan)` — evidence: `packages/2-sql/4-lanes/relational-core/src/runtime-scope.ts:23-26`, `packages/2-sql/4-lanes/relational-core/src/ast/driver-types.ts:24-26`, `examples/prisma-8-demo/src/queries/get-users.ts:5` +- `(index)/prisma-orm/add-to-existing-project/mongodb.mdx:148` — `const rows = await runtime.execute(plan)` for a `from("users").match(...).project(...)` pipeline — `MongoRuntime.execute` returns statement statistics and throws `RUNTIME.MONGO_STATISTICS_UNSUPPORTED` for a command with no count field (an aggregate/find); reads go through `runtime.query(plan)` — evidence: `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-100, 282-289`, `examples/mongo-demo/src/server.ts:75` +- `guides/upgrade-prisma-orm/mongodb.mdx:266` (repeated at 293, 345, 392, 393) — `await db.execute(plan).toArray()` — the Mongo client has no `execute` method; the surface is `orm`, `query`, `raw`, `connect`, `runtime`, `close`. A plan runs as `(await db.runtime()).query(plan).toArray()` — evidence: `packages/3-extensions/mongo/src/runtime/mongo.ts:28-41`, `examples/mongo-demo/scripts/cache-demo.ts:77` + +## Misleading + +- `(index)/prisma-orm/add-to-existing-project/postgresql.mdx:41` (same on `add-to-existing-project/mongodb.mdx:43`) — "`orm init` also adds `prisma-next.md` and project-level Prisma 8 skills for Cursor, Claude Code, Codex, and Windsurf" — `orm init` writes `prisma-next.md` but installs no skills; its only skill work is deleting retired skill directories, and its own next-steps output says to run `prisma init` for skills — evidence: `packages/1-framework/3-tooling/cli/src/commands/init/skill-sources.ts:1-5`, `packages/1-framework/3-tooling/cli/src/commands/init/output.ts:106-108` +- `(index)/prisma-orm/add-to-existing-project/postgresql.mdx:43-46, 50` (same on `mongodb.mdx:45-48, 52`) — lists the prompts as "choose PSL" and "keep the default schema path", then says "Update `.env`" — `orm init` also asks "Also write a .env file from .env.example?" (default No); by default it writes `.env.example` only, so there may be no `.env` to update. `--write-env` skips the prompt — evidence: `packages/1-framework/3-tooling/cli/src/orm/init-inputs.ts:229-233`, `packages/1-framework/3-tooling/cli/src/orm/init-scaffold.ts:199, 211-218` +- `(index)/prisma-orm/create-prisma.mdx:86` — "Review `DATABASE_URL` in `.env`, then initialize the database" — for PostgreSQL the scaffold writes no `.env` (it only does for MongoDB), calls `orm init` without `--write-env`, and the generated `prisma.config.ts` has no `dotenv` import, so `DATABASE_URL` must be in the shell environment. `quickstart/postgresql.mdx:43` says this correctly — evidence: `wip/create-prisma-src/src/tasks/prisma-setup/project-files.ts:17-29`, `wip/create-prisma-src/src/tasks/prisma-setup/commands.ts:47-59`, `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs:18-37`, `wip/create-prisma-src/templates/create/_shared/README.md.hbs:71` +- `(index)/prisma-orm/quickstart/mongodb.mdx:27` and `add-to-existing-project/mongodb.mdx:19` — "Prisma 8 needs a MongoDB replica set" — nothing in the Mongo runtime or migration runner opens a session or transaction (the client has no `transaction` method and the runner deliberately avoids transactions); `orm init`'s `.env.example` says a standalone `mongod` works for first-run queries and a replica set is only needed for transactions and change streams. Only the scaffold's connection string (`replicaSet=rs0&directConnection=true`) demands one — evidence: `packages/1-framework/3-tooling/cli/src/commands/init/templates/env.ts:43-48`, `packages/3-mongo-target/1-mongo-target/src/core/control-target.ts:84-86`, `packages/3-extensions/mongo/src/runtime/mongo.ts:28-41`, `wip/create-prisma-src/src/tasks/prisma-setup/project-files.ts:25` +- `(index)/prisma-orm/create-prisma.mdx:9` (and every quickstart that says "installs Prisma 8") — create-prisma 0.11.7 pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` while the current release is rc.9, so a fresh scaffold does not get rc.9 behaviour the site documents (for example the rc.9 Mongo attribute rejection and index argument format) — evidence: `wip/create-prisma-src/src/constants/dependencies.ts:8-10`, `packages/9-public/@prisma/orm-postgres/package.json` (version `8.0.0-rc.9`), `docs/releases/v8.0.0-rc.9.md:9-25` +- `(index)/prisma-orm/create-prisma.mdx:57` — `--force` "Allows scaffolding into a non-empty directory" — it also overwrites the generated Prisma config, contract, and `db.ts`, and refuses when the target has a non-empty `migrations/` directory — evidence: `wip/create-prisma-src/src/index.ts:67-70`, `wip/create-prisma-src/src/commands/create-context.ts:181-192` +- `(index)/prisma-orm/create-prisma.mdx:35, 54, 56` — describes the deploy prompt and `--yes` without saying the defaults differ: interactively the prompt defaults to Yes, `--yes` answers No, and `--json` (not on the page) deploys unless `--no-deploy` is passed — evidence: `wip/create-prisma-src/src/tasks/prisma-setup/context.ts:112-121, 163-166`, `wip/create-prisma-src/src/index.ts:73-76` +- `(index)/prisma-orm/create-prisma.mdx:79` — the Deno command omits `--minimum-dependency-age=0`; create-prisma's README says Deno 2.9 blocks packages published in the last 24 hours, so a fresh release resolves to an older cached version without it — evidence: `wip/create-prisma-src/README.md:46-52` +- `(index)/getting-started.mdx:36`, `(index)/index.mdx:111`, `(index)/prisma-orm/index.mdx:43` — "Valid --template values: next, hono, nuxt, astro, nest, svelte, tanstack-start, elysia" omits `minimal`, which is also the default — evidence: `wip/create-prisma-src/src/types.ts:7-17`, `wip/create-prisma-src/src/commands/create-context.ts:13` +- `guides/upgrade-prisma-orm/postgresql.mdx:470-471, 510` — "Without a ref, the next `migration plan` starts from scratch and plans `CREATE TABLE` operations all over again" / "If you see `CREATE TABLE` operations instead, the `db` ref from step 4.3 is missing" — since rc.8 `migration plan` refuses to plan from an empty database when migrations already exist on disk and raises a structured error instead, so the symptom the guide tells the user to look for no longer appears — evidence: `docs/releases/v8.0.0-rc.8.md:17` +- `guides/upgrade-prisma-orm/postgresql.mdx:455` — expected output "`Database signed (marker created)`" — the command prints `Database signed` — evidence: `packages/1-framework/3-tooling/cli/src/orm/db/sign.ts:68` +- `guides/upgrade-prisma-orm/mongodb.mdx:27` — "validated against `@prisma/orm-mongo@0.16.0`" — the current package is `8.0.0-rc.9`, and breaking changes since 0.16.0 affect this guide's material (rc.7 pagination rename, rc.9 Mongo attribute rejection and index argument format) — evidence: `packages/9-public/@prisma/orm-mongo/package.json`, `docs/releases/v8.0.0-rc.7.md:9`, `docs/releases/v8.0.0-rc.9.md:9-25` +- `guides/index.mdx:35-39, 43` — lists "Upgrading: moving from Prisma 7" and "Databases" under "Coming as they land" and never links the upgrade, database, or switch guides, while `guides/upgrade-prisma-orm/postgresql.mdx` exists and is in the nav — evidence (site only): `guides/meta.json`, `guides/upgrade-prisma-orm/meta.json` +- `guides/switch-to-prisma-orm/from-drizzle.mdx`, `from-sql-orms.mdx`, `from-mongoose.mdx`, `guides/database/schema-changes.mdx`, `data-migration.mdx`, `multiple-databases.mdx` — all six sit in the Prisma 8 guides tree but are Prisma 7 / v6 guides: they install `prisma@7.10.0` or `prisma@6.19` and `@prisma/client` (`from-drizzle.mdx:52-53`, `from-sql-orms.mdx:40-41`, `from-mongoose.mdx:57-61`, `data-migration.mdx:73-77`, `multiple-databases.mdx:59-63`) and run `prisma init`, `db pull`, `migrate diff`, `migrate resolve`, `migrate dev`, `migrate deploy`, `generate`, `studio` (`from-drizzle.mdx:69, 169, 201, 209, 246`; `from-sql-orms.mdx:49, 61, 67-69, 75`; `from-mongoose.mdx:77, 170, 307`; `schema-changes.mdx:88, 155`; `data-migration.mdx:121, 243`; `multiple-databases.mdx:79, 233-237`). None of those commands exist in the Prisma ORM 8 CLI, whose tree is `orm init`, `contract *`, `db *`, `migration *`. A user coming from the Prisma 8 guides index is sent to a different product — evidence: `packages/1-framework/3-tooling/cli/src/orm/cli.ts:97-121`, `guides/meta.json` +- `guides/switch-to-prisma-orm/from-mongoose.mdx:14-20, 64-70` — "MongoDB support for Prisma ORM v7 is coming in the near future... use Prisma ORM v6.19" — Prisma ORM 8 ships MongoDB support as `@prisma/orm-mongo`, and the site's own MongoDB quickstart uses it — evidence: `packages/9-public/@prisma/orm-mongo/package.json`, `packages/3-extensions/mongo/src/runtime/mongo.ts:110-118` + +## Missing + +- Temporal requirement for inferred contracts — `contract infer` maps `timestamp`/`timestamptz` columns to `Timestamp`/`Timestamptz`, which are Temporal-backed; on a runtime without a global `Temporal` (no stable Node ships one) every read of such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported first or the type is changed to `TimestamptzString`. create-prisma installs the polyfill for this reason; `orm init` does not. Neither existing-project page nor the Prisma 7 upgrade guide (whose real-world schemas have `DateTime` columns) mentions it — evidence: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`, `packages/3-targets/3-targets/postgres/src/core/errors.ts:74-86`, `skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md:38-47`, `wip/create-prisma-src/src/constants/dependencies.ts:21-23`, `wip/create-prisma-src/templates/create/_shared/src/prisma/db.ts.hbs:15` — belongs on `add-to-existing-project/postgresql.mdx` step 4 and `guides/upgrade-prisma-orm/postgresql.mdx` section 2.4 +- `create-prisma --json` — non-interactive machine-readable mode for agents; not in the flag table — evidence: `wip/create-prisma-src/src/index.ts:73-76`, `wip/create-prisma-src/README.md:66-81` — belongs in the `create-prisma.mdx` flag table and the agent prompts on `getting-started.mdx` / `index.mdx` +- The full set of generated package scripts — the scaffold adds `db:update`, `db:verify`, `migration:status`, `migration:show`, `skills:sync`, `composer:dev`, `composer:deploy`, and `deploy` alongside the four the site mentions — evidence: `wip/create-prisma-src/src/tasks/install.ts:47-70` — belongs in `create-prisma.mdx` "Start the app" +- `orm init` flags — `--schema-path`, `--write-env`, `--probe-db`, `--strict-probe`, `--skip-install`, `--keep-previous-facade`, plus `--confirm ` for re-running init in an already scaffolded directory — evidence: `packages/1-framework/3-tooling/cli/src/orm/init.ts:87-112`, `packages/1-framework/3-tooling/cli/src/orm/init-inputs.ts:218-227` — `--write-env` and `--schema-path` belong on both add-to-existing-project pages, which currently rely on the defaults they describe wrongly +- Minimum database server versions — PostgreSQL 15 and MongoDB 8.0, written into `.env.example` by `orm init` — evidence: `packages/1-framework/3-tooling/cli/src/commands/init/templates/env.ts:16-19` — belongs on the PostgreSQL quickstart and existing-project pages (only the MongoDB upgrade guide states the Mongo minimum) +- MongoDB projects and Composer — Composer does not provision MongoDB; `dev:composer` and `deploy` need `MONGODB_URL` set as the secret bound in `module.ts` — evidence: `wip/create-prisma-src/templates/create/_shared/README.md.hbs:55-57`, `wip/create-prisma-src/templates/create/_shared/module.ts.hbs:24-27`, `wip/create-prisma-src/src/tasks/prisma-setup/presentation.ts:44-49` — belongs on `quickstart/mongodb.mdx`, which never mentions the Composer scripts, and on `prisma-orm/index.mdx` step 6 of the agent prompt, which assumes PostgreSQL provisioning +- A Prisma ORM 8 path for switching from another ORM — the shipped skill describes the brownfield flow (`orm init`, `contract infer --output`, review, `contract emit`, `db sign`, `db verify`) that replaces the Prisma 7 `db pull` / baseline guides — evidence: `skills/prisma-8/references/quickstart.md:229-263` — belongs in `guides/switch-to-prisma-orm/*`, which are Prisma 7 only +- Prisma ORM 8 team and data-migration workflow (`migration plan`, refs, `db update` for local iteration, `db verify`) — evidence: `skills/prisma-8/references/migrations.md`, `packages/1-framework/3-tooling/cli/src/orm/db/update.ts` — belongs in `guides/database/*`, which are Prisma 7 only +- `db init --dry-run` / `db update --dry-run` to preview operations before touching a database — evidence: `packages/1-framework/3-tooling/cli/src/orm/db/init.ts` and `db/update.ts` flag specs — useful on the quickstart step that runs `db:init` + +## Unverified + +- `(index)/getting-started.mdx:41`, `(index)/index.mdx:115`, `(index)/prisma-orm/index.mdx:48` — `npx prisma@latest db migrate --yes` — `db migrate` declares no `--yes` flag (`packages/1-framework/3-tooling/cli/src/orm/migrate.ts` flags: `db`, `to`, `advance-ref`, `show`, `from`); a global `--yes` would live in `@prisma/cli-engine`, which is not in the monorepo. create-prisma does pass `--yes` to `orm init` (`wip/create-prisma-src/src/tasks/prisma-setup/commands.ts:50`), so it exists at least there +- `(index)/index.mdx:96`, `(index)/getting-started.mdx:71` — "`orm init` may end with `CLI.INIT_SKILL_INSTALL_FAILED`, which `skills sync` repairs" — no such code exists in the monorepo and `orm init` installs no skills (`skill-sources.ts:1-5`); `skills sync` and `prisma init` are unified-CLI commands outside the monorepo +- `guides/upgrade-prisma-orm/postgresql.mdx:17, 161, 237-238` — `@prisma/prisma7@7.10.0-dev.58` and `definePrismaConfig` from `prisma/config` — both come from the prisma-cli repo; the monorepo's own `orm init` scaffold imports `definePrismaConfig` from `@prisma/cli-engine` (`code-templates.ts:304`) while create-prisma's template imports it from `prisma/config` (`prisma.config.ts.hbs:18`) +- `guides/upgrade-prisma-orm/mongodb.mdx:13` — the `prisma-mongodb-upgrade` skill and `npx skills add prisma/skills` — external repository, not checked +- `guides/upgrade-prisma-orm/mongodb.mdx:280` — "the typed builder sends the id through as a plain string, so the stage silently matches nothing" for `.match((f) => f.authorId.eq(authorId))` — did not trace ObjectId encoding in the pipeline builder's `match` path +- `(index)/prisma-orm/quickstart/postgresql.mdx:59` and `quickstart/mongodb.mdx:64` — the quoted output lines for `db init` and `db migrate` — did not locate the exact strings + +## Skill vs site + +- `skills/prisma-8/references/quickstart.md:73, 189, 201` says `orm init` scaffolds `prisma/contract.prisma` by default (TML-2532) and the site's existing-project pages (`add-to-existing-project/postgresql.mdx:46`) say the same; the source defaults to `src/prisma/contract.prisma` (`config-types.ts:45`, `code-templates.ts:63-67`). Source disagrees with both; the skill's note is stale +- `skills/prisma-8/references/queries-postgres.md:289, 302, 333` runs SQL-builder reads with `const rows = await db.runtime().execute(plan)`, and `queries-mongo.md:12, 140, 164, 178` runs pipeline reads with `runtime.execute(plan)`; the site's existing-project pages do the same. Source: `execute` returns statistics on both families and the Mongo runtime throws for a find/aggregate (`runtime-scope.ts:25`, `mongo-runtime.ts:99, 282-289`); the examples use `runtime.query(plan)`. Both skill and site are wrong +- `skills/prisma-8/references/contract.md:221` says `@@discriminator` / `@@base` are SQL-only in PSL; the site's MongoDB upgrade guide (`guides/upgrade-prisma-orm/mongodb.mdx:129, 164, 171`) uses them on MongoDB. The Mongo PSL interpreter implements both (`packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts:276-418`), so the site matches the source +- `skills/prisma-8/references/quickstart.md:196` documents an `orm init --skip-skills` flag; the site does not mention it and `orm init` declares no such flag (`packages/1-framework/3-tooling/cli/src/orm/init.ts:87-112`). Site matches the source +- `skills/prisma-8/references/quickstart.md:37` / mongo note at line 99 and the site's MongoDB pages agree on storage-name addressing (`db.orm.users`), and the scaffold's seed confirms it (`wip/create-prisma-src/templates/create/_shared/src/prisma/seed.ts.hbs:16`); no disagreement, listed for completeness diff --git a/docs/orm-docs-audit/brief-db-ref-on-adoption.md b/docs/orm-docs-audit/brief-db-ref-on-adoption.md new file mode 100644 index 0000000000..77d8448fb8 --- /dev/null +++ b/docs/orm-docs-audit/brief-db-ref-on-adoption.md @@ -0,0 +1,53 @@ +# Brief: set the `db` ref when a database is adopted + +Written 2026-09-10 for an agent with no prior context. Repo: `prisma/prisma` `main` (the Prisma 8 monorepo, rc.9). PRs go to `prisma/orm`. + +## What we want + +After adopting a database, the migration system knows the baseline. Concretely: `db sign` on a database with no prior signature should leave the project in a state where the next `migration plan` chains from the signed contract, with no extra commands. + +The shape we have in mind: `db sign` records the signed contract hash as the baseline state and sets the `db` ref to it, writing the contract snapshot so the ref resolves. Whether that also needs a baseline migration package on disk, or whether a snapshot alone is enough for `migration plan` to chain from and for `migration status` to report cleanly, is for the implementer to determine from how the planner and status resolve origins. + +Open questions to settle in the design, not to guess at: + +1. Should `db sign` on an already-signed database (re-signing under a newer hash) also move the ref? Probably yes, for the same reason, but it changes an existing behaviour. +2. Does `db sign --db ` follow the same rule as `db init --db ` and skip the ref? The existing rule is that an explicit `--db` means "not my dev database, don't move my ref". Adoption is usually done against the real database, so the rule may be wrong for sign. Decide and document. +3. If the ref already exists and points elsewhere, refuse, overwrite, or require `--advance-ref`. +4. `migration plan` with no `--from`, no ref, and no migrations on disk currently plans silently from empty. Consider warning or refusing the same way it does when migrations exist, since after this change the silent case means "you never ran init, update, or sign". + +## Acceptance + +- A test in `test/integration/` that: creates tables directly, runs `contract infer`, `contract emit`, `db sign`, changes the contract, emits, runs `migration plan`, and asserts the plan contains only the delta. +- The same flow with `--db ` on `db sign`, asserting whichever behaviour the design settles on. +- `migration status` after `db sign` reports current and target hashes equal and nothing pending. +- Update the shipped skill: `skills/prisma-8/references/migration-model.md` ("The trap" section and the origin rules) and `references/quickstart.md` (the brownfield adoption path). +- Update the monorepo docs that describe the ref rules: `docs/glossary.md` under "Ref", and any release note for the version this ships in (`docs/releases/`). +- Record upgrade instructions if the behaviour change is user-visible (the `record-upgrade-instructions` skill). + +The docs site (`prisma/web`) changes are handled separately; note in the PR what the new user-facing sequence is so the docs page can be written from it. + +## The problem + +A user with an existing database brings it under Prisma 8 by running `contract infer`, `contract emit`, and `db sign`. That is what the getting-started page for existing projects tells them to do. Then they change the contract and run `migration plan`. The plan proposes creating every table again. + +Cause: `migration plan` takes its origin from `--from`, else the `db` ref, else the empty contract. `db sign` writes the database marker but never sets the `db` ref, and there are no migrations on disk, so the plan resolves to the empty origin and the CLI does not refuse (the `MIGRATION.PLAN_ORIGIN_UNKNOWN` refusal only fires when migrations already exist on disk). + +Two Discord users hit this in one week and asked what `--from` is for. The incremental upgrade guide avoids it by teaching three extra commands (`migration plan --name baseline`, `db sign`, `migration ref set db `), and the "add to existing project" page does not teach them at all. + +## What exists today + +- `db init` and `db update` advance the `db` ref by default. `computeRefAdvancementName` in `packages/1-framework/3-tooling/cli/src/control-api/operations/ref-advancement.ts` returns `db` when no `--db` flag is given and `null` when `--db ` is passed, so passing `--db` also skips the ref. That second rule is a separate trap the shipped skill documents under "The trap" in `skills/prisma-8/references/migration-model.md`. +- `db migrate --advance-ref db` advances the ref after applying. +- `db sign` (`packages/1-framework/3-tooling/cli/src/orm/db/sign.ts`) verifies the live schema against the emitted contract and writes the marker. It does not touch refs. +- `migration ref set ` sets a ref by hand. +- `executeRefAdvancement` writes a contract snapshot under `migrations/snapshots/` and then the ref file. A ref must point at a hash that has a snapshot. + +## Pointers + +- Ref advancement: `packages/1-framework/3-tooling/cli/src/control-api/operations/ref-advancement.ts` +- Sign command: `packages/1-framework/3-tooling/cli/src/orm/db/sign.ts` +- Plan command and origin flag: `packages/1-framework/3-tooling/cli/src/orm/migration/plan.ts`, `control-api/operations/migration-plan.ts` +- Refusal text: `PLAN_ORIGIN_UNKNOWN` in `packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts` +- Existing ref tests: `test/integration/test/cli.db-ref-advancement.e2e.test.ts` +- The documented workaround: `wip/web/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx` §4.1 to 4.3 +- Migration graph ADRs: search `docs/architecture docs/adrs/` for "ref" diff --git a/docs/orm-docs-audit/brief-skills-opt-out.md b/docs/orm-docs-audit/brief-skills-opt-out.md new file mode 100644 index 0000000000..917d02d7fb --- /dev/null +++ b/docs/orm-docs-audit/brief-skills-opt-out.md @@ -0,0 +1,47 @@ +# Brief: let users opt out of agent skill files at scaffold time + +Written 2026-09-10 for an agent with no prior context. Repos: `prisma/create-prisma` (the scaffolder) and `prisma/prisma-cli` (the unified `prisma` binary, whose `init` and `orm init` commands are involved). A read-only clone of create-prisma is at `wip/create-prisma-src` in this worktree. + +## What we want + +1. `create-prisma` asks. Add a prompt in the interactive flow, "Install agent skills for coding assistants?" or similar, alongside the existing prompts, defaulting to yes. Add a flag for the non-interactive path, `--skills ` matching `prisma init --skills`, so `--yes` plus `--skills none` produces a project with no agent files, no `postinstall` hook, and `skills: { agents: [] }` in the config. +2. When the answer is no, the generated project has no `.claude/`, `.cursor/`, `.agents/`, or Devin directories, no `postinstall`, and no `skills:sync` script. `prisma-next.md` is a separate question: decide whether it is an agent file or a human readme and treat it accordingly. +3. `prisma orm init` on the existing-project path asks the same question when interactive, and honours `--skills` for parity with `--skip-skills`. +4. Removing skills after the fact: `prisma skills sync` with `agents: []` should remove the directories it previously wrote, or there should be a `prisma skills remove`. Decide which; the current behaviour (write nothing, leave the old copies) means the config opt-out looks like it did nothing. + +## Acceptance + +- `create-prisma my-app --yes --skills none` produces a project with none of the four agent directories, no `postinstall`, and `agents: []` in the config. Test in create-prisma's `tests/`. +- The interactive prompt appears and its answer is reflected the same way. +- `prisma orm init --skills none` on an existing project behaves the same. +- `prisma skills sync` after setting `agents: []` removes the previously written directories, or the new remove command does, with a test in prisma-cli. +- The `create-prisma` README and the CLI help text list the new flag. +- Note in the PR the exact user-facing sequence for the docs page, which is written separately: the `create-prisma` reference page, both quickstarts, `cli/init`, `cli/orm-init`, `cli/skills`, and `cli/configuration` on the docs site all need the answer. + +## The problem + +`npx create-prisma@latest` writes agent skill files for Claude, Cursor, Codex-style `.agents`, and Devin into every new project, adds a `postinstall` hook that re-syncs them on every install, and offers no prompt or flag to decline. One user counted "more than 200 files" and left. Five people raised it in one week. The workaround being passed around in the community (`skills sync --disable`, a `PRISMA_DISABLE_AGENT` env var) is wrong: the first only silences the staleness notice and the second does not exist. + +## What exists today + +In `create-prisma`: + +- `templates/create/_shared/prisma.config.ts.hbs` writes `skills: { agents: ["claude", "cursor", "agents", "devin"] }` for every non-Deno project. +- `src/tasks/install.ts` adds a `skills:sync` package script. +- `src/tasks/prisma-setup/commands.ts` first runs `prisma orm init --yes --target ... --authoring ... --skip-install`, which writes `prisma-next.md` (create-prisma deletes it again only for Deno). Then `initializeAgentSkills` runs `prisma init --yes`. That command adds a `postinstall` of `prisma skills sync || exit 0`, leaves the existing `prisma.config.ts` alone, and runs `skills sync` once. +- The CLI flags are `--template`, `--provider`, `--authoring`, `--package-manager`, `--deploy`/`--no-deploy`, `--workspace`, `--yes`, `--force`, `--verbose`, `--json`. Nothing about skills. + +In `prisma-cli`: + +- `prisma init --skills=none` writes `skills: { agents: [] }` when no config exists. With an existing config it does nothing to it. +- `prisma orm init --skip-skills` skips the skill install on the existing-project path. +- `prisma skills sync` writes the directories listed in `skills.agents`; with `agents: []` it writes nothing, but it does not delete copies already on disk. +- `skills: { check: false }` only silences the out-of-date notice. + +So the real opt-out is `skills: { agents: [] }` in `prisma.config.ts`, and nothing on the scaffold path lets the user say that. + +## Pointers + +- create-prisma: `src/tasks/setup-prisma.ts`, `src/tasks/prisma-setup/commands.ts`, `src/tasks/install.ts`, `templates/create/_shared/prisma.config.ts.hbs`, `src/index.ts` for flags +- prisma-cli: the `init`, `orm init`, and `skills` commands +- Docs pages describing current behaviour: `wip/web/apps/docs/content/docs/cli/init.mdx`, `cli/orm-init.mdx`, `cli/skills.mdx`, `cli/configuration.mdx` diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md new file mode 100644 index 0000000000..d19752fc69 --- /dev/null +++ b/docs/orm-docs-audit/changes.md @@ -0,0 +1,205 @@ +# Proposed changes + +Four kinds of change: restructure the docs, improve existing pages, create new pages, change the ORM. Ordered work first, then the items by kind. Nothing here is started. + +Sources: the first-session brief, plus the seven audit files under `audit/` (written 2026-09-10 against rc.9; every item cited below was spot-checked against `wip/prisma-src` unless marked "agent-reported"). Line numbers and full occurrence lists are in the audit files; this document names the defect and the pages. + +## Suggested order + +1. B1 to B4 and B11 to B14 as the first `prisma/web` PR: the site-wide mechanical fixes (`execute` to `query`, `sha256:` prefixes, `extensionPacks`, pagination names, `AndCount` names, snapshot layout). Each is a search-and-replace with a known correct form and breaks every user who copies it today. +2. B15 to B22 as a second PR, page by page: the existing-project pages, the migrations pages, the middleware pages, the raw SQL page, the relations page. These need rewriting sentences, not just names. +3. A7 in the same week as item 2: move or hide the sixteen Prisma 7 guides that sit under Prisma ORM 8 paths. Until then the guides index sends Prisma ORM 8 readers to `prisma generate`. +4. A4 and C4. Two small edits and one short page fix J4 and J5's discoverability. +5. A1, A2, A3, C1, C2 as the restructure, written from `mental-model.md`. This is the work that answers the Discord thread. +6. D1, D2, D3, D6, D8, D9, D10, D14, D17 raised as product tickets now, because C3, C4, and the deployment pages depend on the answers. +7. C3, C5 to C20 as each dependency clears. C9 (deployment) and C10 (Supabase and RLS) are the two largest gaps the audit found and have no page at all today. + +## Naming, across everything + +The product is "Prisma ORM"; a version number appears only when two versions are being contrasted. Rule, counts, and exceptions are in `naming.md`. Applies to every item below and to the proposed nodes in `ia.md`. + +## A. Restructure + +The current and proposed sidebar trees are in `ia.md`. The items below are the individual moves that tree implies. + +**A1. Give the ORM its own front door, organised by starting state.** Replace the current split (quickstart vs. add-to-existing) with four doors on `/prisma-orm` and `/orm`: new app from scratch, app I already started with an empty database, an existing database with data, and an existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. + +**A2. Put "Coming from Prisma 7" in the ORM sidebar at the top level and link it from the root page, `/getting-started`, `/orm`, and reading-data.** One page, with the mapping table from `mental-model.md` expanded. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. + +**A3. Human content first, agent prompts last, on every ORM page.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end of the page or into a collapsed block. Addresses the "written for AI" complaint directly. Unblocks the Newcomer and the Upgrader on every page. + +**A4. Fix the navigation labels that hide existing content.** The upgrade guide's sidebar label is "PostgreSQL" under "Upgrade Prisma ORM"; rename to "Prisma 7 to 8 (PostgreSQL)". The guides index says upgrading is "coming as they land"; remove that line. Files: `guides/upgrade-prisma-orm/meta.json`, `guides/index.mdx`. Unblocks J5. + +**A5. Root page: make the ORM line a section.** The root is the platform's page and should stay so, but the ORM needs more than "Here for the ORM? Jump to Prisma 7 or Prisma 8". Give it the four doors from A1 in one row. File: `(index)/index.mdx`. + +**A6. Absorb core-concepts into a narrative page written from `mental-model.md`.** The current page is a good glossary but reads as a list of terms. The mental model page answers "why" in the order a person meets each piece. Keep the glossary as a section at the end. File: `orm/core-concepts.mdx`. + +**A7. Get the Prisma 7 guides out of the Prisma ORM 8 tree.** Sixteen pages under the Prisma ORM 8 guides paths are Prisma 7 content end to end (`prisma@7.10.0`, `@prisma/client`, generator blocks, `prisma generate`, `migrate dev`, `db push`, `db seed`, `studio`): `guides/frameworks/react-router-7`, `guides/frameworks/solid-start`, all six of `guides/deployment/*`, `guides/integrations/github-actions`, `guides/integrations/ai-sdk`, all three of `guides/switch-to-prisma-orm/*`, all three of `guides/database/*`. None has a copy under `guides/v7/`. Move them to `guides/v7/` with the same slugs and redirect, then either write the Prisma ORM 8 replacement (C9, C11, C12) or leave the label off the Prisma ORM 8 sidebar until it exists. Evidence: `audit/gaps.md` Breaks copy-paste, `audit/start-guides.md` Misleading. Changes `ia.md`: the "Guides" tree for Prisma ORM 8 loses six labels until replacements land. + +**A8. One error reference, or two that link.** `cli/error-reference.mdx` says it lists every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code lives on `orm/reference/error-reference.mdx`, and the two pages do not link. The structured errors' `docsUrl` points at the ORM page. Either merge, or state the split on both pages and cross-link. Evidence: `audit/migrations-cli.md` Misleading. + +## B. Improve existing pages + +Copy-paste defects a user hits today, grouped by theme. B1 to B10 are from the first-session brief; B11 onward are from the audit. Full line lists are in the audit files named on each item. + +### Site-wide mechanical fixes + +**B1. `.take()`/`.skip()` to `.limit()`/`.offset()`.** 29 sites on 8 pages: `orm/fundamentals/reading-data.mdx` (8, including the meta description), `orm/reference/orm-client.mdx` (13, including two section headings), `orm/fundamentals/relations-and-joins.mdx`, `orm/reference/pipeline-builder.mdx` (3, check which are the Mongo pipeline `$skip` stage and keep those), `orm/middleware/authoring-custom-middleware.mdx`, `guides/runtimes/deno.mdx`, `(index)/full-stack-tutorial.mdx`, `(index)/prisma-orm/add-to-existing-project/postgresql.mdx`. + +**B2. `createCount`/`updateCount`/`deleteCount` to the `AndCount` names.** 31 sites on `orm/fundamentals/writing-data.mdx` and `orm/reference/orm-client.mdx`, including three section headings. + +**B3. Existing-project PostgreSQL page.** `db.orm.User` to `db.orm.public.User`; `db.sql.user` to `db.sql.public.user`; drop the `db.connect()` call or the `db.runtime()` call, not both; show `src/prisma/db.ts` once with one sentence on what it does; pick one story for `DATABASE_URL` (the page uses `.env` with `dotenv/config`, the quickstart says environment only) and say why. Then add the missing steps from J2: baseline migration and `migration ref set db` before the "next steps" section. See also B15, which found the page's default path is wrong. File: `(index)/prisma-orm/add-to-existing-project/postgresql.mdx`. + +**B4. Remove `@db.Uuid` from the PSL syntax page.** Lines 19 and 177 of `orm/contract-authoring/psl-syntax.mdx` show `Uuid = String @db.Uuid`. Removed in 0.17; `Uuid` is a built-in type name in type position and needs no alias, so the "Named types" example should alias a real type instead (for example `ShortName = VarChar(35)`). Check the rest of the page for other `@db.` forms. + +**B11. `execute()` to `query()` for every row-returning plan.** The largest defect the audit found. Since rc.2, `runtime.execute(plan)` returns `{ affectedRows }` and rows come from `runtime.query(plan)` (an `AsyncIterableResult`, awaitable to an array or iterated with `for await`). The MongoDB client's `db.execute(plan)` facade method was removed in the same release; rows come from `(await db.runtime()).query(plan)`. Prepared statements split the same way: `ps.query(runtime, params)` for rows, `execute` only for `.affectedCount()` plans. Roughly 200 lines on 14 pages: `orm/reference/sql-query-builder.mdx` (about 31), `orm/reference/pipeline-builder.mdx` (about 50), `orm/reference/raw-queries.mdx` (about 20), `orm/fundamentals/advanced-queries.mdx` (10), `orm/reference/transactions-and-runtime.mdx` (about 12, including `withTransaction`'s `tx` surface and `executePrepared`, which does not exist), `orm/core-concepts.mdx`, `orm/fundamentals/reading-data.mdx`, `orm/fundamentals/relations-and-joins.mdx`, `orm/extensions/using-extensions.mdx`, `orm/middleware/built-in-cache.mdx`, both `add-to-existing-project` pages, `guides/upgrade-prisma-orm/mongodb.mdx` (5). Non-returning writes such as `orm/fundamentals/transactions.mdx:60` are correct and stay on `execute`. The shipped skill has the same defect (D14). Evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `packages/3-extensions/mongo/src/runtime/mongo.ts:28-39`, `docs/releases/v8.0.0-rc.2.md`. Audit: `orm-client`, `builders`, `start-guides`. + +**B12. Bare hex hashes.** Every hash the site prints is `sha256:…`; since 0.17 hashes are bare hex and loaders and `migration ref set` reject the prefixed form. `orm/contract-authoring/the-contract-artifact.mdx` (5 sites, in JSON and in `StorageHashBase<"sha256:…">`), all six `orm/migrations/*` pages, `cli/migration-ref.mdx`. Evidence: `docs/releases/v0.17.0.md:45`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:14-24`. Audit: `contract`, `migrations-cli`. + +**B13. `extensionPacks` to `extensions`.** Renamed in 0.17 and the old key fails loudly. `orm/contract-authoring/typescript-schema-builder.mdx` (5 sites in `defineContract`; the PostgreSQL contract on that page does not build) and `orm/contract-authoring/the-contract-artifact.mdx` (2 sites as the `contract.json` top-level key). Evidence: `docs/releases/v0.17.0.md:73`, `packages/3-extensions/postgres/src/contract/define-contract.ts`. Audit: `contract`. + +**B14. Migration directory layout and imports.** The site shows `start-contract.json` / `end-contract.json` inside each migration directory and `migration.ts` importing `./end-contract`. Since 0.17 snapshots live once under `migrations/snapshots//contract.json` plus `contract.d.ts`, and `migration.ts` imports `../../snapshots//contract.json`. The directory holds `migration.ts`, `ops.json`, `migration.json`. Pages: `orm/migrations/how-migrations-work.mdx`, `generating-a-migration.mdx`, `editing-a-migration.mdx`. Evidence: `docs/releases/v0.17.0.md:47`, `examples/prisma-8-demo/migrations/app/*/migration.ts`. Audit: `migrations-cli`. + +### Page rewrites + +**B15. Existing-project pages: the default path is `src/prisma/`, not `prisma/`.** Both `add-to-existing-project` pages tell the reader to keep the default schema path `prisma/contract.prisma` and build every later command on it (`contract infer --output ./prisma/contract.prisma`, `import "./prisma/db"`). `orm init` defaults to `src/prisma/contract.prisma` and writes `db.ts` beside it, so a reader who accepts the default gets a file `prisma.config.ts` never reads and an import that does not resolve. Same pages also say `orm init` installs agent skills (it stopped in rc.6; it writes `prisma-next.md` only), omit the `.env` prompt (default No, so there may be no `.env` to "update"), and the MongoDB page's `runtime.execute(plan)` on an aggregate throws `RUNTIME.MONGO_STATISTICS_UNSUPPORTED`. Add the Temporal polyfill note (D10) and the `--write-env` / `--schema-path` flags. Evidence: `packages/1-framework/1-core/config/src/config-types.ts:45`, `packages/1-framework/3-tooling/cli/src/orm/init-inputs.ts:229-233`, `docs/releases/v8.0.0-rc.6.md:29`. Audit: `start-guides`. + +**B16. The `db` ref and plan-origin story on the migrations pages.** Three connected errors. (a) The pages say `migration plan` without `--from` or a `db` ref plans a full CREATE migration; since rc.8 it refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` when migrations exist on disk, and names the exits (`migration ref set db `, `--from `, `--from @empty`). The upgrade guide tells readers to look for the CREATE TABLE symptom that no longer appears. (b) `db init` and `db update` advance the `db` ref automatically only when `--db` is omitted; every example on the site passes `--db "$DATABASE_URL"`, which suppresses that unless `--advance-ref` is also given, so a reader following the site's loop hits (a) on the second plan. No page says this. (c) Retracted after PR 2: the audit said `MIGRATION.NO_TARGET` never comes from `migration plan`, but `plan-resolution.ts` calls `findLatestMigration`, which calls `findLeaf`, which throws it on a cyclic graph, and the monorepo's `gotchas.md:83-110` reproduces exactly the rollback case `rollbacks-and-recovery.mdx` describes. That page was right. Also `the-migration-graph.mdx` says there is no baseline mechanism; the planner writes an automatic baseline when the graph is empty and the `db` ref names a snapshot, and `--from @empty` is the supported retrofit. Pages: all six `orm/migrations/*`, `cli/migration-plan.mdx`, `cli/db-init.mdx`, `cli/db-update.mdx`, `cli/migration-ref.mdx`, `cli/index.mdx`, `guides/upgrade-prisma-orm/postgresql.mdx`. Evidence: `packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts:428-475`, `cli/src/control-api/operations/ref-advancement.ts:19-28`, `cli/src/control-api/operations/migration-plan.ts:369,505-545`. Audit: `migrations-cli`, `start-guides`. Ties to D1, D2, D9. + +**B17. Middleware pages: the hook model is wrong.** The pages document five hooks with `intercept` and `beforeExecute` for reads. Since rc.2 there are two lifecycles: `beforeQuery` / `interceptQuery` / `onRow` / `afterQuery` for row queries, and `beforeExecute` / `interceptExecute` / `afterExecute` for non-returning writes. There is no `intercept`, no compatibility alias, and `afterExecute` carries `stats.affectedRows`, not `rowCount`. The authoring guide's flagship query logger implements only `afterExecute` and reads `result.rowCount`, so it is a type error and would never log the SELECT the page shows it logging. Also: `unindexedPredicate` is not a lint severity key; `severities.latency` on budgets is read (page says it is not); "permissive mode" is unreachable from the Postgres client (D12); the cache runs on the query lifecycle. Pages: all five `orm/middleware/*`. Evidence: `packages/2-sql/5-runtime/src/middleware/sql-middleware.ts`, `packages/2-sql/5-runtime/src/middleware/lints.ts:13-23`, `budgets.ts:97-125`, `examples/prisma-8-demo/src/prisma/slow-query-warning.ts`. Audit: `builders`. + +**B18. Raw SQL page says the opposite of what ships.** `orm/reference/raw-queries.mdx` and `advanced-queries.mdx` say there is no way to run a standalone raw statement. Since rc.2 there is: `db.raw.sql\`…\`.returnsRow(spec).build()` for rows and `.affectedCount().build()` for writes; raw row queries compose as subqueries and CTEs. The page also calls `db.raw` as a template tag; it is a lane object and the tag is `db.raw.sql`. The "bare scalar interpolation is broken because the inferer emits unversioned ids" callout is contradicted by the adapter source, which emits versioned ids. Evidence: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:117-170`, `packages/3-targets/6-adapters/postgres/src/core/adapter.ts:112-140`, `examples/prisma-8-demo/src/queries/raw-query-demo.ts`. Audit: `builders`, `orm-client`. + +**B19. Relations and data-modeling pages say things are unsupported that work.** (a) The 1:1 mirror field `profile Profile?` "is not supported yet": it is accepted (rejected only when the foreign key is not unique) and `include('profile')` type-checks as a to-one include. (b) Implicit many-to-many `include` "not supported yet": the ORM resolves `through` relations and the demo includes `Post.tags`; nested `create` / `connect` / `disconnect` through the junction also work, and `orm-client.mdx` already documents `disconnect` through the junction. (c) Referential actions "as it lands": `onDelete` / `onUpdate` with `Cascade` / `Restrict` / `SetNull` / `NoAction` are lowered today. (d) The discriminator "is not filled in automatically": `.variant('Bug').create()` injects it; the page never mentions `.variant()`. Both pages send users to the SQL builder for things the ORM does. Pages: `orm/fundamentals/relations-and-joins.mdx`, `orm/data-modeling/relational-databases.mdx`. Evidence: `packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts:78`, `packages/3-extensions/sql-orm-client/src/collection-contract.ts:356-379`, `mutation-executor.ts:836-926`, `collection.ts:406`, `psl-relation-resolution.ts:19-22`. Audit: `contract`, `orm-client`. + +**B20. Aggregates decode as numbers, not strings.** `sql-query-builder.mdx` and `advanced-queries.mdx` tell users `COUNT` / `SUM` / `AVG` come back as strings and to call `Number(...)`. Since rc.2 `count()`, integer `sum()`, and `avg()` return `number` (throwing `RUNTIME.DECODE_FAILED` outside the safe range), with `countBigInt()`, `sumBigInt()`, `avgDecimal()` beside them. The "fixed" function list on `sql-query-builder.mdx` omits these; `min` / `max` are not numeric-only. Correction after PR 2: the audit said the `DateTime` column (`pg/timestamptz@1`) is still excluded from `min`/`max`; no such codec exists at rc.9. `DateTime` maps to `pg/timestamptz-temporal@1`, which is in `MIN_MAX_PRESERVING_CODECS`, so `min('createdAt')` type-checks; the compile error the page should show is `sum`/`avg` over a timestamp column. Evidence: `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:126-213`, `docs/releases/v8.0.0-rc.2.md:32-53`. Audit: `builders`, `orm-client`. + +**B21. Stale CLI names, flags, codes, and output.** One pass over `cli/*` and `orm/migrations/*`: `--skip-skills` and `CLI.INIT_SKILL_INSTALL_FAILED` on `orm-init.mdx` (removed rc.6; also cited on `(index)/index.mdx` and `getting-started.mdx`); `ref set` / `ref list` bare group (rc.5: `migration ref set`) and `ref set prod @db` (fails, `@db` is not accepted by the offline command); `prisma-cli migrate` hint text and the sentence explaining it (rc.5: hints print `prisma db migrate`); `(PN-RUN-3000)` (0.17: dotted codes, `MIGRATION.RUNNER_FAILED` and siblings); `from: null` (prints `from: (baseline)`); the "Applied 1 migration(s)…" summary line (no migration count); `git clone …/orm` then `cd prisma`; `npx prisma@latest migrate` on `create-prisma.mdx` (the command is `db migrate`); hyphenated `--name add-users-table` shown as the directory name (slugs become `add_users_table`); `contract infer` presents `--db` as required (falls back to config); `orm-init.mdx` says the scaffolded `db.ts` does not load `.env` (it starts with `import 'dotenv/config'`) and that `contract:emit` calls `prisma-cli`. Audit: `migrations-cli`, `start-guides`, `contract`. + +**B22. `editing-a-migration.mdx` data-transform example does not typecheck.** `sql({ context })` omits the required `rawCodecInferer`, so `node migration.ts` fails before writing `ops.json`. Evidence: `packages/2-sql/4-lanes/sql-builder/src/runtime/sql.ts:11-19`. Audit: `migrations-cli`. + +### Smaller fixes, one line each + +**B5. Supported databases.** `orm/index.mdx` says SQLite is planned. It ships as `@prisma/orm-sqlite`; `sql-query-builder.mdx` also says "PostgreSQL is supported today". Say Postgres, MongoDB, SQLite, and what is next. + +**B6. Un-pin the upgrade guides.** The PostgreSQL guide says every command was validated on rc.6 and rc.4; the MongoDB guide says `0.16.0`. Re-run on rc.9 (the Mongo guide is also hit by the rc.7 pagination rename and the rc.9 attribute rejection) and either drop the version callout or keep it current per release. Also `Database signed (marker created)` is printed as `Database signed`. Files: `guides/upgrade-prisma-orm/postgresql.mdx`, `mongodb.mdx`. + +**B7. One line on agent files, on three pages.** On `create-prisma.mdx`, both quickstarts, and the existing-project page: "Prisma writes skill files for coding agents into your repo. To stop that, set `skills: { agents: [] }` in `prisma.config.ts`; see Configuration." Until D3 lands, that is the only correct answer. + +**B8. Node version.** The quickstart says 24 or newer; seven framework guides say "Node.js 24 or later"; the scaffold's `engines` says `^22.18.0 || >=24.11.0` and create-prisma refuses below 22.18; the upgrade guide says 22.18+. Node 24.0 to 24.10 does not work. Say the true floor once. + +**B9. Explain `// use prisma-next`.** It appears at the top of every PSL example and is never explained. One sentence where the contract file is first introduced, and on the editor page (C5). + +**B10. `db.runtime()` on Mongo.** Mongo needs `(await db.runtime())`, Postgres does not. Say so where `db.ts` is first shown, not only in the transactions reference. + +**B23. `db.close()`, not `db.runtime().close()`.** Four guides (Bun, Hono, Elysia, NestJS) tear down with `db.runtime().close()`; the client method is `db.close()` (idempotent, also `Symbol.asyncDispose`), and every other page uses it. Audit: `gaps`. + +**B24. Upsert needs `conflictOn`.** `writing-data.mdx:182-195` upserts without `conflictOn` and says the match is on `email`; without `conflictOn` the target is the primary key, so the sample inserts a duplicate or fails on the unique constraint. Audit: `orm-client`. + +**B25. Streaming claim.** `reading-data.mdx` promises a flat memory footprint for `for await` over millions of rows; the `postgres()` facade constructs its driver with `cursor: { disabled: true }`, so the whole result is buffered first. Either soften the page or fix the ORM (D8). Audit: `orm-client`. + +**B26. Enum ordering changed in rc.9.** `orm-client.mdx:478,513` say text-backed enums sort in declaration order; rc.9 sorts by stored value, only native enums keep database order. Audit: `orm-client`. + +**B27. Structured errors, not plain `Error`.** `transactions-and-runtime.mdx` shows closed / double-connect failures as plain `Error` strings; they are `DRIVER.NOT_CONNECTED` / `DRIVER.ALREADY_CONNECTED` envelopes, and the latter is raised by Postgres too. Its `db.prepare` then `db.connect()` sample throws `DRIVER.ALREADY_CONNECTED`. `pipeline-builder.mdx` calls the unknown-root error a plain `Error`; it is `ORM.MODEL_UNKNOWN`. Audit: `orm-client`, `builders`. + +**B28. create-prisma page details.** The `--template` list omits `minimal` (the default) on three pages; for PostgreSQL the scaffold writes no `.env` (page says "review `DATABASE_URL` in `.env`"); `--force` also overwrites the generated Prisma files and refuses on a non-empty `migrations/`; the deploy prompt defaults differ between interactive, `--yes`, and `--json`; the Deno command needs `--minimum-dependency-age=0`; the page lists four of the twelve generated scripts. Audit: `start-guides`, `gaps`. + +**B29. MongoDB replica set.** Both MongoDB start pages say Prisma 8 needs a replica set; nothing in the runtime or migration runner opens a session or transaction, and `orm init`'s `.env.example` says a standalone `mongod` works. Only the scaffold's connection string demands one. Audit: `start-guides`. + +**B30. Framework guide details.** The Bun guide's `esbuild` build step fails (the scaffold builds with `tsdown`; edit `tsdown.config.ts` instead) and `bun run dev` is `tsx watch`, so "no build step" and the one-shot output are wrong; the NestJS `@Inject` workaround describes a defect the template fixed; seven guides say `db:init` applies `src/prisma/contract.prisma` without saying the TypeScript authoring path is `contract.ts` with output under `src/prisma/generated/`; the Deno page's "separate Deno CLI entry point" note is stale and its sample output omits fields. Audit: `gaps`. + +**B31. `data-modeling/index.mdx` scalar table.** `Json` binds to native `json` since 0.17; `Jsonb` is the separate scalar (what `field.json()` and value objects use). The table never mentions `Jsonb`, `Decimal`, `Bytes`. Audit: `contract`. + +**B33. `ai/tools/skills.mdx` describes skills that do not exist.** It says `orm init --skip-skills` skips installation (no such flag; `orm init` does not touch skills since rc.6), lists `prisma-next-upgrade` and `prisma-8-extension-upgrade` as installable (retired; `prisma init` deletes those directories; only `prisma-8` ships, with upgrading as a branch inside it), says `orm init` pins the GitHub install (the skill ships inside the `@prisma/orm-*` tarball and `prisma skills sync` copies it), and leads with `npx skills add prisma/prisma/skills`, which the monorepo README calls a fallback nothing keeps current. Evidence: `skills/README.md`, `cli/src/commands/init/skill-sources.ts:1-49`. Audit: `extras`. + +**B34. Full-stack tutorial.** The tutorial shows the scaffold's `User` model with `createdAt DateTime` and `updatedAt temporal.updatedAt()`; the rc.9 starter contract writes `TimestamptzString` and `temporal.updatedAtString()`, which store a different runtime type. It also says the scaffold added a `postinstall` hook for skills; create-prisma adds a `skills:sync` script and runs `prisma init --yes` once. Evidence: `cli/src/commands/init/templates/code-templates.ts:171-193`, `wip/create-prisma-src/src/tasks/install.ts:56`. Audit: `extras`. + +**B35. `using-extensions.mdx` recipe and links.** The generic five-step recipe (import `/control`, pass to `postgres({ extensions })`) does not work for Supabase, which is wired with `extensions: [supabasePack]` from `/pack` and a client built by `supabase()` from `/runtime`. Every catalog row links to a monorepo README whose install command is `pnpm add @internal/extension-`, a private name. Also `orm/data-modeling/index.mdx:159` lists `Json` without saying filtering is whole-value equality only (D17). Audit: `extras`. + +**B32. Guides index.** `guides/index.mdx` lists "Upgrading" and "Databases" under "Coming as they land" while the upgrade guide exists and is in the nav. Fold into A4. + +## C. New pages + +**C1. Coming from Prisma 7.** The mapping table from `mental-model.md`, in four sections: schema and types, CLI commands, client API, and "not in Prisma 8 yet" with a status per item. The last section is the one users asked for most and the one no page has: `skipDuplicates`, `increment`/`decrement`, `findUniqueOrThrow`, case-insensitive filters, `$transaction` arrays, model and payload types (with a link to the PRs), `@updatedAt` (rejected with a hint to use `temporal.updatedAt()`), `cuid()` (rejected; use `cuid(2)`). Unblocks J3. Depends on A2 for placement. + +**C2. Add Prisma ORM to an app you already started.** The J1 page. Starts from "you have a project directory and an empty or absent database". `orm init`, edit the contract, `contract emit`, `db init`, one query, with `db.ts` shown. Bun as the worked example, since it is the case reported, with a note for Node. Replaces the Bun guide's scaffold-first opening or sits beside it. + +**C3. Adopt an existing database.** The J2 page, split out from the current existing-project page so B3 and B15's fixes have room. Adds what to expect from `contract infer` (it is SQL-only; it captures indexes, checks, RLS, and 1:1 relations from unique indexes; it emits Temporal-backed `Timestamp` types that need the polyfill, D10), what `db sign` checks and what exit code 4 means, the baseline migration, the `db` ref, and the second migration with `--advance-ref db`. Depends on D1 for how short this can be. + +**C4. Prisma ORM 8 release status.** One short page: Prisma ORM 8 is a release candidate; GA expected in the window Will has stated publicly; Prisma ORM 7 receives bug fixes and security updates for 12 months; `npx prisma` and `npm install prisma` now resolve to Prisma ORM 8; to stay on 7, install `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. Depends on D6 for whether the tag stays. + +**C5. Editor setup.** VS Code extension location (open-vsx), that Prisma ORM 8 does not bundle a language server and uses the locally installed CLI, that `contract.prisma` needs `// use prisma-next` on line one, and `prisma contract format` as the fallback. Under getting started. Unblocks J7. Needs Serhii to confirm the current state. + +**C6. Types.** Model types, result types, where and input types, with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch and published the day prisma/orm#30231, #30236, and #30158 ship. Unblocks J9. Also covers what `contract.d.ts` already exports today: `AddressInput` beside `AddressOutput`, `FieldOutputTypes`, `TypeMaps`, `QueryOperationTypes`, `AggregateTypes`. + +**C7. Advanced Postgres.** The audit answered the product questions the first brief left open: RLS and policies are expressible in PSL (`@@rls`, `policy_select` and siblings, `role` blocks) and in the TypeScript builder; expression and partial indexes are `@@index(expression:, where:, unique:, type:)`; hand-written checks are `@@check`; `@noCheck` waives generated checks; `installExtension` / `createExtension` are migration factories; `@@control` sets how much of a table Prisma manages. None of it is on the site. Write the page from `skills/prisma-8/references/contract.md:101-108,265-367` and `packages/2-sql/2-authoring/contract-psl/README.md`. Unblocks J8. Audit: `contract`, `gaps`. + +**C8. Money and Decimal.** Short page or section under data modeling: cents as integers (already there), `Decimal` with precision and scale in type position (`Numeric(p, s)`), what `@default` accepts on it, and the aggregate return types (`avgDecimal`). Answers the open Discord question. + +**C9. Deploying Prisma ORM 8.** (See also the production caveat at the end of this item.) There is no Prisma ORM 8 deployment guide for any host; all six `guides/deployment/*` pages are Prisma 7 (A7). What a deploy needs is in the source: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). One page with sections for Docker, Vercel, Cloudflare Workers, and monorepos, or one page per host under the same label. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, 128 MiB isolate memory so `limit()` is the memory cap) and carries a production caveat with zero site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s), workaround `cursor: { disabled: true }`. Evidence: `skills/prisma-8/references/build.md:421-435`, `migrations.md:487`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. Audit: `gaps`, `extras`. + +**C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, the async `supabase({ contractJson, url, jwksUrl | jwtSecret })` factory, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*` reads, and `SUPABASE.JWT_INVALID` / `SUPABASE.CONFIG_INVALID`. A page under `orm/extensions/` and a guide. Evidence: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. Audit: `gaps`. + +**C11. CI with Prisma ORM 8.** The only CI guide is Prisma 7 (A7). The Prisma ORM 8 shape: `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Evidence: `skills/prisma-8/references/migration-review.md:172-197`, `cli/src/orm/migration/status-findings.ts`. Audit: `gaps`, `migrations-cli`. + +**C12. Switching from another ORM, and team schema workflow.** The three `switch-to-prisma-orm/*` and three `database/*` guides are Prisma 7 (A7). The Prisma ORM 8 replacements are the brownfield flow (`orm init`, `contract infer --output`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Much of C3 and C11 can be reused. Audit: `start-guides`. + +**C13. Migration factory reference.** The site shows six migration factories (`createSchema`, `createTable`, `addColumn`, `setNotNull`, `dataTransform`, `rawSql`). The `Migration` base class has about thirty: indexes, foreign keys, uniques, checks, column type and default changes, native enum create / drop / add-value, `installExtension`, RLS enable / disable, policy create / drop / rename, plus the free factories `createExtension`, `foreignKey`, `unique`, `checkExpression`, `fn`, `lit`. Also the `node migration.ts` self-emit CLI's `--dry-run` and `--config`. A reference page beside `editing-a-migration.mdx`. Evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. Audit: `migrations-cli`. + +**C14. PSL and TypeScript builder completeness.** Not a new page but a rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. Missing from PSL: native types in type position (`Uuid`, `VarChar(255)`, `Numeric`, `Timestamptz`, `TimestamptzString`, `Jsonb`, `BigIntNumber`, `UnboundedInt`, and the rest), the `@default` generator list (`uuid(4|7)`, `cuid(2)`, `ulid()`, `nanoid(n)`, `dbgenerated`), `temporal.createdAt()` / `updatedAt()` presets, scalar lists and which targets support them, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks and cross-space relation targets, `native_enum` blocks, `@relation("Name")` disambiguation, `onDelete` / `onUpdate`, extension types inline in field position, MongoDB index options (`sort:`, `@@textIndex`), and `.variant()` for polymorphic reads. Missing from the TypeScript page: the field helpers beyond four, `.attributes()` for composite keys and uniques (the page shows no way to declare a composite primary key), `constraints.index`, `check`, `.noCheck()`, `rel.belongsTo().sql({ fk })`, `foreignKeyDefaults` / `naming`, the `output` config option, and the MongoDB builder's `valueObject`, `index`, `enumType`, `field.vector()`, and polymorphism. Evidence: `packages/2-sql/2-authoring/contract-psl/README.md`, `contract-ts/README.md`, `packages/2-mongo-family/2-authoring/contract-ts/README.md`. Audit: `contract`. + +**C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute` and `RuntimeStatementStats`; `verifyMarker: 'onFirstUse' | false` (the startup check core-concepts describes without saying how to control it); `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat accessor form `db.orm.User` for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the optional `configure(meta)` callback on every terminal and `meta.annotate(...)` (how cache opt-in works per query); `distinctOn` needs the `postgres.distinctOn` capability; MongoDB `mode: 'strict' | 'permissive'` and the filter classes `MongoAndExpr`, `MongoNotExpr`, `MongoExistsExpr`; the SQLite facade lifecycle; the driver-free static client (`@prisma/orm-postgres/static`); `db.prepare` and prepared bind sites on `limit()` / `offset()`; `ctx.signal` and `MongoMiddleware` on the middleware pages; `createInMemoryCacheStore` and the cache debug events; `RUNTIME.MISSING_EXTENSION_PACK`; `fns.cosineSimilarity`. Audit: `orm-client`, `builders`. + +**C16. Build integration.** The Vite plugin `@prisma/orm-postgres/vite-plugin-contract-emit` (re-emits on save; Vite 7 and 8; dev server only) and the `"prebuild": "prisma contract emit"` pattern for every other bundler. Zero hits on the site; the Vite-based framework guides (SvelteKit, Astro, Nuxt, TanStack Start) tell readers to run `contract:emit` by hand. A section on `the-contract-artifact.mdx` plus one paragraph per framework guide. Evidence: `packages/1-framework/3-tooling/vite-plugin-contract-emit/README.md`, `skills/prisma-8/references/build.md`. Audit: `gaps`, `contract`. + +**C18. Supported versions and requirements.** No page states the floors. The monorepo's `docs/Supported Versions.md` says Node 24, Bun 1.2, Deno 2.0, PostgreSQL 15, MongoDB 8.0, TypeScript 5.9, `tsconfig` with `moduleResolution: "bundler"` and `strict: true`, and ESM-only with no CommonJS. The site says Bun 1.1, states no PostgreSQL floor anywhere, says nothing about ESM or `strict`, and the upgrade guide shows `module: nodenext`. The doc's Node 24 disagrees with the scaffold's `^22.18.0 || >=24.11.0` (B8) and its `--merge-tsconfig` flag does not exist at rc.9, so confirm each number with product before publishing. One short page under getting started, linked from every quickstart. Audit: `extras`. + +**C19. Extension pages beyond pgvector.** PostGIS (`Geometry` type, its seven operations, the `pg/geometry@1` JSON round-trip exemption), ParadeDB (`key_field`-only), and arktype-json (`arktypeJson(schema)`, never shown) each have one catalog row. One section per pack on `using-extensions.mdx` or one page each, with the real public import paths. Audit: `extras`. + +**C20. Telemetry page.** `cli/telemetry.mdx` never mentions `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file and its `enableTelemetry` field, that CI never sends, the first-run notice, that the preference is per-user, agent detection, or the event fields (the monorepo's `docs/Telemetry.md` is itself stale: rc.9 also sends `exitCode`). The rc.9 first-run notice links to `prisma-next.dev/docs/cli/telemetry`, not this page. Evidence: `packages/1-framework/3-tooling/cli-telemetry/src/`, `cli/src/orm/telemetry/reporting.ts`. Audit: `extras`. + +**C17. CLI page additions.** `cli/configuration.mdx`: the `migrations.dir` and `formatter` keys, the `composer` section every scaffold ships, telemetry opt-out variables (`DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`). `cli/orm-init.mdx`: the full flag list, exit codes 4 and 5, `prisma-next.md`, `--confirm` for re-running. `cli/db-update.mdx`: it never plans `data`-class operations. `cli/migration-ref.mdx`: the refusals. `cli/migration-new.mdx`: default origin rules. `cli/migration-status.mdx`: `--json` diagnostics. `cli/db-migrate.mdx`: `MIGRATION.MARKER_MISMATCH` and `PATH_UNREACHABLE`. `cli/contract-emit.mdx`: `--json` output and the `output` config option. `cli/index.mdx`: `@prisma/orm-toolchain` and `@prisma/orm-framework`. Audit: `migrations-cli`, `contract`, `gaps`. + +## D. Change the ORM + +These are places where the docs are hard because the tool is. Each is a candidate for the product backlog, not a docs fix. D1 and D3 have briefs (`brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`) and are handed off. + +**D1. Make adoption one step.** Today: `contract infer`, edit, `contract emit`, `db sign`, `migration plan --name baseline` (or equivalent), `migration ref set db `. Two options: have `db sign` also set the `db` ref when no ref exists, or add a `db adopt` command that runs sign plus ref. Either removes the recreate-everything trap in J2 and cuts C3 in half. Handed off. + +**D2. `migration plan` with no origin and no migrations on disk.** The CLI refuses when migrations exist on disk with no ref (`MIGRATION.PLAN_ORIGIN_UNKNOWN`). When no migrations exist it silently plans from empty. For a signed database with no ref that is the wrong default; it should warn or refuse the same way. Related to D1. + +**D3. Opt out of agent files at scaffold time.** `create-prisma` has no flag and always writes all four agents plus a `postinstall`. Add a prompt and a `--skills none` flag, and have `orm init` ask. Five users in one week; the circulating workaround is wrong. Handed off. + +**D4. Missing client API.** Verified absent from the SQL ORM client source: `firstOrThrow` on the collection (it exists on `AsyncIterableResult`, so `.all().firstOrThrow()` works and could be documented as the workaround), atomic `increment`/`decrement` on update, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), and filtering on JSON columns by path or containment (the `jsonb` codec declares only the `equality` trait and the SQL builder has no `->>` or `@>` functions; the workaround is `db.raw.sql`). Also confirmed not supported, for C1's "not yet" list: soft delete, model validations, lifecycle callbacks, custom `Collection` subclasses (`CollectionImpl` has private clone methods), read replicas and multi-database routing, MongoDB referential actions. Each needs a decision: build it, or document the workaround (SQL builder or raw) and say it is not planned. The types work (`Models`, `Shape<>`, where types) is already in PRs. + +**D5. `contract infer` output on Prisma 7 databases.** Users report the inferred contract failing to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether infer on rc.9 still emits removed syntax, and whether the `Decimal @default(0.00)` failure is a bug. Infer should produce a contract that emits. See also D10. + +**D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Either move the RC to a `next` tag until GA or state the policy on C4. Serhii said he would find out why; no update. + +**D7. `db.connect()` versus `db.runtime()`, and `db.close()` versus `db.runtime().close()`.** Two names for adjacent things, used interchangeably across pages, with a Mongo-only `await`, and now a third pair for teardown. `db.prepare` followed by `db.connect()` throws `DRIVER.ALREADY_CONNECTED` because `prepare` connects in the background. If the API can be one call on both targets, the docs get simpler on every page that shows a script. + +**D8. Streaming does not stream.** `postgres()` builds its driver with `cursor: { disabled: true }`, so `for await` over a result iterates an already-buffered array; only the serverless facade exposes cursor batches. The reading-data page promises the opposite. Either expose `cursor` / `batchSize` on `postgres()` or drop the promise (B25). Evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`, `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:39-53`. + +**D9. `--db` suppresses `db` ref advancement.** `db init` and `db update` advance the `db` ref only when `--db` is omitted; with `--db` they do not unless `--advance-ref` is also passed. Every doc example passes `--db`, and the result is `MIGRATION.PLAN_ORIGIN_UNKNOWN` on the second plan. The rule is surprising and undocumented. Consider advancing regardless of how the URL was supplied, or warning when `--db` is used without `--advance-ref` and no `db` ref exists. Related to D1 and D2. Evidence: `cli/src/control-api/operations/ref-advancement.ts:19-28`. + +**D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps `timestamp` / `timestamptz` columns to Temporal-backed `Timestamp` / `Timestamptz`; on Node.js before 26.8.2 (checked: 26.8.1, 24.16, and 22.22 have no `globalThis.Temporal`; 26.8.2 does) every read of such a column throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported first. `create-prisma` installs the polyfill; `orm init` does not, and neither the existing-project page nor the upgrade guide mentions it, so real upgrades with `DateTime` columns break after step 3. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit time with a clear message. Evidence: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`, `packages/3-targets/3-targets/postgres/src/core/errors.ts:74-86`. + +**D11. create-prisma pins rc.8.** `create-prisma@0.11.7` pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` (to match a Composer peer dependency), so a fresh scaffold does not get the rc.9 behaviour the site documents. Either bump on every RC or document the lag. Evidence: `wip/create-prisma-src/src/constants/dependencies.ts:8-10`. + +**D12. Permissive mode is unreachable on Postgres.** `postgres(...)` never forwards a `mode`, so the runtime is always strict and every "warn in permissive mode" path on the lints and budgets pages cannot happen; only `mongo(...)` accepts `mode`. Either expose `mode` on `postgres()` or remove the branches and the docs. Evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. + +**D13. `migration ref set … @db` fails.** `@db` parses to the empty sentinel for the offline command and fails with `MIGRATION.HASH_NOT_IN_GRAPH` instead of reading the database marker. Either support it (read the marker when a `--db` is available) or reject it with a message that says so. Evidence: `cli/src/control-api/operations/ref.ts:104-118`. + +**D14. The shipped skill is stale in the same places as the site, and a few more.** (Also: `cipherstash.EncryptedString` as the canonical extension example although that package was dropped, `createTelemetryMiddleware` from a package that does not exist, and no mention of the cache middleware.) Will said skills are not the focus, but every audit found the skill wrong where the site is wrong, and it is what agents read. Verified stale in `skills/prisma-8/references/`: `execute` for row reads (should be `query`), `PN-CLI-*` / `PN-MIG-*` / `PN-RUN-*` codes (dotted since 0.17), the flat `defineConfig` config file (envelope since rc.4), `orm init --skip-skills` and the `prisma/contract.prisma` default (`src/prisma/`), "N:M include and nested mutations unsupported" (they work), `pn_meta_marker` (it is `prisma_contract.marker`), `createTelemetryMiddleware` from a package that does not exist, `@@discriminator` / `@@base` "SQL-only" (Mongo has them), scalar lists "rejected" (Postgres accepts them), `-y` for destructive consent (it is `--confirm `), free-function migration factories (they are `this.` methods), `migration show` with no argument (positional required). One ticket to the skills owner with this list; the audit files have the line numbers. + +**D15. `db update` never plans data operations.** Its allowed classes are additive, widening, destructive; a change that needs a backfill fails and the user must switch to `migration plan`. Undocumented. Either allow it or print the switch hint. Evidence: `cli/src/control-api/operations/db-update.ts:17`. + +**D16. `migration status` exits 0 on warnings.** CI must parse `--json` `diagnostics[]` to catch `MIGRATION.DIVERGED`, `MARKER_NOT_IN_HISTORY`, `CONTRACT.AHEAD`, `NO_MARKER`. A `--strict` flag or a non-zero exit on warn-level findings would make C11 one line. Evidence: `cli/src/orm/migration/status-findings.ts`. + +**D17. `docs/reference/` and `docs/Supported Versions.md` disagree with the site and partly with the source.** `reference/capabilities.md` and the site's capabilities page disagree on key namespacing (`sql.lateral` vs `postgres.lateral`), pack key nesting, the error code spelling, and whether capabilities are negotiated at connect time or fixed at emit time. `Supported Versions.md` says Node 24 and documents `--merge-tsconfig`; the scaffold says 22.18 and the flag does not exist. `Telemetry.md` says no exit code is sent; rc.9 sends one. `docs/reference/error-reference.md` (from which the site's ORM error reference is generated word for word) still writes `ref set`, `ref list`, and `prisma ref set ` in eight entries; the mounted command has been `migration ref set` since rc.5, so the fix belongs in the error definitions' `fix` text. `mongodb-user-promise.md` promises MongoDB referential actions that are not implemented. Whoever owns `docs/` in the monorepo should reconcile these before the site is written from them; until then the audit treats `packages/` and `docs/releases/` as the only truth. + +**D18. create-prisma's MongoDB scaffold writes a `.env` nothing reads.** For MongoDB the scaffold writes `.env` with `DATABASE_URL`, but the generated `prisma.config.ts` reads `MONGODB_URL` and loads no dotenv file, so the file is dead and the CLI's own next-step text says to set `MONGODB_URL` in the environment. Found during the PR 3 review. Evidence: `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs:13,31`, `src/tasks/prisma-setup/project-files.ts:22-26`, `src/tasks/prisma-setup/presentation.ts:46`. + +## Unverified, carried from the audits + +Things the agents flagged but could not confirm against the monorepo, mostly because the `prisma` binary and `@prisma/cli-engine` live in the uncloned `prisma-cli` repo. Check before acting: the global `--yes` flag on `db migrate`; `cli/global-flags.mdx`, `cli/init.mdx`, `cli/skills.mdx` wholesale; `definePrismaConfig` from `prisma/config` versus `@prisma/cli-engine`; `HostedStateBootstrapError` and `--name`; Mongo `_id` decoding through `$lookup` and `findOneAndUpdate`; `_id` equality inside `match()`; the apply order of extension spaces versus `app`; whether `DateTime` still parses in PSL now that the starter contract writes `TimestamptzString`; the raw `EXTRACT(...)` codec claim; the `ilike` `fns` helper; "ParadeDB and Supabase are experimental"; which agent directory list is current (`ai/tools/skills.mdx` says Claude Code, Cursor, Codex, Windsurf; `cli/skills.mdx` and the scaffold say `claude`, `cursor`, `agents`, `devin`); whether `npx skills add` wants `prisma/prisma/skills` or `prisma/orm/skills`; the real capability key strings (see D17). Full list in the `## Unverified` section of each audit file. diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md new file mode 100644 index 0000000000..eae7f20730 --- /dev/null +++ b/docs/orm-docs-audit/ia.md @@ -0,0 +1,178 @@ +# Information architecture: proposal + +Proposal first, then why, then the current state it changes. Source: the `meta.json` files and page titles in `wip/web/apps/docs/content/docs/` on 2026-09-10. Labels are what the sidebar shows. + +## Proposed + +Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and two labels under Guides. Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. + +### Getting Started > Prisma ORM + +``` +Prisma ORM + Introduction to Prisma 8 human content first, agent prompt last + + Prisma 8 release status RC, GA window, 7 support period, what npx prisma installs, how to pin 7 + ~ Start a new app was "Quickstart"; same two pages + PostgreSQL + MongoDB + + Add to an app you already have empty or no database: orm init, contract, emit, db init, first query, db.ts shown + PostgreSQL + MongoDB + ~ Adopt an existing database was "Add to Existing Project"; adds baseline, ref, second migration + PostgreSQL + MongoDB + + Coming from Prisma 7 link to the ORM page below, so the Upgrader finds it from here + + Editor setup + create-prisma reference; moved to last +``` + +Four starting states, one group each. "Coming from Prisma 7" is a link node here because the page itself belongs with the API it maps. + +### ORM > Introduction + +``` +Introduction + Prisma 8 + + Coming from Prisma 7 the mapping page: schema and types, CLI, client API, not-yet list + ~ Core concepts rewritten as narrative from mental-model.md; glossary kept at the end +``` + +### Guides + +``` +Overview remove "Upgrading: moving from Prisma 7" from the coming-soon list +Upgrade Prisma ORM + ~ Prisma 7 to 8 (PostgreSQL) was "PostgreSQL" + ~ Prisma 6 to 8 (MongoDB) was "MongoDB" + v7, v6, v5, v4, v3, v1 +``` + +### The ORM root page (`/orm`) + +Today the page has five sections: "Your schema becomes a contract", "What changed for developers", "Supported databases", "Get started" (three cards), "Go deeper" (five cards), and "Learn more about the design of Prisma 8" (five blog links). Three of the six argue for the design against Prisma 7. There is no query on the page. A Newcomer cannot tell from it what the product does; an Upgrader is told why it is different before being shown what it is. + +Proposed structure, in order: + +1. One sentence saying what it is: a typed data layer for TypeScript, for PostgreSQL, MongoDB, and SQLite. +2. The product in one screen: a short contract, the query it enables, and the typed result, side by side. Nothing else above the fold. +3. The four starting-state doors from the Getting Started subtree. +4. What you can do with it: one line and one link each for modeling, querying, relations, transactions, migrations, middleware, extensions. This is the section map, not an argument. +5. Coming from Prisma 7: one line linking to the mapping page. +6. Release status: one line linking to the status page. + +Removed from this page: the three-step workflow explanation, "What changed for developers", and the blog list. The first moves into Core concepts; the other two go, or the blog list moves to the bottom of Core concepts. + +### Root page (`/`) + +The ORM line becomes a short row with the four starting states, linking into the subtree above. The platform hero stays. + +### What each proposed node fixes + +| Node | Jobs | +| --- | --- | +| Prisma 8 release status | J4 | +| Add to an app you already have | J1 | +| Adopt an existing database (rewritten) | J2 | +| Coming from Prisma 7 | J3, J5 (links to the incremental guide), J6 (attribute map) | +| Editor setup | J7 | +| Guides labels and overview line | J5 | +| Core concepts rewritten | the "written for AI" complaint, by giving the Newcomer a why-first page | + +J8, J9, and J10 need product decisions or shipped code before a node makes sense; they are in `changes.md` under C and D. + +### Not proposed + +No change to the top-level section list, to Data Modeling, Contract Authoring, Fundamentals, Migrations, Middleware, Extensions, Reference, or to any Guides subtree except the two labels. The "Prisma 7" group at the bottom of Getting Started stays as the home for people staying on 7. + +## Why: where each job lands today, and where the structure fails it + +| Job | Lands on | Structural failure | +| --- | --- | --- | +| J1 existing app, empty database | Add to Existing Project > PostgreSQL | page assumes tables exist; no node for this state | +| J2 existing database with data | Add to Existing Project > PostgreSQL | right node, page stops before the ref step | +| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; content spread over nine pages | +| J4 should I move now | root, `/prisma-orm` | no node; note box only says 7 is supported | +| J5 incremental upgrade | Guides > Upgrade Prisma ORM > PostgreSQL | not linked from any ORM node; label hides it | +| J6 data types | Data Modeling > Overview | right node; one stale example | +| J7 editor setup | none | no node | +| J8 advanced Postgres | none | no node; needs product answers | +| J9 types | none | no node; API in PRs | +| J10 opt out of agent files | CLI > configuration | right node, unreachable from Getting Started | + +Two observations follow from the table. + +First, the Getting Started > Prisma ORM subtree is organised by the tool that runs (`create-prisma` for Quickstart, `orm init` for Add to Existing Project) and then by database. The reader does not know those tools yet. The failures in J1 and J2 both happen at the point where the reader's situation differs from the page's assumption about it. The reader knows their situation: do I have an app, do I have a database, does it have data, was it Prisma 7. That is why I proposed organising this subtree by starting state. The database split (PostgreSQL / MongoDB) stays inside each. + +Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides with a database name as its label. + +## Current state + +Top-level sections, in nav order: Getting Started, ORM, Composer, Local development, AI, Compute, Postgres, Storage, Studio, Query insights, Console, Guides, CLI, REST API, Accelerate. + +### Getting Started + +``` +Start + Get started with Prisma / platform landing; ORM is one line + Choose a Prisma 8 setup path /getting-started + Deploy the full Prisma stack /full-stack-tutorial + Deploy your first app /prisma-compute/deploy +Prisma ORM + Introduction to Prisma 8 /prisma-orm + create-prisma /prisma-orm/create-prisma + Quickstart + PostgreSQL /prisma-orm/quickstart/postgresql + MongoDB /prisma-orm/quickstart/mongodb + Add to Existing Project + PostgreSQL /prisma-orm/add-to-existing-project/postgresql + MongoDB /prisma-orm/add-to-existing-project/mongodb +Prisma Postgres + (quickstarts per ORM, import from existing database, from the CLI) +Prisma 7 + Prisma 7 setup paths /v7/getting-started (for people staying on 7) +``` + +### ORM + +``` +Introduction + Prisma 8 /orm + Core concepts /orm/core-concepts +Data Modeling + Overview, Relational data modeling, MongoDB data modeling +Contract Authoring + The data contract, Author in PSL, Author in TypeScript, The emitted artifacts, Capabilities +Fundamentals + Reading data, Writing data, Relations and joins, Transactions, Advanced queries +Migrations + How migrations work, The migration graph, Generating, Editing, Applying, Rollbacks and recovery +Middleware + How middleware works, Built-in: budgets, lints, cache, Authoring custom middleware +Extensions + Using extensions +Reference + API reference, ORM client, SQL query builder, Pipeline builder, Raw queries, Transactions and runtime, Error reference +``` + +### Guides (ORM-relevant parts) + +``` +Overview /guides says "Upgrading: moving from Prisma 7" is coming +v7 +Frameworks (Next.js, Hono, TanStack Start, NestJS, Astro, Nuxt, SvelteKit, Elysia, React Router 7, SolidStart) +Runtimes (Bun, Deno) +Deployment, Authentication, Integrations, Postgres +Database (Expand-and-contract migrations, Multiple databases, Schema management in teams) +Switch to Prisma ORM, Switch to Prisma Postgres +Upgrade Prisma ORM + PostgreSQL /guides/upgrade-prisma-orm/postgresql title: "Migrate from Prisma 7 to Prisma 8" + MongoDB /guides/upgrade-prisma-orm/mongodb v6 Mongo to 8 + v7, v6, v5, v4, v3, v1 older version-to-version guides +Making guides +``` + +### Where Prisma 7 readers are pointed today + +- Root page: one line, "Here for the ORM? Jump straight to Prisma 7 or Prisma 8". +- A "Using Prisma 7?" note box on `/orm`, `/prisma-orm`, both PostgreSQL getting-started pages, and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. +- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides, where the label is "PostgreSQL". diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md new file mode 100644 index 0000000000..b2bd7e7bcc --- /dev/null +++ b/docs/orm-docs-audit/journeys.md @@ -0,0 +1,147 @@ +# Jobs users come to the docs to do, and how the docs serve them today + +Each job has: who, where they land, what "done" looks like, the path through the current site, and a verdict. Paths were traced in the `prisma/web` source at `wip/web/apps/docs/content/docs/` and checked against the live site on 2026-09-10. Verdicts: **green** works, **amber** works with friction, **red** fails or is missing. + +## J1. Add Prisma 8 to an app I already started, with an empty database + +Who: Newcomer, sometimes Upgrader. The Bun user in Discord is this job. + +Done: models defined, tables created, one query returns rows, from inside the app they already have. + +Path today: + +- Search "prisma bun" lands on the Bun guide. It starts with `create-prisma`, so it scaffolds a new app instead of joining theirs. +- `/getting-started` offers "Add to an existing project", which goes to the existing-project PostgreSQL page. That page assumes the database already has tables: step 4 is `contract infer`. There is no branch for "empty database". +- The right three commands (`orm init`, `contract emit`, `db init`) exist only as a snippet on the CLI reference overview, under "Start in an existing project". +- Whichever page they use, the query example is wrong: the existing-project page uses `db.orm.User` (must be `db.orm.public.User` on Postgres) and `.take(2)` (removed in rc.7). +- `orm init` writes `src/prisma/db.ts`, but no getting-started page shows the file, so `import { db } from "./prisma/db"` is unexplained. +- The quickstart says scripts read `DATABASE_URL` from the environment, not `.env`; the existing-project page uses `.env` with `dotenv/config`. The two pages disagree and neither says why. +- The existing-project script calls both `db.connect()` and `db.runtime()`. The difference is explained only deep in the transactions-and-runtime reference. +- Skill files land in the repo with no mention of how to stop that. + +Verdict: **red**. No page is written for this job, and the nearest page has two copy-paste errors. + +## J2. Bring an existing database with data under Prisma 8, then make the next schema change + +Who: Upgrader mostly, some Newcomers with a legacy database. + +Done: contract matches the database, database is signed, first query works, and `migration plan` for the next change produces one small migration rather than a full recreate. + +Path today: the existing-project PostgreSQL page, steps 2 to 9. + +- Steps 2 to 7 are in the right order: init, connection, infer, review, emit, sign, query. +- Step 4 says "review the inferred contract" but not what to expect. Users hit `@db.*` attributes (removed in 0.17), non-`public` schemas, and a `Decimal` default that fails to emit, with no guidance. +- Step 6 signs the database but never explains what a signature is or what to do if `db sign` exits 4. +- Step 9 says "use `db update` or `migration plan`". It never mentions the `db` ref. `db sign` does not set the ref (only `db init`, `db update`, and `db migrate --advance-ref` do). With no migrations on disk and no ref, `migration plan` silently plans from an empty database and proposes recreating every table. This is the `--from` confusion reported twice in Discord. +- The upgrade guide gets this right (baseline migration, sign, `migration ref set db`, then `--advance-ref db` on each migrate), but J2 users on the existing-project page never see it. + +Verdict: **red**. The page stops one step short and the missing step produces a destructive-looking plan. + +## J3. Rewrite Prisma 7 queries in Prisma 8 + +Who: Upgrader. + +Done: for every Prisma 7 call in their code, they know the Prisma 8 call or that it does not exist. + +Path today: + +- No single mapping page. Sixteen inline "For Prisma 7 users" diff blocks are spread across reading-data, writing-data, transactions-and-runtime, pipeline-builder, data-modeling, and eight places in the ORM reference. +- Pagination is taught as `.take()`/`.skip()` on eight pages (29 sites). Those were renamed to `.limit()`/`.offset()` in rc.7 and the old names removed. +- The bulk count mutations are taught as `createCount`/`updateCount`/`deleteCount` (31 sites on two pages). They were renamed to `createAndCount` and friends in 0.17. +- `createMany` appears on no Prisma 8 page. `createAll` and `createAndCount` are documented but nothing says they replace it. `skipDuplicates` has no equivalent and no page says so. +- `findUniqueOrThrow`, `findFirstOrThrow`, atomic `increment`/`decrement`, and case-insensitive filters have no Prisma 8 equivalent in the SQL ORM client source. No page says so. +- `$transaction([...])` is covered in one inline block. `Prisma.UserGetPayload` and the model types have no page at all; the replacements are in open PRs. +- Accessor casing (`prisma.user` became `db.orm.public.User`) is stated once in reading-data and nowhere else. + +Verdict: **red**. The answers that exist are scattered, two of them are wrong, and the missing features are not admitted. + +## J4. Decide whether to move to Prisma 8 now + +Who: Upgrader, also a Newcomer choosing an ORM. + +Done: they know Prisma 8 is a release candidate, when GA is expected, how long 7 is supported, what `npx prisma` now installs, and how to pin 7. + +Path today: the root page says "Prisma 7 remains fully supported" and shows `npx prisma@7.10.0 init`. Nothing on the site says Prisma 8 is an RC, gives a GA window, states the 12-month support commitment for 7, or explains the npm `latest` tag. Five people asked this in Discord in one week. + +Verdict: **red**, and the cheapest fix on the list. + +## J5. Migrate a whole Prisma 7 app incrementally + +Who: Upgrader with a team and a production database. + +Done: both versions run side by side, routes move one at a time, migrations hand over, Prisma 7 is removed. + +Path today: `guides/upgrade-prisma-orm/postgresql` covers all five phases and is the best page on the site for the Upgrader. Getting there is the problem: the root page, `/getting-started`, and the ORM overview never link to it. The guides index lists "Upgrading: moving from Prisma 7" under "Coming as they land". In the sidebar it sits under "Upgrade Prisma ORM" as "PostgreSQL", with no "7 to 8" in the label. It is also pinned to rc.6 and rc.4 and says so in a callout. + +Verdict: content **amber**, discoverability **red**. + +## J6. Model my data, especially types Prisma 7 handled with `@db.*` + +Who: Newcomer and Upgrader. + +Done: they can write `Text`, `VarChar(100)`, `Uuid`, `Decimal`, enums, relations, and know which Prisma 7 attributes are gone. + +Path today: + +- The data-modeling overview has a scalar table (`String` is `Text`) and a money-in-cents recommendation. Good. +- The PSL syntax page shows `Uuid = String @db.Uuid` in its opening example and again at line 177. That syntax was removed in 0.17. Copying it fails emission. +- No page maps Prisma 7 attributes (`@db.Text`, `@db.VarChar(n)`, `@db.Decimal(p,s)`) to Prisma 8 types. +- `Decimal` defaults and money beyond "use cents" are not covered. One user asked and got no answer. +- Implicit many-to-many is honestly marked unsupported. Good. + +Verdict: **amber**, with one stale example that must go. + +## J7. Set up my editor + +Who: Newcomer and Upgrader. + +Done: syntax highlighting and formatting work for `contract.prisma`. + +Path today: no page. The facts (extension is on open-vsx not the Microsoft marketplace, no bundled language server, needs the CLI installed locally, file needs `// use prisma-next` on line one) were given by Serhii in a Discord thread. The `// use prisma-next` line appears in examples but is never explained. + +Verdict: **red**, missing. + +## J8. Use advanced Postgres features + +Who: Newcomer and Upgrader on real projects. RLS, policies, expression and functional indexes, extensions such as pg_trgm. + +Done: they know whether the contract can express it, and how, or that they must manage it outside Prisma. + +Path today: nothing under `orm/`. RLS is covered only through the Supabase extension in the shipped skill. One user's agent invented a contract-builder API because there was nothing to read. + +Verdict: **red**, missing. Needs a product answer before a docs answer. + +## J9. Name a model or result type for reuse + +Who: Newcomer and Upgrader. + +Done: `type User = ...` and the type of a query result, without reading `contract.d.ts`. + +Path today: no page. `ResultType` for SQL builder plans is the only documented helper. The `Models` namespace, `Shape<>`, and where-type exports are in open PRs. + +Verdict: **red** until the PRs ship, then a page is needed on release day. + +## J10. Stop Prisma from writing agent files into my repo + +Who: Newcomer and Upgrader, five people in one week. + +Done: one config line, and they know it. + +Path today: `skills: { agents: [] }` is documented on the CLI configuration page and `init --skills=none` on the init page. Neither is linked from create-prisma, the quickstarts, or the existing-project page. The advice circulating in Discord (`skills sync --disable`, an env var) is wrong. `create-prisma` has no flag. + +Verdict: **amber** for docs, **red** for the tool. + +## Summary + +| Job | Verdict | Cheapest fix | +| --- | --- | --- | +| J1 existing app, empty DB | red | new page | +| J2 existing DB, next migration | red | add baseline and ref steps | +| J3 Prisma 7 query mapping | red | one mapping page plus rename fixes | +| J4 should I move now | red | one short page, linked from root | +| J5 incremental upgrade | amber / red | links and a nav label | +| J6 data types | amber | remove `@db.` example, add attribute map | +| J7 editor | red | new page | +| J8 advanced Postgres | red | product decision first | +| J9 types | red | page on PR merge | +| J10 agent files | amber | one line on three pages | diff --git a/docs/orm-docs-audit/mental-model.md b/docs/orm-docs-audit/mental-model.md new file mode 100644 index 0000000000..8f70f0eeaf --- /dev/null +++ b/docs/orm-docs-audit/mental-model.md @@ -0,0 +1,112 @@ +# The Prisma 8 mental model, from first principles + +This is the source we write docs pages from. It explains why Prisma 8 has the pieces it has, in the order a person meets them. Everything here was checked against the monorepo glossary, the architecture overview, and the rc.9 release notes. + +## The one idea + +Your application and your database each have an opinion about what the data looks like. In Prisma 7 the schema file was the only written-down version, and the generated client trusted that the database matched it. Prisma 8 makes the agreement explicit and checkable from both sides. Everything else follows from that. + +## Two things, not one: the contract and the schema + +The **contract** is what you write. It is your description of the models, fields, relations, and how they map to tables. It lives in your repository, in `contract.prisma` or in TypeScript. + +The **schema** is what the database actually has right now: the tables, columns, and indexes. + +Prisma 7 called your file the schema. Prisma 8 reserves that word for the database side, because the whole point is that the two can disagree. When a command or error says "schema", it means the database. + +Every Prisma 8 operation is a relationship between these two: queries are typed against the contract, migrations move the schema toward the contract, and verification checks that the schema still satisfies the contract. + +## Emit: the build step that replaces `prisma generate` + +Prisma 7 generated a client package from your schema. Prisma 8 emits two plain files from your contract: + +- `contract.json`, a canonical description of the models, storage layout, and the database features it needs. +- `contract.d.ts`, the TypeScript types derived from it. + +The command is `prisma contract emit`. It is deterministic, so the same source always produces byte-identical output, and you commit both files. Think of the pair as `package.json` and its lockfile: the source is what you asked for, the artifacts are the resolved result. + +Why a build step at all: every other tool reads the artifacts, not your source. The query APIs read the types. The migration planner diffs two `contract.json` files. The runtime compares `contract.json` with the database. That is why "emit first" comes before almost every other command, and why forgetting it produces stale types or an empty migration plan. + +## The signature: how the database says which contract it satisfies + +Because emit is deterministic, hashing `contract.json` gives a short identifier for that exact contract, the way a commit hash identifies an exact state of your code. + +The database stores a small marker record, the **signature**, naming the contract hash it currently satisfies. Three commands write it: + +- `db init` creates the tables for the contract in an empty database and signs it. +- `db sign` checks that an existing database already matches the emitted contract and, if so, signs it. This is how you adopt a database you did not create with Prisma 8. +- `db migrate` applies a migration and updates the signature to the migration's target hash. + +`db verify` reads it and reports **drift**: any disagreement between contract and schema. + +Why this exists: a deploy against an unmigrated database, or a migration run against the wrong database, is caught before any query runs, because the runtime and the migration runner both check the signature first. In Prisma 7 the same mistake produced wrong results or a failed query later. + +## Queries: every query becomes a plan + +All query APIs are typed against `contract.d.ts`. Each query compiles to a **plan**, a plain data object holding the statement, its parameters, and metadata about what it touches. Running the plan is a separate step. + +Why: one pipeline. The ORM client, the SQL builder, and raw SQL all reach the database as plans, so middleware, telemetry, budgets, and authorization see every query in the same shape. A plan is data, so it can be inspected before anything touches the database. + +The three query surfaces on Postgres, from highest to lowest: + +1. The **ORM client**: `db.orm.public.User.where({ ... }).all()`. Model-based, coordinates several statements for `.include()`, hands back one typed result. Start here. +2. The **SQL builder**: `db.sql.public.user.select(...).where(...).build()`. Composable joins, grouping, and projections. One plan is exactly one statement. +3. **Raw fragments** spliced into builder queries when the builder cannot express it. + +Why `db.orm.public.User` and not `prisma.user`: Postgres tables live in schemas, and Prisma 8 addresses models through the schema namespace so a contract can span more than one. `public` is the default schema. Aliasing by assignment (`const User = db.orm.public.User`) is fine. On MongoDB the key is the collection's storage name (`db.orm.users`) and there is no SQL builder. + +## Migrations: edges between contract hashes + +A migration is a step from one contract hash to another. Together they form a graph, not a timestamped list. Every migration records the hash it starts from and the hash it produces. + +`migration plan` diffs two contracts and writes a migration package. The target is always your emitted contract. The origin is, in order: `--from` if you pass it, otherwise the `db` ref, otherwise an empty database. + +The `db` **ref** is a named pointer to a contract hash, kept in the repo, meaning "the state I consider the database to be at". `db init`, `db update`, and `db migrate --advance-ref db` move it. `db sign` does not. + +Why this matters more than it seems: a project with no `db` ref plans every migration from empty, which proposes recreating every table. This is the trap for anyone who adopts an existing database with `db sign` and then runs `migration plan`. The fix is a baseline migration plus `migration ref set db ` once, then `--advance-ref db` on each migrate. The incremental upgrade guide does this; the existing-project page does not. + +Why a graph and not a list: two branches can each add a migration, and the graph resolves the merge by hashes instead of by timestamp order. Partial failures are safe to retry because each edge has a verifiable precondition. + +`db update` is the development shortcut: diff the contract against the live database and apply the difference directly, no migration package, ref advanced for you. Use it while iterating; use `migration plan` plus `db migrate` when you want the change checked in. + +## The command vocabulary in one table + +| Command | Reads | Writes | When | +| --- | --- | --- | --- | +| `contract emit` | contract source | `contract.json`, `contract.d.ts` | after every contract change, before anything else | +| `db init` | emitted contract | tables, signature, `db` ref | empty database, first time | +| `db sign` | emitted contract, live schema | signature | adopting a database that already matches | +| `db verify` | emitted contract, live schema | nothing | check for drift | +| `db update` | emitted contract, live schema | schema diff, signature, `db` ref | development iteration | +| `migration plan` | origin contract, emitted contract | a migration package | change you want checked in | +| `db migrate` | migration packages, signature | schema, signature, `db` ref with `--advance-ref` | apply checked-in migrations | +| `migration ref set` | a hash | the ref | after a baseline, or to repoint | +| `contract infer` | live schema | a draft contract source | first contract for an existing database | + +## What moved from Prisma 7, and why + +| Prisma 7 | Prisma 8 | Why | +| --- | --- | --- | +| `schema.prisma` | `contract.prisma` | the file describes an agreement, not the database | +| `prisma generate` | `prisma contract emit` | data artifacts instead of a generated client | +| `prisma migrate dev` | `db update` (dev) or `migration plan` + `db migrate` | plans are explicit and reviewable | +| `prisma db push` | `db update` | same job, now also signs | +| `prisma db pull` | `contract infer` | produces a contract draft | +| `new PrismaClient()` | `postgres({ contractJson, url })` in `db.ts` | the client is built from the contract at runtime | +| `prisma.user.findMany({ where })` | `db.orm.public.User.where(...).all()` | chainable, namespace-qualified | +| `findUnique` / `findFirst` | `.first()` | one terminal for one row | +| `{ data: { ... } }` | the fields directly | no wrapper | +| `take` / `skip` | `.limit()` / `.offset()` | renamed in rc.7 | +| `createMany` | `createAll` (rows back) or `createAndCount` (count back) | the return shape is in the name | +| `$transaction([...])` | `db.transaction(async tx => ...)` | callback form only | +| `@db.Text`, `@db.VarChar(n)` | `Text`, `VarChar(n)` in type position | native types are types, not attributes | +| `Prisma.UserGetPayload<...>` | `Shape<...>` (in an open PR) | not shipped yet | +| `skipDuplicates`, `increment`, `findUniqueOrThrow`, `mode: "insensitive"` | no equivalent yet | say so plainly | + +## The eight words + +**Contract**: what you write. **Schema**: what the database has. **Emit**: build the contract into artifacts. **Hash**: the identifier of one exact contract. **Signature**: the database's record of which hash it satisfies. **Drift**: the two disagree. **Plan**: a compiled query or migration, as data. **Ref**: a named pointer to a hash, used as the migration origin. + +## What the model costs, honestly + +Two extra concepts before the first query: the emit step and the signature. Prisma 7 had neither. The docs must pay that cost back on the same page by showing what it buys: a deploy that refuses to run against the wrong database, a migration plan you can read before it runs, and a query you can inspect before it executes. If a page introduces the concept without the payoff, cut the concept from that page. diff --git a/docs/orm-docs-audit/naming.md b/docs/orm-docs-audit/naming.md new file mode 100644 index 0000000000..7e9752c14f --- /dev/null +++ b/docs/orm-docs-audit/naming.md @@ -0,0 +1,37 @@ +# Naming: the product is "Prisma ORM" + +## The rule + +"Prisma ORM" names the product. A version number appears only when two versions are being told apart. So: + +- "Add Prisma ORM to an existing project", not "Add Prisma 8 to an existing project". +- "Prisma ORM emits the contract", not "Prisma 8 emits the contract". +- "Coming from Prisma ORM 7" and "Migrate from Prisma ORM 7 to 8" keep the numbers, because the contrast is the point. +- The release status page says "Prisma ORM 8 is a release candidate; Prisma ORM 7 is supported until ...". +- The Prisma 7 docs trees (`orm/v7`, `(index)/v7`, `guides/v7`, `cli/v7`) keep their version label in the nav, because that is what they are. + +"Prisma 8" as a bare product name reads as a different product from "Prisma ORM", which is the Upgrader's fear stated back to them. It also collides with the platform, where "Prisma" alone means the whole stack. + +## How to do it + +Not a global replace. Each of the 109 files needs a read, because "Prisma 8" in a contrast sentence becomes "Prisma ORM 8" and elsewhere becomes "Prisma ORM". Do it per page as each page is touched by the restructure and the content fixes, and sweep the remainder at the end. The 96 titles are the visible part and should go first, since they are the sidebar and the browser tab. + +## What stays as is + +- Identifiers: `prisma-next.md`, `// use prisma-next`, `@prisma/orm-postgres`, `/studio/prisma-next`, package names, error codes. 40 occurrences of `prisma-next` as an identifier; none as prose ("Prisma Next" appears zero times on the site). +- The "Prisma 7" group at the bottom of Getting Started and the v7 doc trees. +- Release notes and changelogs, which name versions by nature. + +## Scope on the site today + +Outside the v6 and v7 trees: + +| Term | Occurrences | Files | +| --- | --- | --- | +| "Prisma 8" | 691 | 109 | +| "Prisma 7" | 198 | 33 | +| "Prisma ORM" | 2816 | 95 | + +By area: `orm/` 225, `guides/` 196, `(index)/` 135, `cli/` 81. 96 page titles or meta titles contain "Prisma 8". No sidebar label does; the labels come from titles. + +The most common sentence shapes ("Add Prisma 8 to an ...", "Prisma 8 is the ...", "Prisma 8 app with ...", "Prisma 8 skills for ...") all take "Prisma ORM" as a drop-in replacement. The ones that do not are the contrast sentences, which should keep the number and add "ORM". diff --git a/docs/orm-docs-audit/personas.md b/docs/orm-docs-audit/personas.md new file mode 100644 index 0000000000..7a95be649f --- /dev/null +++ b/docs/orm-docs-audit/personas.md @@ -0,0 +1,33 @@ +# Who reads the Prisma 8 docs + +Four readers arrive at the docs. The first two produce almost all the complaints. The docs outside `orm/` are built for the third. The fourth never complains. + +## The Newcomer + +Has never used Prisma. Has an app, or is about to start one, and wants typed queries against a database. Arrives from npm, a search result, or a framework tutorial. Often already ran `bun init` or `npm create next-app` before looking for an ORM, so scaffolding tools that create the app for them are the wrong shape. + +What they need on the first visit: install, define models, connect, run one query, in one sitting. They will accept one new idea (the contract) if it pays off on the same page. They will not read a philosophy page first. + +How they judge the docs: can I copy the example and does it run. + +## The Upgrader + +Has used Prisma 5, 6, or 7. Has a running app, a database with data in it, and a migration history. Arrived because `npx prisma` installed Prisma 8 without them choosing it, or because they saw the announcement. Most of the Discord complaints are from this reader. + +What they need: first, a straight answer on whether to move now and how to stay on 7 if not. Second, the Prisma 8 name for every Prisma 7 thing they know, or a plain statement that it does not exist yet. Third, the exact sequence to bring an existing database under Prisma 8 control and make the next migration work. + +How they judge the docs: against the mental model they already have. Every page that explains contracts before answering "where did `findMany` go" costs trust. + +## The Builder + +Wants to ship a product on the Prisma platform: Composer, Compute, Postgres, Storage. May be technical, may lean on a coding agent. The ORM is one component. Happy to have tools scaffold the app and happy to hand a prompt to an agent. + +The docs root, the framework guides, the agent prompts, and the full-stack tutorial serve this reader well. They are not the problem, but their content occupies the entry points the Newcomer and the Upgrader land on. + +## The Agent + +Reads the shipped skill, `llms.txt`, and the `.md` version of any page. Never complains. The skill is out of scope for this audit except where the human pages feed into it. + +## What this means for the audit + +The ORM entry points must serve the Newcomer and the Upgrader before the Builder. Today the order is reversed: the root page is the Builder's, the ORM landing opens with an Agent prompt, and the Upgrader gets a two-line note saying Prisma 7 still exists. diff --git a/docs/orm-docs-audit/slice-corrections.md b/docs/orm-docs-audit/slice-corrections.md new file mode 100644 index 0000000000..e7d5d50e5a --- /dev/null +++ b/docs/orm-docs-audit/slice-corrections.md @@ -0,0 +1,83 @@ +# Slice 1: corrections to published pages + +Scope: fix what is wrong on pages that exist today, without moving, adding, or removing pages. Everything in `changes.md` section B, plus A4 (two label edits). Sections A, C, D are out of scope and come after the IA discussion. Each fix cites the rc.9 source line it was verified against; the audit files under `audit/` hold the line lists. + +## Proposed batches + +Three PRs to `prisma/web`, in this order. Each is reviewable on its own and does not depend on the others. + +### PR 1: mechanical renames (about 350 lines, 20 pages) + +Search-and-replace with a known correct form. Low judgement, high volume. Reviewer checks the diff is uniform. + +| Item | What changes | Pages | +|---|---|---| +| B11 | `execute(plan)` to `query(plan)` for row reads; Mongo `db.execute(plan)` to `(await db.runtime()).query(plan)`; `ps.execute` to `ps.query`; drop `executePrepared`. Writes with no returned rows stay on `execute`. | 14 | +| B1 | `.take()`/`.skip()` to `.limit()`/`.offset()`; keep Mongo pipeline `skip` stages | 8 | +| B2 | `createCount` and siblings to `createAndCount` and siblings, including headings | 2 | +| B12 | drop the `sha256:` prefix on every hash | 9 | +| B13 | `extensionPacks` to `extensions` | 2 | +| B14 | migration directory listing and `migration.ts` imports to the `migrations/snapshots//` layout | 3 | +| B4 | remove `@db.Uuid`; re-point the named-types example at a real alias | 1 | +| B21 | stale flags, codes, command names, and printed output (`--skip-skills`, `CLI.INIT_SKILL_INSTALL_FAILED`, bare `ref set`, `prisma-cli` hints, `PN-RUN-3000`, `from: null`, the "Applied 1 migration(s)" line, `cd prisma`, top-level `migrate`, hyphenated slugs, `--db` shown as required) | 10 | +| B23 | `db.runtime().close()` to `db.close()` | 4 | +| B26 | enum ordering note updated for rc.9 | 1 | + +### PR 2: page rewrites (about 12 pages) + +Sentences change, not just names. Each page gets one commit so the reviewer can read it as prose. + +| Item | Page | What changes | +|---|---|---| +| B15 + B3 + B10 | both `add-to-existing-project` pages | default path is `src/prisma/`; `orm init` writes no skills; `.env` is a prompt; show `db.ts` once; one `DATABASE_URL` story; Temporal polyfill note; `--write-env` / `--schema-path`; `db.orm.public.User` | +| B16 | six `orm/migrations/*`, `cli/migration-plan`, `cli/db-init`, `cli/db-update`, `cli/migration-ref`, `cli/index`, upgrade guide | `migration plan` refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN`; `db init` / `db update` advance the ref only without `--db`; `NO_TARGET` belongs to `migration new`; the automatic baseline and `--from @empty` | +| B17 | five `orm/middleware/*` | two lifecycles, no `intercept`; rewrite the logger example on `afterQuery`; fix lint keys, budgets latency, cache hooks; drop "permissive mode" on Postgres | +| B18 | `orm/reference/raw-queries`, `advanced-queries` | whole-query raw SQL exists; `db.raw.sql`; drop the "unversioned ids" callout | +| B19 | `relations-and-joins`, `data-modeling/relational-databases` | 1:1 back side, N:M include and nested writes, referential actions, `.variant()` all work; stop sending readers to the SQL builder | +| B20 | `sql-query-builder`, `advanced-queries`, `orm-client` | aggregates return numbers; the `BigInt` / `Decimal` variants; `min` / `max` typing | +| B22 | `editing-a-migration` | add `rawCodecInferer` so the data-transform example typechecks | +| B24 | `writing-data` | upsert needs `conflictOn` | +| B27 | `transactions-and-runtime`, `pipeline-builder` | structured error codes, not plain `Error`; fix the `prepare` then `connect()` sample | +| B31 | `data-modeling/index` | scalar table: `Json` vs `Jsonb`, add `Decimal`, `Bytes` | +| B35 | `using-extensions` | the recipe does not fit Supabase; catalog links lead to `@internal` install commands | + +### PR 3: start pages and guides, small facts (about 20 pages) + +One-line or one-paragraph facts on the getting-started pages and guides. + +| Item | What changes | +|---|---| +| B5 | SQLite ships; `orm/index` and `sql-query-builder` | +| B6 | upgrade guides: version pins, `Database signed` output, the CREATE TABLE symptom that no longer appears | +| B8 | one Node floor, stated once (needs decision 2) | +| B9 | explain `// use prisma-next` where the contract is introduced | +| B28 | `create-prisma` page: `minimal` template, no `.env` for Postgres, `--force`, deploy defaults, Deno flag, script list | +| B29 | MongoDB pages: replica set is not required | +| B30 | Bun guide build and dev scripts; NestJS `@Inject` note; TypeScript authoring paths; Deno page staleness | +| B32 + A4 | guides index and the upgrade guide's sidebar label | +| B33 | `ai/tools/skills` page: one skill, no `--skip-skills`, `orm init` does not install | +| B34 | full-stack tutorial: `TimestamptzString`, no `postinstall` | +| B7 | the agent-files line on four pages (needs decision 1) | +| B25 | streaming claim on `reading-data` (needs decision 3) | + +## What this slice does not do + +- It does not touch the sixteen Prisma 7 guides under Prisma ORM 8 paths (A7). They are wrong for a Prisma ORM 8 reader, but fixing them means moving or rewriting whole pages, which is the IA discussion. If you want something now, the smallest honest change is a one-line banner at the top of each saying it is written for Prisma ORM 7; say so and I will add it to PR 3. +- It does not add missing content (C). Where a fix would leave a hole (for example B18 removes "raw SQL does not exist" but the page still needs a section on what does), the fix states the fact in one paragraph and stops. +- It does not touch the skill (D14) or the monorepo docs (D17). +- It does not rename "Prisma 8" to "Prisma ORM" (naming.md). That is a site-wide pass and cleaner as its own PR after this slice; mixing it in would bury the corrections in a 700-line diff. + +## Decisions before PR 3 + +Will answered on 2026-09-10: 1 and 4 as proposed; 2 and 3 checked as below. + +1. **B7, agent files.** Write the `skills: { agents: [] }` workaround now; replace it when the opt-out brief lands. +2. **B8, Node floor.** Checked by running rc.9 end to end (`contract emit`, `db init`, ORM create and read, `for await`, SQL builder) in a scratch project under Node 22.12.0, 22.18.0, and 22.22.3: all pass. Node release schedule (`nodejs/Release/schedule.json`): 22 "Jod" is Maintenance LTS until 2027-04-30; 23 reached end of life 2025-06-01; 24 "Krypton" is Active LTS, Maintenance from 2026-10-20, end of life 2028-04-30; 26 becomes LTS 2026-10-28. So Node 22 is supported and in LTS for another seven months, and 23 is dead. The scaffold's `engines` range `^22.18.0 || >=24.11.0` is what `create-prisma` enforces; the excluded 24.0 to 24.10 band is odd and worth asking the create-prisma owner about, but the site should not contradict what the scaffold refuses. Site wording: "Node.js 22.18 or newer; Node.js 24 recommended." The monorepo's `Supported Versions.md` says 24 and is wrong about what runs. +3. **B25, streaming.** What the page says: `for await` over `.all()` "streams" rows with a "steady, flat memory footprint" for millions of rows, you "start working on the first record before the last one has arrived", and on early exit "unprocessed records are never buffered". What the implementation does: `postgres()` creates its driver with `cursor: { disabled: true }` (`packages/3-extensions/postgres/src/runtime/postgres.ts:245`), and the driver's own comment calls that "buffered execution": the whole result set is fetched into memory before iteration starts; only decoding through the codecs happens per row as your loop pulls. Cursor batches (`batchSize`, default 100) exist in the driver and are only reachable through the serverless facade's `cursor` option. Measured on a 400,006-row table under Node 22.18: `for await` that breaks after the first row took 186 ms and grew the heap by 64 MB (every row was fetched), versus 824 ms for `await ...all()` (fetch plus decode of every row). So `for await` saves the decode work and the decoded array, not the fetch. The page's three claims about memory and arrival order are false on `postgres()`; the "read once" rule and the per-row hand-off are true. Fix for this slice: rewrite the section to say what actually happens (rows are fetched in full, decoded one at a time as you iterate, use `limit()` or the serverless facade with cursors for genuinely large results). Whether `postgres()` should expose `cursor` is D8 and is out of this slice. +4. **B16, the `--db` quirk.** Document the current behaviour as-is, with `--advance-ref db` shown in every example that passes `--db`. + +## How the work runs + +- One implementer per PR, working from the audit files and `changes.md`, in this worktree on a branch off `main`. Every changed code sample cites the source line in the commit message. Where a sample can be typechecked against `wip/prisma-src/examples/prisma-8-demo`, it is. +- I review each PR against the source before it goes to you. You do the prose pass. +- No push and no PR until you say so; the branches sit here until then. From cdd48e5fce24920247b6b9b4c5245c56a23e2ee5 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 14:38:33 +0200 Subject: [PATCH 02/28] docs: add the prisma-8 skill staleness brief to the audit Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/README.md | 2 +- docs/orm-docs-audit/brief-skill-staleness.md | 42 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docs/orm-docs-audit/brief-skill-staleness.md diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md index 792005a9d2..86d3af4ed9 100644 --- a/docs/orm-docs-audit/README.md +++ b/docs/orm-docs-audit/README.md @@ -11,7 +11,7 @@ Read in this order: 5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B, shipped), new pages (C), ORM changes (D). Leads with the suggested order. 6. `naming.md` — the "Prisma ORM" naming rule. 7. `slice-corrections.md` — how the shipped corrections were sliced, and the decisions taken. -8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md` — two ORM changes handed to other agents. +8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). 9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. Prose is a draft throughout; the structure and the cited facts are what has been verified. diff --git a/docs/orm-docs-audit/brief-skill-staleness.md b/docs/orm-docs-audit/brief-skill-staleness.md new file mode 100644 index 0000000000..a93628008e --- /dev/null +++ b/docs/orm-docs-audit/brief-skill-staleness.md @@ -0,0 +1,42 @@ +# Brief: bring the `prisma-8` agent skill up to rc.9 + +Written 2026-09-11 for an ORM-focused agent with no prior context. Repo: `prisma/orm` (the Prisma ORM 8 monorepo). The skill is `skills/prisma-8/`: `SKILL.md` plus `references/*.md` and `upgrading/`. It ships inside the `@prisma/orm-postgres`, `@prisma/orm-sqlite`, and `@prisma/orm-mongo` tarballs (each package's `files` includes `skills`, and `prepack` runs `sync-package-skills.ts`), and `prisma init` / `prisma skills sync` copy it into user repos for Claude Code, Cursor, Codex, and Windsurf. It is what coding agents read instead of the docs site, so every stale line below is an agent writing broken code into a user's project. + +## What we want + +Every claim, sample, import path, command, flag, and error code in `skills/prisma-8/references/*.md` true on the current release, verified against `packages/`, `docs/releases/`, and `examples/`, with the specific defects below fixed first. Do not rewrite the skill's structure or voice; fix facts. Where the skill deliberately uses `@internal/*` import paths, leave them: that is a known convention users read as `@prisma/orm-postgres/*`. + +## Verified defects, most damaging first + +Line numbers are from the rc.9 tag. "Source" is the file that proves the correct form. + +1. **Row reads through `execute()`.** `queries-postgres.md:255-300` (and 289, 302, 333, 355), `queries.md:144, 149`, `queries-mongo.md:12, 140, 164, 178` read rows with `db.runtime().execute(plan)` or `(await db.runtime()).execute(plan)`. Since rc.2, `execute()` resolves `{ affectedRows }` and rows come from `query()`, which returns an `AsyncIterableResult`. On Mongo, `execute()` on a find or aggregate throws `RUNTIME.MONGO_STATISTICS_UNSUPPORTED`. Only non-returning writes stay on `execute`. Source: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `packages/2-mongo-family/7-runtime/src/mongo-runtime.ts:98-100,282-289`, `docs/releases/v8.0.0-rc.2.md`, `examples/prisma-8-demo/src/queries/*.ts`, `examples/mongo-demo/test/query-builder-writes.test.ts`. +2. **`PN-*` error codes.** `debug.md:12, 78-110, 306-338`, `contract.md:28, 62-66`, `migrations.md:21, 67-75` route on `PN-CLI-4001…4020`, `PN-MIG-2001…2005`, `PN-RUN-3001…3030`, `PN-SCHEMA-0001`. No such string exists in `packages/`. Every published error is a dotted structured code since 0.17 (`MIGRATION.RUNNER_FAILED`, `CONTRACT.MARKER_MISSING`, `CONTRACT.MARKER_MISMATCH`, `MIGRATION.UNFILLED_PLACEHOLDER`, `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`, and so on). Source: `docs/releases/v0.17.0.md:27`, `docs/reference/error-reference.md`, `packages/1-framework/1-core/errors/src/`. +3. **Flat config file.** `contract.md:47, 164-170` shows `defineConfig({ contract, extensions })` from `@internal/postgres/config` as the whole `prisma.config.ts`. The envelope form `definePrismaConfig({ orm: ormConfig({ contract, db: { connection }, extensions }) })` replaced it in rc.4 and the flat fallback is gone. Source: `docs/releases/v8.0.0-rc.4.md`, `examples/prisma-8-demo/prisma.config.ts`. +4. **`orm init` facts.** `quickstart.md:73, 189, 201` says the default schema path is `prisma/contract.prisma` (it is `src/prisma/contract.prisma`, with `db.ts` beside it); `quickstart.md:196` documents `orm init --skip-skills` (removed in rc.6; `orm init` no longer touches skills at all). Source: `packages/1-framework/1-core/config/src/config-types.ts:45`, `packages/1-framework/3-tooling/cli/src/orm/init.ts:87-112`, `cli/src/commands/init/skill-sources.ts:1-5`, `docs/releases/v8.0.0-rc.6.md:29`. +5. **Many-to-many.** `queries.md:139-140` says N:M `.include()` and nested N:M mutations are unsupported and that `mutation-executor.ts` throws. Both work through the junction: `include('tags', …)`, nested `create` / `connect` / `disconnect`. The quoted throw string no longer exists. Source: `packages/3-extensions/sql-orm-client/src/mutation-executor.ts:836-926`, `collection-contract.ts:356-379`, `examples/prisma-8-demo/src/orm-client/get-post-tags.ts`, `create-post-with-tags.ts`. +6. **Destructive consent.** `migrations.md:33, 146, 470` says pass `-y` to auto-accept a destructive `db update`. `--yes` does not grant consent; the user types the database name or passes `--confirm `. Source: `cli/src/orm/db/update.ts:118-124, 218-224`, `cli/src/orm/db/consent.ts`. +7. **Migration factories as free functions.** `migrations.md:231-235, 254-270` renders `addColumn('public', 'user', {...})` and `setNotNull('public', 'user', 'name')`. They are methods on the `Migration` base class with object arguments: `this.addColumn({ schema, table, column: col(...) })`, `this.setNotNull({ schema, table, column })`. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:231, 364`, `examples/prisma-8-demo/migrations/app/20260810T1108_add_post_engagement_counters/migration.ts:17-21`. +8. **Transaction scope of `db migrate`.** `migrations.md:48` says each migration runs in its own `BEGIN … COMMIT`. The runner issues one `BEGIN`, applies every space's plan, then one `COMMIT` or `ROLLBACK`. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/runner.ts:176-215, 684-696`. +9. **Marker name.** `quickstart.md:125` calls the marker a `pn_meta_marker` row. It is `prisma_contract.marker`. Source: `runner.ts:321-326`. +10. **Middleware that does not exist, and one that does.** `runtime.md:11, 135-158, 315, 322` imports `createTelemetryMiddleware` from `@internal/middleware-telemetry`; no such package exists. `runtime.md` also says lints and budgets must come from `@internal/sql-runtime` because the facade has no middleware subpath; the public path is `@prisma/orm-postgres/family-runtime`. And it never mentions the cache middleware (`@prisma/orm-extension-middleware-cache`), which ships. Source: `packages/9-public/@prisma/orm-postgres/package.json` (`./family-runtime`), `packages/3-extensions/middleware-cache/`, `examples/prisma-8-demo/src/prisma/db.ts`. +11. **Dropped extension as the canonical example.** `contract.md:25, 29, 49` uses `cipherstash.EncryptedString(...)`. The in-tree cipherstash extension was dropped in favour of CipherStash's own package (`CHANGELOG.md:1040`). Use `pgvector.Vector(1536)` as the demo does. +12. **Mongo PSL attributes.** `contract.md:221` says `@@discriminator` / `@@base` are SQL-only and Mongo polymorphism needs the TypeScript builder. The Mongo PSL interpreter implements both and the Mongo demo uses them. Source: `packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts:276-418`, `examples/mongo-demo/src/contract.prisma`. +13. **Scalar lists.** `contract.md:123` says `String[]` is rejected by the SQL interpreter. Lists are gated on the `sql.scalarList` capability, which PostgreSQL declares; only SQLite rejects them. Source: `packages/2-sql/2-authoring/contract-psl/src/psl-field-resolution.ts:497-500`, `examples/prisma-8-demo/src/prisma/contract.json` (`"scalarList": true`). +14. **`.count()` as a collection terminal.** `queries-postgres.md:30` lists `.count()` beside `.all()` / `.first()`. There is no `count` method on the collection; `count()` exists as an `include` reducer and inside `aggregate()`. Source: `packages/3-extensions/sql-orm-client/src/collection.ts`. +15. **SQL-builder `insert` input.** `queries-postgres.md:258, 298-299` passes a single object; `insert()` takes an array of rows. Source: `packages/2-sql/4-lanes/sql-builder/src/types/table-proxy.ts:122-123`. +16. **Combinator import path.** `queries.md:141`, `queries-postgres.md:75, 86, 251` say `and` / `or` / `not` are internal-only. `@prisma/orm-postgres/orm-client` exports them. Source: `packages/9-public/@prisma/orm-postgres/package.json`, `test/facade-tarball.test.ts:58, 171`. +17. **Prepared statements.** `debug.md:127` says you cannot pre-prepare and re-execute a statement and points to TypedSQL (which `queries.md:144` says does not exist). `db.prepare(...)` and `runtime.prepare(...)` exist; a row-returning prepared statement runs with `ps.query(runtime, params)`. Source: `packages/2-sql/5-runtime/src/sql-runtime.ts:110, 549`, `packages/2-sql/5-runtime/src/prepared/types.ts:55-105`. +18. **Streaming.** `queries.md:146` says there is no streaming surface and recommends holding a `pg.Client`. The read terminals return an `AsyncIterableResult` you can `for await`; but on the long-lived `postgres()` facade the driver runs with cursors disabled, so the full result is fetched before iteration and only decoding is per row. The serverless facade (`@prisma/orm-postgres/serverless`) reads through a cursor in batches of 100. Say exactly that. Source: `packages/3-extensions/sql-orm-client/src/collection.ts:998-1022`, `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`, `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:39-53`, `postgres-serverless.ts:28-42`. +19. **`migration show` with no argument.** `migrations.md:189` runs it bare; the `` positional is required. Source: `cli/src/orm/migration/show.ts:3-6`. +20. **`--from` grammar.** `migration-model.md:67` lists `@contract | @db | @empty` for `migration plan --from`. The command is offline: only `@empty` resolves there (`@db` needs the live marker, `@contract` needs a contract hash the plan resolver does not pass). Source: `cli/src/control-api/operations/plan-resolution.ts:224-229`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:39-56`. +21. **Node.js floor for Temporal.** Wherever the skill says Temporal-backed types need a polyfill "on Node", say: Node.js 26.8.2 and later ship `globalThis.Temporal`; 26.8.1 and earlier, including every 22 and 24, do not, so `temporal-polyfill/full/global` must be imported before the first read or the column authored as a `*String` type. Checked empirically on 22.22.3, 24.16.0, 26.8.1, 26.8.2. + +Things the skill gets right that the site had wrong (keep them): `db.raw.sql` as the raw tag and whole-query raw SQL with `.returnsRow()` / `.affectedCount()` (`queries.md:143`, `queries-postgres.md:392, 415`); `extensions` not `extensionPacks` in `defineContract` (`contract.md:51, 386`); the five lint severity keys (`runtime.md`); `../../snapshots//contract.json` imports (`migrations.md:225, 253`); `db.close()` for teardown (`runtime.md:66-78`); the `prebuild` emit for Next.js (`build.md:466`). + +## Acceptance + +- Every item above is fixed, with the commit citing the source line used. +- A pass over the rest of `references/*.md` for the same classes of defect: any `execute(` on a row-returning plan, any `PN-` code, any flat `defineConfig`, any `@internal/middleware-telemetry`, any `--skip-skills`, any `prisma/contract.prisma` default. +- The skill's own journey tests (`skills/journey-tests/`) pass, and any sample that can be typechecked against `examples/prisma-8-demo` or `examples/mongo-demo` is. +- The `skills/prisma-8/upgrading/` instructions are not in scope unless they repeat one of the defects above. From f25edb93fad050eecd6eefce4060f75aa37f37cb Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 14:44:11 +0200 Subject: [PATCH 03/28] docs: rewrite the audit change list for readers without the audit context Status first, open work only in the recommended order, decisions with owners, the shipped corrections collapsed to a summary, new pages grouped by where they live, ORM changes grouped by owner, process residue removed. Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 268 +++++++++++++-------------------- 1 file changed, 106 insertions(+), 162 deletions(-) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index d19752fc69..ef0458832d 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -1,205 +1,149 @@ -# Proposed changes +# Prisma ORM 8 docs: what to change, and in what order -Four kinds of change: restructure the docs, improve existing pages, create new pages, change the ORM. Ordered work first, then the items by kind. Nothing here is started. +This is the working list of changes to the Prisma ORM 8 documentation, built from a page-by-page audit against `@prisma/orm-postgres@8.0.0-rc.9` (the audit files are under `audit/`, with a source citation for every finding). Four kinds of change: restructure the site, correct existing pages, write new pages, change the ORM or its tooling where the docs are hard because the tool is. -Sources: the first-session brief, plus the seven audit files under `audit/` (written 2026-09-10 against rc.9; every item cited below was spot-checked against `wip/prisma-src` unless marked "agent-reported"). Line numbers and full occurrence lists are in the audit files; this document names the defect and the pages. +Item numbers (A1, B11, C9, D4) are stable identifiers used in the audit files and the PRs; some are out of sequence because items were added as they were found. "J1" to "J10" are the reader jobs defined in `journeys.md`. Source paths are in `prisma/orm` at rc.9 unless they start with `create-prisma`. -## Suggested order +Status as of 2026-09-11. -1. B1 to B4 and B11 to B14 as the first `prisma/web` PR: the site-wide mechanical fixes (`execute` to `query`, `sha256:` prefixes, `extensionPacks`, pagination names, `AndCount` names, snapshot layout). Each is a search-and-replace with a known correct form and breaks every user who copies it today. -2. B15 to B22 as a second PR, page by page: the existing-project pages, the migrations pages, the middleware pages, the raw SQL page, the relations page. These need rewriting sentences, not just names. -3. A7 in the same week as item 2: move or hide the sixteen Prisma 7 guides that sit under Prisma ORM 8 paths. Until then the guides index sends Prisma ORM 8 readers to `prisma generate`. -4. A4 and C4. Two small edits and one short page fix J4 and J5's discoverability. -5. A1, A2, A3, C1, C2 as the restructure, written from `mental-model.md`. This is the work that answers the Discord thread. -6. D1, D2, D3, D6, D8, D9, D10, D14, D17 raised as product tickets now, because C3, C4, and the deployment pages depend on the answers. -7. C3, C5 to C20 as each dependency clears. C9 (deployment) and C10 (Supabase and RLS) are the two largest gaps the audit found and have no page at all today. +## Where things stand -## Naming, across everything +**Shipped.** Every correction to an existing page (section B, 35 items) went out in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist), #8237 (pages whose explanations were wrong), and #8238 (facts on the getting-started pages and guides). Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -The product is "Prisma ORM"; a version number appears only when two versions are being contrasted. Rule, counts, and exceptions are in `naming.md`. Applies to every item below and to the proposed nodes in `ia.md`. +**In progress.** A7 (moving the sixteen Prisma 7 guides out of the Latest tree) is with Ankur. D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. -## A. Restructure - -The current and proposed sidebar trees are in `ia.md`. The items below are the individual moves that tree implies. - -**A1. Give the ORM its own front door, organised by starting state.** Replace the current split (quickstart vs. add-to-existing) with four doors on `/prisma-orm` and `/orm`: new app from scratch, app I already started with an empty database, an existing database with data, and an existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. - -**A2. Put "Coming from Prisma 7" in the ORM sidebar at the top level and link it from the root page, `/getting-started`, `/orm`, and reading-data.** One page, with the mapping table from `mental-model.md` expanded. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. - -**A3. Human content first, agent prompts last, on every ORM page.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end of the page or into a collapsed block. Addresses the "written for AI" complaint directly. Unblocks the Newcomer and the Upgrader on every page. - -**A4. Fix the navigation labels that hide existing content.** The upgrade guide's sidebar label is "PostgreSQL" under "Upgrade Prisma ORM"; rename to "Prisma 7 to 8 (PostgreSQL)". The guides index says upgrading is "coming as they land"; remove that line. Files: `guides/upgrade-prisma-orm/meta.json`, `guides/index.mdx`. Unblocks J5. - -**A5. Root page: make the ORM line a section.** The root is the platform's page and should stay so, but the ORM needs more than "Here for the ORM? Jump to Prisma 7 or Prisma 8". Give it the four doors from A1 in one row. File: `(index)/index.mdx`. - -**A6. Absorb core-concepts into a narrative page written from `mental-model.md`.** The current page is a good glossary but reads as a list of terms. The mental model page answers "why" in the order a person meets each piece. Keep the glossary as a section at the end. File: `orm/core-concepts.mdx`. - -**A7. Get the Prisma 7 guides out of the Prisma ORM 8 tree.** Sixteen pages under the Prisma ORM 8 guides paths are Prisma 7 content end to end (`prisma@7.10.0`, `@prisma/client`, generator blocks, `prisma generate`, `migrate dev`, `db push`, `db seed`, `studio`): `guides/frameworks/react-router-7`, `guides/frameworks/solid-start`, all six of `guides/deployment/*`, `guides/integrations/github-actions`, `guides/integrations/ai-sdk`, all three of `guides/switch-to-prisma-orm/*`, all three of `guides/database/*`. None has a copy under `guides/v7/`. Move them to `guides/v7/` with the same slugs and redirect, then either write the Prisma ORM 8 replacement (C9, C11, C12) or leave the label off the Prisma ORM 8 sidebar until it exists. Evidence: `audit/gaps.md` Breaks copy-paste, `audit/start-guides.md` Misleading. Changes `ia.md`: the "Guides" tree for Prisma ORM 8 loses six labels until replacements land. - -**A8. One error reference, or two that link.** `cli/error-reference.mdx` says it lists every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code lives on `orm/reference/error-reference.mdx`, and the two pages do not link. The structured errors' `docsUrl` points at the ORM page. Either merge, or state the split on both pages and cross-link. Evidence: `audit/migrations-cli.md` Misleading. - -## B. Improve existing pages - -Copy-paste defects a user hits today, grouped by theme. B1 to B10 are from the first-session brief; B11 onward are from the audit. Full line lists are in the audit files named on each item. - -### Site-wide mechanical fixes - -**B1. `.take()`/`.skip()` to `.limit()`/`.offset()`.** 29 sites on 8 pages: `orm/fundamentals/reading-data.mdx` (8, including the meta description), `orm/reference/orm-client.mdx` (13, including two section headings), `orm/fundamentals/relations-and-joins.mdx`, `orm/reference/pipeline-builder.mdx` (3, check which are the Mongo pipeline `$skip` stage and keep those), `orm/middleware/authoring-custom-middleware.mdx`, `guides/runtimes/deno.mdx`, `(index)/full-stack-tutorial.mdx`, `(index)/prisma-orm/add-to-existing-project/postgresql.mdx`. - -**B2. `createCount`/`updateCount`/`deleteCount` to the `AndCount` names.** 31 sites on `orm/fundamentals/writing-data.mdx` and `orm/reference/orm-client.mdx`, including three section headings. - -**B3. Existing-project PostgreSQL page.** `db.orm.User` to `db.orm.public.User`; `db.sql.user` to `db.sql.public.user`; drop the `db.connect()` call or the `db.runtime()` call, not both; show `src/prisma/db.ts` once with one sentence on what it does; pick one story for `DATABASE_URL` (the page uses `.env` with `dotenv/config`, the quickstart says environment only) and say why. Then add the missing steps from J2: baseline migration and `migration ref set db` before the "next steps" section. See also B15, which found the page's default path is wrong. File: `(index)/prisma-orm/add-to-existing-project/postgresql.mdx`. - -**B4. Remove `@db.Uuid` from the PSL syntax page.** Lines 19 and 177 of `orm/contract-authoring/psl-syntax.mdx` show `Uuid = String @db.Uuid`. Removed in 0.17; `Uuid` is a built-in type name in type position and needs no alias, so the "Named types" example should alias a real type instead (for example `ShortName = VarChar(35)`). Check the rest of the page for other `@db.` forms. - -**B11. `execute()` to `query()` for every row-returning plan.** The largest defect the audit found. Since rc.2, `runtime.execute(plan)` returns `{ affectedRows }` and rows come from `runtime.query(plan)` (an `AsyncIterableResult`, awaitable to an array or iterated with `for await`). The MongoDB client's `db.execute(plan)` facade method was removed in the same release; rows come from `(await db.runtime()).query(plan)`. Prepared statements split the same way: `ps.query(runtime, params)` for rows, `execute` only for `.affectedCount()` plans. Roughly 200 lines on 14 pages: `orm/reference/sql-query-builder.mdx` (about 31), `orm/reference/pipeline-builder.mdx` (about 50), `orm/reference/raw-queries.mdx` (about 20), `orm/fundamentals/advanced-queries.mdx` (10), `orm/reference/transactions-and-runtime.mdx` (about 12, including `withTransaction`'s `tx` surface and `executePrepared`, which does not exist), `orm/core-concepts.mdx`, `orm/fundamentals/reading-data.mdx`, `orm/fundamentals/relations-and-joins.mdx`, `orm/extensions/using-extensions.mdx`, `orm/middleware/built-in-cache.mdx`, both `add-to-existing-project` pages, `guides/upgrade-prisma-orm/mongodb.mdx` (5). Non-returning writes such as `orm/fundamentals/transactions.mdx:60` are correct and stay on `execute`. The shipped skill has the same defect (D14). Evidence: `packages/2-sql/5-runtime/src/sql-runtime.ts:309-322`, `packages/3-extensions/mongo/src/runtime/mongo.ts:28-39`, `docs/releases/v8.0.0-rc.2.md`. Audit: `orm-client`, `builders`, `start-guides`. - -**B12. Bare hex hashes.** Every hash the site prints is `sha256:…`; since 0.17 hashes are bare hex and loaders and `migration ref set` reject the prefixed form. `orm/contract-authoring/the-contract-artifact.mdx` (5 sites, in JSON and in `StorageHashBase<"sha256:…">`), all six `orm/migrations/*` pages, `cli/migration-ref.mdx`. Evidence: `docs/releases/v0.17.0.md:45`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:14-24`. Audit: `contract`, `migrations-cli`. - -**B13. `extensionPacks` to `extensions`.** Renamed in 0.17 and the old key fails loudly. `orm/contract-authoring/typescript-schema-builder.mdx` (5 sites in `defineContract`; the PostgreSQL contract on that page does not build) and `orm/contract-authoring/the-contract-artifact.mdx` (2 sites as the `contract.json` top-level key). Evidence: `docs/releases/v0.17.0.md:73`, `packages/3-extensions/postgres/src/contract/define-contract.ts`. Audit: `contract`. - -**B14. Migration directory layout and imports.** The site shows `start-contract.json` / `end-contract.json` inside each migration directory and `migration.ts` importing `./end-contract`. Since 0.17 snapshots live once under `migrations/snapshots//contract.json` plus `contract.d.ts`, and `migration.ts` imports `../../snapshots//contract.json`. The directory holds `migration.ts`, `ops.json`, `migration.json`. Pages: `orm/migrations/how-migrations-work.mdx`, `generating-a-migration.mdx`, `editing-a-migration.mdx`. Evidence: `docs/releases/v0.17.0.md:47`, `examples/prisma-8-demo/migrations/app/*/migration.ts`. Audit: `migrations-cli`. - -### Page rewrites - -**B15. Existing-project pages: the default path is `src/prisma/`, not `prisma/`.** Both `add-to-existing-project` pages tell the reader to keep the default schema path `prisma/contract.prisma` and build every later command on it (`contract infer --output ./prisma/contract.prisma`, `import "./prisma/db"`). `orm init` defaults to `src/prisma/contract.prisma` and writes `db.ts` beside it, so a reader who accepts the default gets a file `prisma.config.ts` never reads and an import that does not resolve. Same pages also say `orm init` installs agent skills (it stopped in rc.6; it writes `prisma-next.md` only), omit the `.env` prompt (default No, so there may be no `.env` to "update"), and the MongoDB page's `runtime.execute(plan)` on an aggregate throws `RUNTIME.MONGO_STATISTICS_UNSUPPORTED`. Add the Temporal polyfill note (D10) and the `--write-env` / `--schema-path` flags. Evidence: `packages/1-framework/1-core/config/src/config-types.ts:45`, `packages/1-framework/3-tooling/cli/src/orm/init-inputs.ts:229-233`, `docs/releases/v8.0.0-rc.6.md:29`. Audit: `start-guides`. - -**B16. The `db` ref and plan-origin story on the migrations pages.** Three connected errors. (a) The pages say `migration plan` without `--from` or a `db` ref plans a full CREATE migration; since rc.8 it refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` when migrations exist on disk, and names the exits (`migration ref set db `, `--from `, `--from @empty`). The upgrade guide tells readers to look for the CREATE TABLE symptom that no longer appears. (b) `db init` and `db update` advance the `db` ref automatically only when `--db` is omitted; every example on the site passes `--db "$DATABASE_URL"`, which suppresses that unless `--advance-ref` is also given, so a reader following the site's loop hits (a) on the second plan. No page says this. (c) Retracted after PR 2: the audit said `MIGRATION.NO_TARGET` never comes from `migration plan`, but `plan-resolution.ts` calls `findLatestMigration`, which calls `findLeaf`, which throws it on a cyclic graph, and the monorepo's `gotchas.md:83-110` reproduces exactly the rollback case `rollbacks-and-recovery.mdx` describes. That page was right. Also `the-migration-graph.mdx` says there is no baseline mechanism; the planner writes an automatic baseline when the graph is empty and the `db` ref names a snapshot, and `--from @empty` is the supported retrofit. Pages: all six `orm/migrations/*`, `cli/migration-plan.mdx`, `cli/db-init.mdx`, `cli/db-update.mdx`, `cli/migration-ref.mdx`, `cli/index.mdx`, `guides/upgrade-prisma-orm/postgresql.mdx`. Evidence: `packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts:428-475`, `cli/src/control-api/operations/ref-advancement.ts:19-28`, `cli/src/control-api/operations/migration-plan.ts:369,505-545`. Audit: `migrations-cli`, `start-guides`. Ties to D1, D2, D9. - -**B17. Middleware pages: the hook model is wrong.** The pages document five hooks with `intercept` and `beforeExecute` for reads. Since rc.2 there are two lifecycles: `beforeQuery` / `interceptQuery` / `onRow` / `afterQuery` for row queries, and `beforeExecute` / `interceptExecute` / `afterExecute` for non-returning writes. There is no `intercept`, no compatibility alias, and `afterExecute` carries `stats.affectedRows`, not `rowCount`. The authoring guide's flagship query logger implements only `afterExecute` and reads `result.rowCount`, so it is a type error and would never log the SELECT the page shows it logging. Also: `unindexedPredicate` is not a lint severity key; `severities.latency` on budgets is read (page says it is not); "permissive mode" is unreachable from the Postgres client (D12); the cache runs on the query lifecycle. Pages: all five `orm/middleware/*`. Evidence: `packages/2-sql/5-runtime/src/middleware/sql-middleware.ts`, `packages/2-sql/5-runtime/src/middleware/lints.ts:13-23`, `budgets.ts:97-125`, `examples/prisma-8-demo/src/prisma/slow-query-warning.ts`. Audit: `builders`. - -**B18. Raw SQL page says the opposite of what ships.** `orm/reference/raw-queries.mdx` and `advanced-queries.mdx` say there is no way to run a standalone raw statement. Since rc.2 there is: `db.raw.sql\`…\`.returnsRow(spec).build()` for rows and `.affectedCount().build()` for writes; raw row queries compose as subqueries and CTEs. The page also calls `db.raw` as a template tag; it is a lane object and the tag is `db.raw.sql`. The "bare scalar interpolation is broken because the inferer emits unversioned ids" callout is contradicted by the adapter source, which emits versioned ids. Evidence: `packages/2-sql/4-lanes/sql-builder/src/types/raw-query.ts:117-170`, `packages/3-targets/6-adapters/postgres/src/core/adapter.ts:112-140`, `examples/prisma-8-demo/src/queries/raw-query-demo.ts`. Audit: `builders`, `orm-client`. - -**B19. Relations and data-modeling pages say things are unsupported that work.** (a) The 1:1 mirror field `profile Profile?` "is not supported yet": it is accepted (rejected only when the foreign key is not unique) and `include('profile')` type-checks as a to-one include. (b) Implicit many-to-many `include` "not supported yet": the ORM resolves `through` relations and the demo includes `Post.tags`; nested `create` / `connect` / `disconnect` through the junction also work, and `orm-client.mdx` already documents `disconnect` through the junction. (c) Referential actions "as it lands": `onDelete` / `onUpdate` with `Cascade` / `Restrict` / `SetNull` / `NoAction` are lowered today. (d) The discriminator "is not filled in automatically": `.variant('Bug').create()` injects it; the page never mentions `.variant()`. Both pages send users to the SQL builder for things the ORM does. Pages: `orm/fundamentals/relations-and-joins.mdx`, `orm/data-modeling/relational-databases.mdx`. Evidence: `packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts:78`, `packages/3-extensions/sql-orm-client/src/collection-contract.ts:356-379`, `mutation-executor.ts:836-926`, `collection.ts:406`, `psl-relation-resolution.ts:19-22`. Audit: `contract`, `orm-client`. - -**B20. Aggregates decode as numbers, not strings.** `sql-query-builder.mdx` and `advanced-queries.mdx` tell users `COUNT` / `SUM` / `AVG` come back as strings and to call `Number(...)`. Since rc.2 `count()`, integer `sum()`, and `avg()` return `number` (throwing `RUNTIME.DECODE_FAILED` outside the safe range), with `countBigInt()`, `sumBigInt()`, `avgDecimal()` beside them. The "fixed" function list on `sql-query-builder.mdx` omits these; `min` / `max` are not numeric-only. Correction after PR 2: the audit said the `DateTime` column (`pg/timestamptz@1`) is still excluded from `min`/`max`; no such codec exists at rc.9. `DateTime` maps to `pg/timestamptz-temporal@1`, which is in `MIN_MAX_PRESERVING_CODECS`, so `min('createdAt')` type-checks; the compile error the page should show is `sum`/`avg` over a timestamp column. Evidence: `packages/3-targets/3-targets/postgres/src/core/aggregates.ts:126-213`, `docs/releases/v8.0.0-rc.2.md:32-53`. Audit: `builders`, `orm-client`. - -**B21. Stale CLI names, flags, codes, and output.** One pass over `cli/*` and `orm/migrations/*`: `--skip-skills` and `CLI.INIT_SKILL_INSTALL_FAILED` on `orm-init.mdx` (removed rc.6; also cited on `(index)/index.mdx` and `getting-started.mdx`); `ref set` / `ref list` bare group (rc.5: `migration ref set`) and `ref set prod @db` (fails, `@db` is not accepted by the offline command); `prisma-cli migrate` hint text and the sentence explaining it (rc.5: hints print `prisma db migrate`); `(PN-RUN-3000)` (0.17: dotted codes, `MIGRATION.RUNNER_FAILED` and siblings); `from: null` (prints `from: (baseline)`); the "Applied 1 migration(s)…" summary line (no migration count); `git clone …/orm` then `cd prisma`; `npx prisma@latest migrate` on `create-prisma.mdx` (the command is `db migrate`); hyphenated `--name add-users-table` shown as the directory name (slugs become `add_users_table`); `contract infer` presents `--db` as required (falls back to config); `orm-init.mdx` says the scaffolded `db.ts` does not load `.env` (it starts with `import 'dotenv/config'`) and that `contract:emit` calls `prisma-cli`. Audit: `migrations-cli`, `start-guides`, `contract`. - -**B22. `editing-a-migration.mdx` data-transform example does not typecheck.** `sql({ context })` omits the required `rawCodecInferer`, so `node migration.ts` fails before writing `ops.json`. Evidence: `packages/2-sql/4-lanes/sql-builder/src/runtime/sql.ts:11-19`. Audit: `migrations-cli`. +**Not started.** The naming pass, the restructure (A1 to A3, A5, A6, A8), every new page (C), and the rest of D. -### Smaller fixes, one line each +## Recommended order for the open work -**B5. Supported databases.** `orm/index.mdx` says SQLite is planned. It ships as `@prisma/orm-sqlite`; `sql-query-builder.mdx` also says "PostgreSQL is supported today". Say Postgres, MongoDB, SQLite, and what is next. +1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (691 occurrences in 109 files). Mechanical, one PR, done after A7 lands so the two do not conflict. +2. **C4, release status page.** Half a page; unblocks J4 (the reader who got upgraded by accident). Needs the GA window and the Prisma ORM 7 support policy from Will. +3. **C2, add Prisma ORM to an app you already started.** The J1 page and the complaint that started this work. One page, written from `mental-model.md`. +4. **C1, coming from Prisma 7.** The mapping table and the "not yet" list. Unblocks J3. +5. **C9, deployment.** The largest hole: zero Prisma ORM 8 coverage for any host, and the six pages A7 removes had been standing in for it. +6. **The restructure** (A1, A2, A3, A5, A6) as one piece of work, after the pages above exist to be organised. +7. **Everything else in C** as its dependency in D clears. -**B6. Un-pin the upgrade guides.** The PostgreSQL guide says every command was validated on rc.6 and rc.4; the MongoDB guide says `0.16.0`. Re-run on rc.9 (the Mongo guide is also hit by the rc.7 pagination rename and the rc.9 attribute rejection) and either drop the version callout or keep it current per release. Also `Database signed (marker created)` is printed as `Database signed`. Files: `guides/upgrade-prisma-orm/postgresql.mdx`, `mongodb.mdx`. +## Decisions needed, and from whom -**B7. One line on agent files, on three pages.** On `create-prisma.mdx`, both quickstarts, and the existing-project page: "Prisma writes skill files for coding agents into your repo. To stop that, set `skills: { agents: [] }` in `prisma.config.ts`; see Configuration." Until D3 lands, that is the only correct answer. +| Item | Decision | Who | +|---|---|---| +| C4 | GA window to state publicly; Prisma ORM 7 support policy | Will | +| D6 | Keep the release candidate on npm `latest`, or move it to `next` until GA | Will, with whoever owns publishing | +| D4 | For each missing client API: build it, or document the workaround and say it is not planned | ORM product | +| D1 | Which of the two designs for one-step adoption | ORM (brief in `brief-db-ref-on-adoption.md`) | +| D3 | Flag name and prompt wording for the skills opt-out | create-prisma (brief in `brief-skills-opt-out.md`) | +| C18 | The version floors to publish: the monorepo's `docs/Supported Versions.md` says Node 24; the scaffold enforces 22.18 and rc.9 runs on 22.12 | ORM product | +| C5 | Current state of the VS Code extension and language server | Serhii | +| C7 | Whether RLS, expression indexes, and `@@control` are documented as supported or as preview | ORM product | -**B8. Node version.** The quickstart says 24 or newer; seven framework guides say "Node.js 24 or later"; the scaffold's `engines` says `^22.18.0 || >=24.11.0` and create-prisma refuses below 22.18; the upgrade guide says 22.18+. Node 24.0 to 24.10 does not work. Say the true floor once. - -**B9. Explain `// use prisma-next`.** It appears at the top of every PSL example and is never explained. One sentence where the contract file is first introduced, and on the editor page (C5). - -**B10. `db.runtime()` on Mongo.** Mongo needs `(await db.runtime())`, Postgres does not. Say so where `db.ts` is first shown, not only in the transactions reference. - -**B23. `db.close()`, not `db.runtime().close()`.** Four guides (Bun, Hono, Elysia, NestJS) tear down with `db.runtime().close()`; the client method is `db.close()` (idempotent, also `Symbol.asyncDispose`), and every other page uses it. Audit: `gaps`. - -**B24. Upsert needs `conflictOn`.** `writing-data.mdx:182-195` upserts without `conflictOn` and says the match is on `email`; without `conflictOn` the target is the primary key, so the sample inserts a duplicate or fails on the unique constraint. Audit: `orm-client`. - -**B25. Streaming claim.** `reading-data.mdx` promises a flat memory footprint for `for await` over millions of rows; the `postgres()` facade constructs its driver with `cursor: { disabled: true }`, so the whole result is buffered first. Either soften the page or fix the ORM (D8). Audit: `orm-client`. - -**B26. Enum ordering changed in rc.9.** `orm-client.mdx:478,513` say text-backed enums sort in declaration order; rc.9 sorts by stored value, only native enums keep database order. Audit: `orm-client`. - -**B27. Structured errors, not plain `Error`.** `transactions-and-runtime.mdx` shows closed / double-connect failures as plain `Error` strings; they are `DRIVER.NOT_CONNECTED` / `DRIVER.ALREADY_CONNECTED` envelopes, and the latter is raised by Postgres too. Its `db.prepare` then `db.connect()` sample throws `DRIVER.ALREADY_CONNECTED`. `pipeline-builder.mdx` calls the unknown-root error a plain `Error`; it is `ORM.MODEL_UNKNOWN`. Audit: `orm-client`, `builders`. - -**B28. create-prisma page details.** The `--template` list omits `minimal` (the default) on three pages; for PostgreSQL the scaffold writes no `.env` (page says "review `DATABASE_URL` in `.env`"); `--force` also overwrites the generated Prisma files and refuses on a non-empty `migrations/`; the deploy prompt defaults differ between interactive, `--yes`, and `--json`; the Deno command needs `--minimum-dependency-age=0`; the page lists four of the twelve generated scripts. Audit: `start-guides`, `gaps`. - -**B29. MongoDB replica set.** Both MongoDB start pages say Prisma 8 needs a replica set; nothing in the runtime or migration runner opens a session or transaction, and `orm init`'s `.env.example` says a standalone `mongod` works. Only the scaffold's connection string demands one. Audit: `start-guides`. +## A. Restructure -**B30. Framework guide details.** The Bun guide's `esbuild` build step fails (the scaffold builds with `tsdown`; edit `tsdown.config.ts` instead) and `bun run dev` is `tsx watch`, so "no build step" and the one-shot output are wrong; the NestJS `@Inject` workaround describes a defect the template fixed; seven guides say `db:init` applies `src/prisma/contract.prisma` without saying the TypeScript authoring path is `contract.ts` with output under `src/prisma/generated/`; the Deno page's "separate Deno CLI entry point" note is stale and its sample output omits fields. Audit: `gaps`. +The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These are the moves that tree implies. -**B31. `data-modeling/index.mdx` scalar table.** `Json` binds to native `json` since 0.17; `Jsonb` is the separate scalar (what `field.json()` and value objects use). The table never mentions `Jsonb`, `Decimal`, `Bytes`. Audit: `contract`. +- **A1. Give the ORM its own front door, organised by starting state.** Replace the quickstart-versus-existing-project split with four doors on `/prisma-orm` and `/orm`: new app from scratch; app already started with an empty database; existing database with data; existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. +- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. +- **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. +- **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. +- **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** In progress (Ankur). `guides/frameworks/react-router-7`, `solid-start`, all of `guides/deployment/*`, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` are Prisma 7 end to end and have no copy under `guides/v7/`. Move with the same slugs and redirects; the Latest sidebar loses those labels until C9, C11, and C12 replace them. +- **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. +- **A4** (sidebar labels and the guides index) shipped in #8238. -**B33. `ai/tools/skills.mdx` describes skills that do not exist.** It says `orm init --skip-skills` skips installation (no such flag; `orm init` does not touch skills since rc.6), lists `prisma-next-upgrade` and `prisma-8-extension-upgrade` as installable (retired; `prisma init` deletes those directories; only `prisma-8` ships, with upgrading as a branch inside it), says `orm init` pins the GitHub install (the skill ships inside the `@prisma/orm-*` tarball and `prisma skills sync` copies it), and leads with `npx skills add prisma/prisma/skills`, which the monorepo README calls a fallback nothing keeps current. Evidence: `skills/README.md`, `cli/src/commands/init/skill-sources.ts:1-49`. Audit: `extras`. +## B. Corrections to existing pages (shipped) -**B34. Full-stack tutorial.** The tutorial shows the scaffold's `User` model with `createdAt DateTime` and `updatedAt temporal.updatedAt()`; the rc.9 starter contract writes `TimestamptzString` and `temporal.updatedAtString()`, which store a different runtime type. It also says the scaffold added a `postinstall` hook for skills; create-prisma adds a `skills:sync` script and runs `prisma init --yes` once. Evidence: `cli/src/commands/init/templates/code-templates.ts:171-193`, `wip/create-prisma-src/src/tasks/install.ts:56`. Audit: `extras`. +Thirty-five items, all verified against rc.9 source and shipped in #8236, #8237, #8238. What they fixed, in order of how many readers they hit: -**B35. `using-extensions.mdx` recipe and links.** The generic five-step recipe (import `/control`, pass to `postgres({ extensions })`) does not work for Supabase, which is wired with `extensions: [supabasePack]` from `/pack` and a client built by `supabase()` from `/runtime`. Every catalog row links to a monorepo README whose install command is `pnpm add @internal/extension-`, a private name. Also `orm/data-modeling/index.mdx:159` lists `Json` without saying filtering is whole-value equality only (D17). Audit: `extras`. +| Theme | What was wrong | Items | +|---|---|---| +| Row reads through `execute()` | Since rc.2 `execute()` returns `{ affectedRows }`; rows come from `query()`. About 200 lines on 14 pages, plus Mongo's removed `db.execute`. | B11 | +| Renamed API | `take`/`skip` (rc.7), `createCount` and siblings (0.17), `extensionPacks` (0.17), `@db.*` attributes (0.17), `sha256:` hash prefixes (0.17), the migration snapshot layout (0.17) | B1, B2, B4, B12, B13, B14 | +| Existing-project pages | Wrong default path (`prisma/` vs `src/prisma/`), skills claim, `.env` prompt, Temporal polyfill, namespace-qualified accessors | B3, B15, B10 | +| The `db` ref | `migration plan` refuses (`MIGRATION.PLAN_ORIGIN_UNKNOWN`) instead of planning CREATE-everything; `db init`/`db update` advance the ref only without `--db`; the automatic baseline | B16 | +| Middleware | Five-hook model replaced by the two rc.2 lifecycles; the logger example never fired on reads; lint keys, budgets latency, "permissive mode" | B17 | +| Things called unsupported that work | Whole-query raw SQL, 1:1 back-relations, many-to-many include and nested writes, referential actions, `.variant()` | B18, B19 | +| Aggregates | Return numbers, not strings; the lossless variants | B20 | +| Stale CLI surface | `--skip-skills`, bare `ref` group, `prisma-cli` hints, `PN-RUN-*` codes, printed output, top-level `migrate` | B21 | +| Samples that failed | Data-transform wiring, upsert without `conflictOn`, `prepare` then `connect()`, structured error codes shown as plain `Error` | B22, B24, B27 | +| Getting-started facts | Node floor (22.18; on the 24 line 24.11; 24 recommended), MongoDB replica set not required, create-prisma flags and scripts, `npm create prisma@latest`, SQLite ships, upgrade-guide version targets, `// use prisma-next`, `db.close()`, enum ordering, the scalar table, the skills page, the tutorial's starter model, the extensions recipe, streaming does not stream on `postgres()` | B5 to B9, B23, B25, B26, B28 to B35 | -**B32. Guides index.** `guides/index.mdx` lists "Upgrading" and "Databases" under "Coming as they land" while the upgrade guide exists and is in the nav. Fold into A4. +Two audit claims were overruled by the source during implementation and the pages left as they were: `migration plan` can raise `MIGRATION.NO_TARGET` after a rollback cycle, and `min`/`max` over a `DateTime` column type-checks at rc.9. ## C. New pages -**C1. Coming from Prisma 7.** The mapping table from `mental-model.md`, in four sections: schema and types, CLI commands, client API, and "not in Prisma 8 yet" with a status per item. The last section is the one users asked for most and the one no page has: `skipDuplicates`, `increment`/`decrement`, `findUniqueOrThrow`, case-insensitive filters, `$transaction` arrays, model and payload types (with a link to the PRs), `@updatedAt` (rejected with a hint to use `temporal.updatedAt()`), `cuid()` (rejected; use `cuid(2)`). Unblocks J3. Depends on A2 for placement. - -**C2. Add Prisma ORM to an app you already started.** The J1 page. Starts from "you have a project directory and an empty or absent database". `orm init`, edit the contract, `contract emit`, `db init`, one query, with `db.ts` shown. Bun as the worked example, since it is the case reported, with a note for Node. Replaces the Bun guide's scaffold-first opening or sits beside it. - -**C3. Adopt an existing database.** The J2 page, split out from the current existing-project page so B3 and B15's fixes have room. Adds what to expect from `contract infer` (it is SQL-only; it captures indexes, checks, RLS, and 1:1 relations from unique indexes; it emits Temporal-backed `Timestamp` types that need the polyfill, D10), what `db sign` checks and what exit code 4 means, the baseline migration, the `db` ref, and the second migration with `--advance-ref db`. Depends on D1 for how short this can be. - -**C4. Prisma ORM 8 release status.** One short page: Prisma ORM 8 is a release candidate; GA expected in the window Will has stated publicly; Prisma ORM 7 receives bug fixes and security updates for 12 months; `npx prisma` and `npm install prisma` now resolve to Prisma ORM 8; to stay on 7, install `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. Depends on D6 for whether the tag stays. - -**C5. Editor setup.** VS Code extension location (open-vsx), that Prisma ORM 8 does not bundle a language server and uses the locally installed CLI, that `contract.prisma` needs `// use prisma-next` on line one, and `prisma contract format` as the fallback. Under getting started. Unblocks J7. Needs Serhii to confirm the current state. - -**C6. Types.** Model types, result types, where and input types, with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch and published the day prisma/orm#30231, #30236, and #30158 ship. Unblocks J9. Also covers what `contract.d.ts` already exports today: `AddressInput` beside `AddressOutput`, `FieldOutputTypes`, `TypeMaps`, `QueryOperationTypes`, `AggregateTypes`. - -**C7. Advanced Postgres.** The audit answered the product questions the first brief left open: RLS and policies are expressible in PSL (`@@rls`, `policy_select` and siblings, `role` blocks) and in the TypeScript builder; expression and partial indexes are `@@index(expression:, where:, unique:, type:)`; hand-written checks are `@@check`; `@noCheck` waives generated checks; `installExtension` / `createExtension` are migration factories; `@@control` sets how much of a table Prisma manages. None of it is on the site. Write the page from `skills/prisma-8/references/contract.md:101-108,265-367` and `packages/2-sql/2-authoring/contract-psl/README.md`. Unblocks J8. Audit: `contract`, `gaps`. - -**C8. Money and Decimal.** Short page or section under data modeling: cents as integers (already there), `Decimal` with precision and scale in type position (`Numeric(p, s)`), what `@default` accepts on it, and the aggregate return types (`avgDecimal`). Answers the open Discord question. - -**C9. Deploying Prisma ORM 8.** (See also the production caveat at the end of this item.) There is no Prisma ORM 8 deployment guide for any host; all six `guides/deployment/*` pages are Prisma 7 (A7). What a deploy needs is in the source: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). One page with sections for Docker, Vercel, Cloudflare Workers, and monorepos, or one page per host under the same label. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, 128 MiB isolate memory so `limit()` is the memory cap) and carries a production caveat with zero site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s), workaround `cursor: { disabled: true }`. Evidence: `skills/prisma-8/references/build.md:421-435`, `migrations.md:487`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. Audit: `gaps`, `extras`. - -**C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, the async `supabase({ contractJson, url, jwksUrl | jwtSecret })` factory, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*` reads, and `SUPABASE.JWT_INVALID` / `SUPABASE.CONFIG_INVALID`. A page under `orm/extensions/` and a guide. Evidence: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. Audit: `gaps`. - -**C11. CI with Prisma ORM 8.** The only CI guide is Prisma 7 (A7). The Prisma ORM 8 shape: `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Evidence: `skills/prisma-8/references/migration-review.md:172-197`, `cli/src/orm/migration/status-findings.ts`. Audit: `gaps`, `migrations-cli`. - -**C12. Switching from another ORM, and team schema workflow.** The three `switch-to-prisma-orm/*` and three `database/*` guides are Prisma 7 (A7). The Prisma ORM 8 replacements are the brownfield flow (`orm init`, `contract infer --output`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Much of C3 and C11 can be reused. Audit: `start-guides`. - -**C13. Migration factory reference.** The site shows six migration factories (`createSchema`, `createTable`, `addColumn`, `setNotNull`, `dataTransform`, `rawSql`). The `Migration` base class has about thirty: indexes, foreign keys, uniques, checks, column type and default changes, native enum create / drop / add-value, `installExtension`, RLS enable / disable, policy create / drop / rename, plus the free factories `createExtension`, `foreignKey`, `unique`, `checkExpression`, `fn`, `lit`. Also the `node migration.ts` self-emit CLI's `--dry-run` and `--config`. A reference page beside `editing-a-migration.mdx`. Evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. Audit: `migrations-cli`. - -**C14. PSL and TypeScript builder completeness.** Not a new page but a rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. Missing from PSL: native types in type position (`Uuid`, `VarChar(255)`, `Numeric`, `Timestamptz`, `TimestamptzString`, `Jsonb`, `BigIntNumber`, `UnboundedInt`, and the rest), the `@default` generator list (`uuid(4|7)`, `cuid(2)`, `ulid()`, `nanoid(n)`, `dbgenerated`), `temporal.createdAt()` / `updatedAt()` presets, scalar lists and which targets support them, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks and cross-space relation targets, `native_enum` blocks, `@relation("Name")` disambiguation, `onDelete` / `onUpdate`, extension types inline in field position, MongoDB index options (`sort:`, `@@textIndex`), and `.variant()` for polymorphic reads. Missing from the TypeScript page: the field helpers beyond four, `.attributes()` for composite keys and uniques (the page shows no way to declare a composite primary key), `constraints.index`, `check`, `.noCheck()`, `rel.belongsTo().sql({ fk })`, `foreignKeyDefaults` / `naming`, the `output` config option, and the MongoDB builder's `valueObject`, `index`, `enumType`, `field.vector()`, and polymorphism. Evidence: `packages/2-sql/2-authoring/contract-psl/README.md`, `contract-ts/README.md`, `packages/2-mongo-family/2-authoring/contract-ts/README.md`. Audit: `contract`. - -**C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute` and `RuntimeStatementStats`; `verifyMarker: 'onFirstUse' | false` (the startup check core-concepts describes without saying how to control it); `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat accessor form `db.orm.User` for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the optional `configure(meta)` callback on every terminal and `meta.annotate(...)` (how cache opt-in works per query); `distinctOn` needs the `postgres.distinctOn` capability; MongoDB `mode: 'strict' | 'permissive'` and the filter classes `MongoAndExpr`, `MongoNotExpr`, `MongoExistsExpr`; the SQLite facade lifecycle; the driver-free static client (`@prisma/orm-postgres/static`); `db.prepare` and prepared bind sites on `limit()` / `offset()`; `ctx.signal` and `MongoMiddleware` on the middleware pages; `createInMemoryCacheStore` and the cache debug events; `RUNTIME.MISSING_EXTENSION_PACK`; `fns.cosineSimilarity`. Audit: `orm-client`, `builders`. - -**C16. Build integration.** The Vite plugin `@prisma/orm-postgres/vite-plugin-contract-emit` (re-emits on save; Vite 7 and 8; dev server only) and the `"prebuild": "prisma contract emit"` pattern for every other bundler. Zero hits on the site; the Vite-based framework guides (SvelteKit, Astro, Nuxt, TanStack Start) tell readers to run `contract:emit` by hand. A section on `the-contract-artifact.mdx` plus one paragraph per framework guide. Evidence: `packages/1-framework/3-tooling/vite-plugin-contract-emit/README.md`, `skills/prisma-8/references/build.md`. Audit: `gaps`, `contract`. - -**C18. Supported versions and requirements.** No page states the floors. The monorepo's `docs/Supported Versions.md` says Node 24, Bun 1.2, Deno 2.0, PostgreSQL 15, MongoDB 8.0, TypeScript 5.9, `tsconfig` with `moduleResolution: "bundler"` and `strict: true`, and ESM-only with no CommonJS. The site says Bun 1.1, states no PostgreSQL floor anywhere, says nothing about ESM or `strict`, and the upgrade guide shows `module: nodenext`. The doc's Node 24 disagrees with the scaffold's `^22.18.0 || >=24.11.0` (B8) and its `--merge-tsconfig` flag does not exist at rc.9, so confirm each number with product before publishing. One short page under getting started, linked from every quickstart. Audit: `extras`. - -**C19. Extension pages beyond pgvector.** PostGIS (`Geometry` type, its seven operations, the `pg/geometry@1` JSON round-trip exemption), ParadeDB (`key_field`-only), and arktype-json (`arktypeJson(schema)`, never shown) each have one catalog row. One section per pack on `using-extensions.mdx` or one page each, with the real public import paths. Audit: `extras`. - -**C20. Telemetry page.** `cli/telemetry.mdx` never mentions `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file and its `enableTelemetry` field, that CI never sends, the first-run notice, that the preference is per-user, agent detection, or the event fields (the monorepo's `docs/Telemetry.md` is itself stale: rc.9 also sends `exitCode`). The rc.9 first-run notice links to `prisma-next.dev/docs/cli/telemetry`, not this page. Evidence: `packages/1-framework/3-tooling/cli-telemetry/src/`, `cli/src/orm/telemetry/reporting.ts`. Audit: `extras`. - -**C17. CLI page additions.** `cli/configuration.mdx`: the `migrations.dir` and `formatter` keys, the `composer` section every scaffold ships, telemetry opt-out variables (`DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`). `cli/orm-init.mdx`: the full flag list, exit codes 4 and 5, `prisma-next.md`, `--confirm` for re-running. `cli/db-update.mdx`: it never plans `data`-class operations. `cli/migration-ref.mdx`: the refusals. `cli/migration-new.mdx`: default origin rules. `cli/migration-status.mdx`: `--json` diagnostics. `cli/db-migrate.mdx`: `MIGRATION.MARKER_MISMATCH` and `PATH_UNREACHABLE`. `cli/contract-emit.mdx`: `--json` output and the `output` config option. `cli/index.mdx`: `@prisma/orm-toolchain` and `@prisma/orm-framework`. Audit: `migrations-cli`, `contract`, `gaps`. +Grouped by where the page lives. Each says what the page is for, what it must cover, where the facts come from, and what it waits on. -## D. Change the ORM +### Entry pages -These are places where the docs are hard because the tool is. Each is a candidate for the product backlog, not a docs fix. D1 and D3 have briefs (`brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`) and are handed off. +- **C2. Add Prisma ORM to an app you already started.** Starts from "you have a project directory and an empty or absent database": `orm init`, edit the contract, `contract emit`, `db init`, one query, with `db.ts` shown. Bun as the worked example, since that is the case reported, with a note for Node. Unblocks J1. Source: `mental-model.md`; the scaffold in `create-prisma`. +- **C1. Coming from Prisma 7.** The mapping table from `mental-model.md` in four sections: schema and types, CLI commands, client API, and "not in Prisma ORM 8 yet" with a status per item. The last section is the one readers ask for most and no page has: `skipDuplicates`, `increment`/`decrement`, `findUniqueOrThrow`, case-insensitive filters, `$transaction` arrays, model and payload types, `@updatedAt` (rejected; use `temporal.updatedAt()`), `cuid()` (rejected; use `cuid(2)`), JSON path filtering, soft delete, validations, callbacks, read replicas. Unblocks J3. Placement is A2; content of the "not yet" list depends on D4. +- **C3. Adopt an existing database.** Split from the existing-project page so it has room: what `contract infer` produces (SQL-only; captures indexes, checks, RLS, 1:1 relations; emits Temporal-backed timestamp types that need the polyfill, D10), what `db sign` checks and what exit code 4 means, the baseline migration, the `db` ref, the second migration with `--advance-ref db`. Unblocks J2. Waits on D1, which decides how short it can be. +- **C4. Release status.** One short page: release candidate; GA window; Prisma ORM 7 gets bug fixes and security updates for twelve months; `npx prisma` and `npm install prisma` resolve to Prisma ORM 8; to stay on 7, pin `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. Waits on Will (facts) and D6 (whether the tag stays). +- **C18. Supported versions.** No page states the floors. Candidates: Node (see the decision above), Bun 1.2 (site says 1.1), Deno 2.0, PostgreSQL 15 (stated nowhere), MongoDB 8.0, TypeScript 5.9, `tsconfig` with `moduleResolution: "bundler"` and `strict: true`, ESM-only. The monorepo's `docs/Supported Versions.md` is the draft but is wrong about Node and documents a `--merge-tsconfig` flag that does not exist, so confirm each number. One page under getting started, linked from every quickstart. +- **C5. Editor setup.** Where the VS Code extension lives (open-vsx), that Prisma ORM 8 does not bundle a language server and uses the locally installed CLI, that `// use prisma-next` on line one is what the language server keys on, and `prisma contract format` as the fallback. Unblocks J7. Waits on Serhii. -**D1. Make adoption one step.** Today: `contract infer`, edit, `contract emit`, `db sign`, `migration plan --name baseline` (or equivalent), `migration ref set db `. Two options: have `db sign` also set the `db` ref when no ref exists, or add a `db adopt` command that runs sign plus ref. Either removes the recreate-everything trap in J2 and cuts C3 in half. Handed off. +### Guides -**D2. `migration plan` with no origin and no migrations on disk.** The CLI refuses when migrations exist on disk with no ref (`MIGRATION.PLAN_ORIGIN_UNKNOWN`). When no migrations exist it silently plans from empty. For a signed database with no ref that is the wrong default; it should warn or refuse the same way. Related to D1. +- **C9. Deploying Prisma ORM 8.** Zero coverage today for any host. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. +- **C11. CI.** `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. +- **C12. Switching from another ORM; team schema workflow.** Replaces the six Prisma 7 guides A7 removes. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. +- **C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, `supabase({ contractJson, url, jwksUrl | jwtSecret })`, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*`, and the `SUPABASE.*` errors. Source: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. -**D3. Opt out of agent files at scaffold time.** `create-prisma` has no flag and always writes all four agents plus a `postinstall`. Add a prompt and a `--skills none` flag, and have `orm init` ask. Five users in one week; the circulating workaround is wrong. Handed off. +### Reference completeness -**D4. Missing client API.** Verified absent from the SQL ORM client source: `firstOrThrow` on the collection (it exists on `AsyncIterableResult`, so `.all().firstOrThrow()` works and could be documented as the workaround), atomic `increment`/`decrement` on update, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), and filtering on JSON columns by path or containment (the `jsonb` codec declares only the `equality` trait and the SQL builder has no `->>` or `@>` functions; the workaround is `db.raw.sql`). Also confirmed not supported, for C1's "not yet" list: soft delete, model validations, lifecycle callbacks, custom `Collection` subclasses (`CollectionImpl` has private clone methods), read replicas and multi-database routing, MongoDB referential actions. Each needs a decision: build it, or document the workaround (SQL builder or raw) and say it is not planned. The types work (`Models`, `Shape<>`, where types) is already in PRs. +- **C7. Advanced Postgres.** All of it ships and none of it is documented: RLS and policies in PSL and the TypeScript builder; expression and partial indexes (`@@index(expression:, where:, unique:, type:)`); `@@check`; `@noCheck`; `installExtension` / `createExtension` migration factories; `@@control` for how much of a table Prisma manages. Unblocks J8. Source: `skills/prisma-8/references/contract.md:101-108,265-367`, `packages/2-sql/2-authoring/contract-psl/README.md`. Waits on the product call about how to label these. +- **C8. Money and Decimal.** Cents as integers (already there), `Numeric(p, s)` in type position, what `@default` accepts, `avgDecimal`, and that a decimal string avoids float loss while the declared scale still rounds. Answers an open Discord question. +- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch; publish when prisma/orm#30231, #30236, #30158 ship. Also what `contract.d.ts` already exports today. Unblocks J9. +- **C13. Migration factory reference.** The site shows six factories; the `Migration` base class has about thirty (indexes, foreign keys, uniques, checks, column changes, native enums, `installExtension`, RLS and policies), plus free factories and the `node migration.ts --dry-run` / `--config` self-emit CLI. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. +- **C14. PSL and TypeScript builder completeness.** A rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. The PSL page lacks native types in type position, the `@default` generator list, the `temporal.*` presets, scalar lists, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks, `native_enum`, `@relation("Name")`, `onDelete`/`onUpdate`, inline extension types, MongoDB index options, `.variant()`. The TypeScript page lacks most field helpers, composite keys (`.attributes()`), indexes and checks, `foreignKeyDefaults`, the `output` option, and the MongoDB builder's value objects, indexes, enums, vectors, and polymorphism. The full list is in `audit/contract.md` under Missing. Source: the two `contract-psl` and `contract-ts` READMEs. +- **C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute`; `verifyMarker`; `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat `db.orm.User` accessor for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the `configure(meta)` callback and `meta.annotate(...)` (how cache opt-in works); `distinctOn`'s capability; MongoDB `mode` and the extra filter classes; the SQLite facade; the static client; `db.prepare`; `ctx.signal` and `MongoMiddleware`; `createInMemoryCacheStore`. Full list in `audit/orm-client.md` and `audit/builders.md` under Missing. +- **C16. Build integration.** The Vite plugin `@prisma/orm-postgres/vite-plugin-contract-emit` (re-emits on save; dev server only) and the `"prebuild": "prisma contract emit"` pattern for every other bundler. Zero hits on the site; the Vite-based framework guides tell readers to run emit by hand. Source: `packages/1-framework/3-tooling/vite-plugin-contract-emit/README.md`. +- **C19. Extension pages beyond pgvector.** PostGIS (`Geometry`, seven operations, the `pg/geometry@1` JSON round-trip exemption), ParadeDB (`key_field`-only), arktype-json (`arktypeJson(schema)`) each have one catalog row. +- **C20. Telemetry page.** `cli/telemetry.mdx` omits `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file, that CI never sends, the first-run notice, and the event fields. The rc.9 first-run notice links to `prisma-next.dev/docs/cli/telemetry`, which is not this page. Source: `packages/1-framework/3-tooling/cli-telemetry/src/`. +- **C17. CLI page additions.** `configuration.mdx`: `migrations.dir`, `formatter`, the `composer` section, the telemetry variables. `orm-init.mdx`: full flag list, exit codes 4 and 5, `prisma-next.md`. `db-update.mdx`: never plans `data`-class operations. `migration-ref.mdx`: the refusals. `migration-new.mdx`: default origin rules. `migration-status.mdx`: `--json` diagnostics. `db-migrate.mdx`: `MIGRATION.MARKER_MISMATCH`, `PATH_UNREACHABLE`. `contract-emit.mdx`: `--json` output, the `output` option. `cli/index.mdx`: `@prisma/orm-toolchain`, `@prisma/orm-framework`. -**D5. `contract infer` output on Prisma 7 databases.** Users report the inferred contract failing to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether infer on rc.9 still emits removed syntax, and whether the `Decimal @default(0.00)` failure is a bug. Infer should produce a contract that emits. See also D10. +## D. Change the ORM and its tooling -**D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Either move the RC to a `next` tag until GA or state the policy on C4. Serhii said he would find out why; no update. +Places where the docs are hard because the tool is. Grouped by who owns the fix. -**D7. `db.connect()` versus `db.runtime()`, and `db.close()` versus `db.runtime().close()`.** Two names for adjacent things, used interchangeably across pages, with a Mongo-only `await`, and now a third pair for teardown. `db.prepare` followed by `db.connect()` throws `DRIVER.ALREADY_CONNECTED` because `prepare` connects in the background. If the API can be one call on both targets, the docs get simpler on every page that shows a script. +### ORM behaviour -**D8. Streaming does not stream.** `postgres()` builds its driver with `cursor: { disabled: true }`, so `for await` over a result iterates an already-buffered array; only the serverless facade exposes cursor batches. The reading-data page promises the opposite. Either expose `cursor` / `batchSize` on `postgres()` or drop the promise (B25). Evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`, `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:39-53`. +- **D1. Make adoption one step.** Today: `contract infer`, edit, `contract emit`, `db sign`, `migration plan`, `migration ref set db `. Either `db sign` sets the `db` ref when none exists, or a `db adopt` command does sign plus ref. Removes the recreate-everything trap in J2 and halves C3. In progress; brief in `brief-db-ref-on-adoption.md`. +- **D2. `migration plan` with no origin and no migrations on disk plans from empty silently.** With migrations on disk it refuses (`MIGRATION.PLAN_ORIGIN_UNKNOWN`). For a signed database with no ref the silent case is the wrong default; it should warn or refuse the same way. +- **D9. `--db` suppresses `db` ref advancement.** `db init` and `db update` advance the ref only when the URL comes from config; with `--db` they do not unless `--advance-ref` is also passed. Surprising, and every example passes `--db`. Advance regardless, or warn when `--db` is used without `--advance-ref` and no ref exists. Source: `cli/src/control-api/operations/ref-advancement.ts:19-28`. +- **D13. `migration ref set … @db` fails** with `MIGRATION.HASH_NOT_IN_GRAPH` instead of reading the marker. Support it when a connection is available, or reject it with a message that says why. Source: `cli/src/control-api/operations/ref.ts:104-118`. +- **D15. `db update` never plans data operations.** A change that needs a backfill fails and the user must switch to `migration plan`; nothing says so. Allow it, or print the hint. Source: `cli/src/control-api/operations/db-update.ts:17`. +- **D16. `migration status` exits 0 on warnings.** CI has to parse `--json`. A `--strict` flag or a non-zero exit on warn-level findings makes C11 one line. Source: `cli/src/orm/migration/status-findings.ts`. +- **D8. Streaming does not stream on `postgres()`.** The facade creates its driver with `cursor: { disabled: true }`, so `for await` iterates an already-fetched result; only the serverless facade exposes cursor batches. Measured: breaking after the first row of a 400,000-row table still grew the heap by 64 MB. Expose `cursor` on `postgres()` or keep the docs' new wording. Source: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`. +- **D12. Permissive mode is unreachable on Postgres.** `postgres()` never forwards `mode`, so every "warn in permissive mode" branch in lints and budgets is dead on Postgres; only `mongo()` accepts it. Expose it or remove the branches. Source: `postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. +- **D7. `db.connect()` vs `db.runtime()`, `db.close()` vs `db.runtime().close()`.** Two names for adjacent things, a Mongo-only `await`, and `db.prepare` then `db.connect()` throwing `DRIVER.ALREADY_CONNECTED`. One call on both targets would simplify every page that shows a script. +- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js before 26.8.2 every read throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported. `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. +- **D5. `contract infer` on Prisma 7 databases.** Users report inferred contracts that fail to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether rc.9 still emits removed syntax and whether `Decimal @default(0.00)` is a bug. See D10. -**D9. `--db` suppresses `db` ref advancement.** `db init` and `db update` advance the `db` ref only when `--db` is omitted; with `--db` they do not unless `--advance-ref` is also passed. Every doc example passes `--db`, and the result is `MIGRATION.PLAN_ORIGIN_UNKNOWN` on the second plan. The rule is surprising and undocumented. Consider advancing regardless of how the URL was supplied, or warning when `--db` is used without `--advance-ref` and no `db` ref exists. Related to D1 and D2. Evidence: `cli/src/control-api/operations/ref-advancement.ts:19-28`. +### Product decisions -**D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps `timestamp` / `timestamptz` columns to Temporal-backed `Timestamp` / `Timestamptz`; on Node.js before 26.8.2 (checked: 26.8.1, 24.16, and 22.22 have no `globalThis.Temporal`; 26.8.2 does) every read of such a column throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported first. `create-prisma` installs the polyfill; `orm init` does not, and neither the existing-project page nor the upgrade guide mentions it, so real upgrades with `DateTime` columns break after step 3. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit time with a clear message. Evidence: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`, `packages/3-targets/3-targets/postgres/src/core/errors.ts:74-86`. +- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work (`Models`, `Shape<>`) is in PRs. +- **D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Move the release candidate to `next` until GA, or state the policy on C4. -**D11. create-prisma pins rc.8.** `create-prisma@0.11.7` pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` (to match a Composer peer dependency), so a fresh scaffold does not get the rc.9 behaviour the site documents. Either bump on every RC or document the lag. Evidence: `wip/create-prisma-src/src/constants/dependencies.ts:8-10`. +### create-prisma -**D12. Permissive mode is unreachable on Postgres.** `postgres(...)` never forwards a `mode`, so the runtime is always strict and every "warn in permissive mode" path on the lints and budgets pages cannot happen; only `mongo(...)` accepts `mode`. Either expose `mode` on `postgres()` or remove the branches and the docs. Evidence: `packages/3-extensions/postgres/src/runtime/postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. +- **D3. Opt out of agent files at scaffold time.** No flag exists; every scaffold writes all four agent directories plus a `postinstall` hook. Add a prompt and `--skills none`, and have `orm init` ask. In progress; brief in `brief-skills-opt-out.md`. +- **D11. create-prisma pins rc.8.** `create-prisma@0.11.7` pins the ORM packages to `8.0.0-rc.8` for a Composer peer dependency, so fresh scaffolds lag the site. Bump on every release candidate, or document the lag. Source: `create-prisma/src/constants/dependencies.ts:8-10`. +- **D18. The MongoDB scaffold writes a `.env` nothing reads.** It contains `DATABASE_URL`; the generated `prisma.config.ts` reads `MONGODB_URL` and loads no dotenv file. Source: `create-prisma/templates/create/_shared/prisma.config.ts.hbs:13,31`, `src/tasks/prisma-setup/project-files.ts:22-26`. +- **Node 24.0 to 24.10.** The generated `package.json` declares `^22.18.0 || >=24.11.0` while create-prisma itself accepts `>=22.18.0`. Nobody could say why the 24 sub-range is excluded. Worth a question to the owner. -**D13. `migration ref set … @db` fails.** `@db` parses to the empty sentinel for the offline command and fails with `MIGRATION.HASH_NOT_IN_GRAPH` instead of reading the database marker. Either support it (read the marker when a `--db` is available) or reject it with a message that says so. Evidence: `cli/src/control-api/operations/ref.ts:104-118`. +### The agent skill -**D14. The shipped skill is stale in the same places as the site, and a few more.** (Also: `cipherstash.EncryptedString` as the canonical extension example although that package was dropped, `createTelemetryMiddleware` from a package that does not exist, and no mention of the cache middleware.) Will said skills are not the focus, but every audit found the skill wrong where the site is wrong, and it is what agents read. Verified stale in `skills/prisma-8/references/`: `execute` for row reads (should be `query`), `PN-CLI-*` / `PN-MIG-*` / `PN-RUN-*` codes (dotted since 0.17), the flat `defineConfig` config file (envelope since rc.4), `orm init --skip-skills` and the `prisma/contract.prisma` default (`src/prisma/`), "N:M include and nested mutations unsupported" (they work), `pn_meta_marker` (it is `prisma_contract.marker`), `createTelemetryMiddleware` from a package that does not exist, `@@discriminator` / `@@base` "SQL-only" (Mongo has them), scalar lists "rejected" (Postgres accepts them), `-y` for destructive consent (it is `--confirm `), free-function migration factories (they are `this.` methods), `migration show` with no argument (positional required). One ticket to the skills owner with this list; the audit files have the line numbers. +- **D14. `skills/prisma-8/` is stale in the same places the site was, and more.** Twenty-one verified defects, the worst being row reads through `execute()`, `PN-*` error codes that no longer exist anywhere, and the flat config file removed in rc.4. It ships inside the ORM packages and is what coding agents read instead of the site. Brief ready to hand over: `brief-skill-staleness.md`. -**D15. `db update` never plans data operations.** Its allowed classes are additive, widening, destructive; a change that needs a backfill fails and the user must switch to `migration plan`. Undocumented. Either allow it or print the switch hint. Evidence: `cli/src/control-api/operations/db-update.ts:17`. +### Monorepo docs hygiene -**D16. `migration status` exits 0 on warnings.** CI must parse `--json` `diagnostics[]` to catch `MIGRATION.DIVERGED`, `MARKER_NOT_IN_HISTORY`, `CONTRACT.AHEAD`, `NO_MARKER`. A `--strict` flag or a non-zero exit on warn-level findings would make C11 one line. Evidence: `cli/src/orm/migration/status-findings.ts`. +- **D17. `docs/reference/` and `docs/Supported Versions.md` disagree with the site and partly with the source.** `reference/capabilities.md` disagrees with the site's capabilities page on key namespacing, pack key nesting, the error code spelling, and whether capabilities are fixed at emit or negotiated at connect. `Supported Versions.md` says Node 24 and documents `--merge-tsconfig`, which does not exist. `Telemetry.md` says no exit code is sent; rc.9 sends one. `docs/reference/error-reference.md`, from which the site's error reference is generated verbatim, still says `ref set` and `prisma ref set` in eight entries (the command is `migration ref set` since rc.5). `mongodb-user-promise.md` promises MongoDB referential actions that are not implemented. Until reconciled, the audit treats `packages/` and `docs/releases/` as the only truth. -**D17. `docs/reference/` and `docs/Supported Versions.md` disagree with the site and partly with the source.** `reference/capabilities.md` and the site's capabilities page disagree on key namespacing (`sql.lateral` vs `postgres.lateral`), pack key nesting, the error code spelling, and whether capabilities are negotiated at connect time or fixed at emit time. `Supported Versions.md` says Node 24 and documents `--merge-tsconfig`; the scaffold says 22.18 and the flag does not exist. `Telemetry.md` says no exit code is sent; rc.9 sends one. `docs/reference/error-reference.md` (from which the site's ORM error reference is generated word for word) still writes `ref set`, `ref list`, and `prisma ref set ` in eight entries; the mounted command has been `migration ref set` since rc.5, so the fix belongs in the error definitions' `fix` text. `mongodb-user-promise.md` promises MongoDB referential actions that are not implemented. Whoever owns `docs/` in the monorepo should reconcile these before the site is written from them; until then the audit treats `packages/` and `docs/releases/` as the only truth. +## Naming -**D18. create-prisma's MongoDB scaffold writes a `.env` nothing reads.** For MongoDB the scaffold writes `.env` with `DATABASE_URL`, but the generated `prisma.config.ts` reads `MONGODB_URL` and loads no dotenv file, so the file is dead and the CLI's own next-step text says to set `MONGODB_URL` in the environment. Found during the PR 3 review. Evidence: `wip/create-prisma-src/templates/create/_shared/prisma.config.ts.hbs:13,31`, `src/tasks/prisma-setup/project-files.ts:22-26`, `src/tasks/prisma-setup/presentation.ts:46`. +The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR after A7. -## Unverified, carried from the audits +## Open questions -Things the agents flagged but could not confirm against the monorepo, mostly because the `prisma` binary and `@prisma/cli-engine` live in the uncloned `prisma-cli` repo. Check before acting: the global `--yes` flag on `db migrate`; `cli/global-flags.mdx`, `cli/init.mdx`, `cli/skills.mdx` wholesale; `definePrismaConfig` from `prisma/config` versus `@prisma/cli-engine`; `HostedStateBootstrapError` and `--name`; Mongo `_id` decoding through `$lookup` and `findOneAndUpdate`; `_id` equality inside `match()`; the apply order of extension spaces versus `app`; whether `DateTime` still parses in PSL now that the starter contract writes `TimestamptzString`; the raw `EXTRACT(...)` codec claim; the `ilike` `fns` helper; "ParadeDB and Supabase are experimental"; which agent directory list is current (`ai/tools/skills.mdx` says Claude Code, Cursor, Codex, Windsurf; `cli/skills.mdx` and the scaffold say `claude`, `cursor`, `agents`, `devin`); whether `npx skills add` wants `prisma/prisma/skills` or `prisma/orm/skills`; the real capability key strings (see D17). Full list in the `## Unverified` section of each audit file. +Things the audit flagged but could not settle, mostly because the `prisma` binary and `@prisma/cli-engine` live in the `prisma-cli` repo, which was not audited: the global `--yes` flag on `db migrate`; `cli/global-flags.mdx`, `cli/init.mdx`, `cli/skills.mdx` as whole pages; `definePrismaConfig` from `prisma/config` versus `@prisma/cli-engine`; `HostedStateBootstrapError` and `--name`; Mongo `_id` decoding through `$lookup` and `findOneAndUpdate`; `_id` equality inside `match()`; the apply order of extension spaces versus `app`; whether `DateTime` still parses in PSL now that the starter writes `TimestamptzString`; the raw `EXTRACT(...)` codec claim; the `ilike` `fns` helper; "ParadeDB and Supabase are experimental"; which agent directory list is current (the skills page says Claude Code, Cursor, Codex, Windsurf; `cli/skills.mdx` and the scaffold say `claude`, `cursor`, `agents`, `devin`); whether `npx skills add` wants `prisma/prisma/skills` or `prisma/orm/skills`; the real capability key strings. Each audit file has an `## Unverified` section with what was checked. From 18b607ddc183d0530c4d7805db841befab8bf8fd Mon Sep 17 00:00:00 2001 From: reviewer Date: Fri, 11 Sep 2026 12:45:10 +0000 Subject: [PATCH 04/28] docs: correct repo names, PR status, and citation key in the ORM docs audit The audit's citations use the worktree layout it was run in (wip/prisma-src, wip/create-prisma-src, wip/web); README now says what each prefix maps to. The db-ref brief named the monorepo prisma/prisma and said PRs go to prisma/orm; it is one repository, renamed, so name it once. The "shipped" wording for section B overstated PR 3: #8238 is still open. The model and result type work is no longer "in open PRs": prisma/orm#30158 is in rc.9, and #30231 / #30236 merged to main on 2026-09-10 and await a tagged release. --- docs/orm-docs-audit/README.md | 6 ++++-- docs/orm-docs-audit/brief-db-ref-on-adoption.md | 2 +- docs/orm-docs-audit/changes.md | 12 ++++++------ docs/orm-docs-audit/ia.md | 2 +- docs/orm-docs-audit/journeys.md | 8 ++++---- docs/orm-docs-audit/mental-model.md | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md index 86d3af4ed9..b41a63e6f8 100644 --- a/docs/orm-docs-audit/README.md +++ b/docs/orm-docs-audit/README.md @@ -2,15 +2,17 @@ Working documents behind the Prisma ORM 8 docs corrections (prisma/web #8236, #8237, #8238) and the proposed restructure. Written September 2026 against `@prisma/orm-postgres@8.0.0-rc.9`; source paths refer to the prisma/orm monorepo at that tag (`packages/`, `docs/releases/`, `examples/`, `skills/prisma-8/`) and to prisma/create-prisma. Site paths are relative to `apps/docs/content/docs/`. +Citations in `audit/`, `changes.md`, and the briefs use the worktree layout the audit was run in: `wip/prisma-src/` is prisma/orm (formerly prisma/prisma; the old name still redirects) at `v8.0.0-rc.9`, `wip/create-prisma-src/` is prisma/create-prisma, `wip/web/` is this repository, and `wip/docs-audit/` is this directory. Strip the prefix to get the path in the named repository. + Read in this order: 1. `personas.md` — who reads the ORM docs: the Newcomer, the Upgrader, the Builder, the Agent. 2. `journeys.md` — ten jobs those readers come to do, with an entry point, a done criterion, the path through today's pages, and a verdict. 3. `mental-model.md` — the standalone explanation of Prisma ORM 8 (contract, emit, signature, plans, migrations and refs) that pages get written from. 4. `ia.md` — the proposed sidebar trees and `/orm` page structure, then the current state and the reasons. -5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B, shipped), new pages (C), ORM changes (D). Leads with the suggested order. +5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B; #8236 and #8237 are merged, #8238 is open as of 2026-09-11), new pages (C), ORM changes (D). Leads with the suggested order. 6. `naming.md` — the "Prisma ORM" naming rule. -7. `slice-corrections.md` — how the shipped corrections were sliced, and the decisions taken. +7. `slice-corrections.md` — how the section B corrections were sliced, and the decisions taken. 8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). 9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. diff --git a/docs/orm-docs-audit/brief-db-ref-on-adoption.md b/docs/orm-docs-audit/brief-db-ref-on-adoption.md index 77d8448fb8..a6c95aafc6 100644 --- a/docs/orm-docs-audit/brief-db-ref-on-adoption.md +++ b/docs/orm-docs-audit/brief-db-ref-on-adoption.md @@ -1,6 +1,6 @@ # Brief: set the `db` ref when a database is adopted -Written 2026-09-10 for an agent with no prior context. Repo: `prisma/prisma` `main` (the Prisma 8 monorepo, rc.9). PRs go to `prisma/orm`. +Written 2026-09-10 for an agent with no prior context. Repo: `prisma/orm` `main` (the Prisma 8 monorepo, rc.9; formerly `prisma/prisma`, and the old name still redirects). ## What we want diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index ef0458832d..347e6b4cf7 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -8,7 +8,7 @@ Status as of 2026-09-11. ## Where things stand -**Shipped.** Every correction to an existing page (section B, 35 items) went out in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist), #8237 (pages whose explanations were wrong), and #8238 (facts on the getting-started pages and guides). Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. +**Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. **In progress.** A7 (moving the sixteen Prisma 7 guides out of the Latest tree) is with Ankur. D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. @@ -48,11 +48,11 @@ The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These a - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. - **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** In progress (Ankur). `guides/frameworks/react-router-7`, `solid-start`, all of `guides/deployment/*`, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` are Prisma 7 end to end and have no copy under `guides/v7/`. Move with the same slugs and redirects; the Latest sidebar loses those labels until C9, C11, and C12 replace them. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. -- **A4** (sidebar labels and the guides index) shipped in #8238. +- **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. -## B. Corrections to existing pages (shipped) +## B. Corrections to existing pages (#8236 and #8237 merged; #8238 open) -Thirty-five items, all verified against rc.9 source and shipped in #8236, #8237, #8238. What they fixed, in order of how many readers they hit: +Thirty-five items, all verified against rc.9 source, in #8236 and #8237 (merged) and #8238 (open as of 2026-09-11). What they fixed, in order of how many readers they hit: | Theme | What was wrong | Items | |---|---|---| @@ -93,7 +93,7 @@ Grouped by where the page lives. Each says what the page is for, what it must co - **C7. Advanced Postgres.** All of it ships and none of it is documented: RLS and policies in PSL and the TypeScript builder; expression and partial indexes (`@@index(expression:, where:, unique:, type:)`); `@@check`; `@noCheck`; `installExtension` / `createExtension` migration factories; `@@control` for how much of a table Prisma manages. Unblocks J8. Source: `skills/prisma-8/references/contract.md:101-108,265-367`, `packages/2-sql/2-authoring/contract-psl/README.md`. Waits on the product call about how to label these. - **C8. Money and Decimal.** Cents as integers (already there), `Numeric(p, s)` in type position, what `@default` accepts, `avgDecimal`, and that a decimal string avoids float loss while the declared scale still rounds. Answers an open Discord question. -- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch; publish when prisma/orm#30231, #30236, #30158 ship. Also what `contract.d.ts` already exports today. Unblocks J9. +- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on prisma/orm `main` (#30231 and #30236 merged 2026-09-10); publish when the first tagged release after rc.9 ships them. #30158 (reusable where filter types) is already in rc.9. Also what `contract.d.ts` already exports today. Unblocks J9. - **C13. Migration factory reference.** The site shows six factories; the `Migration` base class has about thirty (indexes, foreign keys, uniques, checks, column changes, native enums, `installExtension`, RLS and policies), plus free factories and the `node migration.ts --dry-run` / `--config` self-emit CLI. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. - **C14. PSL and TypeScript builder completeness.** A rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. The PSL page lacks native types in type position, the `@default` generator list, the `temporal.*` presets, scalar lists, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks, `native_enum`, `@relation("Name")`, `onDelete`/`onUpdate`, inline extension types, MongoDB index options, `.variant()`. The TypeScript page lacks most field helpers, composite keys (`.attributes()`), indexes and checks, `foreignKeyDefaults`, the `output` option, and the MongoDB builder's value objects, indexes, enums, vectors, and polymorphism. The full list is in `audit/contract.md` under Missing. Source: the two `contract-psl` and `contract-ts` READMEs. - **C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute`; `verifyMarker`; `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat `db.orm.User` accessor for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the `configure(meta)` callback and `meta.annotate(...)` (how cache opt-in works); `distinctOn`'s capability; MongoDB `mode` and the extra filter classes; the SQLite facade; the static client; `db.prepare`; `ctx.signal` and `MongoMiddleware`; `createInMemoryCacheStore`. Full list in `audit/orm-client.md` and `audit/builders.md` under Missing. @@ -122,7 +122,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ### Product decisions -- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work (`Models`, `Shape<>`) is in PRs. +- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work is merged: the where filter types (#30158) are in rc.9; `Models` and `Shape<>` (#30231, #30236) are on `main` awaiting a tagged release. - **D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Move the release candidate to `next` until GA, or state the policy on C4. ### create-prisma diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index eae7f20730..6a2ec40b27 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -96,7 +96,7 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | J6 data types | Data Modeling > Overview | right node; one stale example | | J7 editor setup | none | no node | | J8 advanced Postgres | none | no node; needs product answers | -| J9 types | none | no node; API in PRs | +| J9 types | none | no node; API merged, awaiting a tagged release | | J10 opt out of agent files | CLI > configuration | right node, unreachable from Getting Started | Two observations follow from the table. diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md index b2bd7e7bcc..8a840266a5 100644 --- a/docs/orm-docs-audit/journeys.md +++ b/docs/orm-docs-audit/journeys.md @@ -50,7 +50,7 @@ Path today: - The bulk count mutations are taught as `createCount`/`updateCount`/`deleteCount` (31 sites on two pages). They were renamed to `createAndCount` and friends in 0.17. - `createMany` appears on no Prisma 8 page. `createAll` and `createAndCount` are documented but nothing says they replace it. `skipDuplicates` has no equivalent and no page says so. - `findUniqueOrThrow`, `findFirstOrThrow`, atomic `increment`/`decrement`, and case-insensitive filters have no Prisma 8 equivalent in the SQL ORM client source. No page says so. -- `$transaction([...])` is covered in one inline block. `Prisma.UserGetPayload` and the model types have no page at all; the replacements are in open PRs. +- `$transaction([...])` is covered in one inline block. `Prisma.UserGetPayload` and the model types have no page at all; the replacements (`Models`, `Shape<>`) merged to prisma/orm `main` on 2026-09-10 (#30231, #30236) and are not in a tagged release as of rc.9. - Accessor casing (`prisma.user` became `db.orm.public.User`) is stated once in reading-data and nowhere else. Verdict: **red**. The answers that exist are scattered, two of them are wrong, and the missing features are not admitted. @@ -117,9 +117,9 @@ Who: Newcomer and Upgrader. Done: `type User = ...` and the type of a query result, without reading `contract.d.ts`. -Path today: no page. `ResultType` for SQL builder plans is the only documented helper. The `Models` namespace, `Shape<>`, and where-type exports are in open PRs. +Path today: no page. `ResultType` for SQL builder plans is the only documented helper. The `Models` namespace and `Shape<>` (prisma/orm#30231, #30236) merged to `main` on 2026-09-10 and are not in a tagged release as of rc.9; the where-type exports (#30158) shipped in rc.9. -Verdict: **red** until the PRs ship, then a page is needed on release day. +Verdict: **red** until the next tagged release carries `Models` and `Shape<>`, then a page is needed on release day. ## J10. Stop Prisma from writing agent files into my repo @@ -143,5 +143,5 @@ Verdict: **amber** for docs, **red** for the tool. | J6 data types | amber | remove `@db.` example, add attribute map | | J7 editor | red | new page | | J8 advanced Postgres | red | product decision first | -| J9 types | red | page on PR merge | +| J9 types | red | page on the next tagged release | | J10 agent files | amber | one line on three pages | diff --git a/docs/orm-docs-audit/mental-model.md b/docs/orm-docs-audit/mental-model.md index 8f70f0eeaf..ad09b022ff 100644 --- a/docs/orm-docs-audit/mental-model.md +++ b/docs/orm-docs-audit/mental-model.md @@ -100,7 +100,7 @@ Why a graph and not a list: two branches can each add a migration, and the graph | `createMany` | `createAll` (rows back) or `createAndCount` (count back) | the return shape is in the name | | `$transaction([...])` | `db.transaction(async tx => ...)` | callback form only | | `@db.Text`, `@db.VarChar(n)` | `Text`, `VarChar(n)` in type position | native types are types, not attributes | -| `Prisma.UserGetPayload<...>` | `Shape<...>` (in an open PR) | not shipped yet | +| `Prisma.UserGetPayload<...>` | `Shape<...>` (merged to prisma/orm `main` 2026-09-10, #30231) | not in a tagged release as of rc.9 | | `skipDuplicates`, `increment`, `findUniqueOrThrow`, `mode: "insensitive"` | no equivalent yet | say so plainly | ## The eight words From 7e815e77bf578fd79d6c8127828d4f173bcd089d Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 15:11:03 +0200 Subject: [PATCH 05/28] docs: keep the audit design documents free of progress state personas, journeys, mental-model, ia, naming, and the briefs describe readers, jobs, the target structure, and the reasoning; they carry no done/in-progress markers, so they do not go stale as work lands. journeys: per job, what the docs must provide and where the structure fails, with the IA node that serves it. mental-model: naming, the plan origin rule, whole-query raw SQL, the db ref rules and the adoption design. Keeps the repo-name and tagged-release facts from the previous commit. Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- .../brief-db-ref-on-adoption.md | 8 +- docs/orm-docs-audit/brief-skills-opt-out.md | 10 +- docs/orm-docs-audit/ia.md | 26 ++-- docs/orm-docs-audit/journeys.md | 131 ++++++++---------- docs/orm-docs-audit/mental-model.md | 36 ++--- docs/orm-docs-audit/naming.md | 10 +- docs/orm-docs-audit/personas.md | 16 +-- docs/orm-docs-audit/slice-corrections.md | 89 ++---------- 8 files changed, 130 insertions(+), 196 deletions(-) diff --git a/docs/orm-docs-audit/brief-db-ref-on-adoption.md b/docs/orm-docs-audit/brief-db-ref-on-adoption.md index a6c95aafc6..a0710d1aed 100644 --- a/docs/orm-docs-audit/brief-db-ref-on-adoption.md +++ b/docs/orm-docs-audit/brief-db-ref-on-adoption.md @@ -1,6 +1,6 @@ # Brief: set the `db` ref when a database is adopted -Written 2026-09-10 for an agent with no prior context. Repo: `prisma/orm` `main` (the Prisma 8 monorepo, rc.9; formerly `prisma/prisma`, and the old name still redirects). +Written 2026-09-10 for an agent with no prior context. Repo: `prisma/orm` `main` (the Prisma ORM 8 monorepo; formerly `prisma/prisma`, and the old name still redirects). Verified against rc.9. ## What we want @@ -28,9 +28,9 @@ The docs site (`prisma/web`) changes are handled separately; note in the PR what ## The problem -A user with an existing database brings it under Prisma 8 by running `contract infer`, `contract emit`, and `db sign`. That is what the getting-started page for existing projects tells them to do. Then they change the contract and run `migration plan`. The plan proposes creating every table again. +A user with an existing database brings it under Prisma ORM 8 by running `contract infer`, `contract emit`, and `db sign`. That is what the getting-started page for existing projects tells them to do. Then they change the contract and run `migration plan`. The plan proposes creating every table again. -Cause: `migration plan` takes its origin from `--from`, else the `db` ref, else the empty contract. `db sign` writes the database marker but never sets the `db` ref, and there are no migrations on disk, so the plan resolves to the empty origin and the CLI does not refuse (the `MIGRATION.PLAN_ORIGIN_UNKNOWN` refusal only fires when migrations already exist on disk). +Cause: `migration plan` takes its origin from `--from`, else the `db` ref, else the empty contract. `db sign` writes the database marker but never sets the `db` ref, and there are no migrations on disk, so the plan resolves to the empty origin and the CLI does not refuse (the `MIGRATION.PLAN_ORIGIN_UNKNOWN` refusal only fires when migrations already exist on disk). Once the graph has a snapshot the `db` ref can point at, `migration plan` writes an automatic baseline package; the gap is only that nothing after `db sign` creates that snapshot or the ref. Two Discord users hit this in one week and asked what `--from` is for. The incremental upgrade guide avoids it by teaching three extra commands (`migration plan --name baseline`, `db sign`, `migration ref set db `), and the "add to existing project" page does not teach them at all. @@ -49,5 +49,5 @@ Two Discord users hit this in one week and asked what `--from` is for. The incre - Plan command and origin flag: `packages/1-framework/3-tooling/cli/src/orm/migration/plan.ts`, `control-api/operations/migration-plan.ts` - Refusal text: `PLAN_ORIGIN_UNKNOWN` in `packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts` - Existing ref tests: `test/integration/test/cli.db-ref-advancement.e2e.test.ts` -- The documented workaround: `wip/web/apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx` §4.1 to 4.3 +- The documented workaround: `prisma/web` `apps/docs/content/docs/guides/upgrade-prisma-orm/postgresql.mdx`, sections 4.1 to 4.3 - Migration graph ADRs: search `docs/architecture docs/adrs/` for "ref" diff --git a/docs/orm-docs-audit/brief-skills-opt-out.md b/docs/orm-docs-audit/brief-skills-opt-out.md index 917d02d7fb..568020ae81 100644 --- a/docs/orm-docs-audit/brief-skills-opt-out.md +++ b/docs/orm-docs-audit/brief-skills-opt-out.md @@ -1,19 +1,19 @@ # Brief: let users opt out of agent skill files at scaffold time -Written 2026-09-10 for an agent with no prior context. Repos: `prisma/create-prisma` (the scaffolder) and `prisma/prisma-cli` (the unified `prisma` binary, whose `init` and `orm init` commands are involved). A read-only clone of create-prisma is at `wip/create-prisma-src` in this worktree. +Written 2026-09-10 for an agent with no prior context. Repos: `prisma/create-prisma` (the scaffolder, checked at 0.11.7) and `prisma/prisma-cli` (the unified `prisma` binary, whose `init` and `skills` commands are involved). ## What we want 1. `create-prisma` asks. Add a prompt in the interactive flow, "Install agent skills for coding assistants?" or similar, alongside the existing prompts, defaulting to yes. Add a flag for the non-interactive path, `--skills ` matching `prisma init --skills`, so `--yes` plus `--skills none` produces a project with no agent files, no `postinstall` hook, and `skills: { agents: [] }` in the config. 2. When the answer is no, the generated project has no `.claude/`, `.cursor/`, `.agents/`, or Devin directories, no `postinstall`, and no `skills:sync` script. `prisma-next.md` is a separate question: decide whether it is an agent file or a human readme and treat it accordingly. -3. `prisma orm init` on the existing-project path asks the same question when interactive, and honours `--skills` for parity with `--skip-skills`. +3. `prisma init` on the existing-project path (the command that installs skills; `orm init` stopped touching skills in rc.6) asks the same question when interactive, and honours `--skills`. 4. Removing skills after the fact: `prisma skills sync` with `agents: []` should remove the directories it previously wrote, or there should be a `prisma skills remove`. Decide which; the current behaviour (write nothing, leave the old copies) means the config opt-out looks like it did nothing. ## Acceptance - `create-prisma my-app --yes --skills none` produces a project with none of the four agent directories, no `postinstall`, and `agents: []` in the config. Test in create-prisma's `tests/`. - The interactive prompt appears and its answer is reflected the same way. -- `prisma orm init --skills none` on an existing project behaves the same. +- `prisma init --skills=none` on an existing project behaves the same and, with an existing config, writes `agents: []` into it rather than leaving it alone. - `prisma skills sync` after setting `agents: []` removes the previously written directories, or the new remove command does, with a test in prisma-cli. - The `create-prisma` README and the CLI help text list the new flag. - Note in the PR the exact user-facing sequence for the docs page, which is written separately: the `create-prisma` reference page, both quickstarts, `cli/init`, `cli/orm-init`, `cli/skills`, and `cli/configuration` on the docs site all need the answer. @@ -34,7 +34,7 @@ In `create-prisma`: In `prisma-cli`: - `prisma init --skills=none` writes `skills: { agents: [] }` when no config exists. With an existing config it does nothing to it. -- `prisma orm init --skip-skills` skips the skill install on the existing-project path. +- `prisma orm init` does not install skills (the `--skip-skills` flag was removed in rc.6 along with the install); it only deletes retired skill directories. - `prisma skills sync` writes the directories listed in `skills.agents`; with `agents: []` it writes nothing, but it does not delete copies already on disk. - `skills: { check: false }` only silences the out-of-date notice. @@ -44,4 +44,4 @@ So the real opt-out is `skills: { agents: [] }` in `prisma.config.ts`, and nothi - create-prisma: `src/tasks/setup-prisma.ts`, `src/tasks/prisma-setup/commands.ts`, `src/tasks/install.ts`, `templates/create/_shared/prisma.config.ts.hbs`, `src/index.ts` for flags - prisma-cli: the `init`, `orm init`, and `skills` commands -- Docs pages describing current behaviour: `wip/web/apps/docs/content/docs/cli/init.mdx`, `cli/orm-init.mdx`, `cli/skills.mdx`, `cli/configuration.mdx` +- Docs pages describing current behaviour, in `prisma/web` under `apps/docs/content/docs/`: `cli/init.mdx`, `cli/orm-init.mdx`, `cli/skills.mdx`, `cli/configuration.mdx` diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index 6a2ec40b27..f0652d4328 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -1,17 +1,17 @@ # Information architecture: proposal -Proposal first, then why, then the current state it changes. Source: the `meta.json` files and page titles in `wip/web/apps/docs/content/docs/` on 2026-09-10. Labels are what the sidebar shows. +Proposal first, then why, then the current state it changes. Source: the `meta.json` files and page titles under `apps/docs/content/docs/` in `prisma/web` on 2026-09-10. Labels are what the sidebar shows. ## Proposed -Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and two labels under Guides. Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. +Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. ### Getting Started > Prisma ORM ``` Prisma ORM - Introduction to Prisma 8 human content first, agent prompt last - + Prisma 8 release status RC, GA window, 7 support period, what npx prisma installs, how to pin 7 + Introduction to Prisma ORM human content first, agent prompt last + + Release status RC, GA window, 7 support period, what npx prisma installs, how to pin 7 ~ Start a new app was "Quickstart"; same two pages PostgreSQL MongoDB @@ -32,7 +32,7 @@ Four starting states, one group each. "Coming from Prisma 7" is a link node here ``` Introduction - Prisma 8 + Prisma ORM + Coming from Prisma 7 the mapping page: schema and types, CLI, client API, not-yet list ~ Core concepts rewritten as narrative from mental-model.md; glossary kept at the end ``` @@ -40,16 +40,20 @@ Introduction ### Guides ``` -Overview remove "Upgrading: moving from Prisma 7" from the coming-soon list +Overview no "coming soon" line for upgrading; it exists Upgrade Prisma ORM ~ Prisma 7 to 8 (PostgreSQL) was "PostgreSQL" ~ Prisma 6 to 8 (MongoDB) was "MongoDB" v7, v6, v5, v4, v3, v1 + - Deployment, Database, Switch to Prisma ORM, Prisma 7 content; lives under guides/v7 + GitHub Actions, AI SDK, React Router 7, SolidStart ``` +The six Guides labels that leave come back as Prisma ORM 8 pages when C9 (deployment), C11 (CI), and C12 (switching, team workflow) are written. + ### The ORM root page (`/orm`) -Today the page has five sections: "Your schema becomes a contract", "What changed for developers", "Supported databases", "Get started" (three cards), "Go deeper" (five cards), and "Learn more about the design of Prisma 8" (five blog links). Three of the six argue for the design against Prisma 7. There is no query on the page. A Newcomer cannot tell from it what the product does; an Upgrader is told why it is different before being shown what it is. +Today the page has six sections: "Your schema becomes a contract", "What changed for developers", "Supported databases", "Get started" (three cards), "Go deeper" (five cards), and "Learn more about the design of Prisma 8" (five blog links). Three of the six argue for the design against Prisma 7. There is no query on the page. A Newcomer cannot tell from it what the product does; an Upgrader is told why it is different before being shown what it is. Proposed structure, in order: @@ -60,6 +64,8 @@ Proposed structure, in order: 5. Coming from Prisma 7: one line linking to the mapping page. 6. Release status: one line linking to the status page. +The page name follows the naming rule: "Prisma ORM", not "Prisma 8". + Removed from this page: the three-step workflow explanation, "What changed for developers", and the blog list. The first moves into Core concepts; the other two go, or the blog list moves to the bottom of Core concepts. ### Root page (`/`) @@ -70,7 +76,7 @@ The ORM line becomes a short row with the four starting states, linking into the | Node | Jobs | | --- | --- | -| Prisma 8 release status | J4 | +| Release status | J4 | | Add to an app you already have | J1 | | Adopt an existing database (rewritten) | J2 | | Coming from Prisma 7 | J3, J5 (links to the incremental guide), J6 (attribute map) | @@ -82,7 +88,7 @@ J8, J9, and J10 need product decisions or shipped code before a node makes sense ### Not proposed -No change to the top-level section list, to Data Modeling, Contract Authoring, Fundamentals, Migrations, Middleware, Extensions, Reference, or to any Guides subtree except the two labels. The "Prisma 7" group at the bottom of Getting Started stays as the home for people staying on 7. +No change to the top-level section list, to Data Modeling, Contract Authoring, Fundamentals, Migrations, Middleware, Extensions, or Reference. Under Guides, only the label changes above and the removal of the Prisma 7 pages (A7). The "Prisma 7" group at the bottom of Getting Started stays as the home for people staying on 7. ## Why: where each job lands today, and where the structure fails it @@ -96,7 +102,7 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | J6 data types | Data Modeling > Overview | right node; one stale example | | J7 editor setup | none | no node | | J8 advanced Postgres | none | no node; needs product answers | -| J9 types | none | no node; API merged, awaiting a tagged release | +| J9 types | none | no node; API in PRs | | J10 opt out of agent files | CLI > configuration | right node, unreachable from Getting Started | Two observations follow from the table. diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md index 8a840266a5..ca47fac543 100644 --- a/docs/orm-docs-audit/journeys.md +++ b/docs/orm-docs-audit/journeys.md @@ -1,95 +1,78 @@ -# Jobs users come to the docs to do, and how the docs serve them today +# Jobs readers come to the docs to do -Each job has: who, where they land, what "done" looks like, the path through the current site, and a verdict. Paths were traced in the `prisma/web` source at `wip/web/apps/docs/content/docs/` and checked against the live site on 2026-09-10. Verdicts: **green** works, **amber** works with friction, **red** fails or is missing. +Ten jobs. Each names who does it, what "done" looks like, what the docs must provide for it, and where the site's structure fails it. The jobs are the design input for `ia.md` (which node serves each job) and `changes.md` (which page or ORM change supplies what is missing). Verdicts describe the structure, not the state of any one sentence: **green** a page exists for the job and carries it end to end, **amber** the job can be done but the reader has to assemble it from several places or work around a gap, **red** no page is written for the job. -## J1. Add Prisma 8 to an app I already started, with an empty database +## J1. Add Prisma ORM to an app I already started, with an empty database -Who: Newcomer, sometimes Upgrader. The Bun user in Discord is this job. +Who: Newcomer, sometimes Upgrader. The most common Discord complaint is this job. Done: models defined, tables created, one query returns rows, from inside the app they already have. -Path today: +What the docs must provide: one page that starts from "you have a project directory and no tables", runs `orm init`, edit the contract, `contract emit`, `db init`, one query, and shows `db.ts` and where `DATABASE_URL` comes from. -- Search "prisma bun" lands on the Bun guide. It starts with `create-prisma`, so it scaffolds a new app instead of joining theirs. -- `/getting-started` offers "Add to an existing project", which goes to the existing-project PostgreSQL page. That page assumes the database already has tables: step 4 is `contract infer`. There is no branch for "empty database". -- The right three commands (`orm init`, `contract emit`, `db init`) exist only as a snippet on the CLI reference overview, under "Start in an existing project". -- Whichever page they use, the query example is wrong: the existing-project page uses `db.orm.User` (must be `db.orm.public.User` on Postgres) and `.take(2)` (removed in rc.7). -- `orm init` writes `src/prisma/db.ts`, but no getting-started page shows the file, so `import { db } from "./prisma/db"` is unexplained. -- The quickstart says scripts read `DATABASE_URL` from the environment, not `.env`; the existing-project page uses `.env` with `dotenv/config`. The two pages disagree and neither says why. -- The existing-project script calls both `db.connect()` and `db.runtime()`. The difference is explained only deep in the transactions-and-runtime reference. -- Skill files land in the repo with no mention of how to stop that. +Where the structure fails: the getting-started subtree is organised by which tool runs (`create-prisma` for new apps, `orm init` for "existing project"). The reader's situation, an app with no database yet, falls between the two: the scaffold page creates a new app, and the existing-project page assumes tables exist and starts with `contract infer`. The three commands that fit exist only as a snippet on the CLI overview. -Verdict: **red**. No page is written for this job, and the nearest page has two copy-paste errors. +Verdict: **red**. IA node: "Add to an app you already have" (C2). -## J2. Bring an existing database with data under Prisma 8, then make the next schema change +## J2. Bring an existing database with data under Prisma ORM, then make the next schema change Who: Upgrader mostly, some Newcomers with a legacy database. Done: contract matches the database, database is signed, first query works, and `migration plan` for the next change produces one small migration rather than a full recreate. -Path today: the existing-project PostgreSQL page, steps 2 to 9. +What the docs must provide: the adoption sequence end to end, including what to expect from `contract infer` (removed attributes, non-`public` schemas, defaults it cannot express, Temporal-backed timestamp types), what `db sign` checks and what its exit codes mean, and whatever makes the next `migration plan` chain from the signed state. -- Steps 2 to 7 are in the right order: init, connection, infer, review, emit, sign, query. -- Step 4 says "review the inferred contract" but not what to expect. Users hit `@db.*` attributes (removed in 0.17), non-`public` schemas, and a `Decimal` default that fails to emit, with no guidance. -- Step 6 signs the database but never explains what a signature is or what to do if `db sign` exits 4. -- Step 9 says "use `db update` or `migration plan`". It never mentions the `db` ref. `db sign` does not set the ref (only `db init`, `db update`, and `db migrate --advance-ref` do). With no migrations on disk and no ref, `migration plan` silently plans from an empty database and proposes recreating every table. This is the `--from` confusion reported twice in Discord. -- The upgrade guide gets this right (baseline migration, sign, `migration ref set db`, then `--advance-ref db` on each migrate), but J2 users on the existing-project page never see it. +Where the structure fails: the existing-project page stops at "sign, then query". The step that makes the next migration work (today: a baseline migration and `migration ref set db`) is taught only in the incremental upgrade guide, which this reader never sees. That step exists because `db sign` does not record where migrations start from; the design in `brief-db-ref-on-adoption.md` removes it. -Verdict: **red**. The page stops one step short and the missing step produces a destructive-looking plan. +Verdict: **red**. IA node: "Adopt an existing database" (C3); ORM change D1. -## J3. Rewrite Prisma 7 queries in Prisma 8 +## J3. Rewrite Prisma ORM 7 queries in Prisma ORM 8 Who: Upgrader. -Done: for every Prisma 7 call in their code, they know the Prisma 8 call or that it does not exist. +Done: for every Prisma ORM 7 call in their code, they know the Prisma ORM 8 call or that it does not exist. -Path today: +What the docs must provide: one mapping page in four sections (schema and types, CLI commands, client API, not-yet list with a status per item), reachable from every ORM entry point. The not-yet list is the part readers ask for most: `createMany` and `skipDuplicates`, `findUniqueOrThrow`, atomic `increment`/`decrement`, case-insensitive filters, JSON path filters, `$transaction` arrays, the payload types. -- No single mapping page. Sixteen inline "For Prisma 7 users" diff blocks are spread across reading-data, writing-data, transactions-and-runtime, pipeline-builder, data-modeling, and eight places in the ORM reference. -- Pagination is taught as `.take()`/`.skip()` on eight pages (29 sites). Those were renamed to `.limit()`/`.offset()` in rc.7 and the old names removed. -- The bulk count mutations are taught as `createCount`/`updateCount`/`deleteCount` (31 sites on two pages). They were renamed to `createAndCount` and friends in 0.17. -- `createMany` appears on no Prisma 8 page. `createAll` and `createAndCount` are documented but nothing says they replace it. `skipDuplicates` has no equivalent and no page says so. -- `findUniqueOrThrow`, `findFirstOrThrow`, atomic `increment`/`decrement`, and case-insensitive filters have no Prisma 8 equivalent in the SQL ORM client source. No page says so. -- `$transaction([...])` is covered in one inline block. `Prisma.UserGetPayload` and the model types have no page at all; the replacements (`Models`, `Shape<>`) merged to prisma/orm `main` on 2026-09-10 (#30231, #30236) and are not in a tagged release as of rc.9. -- Accessor casing (`prisma.user` became `db.orm.public.User`) is stated once in reading-data and nowhere else. +Where the structure fails: there is no node. The mapping exists as sixteen inline "For Prisma 7 users" blocks across nine pages, so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. -Verdict: **red**. The answers that exist are scattered, two of them are wrong, and the missing features are not admitted. +Verdict: **red**. IA node: "Coming from Prisma 7" (C1, placed by A2); the not-yet list depends on D4. -## J4. Decide whether to move to Prisma 8 now +## J4. Decide whether to move to Prisma ORM 8 now Who: Upgrader, also a Newcomer choosing an ORM. -Done: they know Prisma 8 is a release candidate, when GA is expected, how long 7 is supported, what `npx prisma` now installs, and how to pin 7. +Done: they know Prisma ORM 8 is a release candidate, when GA is expected, how long 7 is supported, what `npx prisma` now installs, and how to pin 7. -Path today: the root page says "Prisma 7 remains fully supported" and shows `npx prisma@7.10.0 init`. Nothing on the site says Prisma 8 is an RC, gives a GA window, states the 12-month support commitment for 7, or explains the npm `latest` tag. Five people asked this in Discord in one week. +What the docs must provide: one short page with those five facts, linked from the root page and from every "Using Prisma 7?" note. -Verdict: **red**, and the cheapest fix on the list. +Where the structure fails: no node. The only signal is a note box saying Prisma 7 remains supported, with links for staying on 7. Nothing says "release candidate", gives a window, or explains that `npm install prisma` now resolves to 8 while `@prisma/client` resolves to 7. -## J5. Migrate a whole Prisma 7 app incrementally +Verdict: **red**. IA node: "Release status" (C4); the npm tag question is D6. + +## J5. Migrate a whole Prisma ORM 7 app incrementally Who: Upgrader with a team and a production database. -Done: both versions run side by side, routes move one at a time, migrations hand over, Prisma 7 is removed. +Done: both versions run side by side, routes move one at a time, migrations hand over, Prisma ORM 7 is removed. + +What the docs must provide: the five-phase guide that exists (`guides/upgrade-prisma-orm/postgresql`), reachable from the ORM entry points and from the mapping page, with a label that says what it is. -Path today: `guides/upgrade-prisma-orm/postgresql` covers all five phases and is the best page on the site for the Upgrader. Getting there is the problem: the root page, `/getting-started`, and the ORM overview never link to it. The guides index lists "Upgrading: moving from Prisma 7" under "Coming as they land". In the sidebar it sits under "Upgrade Prisma ORM" as "PostgreSQL", with no "7 to 8" in the label. It is also pinned to rc.6 and rc.4 and says so in a callout. +Where the structure fails: the page is filed under Guides and nothing under Getting Started or ORM links to it. It is the best page on the site for this reader and the hardest to find. -Verdict: content **amber**, discoverability **red**. +Verdict: content **green**, discoverability **amber**. IA: link it from "Coming from Prisma 7" and the ORM front door (A2). -## J6. Model my data, especially types Prisma 7 handled with `@db.*` +## J6. Model my data, especially types Prisma ORM 7 handled with `@db.*` Who: Newcomer and Upgrader. -Done: they can write `Text`, `VarChar(100)`, `Uuid`, `Decimal`, enums, relations, and know which Prisma 7 attributes are gone. +Done: they can write `Text`, `VarChar(100)`, `Uuid`, `Decimal`, enums, relations, and know which Prisma ORM 7 attributes are gone. -Path today: +What the docs must provide: the scalar table, the native types in type position, the `@default` generators, index and check options, and a Prisma ORM 7 attribute map (`@db.Text`, `@db.VarChar(n)`, `@db.Decimal(p,s)` to their type-position forms), plus a money and `Decimal` section. -- The data-modeling overview has a scalar table (`String` is `Text`) and a money-in-cents recommendation. Good. -- The PSL syntax page shows `Uuid = String @db.Uuid` in its opening example and again at line 177. That syntax was removed in 0.17. Copying it fails emission. -- No page maps Prisma 7 attributes (`@db.Text`, `@db.VarChar(n)`, `@db.Decimal(p,s)`) to Prisma 8 types. -- `Decimal` defaults and money beyond "use cents" are not covered. One user asked and got no answer. -- Implicit many-to-many is honestly marked unsupported. Good. +Where the structure fails: the right nodes exist (Data Modeling, Contract Authoring) but cover a fraction of the authoring surface, and the attribute map has no home. -Verdict: **amber**, with one stale example that must go. +Verdict: **amber**. Pages: C1 (schema section), C14, C8. ## J7. Set up my editor @@ -97,9 +80,11 @@ Who: Newcomer and Upgrader. Done: syntax highlighting and formatting work for `contract.prisma`. -Path today: no page. The facts (extension is on open-vsx not the Microsoft marketplace, no bundled language server, needs the CLI installed locally, file needs `// use prisma-next` on line one) were given by Serhii in a Discord thread. The `// use prisma-next` line appears in examples but is never explained. +What the docs must provide: where the VS Code extension lives (open-vsx, not the Microsoft marketplace), that there is no bundled language server and the locally installed CLI is used, that `// use prisma-next` on line one is what the language server keys on, and `prisma contract format` as the fallback. -Verdict: **red**, missing. +Where the structure fails: no node. The facts were given once, in a Discord thread. + +Verdict: **red**. IA node: "Editor setup" (C5). ## J8. Use advanced Postgres features @@ -107,9 +92,11 @@ Who: Newcomer and Upgrader on real projects. RLS, policies, expression and funct Done: they know whether the contract can express it, and how, or that they must manage it outside Prisma. -Path today: nothing under `orm/`. RLS is covered only through the Supabase extension in the shipped skill. One user's agent invented a contract-builder API because there was nothing to read. +What the docs must provide: one page: `@@rls` and the `policy_*` blocks, `@@index(expression:, where:, unique:, type:)`, `@@check` and `@noCheck`, `installExtension` / `createExtension` in migrations, `@@control` for tables Prisma should not manage. + +Where the structure fails: no node. All of it ships and none of it is documented; readers' agents invent APIs because there is nothing to read. -Verdict: **red**, missing. Needs a product answer before a docs answer. +Verdict: **red**. Page: C7. ## J9. Name a model or result type for reuse @@ -117,31 +104,35 @@ Who: Newcomer and Upgrader. Done: `type User = ...` and the type of a query result, without reading `contract.d.ts`. -Path today: no page. `ResultType` for SQL builder plans is the only documented helper. The `Models` namespace and `Shape<>` (prisma/orm#30231, #30236) merged to `main` on 2026-09-10 and are not in a tagged release as of rc.9; the where-type exports (#30158) shipped in rc.9. +What the docs must provide: a types page with model, result, where, and input types, each beside its Prisma ORM 7 name. The `Models` namespace and `Shape<>` are in `prisma/orm` `main` and ship with the next tagged release; `ResultType` for SQL builder plans exists today. -Verdict: **red** until the next tagged release carries `Models` and `Shape<>`, then a page is needed on release day. +Where the structure fails: no node. + +Verdict: **red**. Page: C6, on the release that carries the types. ## J10. Stop Prisma from writing agent files into my repo -Who: Newcomer and Upgrader, five people in one week. +Who: Newcomer and Upgrader. Done: one config line, and they know it. -Path today: `skills: { agents: [] }` is documented on the CLI configuration page and `init --skills=none` on the init page. Neither is linked from create-prisma, the quickstarts, or the existing-project page. The advice circulating in Discord (`skills sync --disable`, an env var) is wrong. `create-prisma` has no flag. +What the docs must provide: the one line (`skills: { agents: [] }` in `prisma.config.ts`) at the point where the scaffold introduces the files, linking to the configuration reference; and, once it exists, the scaffold-time opt-out. + +Where the structure fails: the reader meets the files on the scaffold pages and the answer lives on the CLI configuration page, which those pages must link. The tool itself has no prompt or flag, and `skills sync` with an empty list does not remove what it wrote. -Verdict: **amber** for docs, **red** for the tool. +Verdict: docs **amber**, tool **red**. Tool change D3. ## Summary -| Job | Verdict | Cheapest fix | +| Job | Verdict | What serves it | | --- | --- | --- | -| J1 existing app, empty DB | red | new page | -| J2 existing DB, next migration | red | add baseline and ref steps | -| J3 Prisma 7 query mapping | red | one mapping page plus rename fixes | -| J4 should I move now | red | one short page, linked from root | -| J5 incremental upgrade | amber / red | links and a nav label | -| J6 data types | amber | remove `@db.` example, add attribute map | -| J7 editor | red | new page | -| J8 advanced Postgres | red | product decision first | -| J9 types | red | page on the next tagged release | -| J10 agent files | amber | one line on three pages | +| J1 existing app, empty DB | red | new node: Add to an app you already have (C2) | +| J2 existing DB, next migration | red | Adopt an existing database (C3) after D1 | +| J3 Prisma ORM 7 query mapping | red | Coming from Prisma 7 (C1, A2); D4 for the not-yet list | +| J4 should I move now | red | Release status (C4); D6 | +| J5 incremental upgrade | green / amber | links from the ORM entry points (A2) | +| J6 data types | amber | C1 schema section, C14, C8 | +| J7 editor | red | Editor setup (C5) | +| J8 advanced Postgres | red | Advanced Postgres (C7) | +| J9 types | red | Types (C6) on the next tagged release | +| J10 agent files | amber / red | the line on scaffold pages; D3 | diff --git a/docs/orm-docs-audit/mental-model.md b/docs/orm-docs-audit/mental-model.md index ad09b022ff..0522ff5b83 100644 --- a/docs/orm-docs-audit/mental-model.md +++ b/docs/orm-docs-audit/mental-model.md @@ -1,10 +1,10 @@ -# The Prisma 8 mental model, from first principles +# The Prisma ORM 8 mental model, from first principles -This is the source we write docs pages from. It explains why Prisma 8 has the pieces it has, in the order a person meets them. Everything here was checked against the monorepo glossary, the architecture overview, and the rc.9 release notes. +This is the source we write docs pages from. It explains why Prisma ORM 8 has the pieces it has, in the order a person meets them. Everything here was checked against the `prisma/orm` glossary, the rc.9 release notes, and the source under `packages/`. ## The one idea -Your application and your database each have an opinion about what the data looks like. In Prisma 7 the schema file was the only written-down version, and the generated client trusted that the database matched it. Prisma 8 makes the agreement explicit and checkable from both sides. Everything else follows from that. +Your application and your database each have an opinion about what the data looks like. In Prisma ORM 7 the schema file was the only written-down version, and the generated client trusted that the database matched it. Prisma ORM 8 makes the agreement explicit and checkable from both sides. Everything else follows from that. ## Two things, not one: the contract and the schema @@ -12,13 +12,13 @@ The **contract** is what you write. It is your description of the models, fields The **schema** is what the database actually has right now: the tables, columns, and indexes. -Prisma 7 called your file the schema. Prisma 8 reserves that word for the database side, because the whole point is that the two can disagree. When a command or error says "schema", it means the database. +Prisma ORM 7 called your file the schema. Prisma ORM 8 reserves that word for the database side, because the whole point is that the two can disagree. When a command or error says "schema", it means the database. -Every Prisma 8 operation is a relationship between these two: queries are typed against the contract, migrations move the schema toward the contract, and verification checks that the schema still satisfies the contract. +Every Prisma ORM 8 operation is a relationship between these two: queries are typed against the contract, migrations move the schema toward the contract, and verification checks that the schema still satisfies the contract. ## Emit: the build step that replaces `prisma generate` -Prisma 7 generated a client package from your schema. Prisma 8 emits two plain files from your contract: +Prisma ORM 7 generated a client package from your schema. Prisma ORM 8 emits two plain files from your contract: - `contract.json`, a canonical description of the models, storage layout, and the database features it needs. - `contract.d.ts`, the TypeScript types derived from it. @@ -34,12 +34,12 @@ Because emit is deterministic, hashing `contract.json` gives a short identifier The database stores a small marker record, the **signature**, naming the contract hash it currently satisfies. Three commands write it: - `db init` creates the tables for the contract in an empty database and signs it. -- `db sign` checks that an existing database already matches the emitted contract and, if so, signs it. This is how you adopt a database you did not create with Prisma 8. +- `db sign` checks that an existing database already matches the emitted contract and, if so, signs it. This is how you adopt a database you did not create with Prisma ORM 8. - `db migrate` applies a migration and updates the signature to the migration's target hash. `db verify` reads it and reports **drift**: any disagreement between contract and schema. -Why this exists: a deploy against an unmigrated database, or a migration run against the wrong database, is caught before any query runs, because the runtime and the migration runner both check the signature first. In Prisma 7 the same mistake produced wrong results or a failed query later. +Why this exists: a deploy against an unmigrated database, or a migration run against the wrong database, is caught before any query runs, because the runtime and the migration runner both check the signature first. In Prisma ORM 7 the same mistake produced wrong results or a failed query later. ## Queries: every query becomes a plan @@ -51,19 +51,19 @@ The three query surfaces on Postgres, from highest to lowest: 1. The **ORM client**: `db.orm.public.User.where({ ... }).all()`. Model-based, coordinates several statements for `.include()`, hands back one typed result. Start here. 2. The **SQL builder**: `db.sql.public.user.select(...).where(...).build()`. Composable joins, grouping, and projections. One plan is exactly one statement. -3. **Raw fragments** spliced into builder queries when the builder cannot express it. +3. **Raw SQL**: a whole statement, `db.raw.sql`\`...\`.returnsRow(spec)`, when the builder cannot express it, or a `fns.raw` fragment spliced into a builder query. Whole statements declare their row shape and are decoded; fragments are not. -Why `db.orm.public.User` and not `prisma.user`: Postgres tables live in schemas, and Prisma 8 addresses models through the schema namespace so a contract can span more than one. `public` is the default schema. Aliasing by assignment (`const User = db.orm.public.User`) is fine. On MongoDB the key is the collection's storage name (`db.orm.users`) and there is no SQL builder. +Why `db.orm.public.User` and not `prisma.user`: Postgres tables live in schemas, and Prisma ORM 8 addresses models through the schema namespace so a contract can span more than one. `public` is the default schema. Aliasing by assignment (`const User = db.orm.public.User`) is fine. On MongoDB the key is the collection's storage name (`db.orm.users`) and there is no SQL builder. ## Migrations: edges between contract hashes A migration is a step from one contract hash to another. Together they form a graph, not a timestamped list. Every migration records the hash it starts from and the hash it produces. -`migration plan` diffs two contracts and writes a migration package. The target is always your emitted contract. The origin is, in order: `--from` if you pass it, otherwise the `db` ref, otherwise an empty database. +`migration plan` diffs two contracts and writes a migration package. The target is always your emitted contract. The origin is `--from` if you pass it, otherwise the `db` ref. With neither, the command refuses (`MIGRATION.PLAN_ORIGIN_UNKNOWN`) when migrations already exist on disk, and plans from an empty database only when the migrations directory is empty. -The `db` **ref** is a named pointer to a contract hash, kept in the repo, meaning "the state I consider the database to be at". `db init`, `db update`, and `db migrate --advance-ref db` move it. `db sign` does not. +The `db` **ref** is a named pointer to a contract hash, kept in the repo, meaning "the state I consider the database to be at". `db init` and `db update` move it when the connection comes from `prisma.config.ts`; with an explicit `--db` they move it only if `--advance-ref db` is also passed. `db migrate --advance-ref db` moves it. `db sign` does not today; the design in `brief-db-ref-on-adoption.md` makes it do so, so that adopting a database is one step. -Why this matters more than it seems: a project with no `db` ref plans every migration from empty, which proposes recreating every table. This is the trap for anyone who adopts an existing database with `db sign` and then runs `migration plan`. The fix is a baseline migration plus `migration ref set db ` once, then `--advance-ref db` on each migrate. The incremental upgrade guide does this; the existing-project page does not. +Why this matters more than it seems: a project with no `db` ref and no migrations on disk plans its first migration from empty, which proposes recreating every table. This is the trap for anyone who adopts an existing database with `db sign` and then runs `migration plan`. The fix today is a baseline migration plus `migration ref set db ` once, then `--advance-ref db` on each migrate. When the graph is empty and the `db` ref names a stored snapshot, `migration plan` writes the baseline for you. Why a graph and not a list: two branches can each add a migration, and the graph resolves the merge by hashes instead of by timestamp order. Partial failures are safe to retry because each edge has a verifiable precondition. @@ -83,9 +83,9 @@ Why a graph and not a list: two branches can each add a migration, and the graph | `migration ref set` | a hash | the ref | after a baseline, or to repoint | | `contract infer` | live schema | a draft contract source | first contract for an existing database | -## What moved from Prisma 7, and why +## What moved from Prisma ORM 7, and why -| Prisma 7 | Prisma 8 | Why | +| Prisma ORM 7 | Prisma ORM 8 | Why | | --- | --- | --- | | `schema.prisma` | `contract.prisma` | the file describes an agreement, not the database | | `prisma generate` | `prisma contract emit` | data artifacts instead of a generated client | @@ -100,8 +100,8 @@ Why a graph and not a list: two branches can each add a migration, and the graph | `createMany` | `createAll` (rows back) or `createAndCount` (count back) | the return shape is in the name | | `$transaction([...])` | `db.transaction(async tx => ...)` | callback form only | | `@db.Text`, `@db.VarChar(n)` | `Text`, `VarChar(n)` in type position | native types are types, not attributes | -| `Prisma.UserGetPayload<...>` | `Shape<...>` (merged to prisma/orm `main` 2026-09-10, #30231) | not in a tagged release as of rc.9 | -| `skipDuplicates`, `increment`, `findUniqueOrThrow`, `mode: "insensitive"` | no equivalent yet | say so plainly | +| `Prisma.UserGetPayload<...>` | `Shape<...>`, with the `Models` namespace | in `prisma/orm` `main`; ships with the next tagged release | +| `skipDuplicates`, `increment`, `findUniqueOrThrow`, `mode: "insensitive"`, JSON path filters | no equivalent yet (`.all().firstOrThrow()` covers the throw case) | say so plainly | ## The eight words @@ -109,4 +109,4 @@ Why a graph and not a list: two branches can each add a migration, and the graph ## What the model costs, honestly -Two extra concepts before the first query: the emit step and the signature. Prisma 7 had neither. The docs must pay that cost back on the same page by showing what it buys: a deploy that refuses to run against the wrong database, a migration plan you can read before it runs, and a query you can inspect before it executes. If a page introduces the concept without the payoff, cut the concept from that page. +Two extra concepts before the first query: the emit step and the signature. Prisma ORM 7 had neither. The docs must pay that cost back on the same page by showing what it buys: a deploy that refuses to run against the wrong database, a migration plan you can read before it runs, and a query you can inspect before it executes. If a page introduces the concept without the payoff, cut the concept from that page. diff --git a/docs/orm-docs-audit/naming.md b/docs/orm-docs-audit/naming.md index 7e9752c14f..c7de792279 100644 --- a/docs/orm-docs-audit/naming.md +++ b/docs/orm-docs-audit/naming.md @@ -14,17 +14,15 @@ ## How to do it -Not a global replace. Each of the 109 files needs a read, because "Prisma 8" in a contrast sentence becomes "Prisma ORM 8" and elsewhere becomes "Prisma ORM". Do it per page as each page is touched by the restructure and the content fixes, and sweep the remainder at the end. The 96 titles are the visible part and should go first, since they are the sidebar and the browser tab. +One pass over the whole site, as its own PR. Not a global replace: each of the 109 files needs a read, because "Prisma 8" in a contrast sentence becomes "Prisma ORM 8" and elsewhere becomes "Prisma ORM". The 96 titles are the visible part and go first; they are the sidebar and the browser tab. ## What stays as is -- Identifiers: `prisma-next.md`, `// use prisma-next`, `@prisma/orm-postgres`, `/studio/prisma-next`, package names, error codes. 40 occurrences of `prisma-next` as an identifier; none as prose ("Prisma Next" appears zero times on the site). +- Identifiers: `prisma-next.md`, `// use prisma-next`, `@prisma/orm-postgres`, `/studio/prisma-next`, package names, error codes. 40 occurrences of `prisma-next` as an identifier; none as prose. - The "Prisma 7" group at the bottom of Getting Started and the v7 doc trees. - Release notes and changelogs, which name versions by nature. -## Scope on the site today - -Outside the v6 and v7 trees: +## Scope on the site (2026-09-10, outside the v6 and v7 trees) | Term | Occurrences | Files | | --- | --- | --- | @@ -34,4 +32,4 @@ Outside the v6 and v7 trees: By area: `orm/` 225, `guides/` 196, `(index)/` 135, `cli/` 81. 96 page titles or meta titles contain "Prisma 8". No sidebar label does; the labels come from titles. -The most common sentence shapes ("Add Prisma 8 to an ...", "Prisma 8 is the ...", "Prisma 8 app with ...", "Prisma 8 skills for ...") all take "Prisma ORM" as a drop-in replacement. The ones that do not are the contrast sentences, which should keep the number and add "ORM". +The common sentence shapes ("Add Prisma 8 to an ...", "Prisma 8 is the ...", "Prisma 8 app with ...", "Prisma 8 skills for ...") all take "Prisma ORM" as a drop-in replacement. The contrast sentences keep the number and add "ORM". diff --git a/docs/orm-docs-audit/personas.md b/docs/orm-docs-audit/personas.md index 7a95be649f..a7244b5b6c 100644 --- a/docs/orm-docs-audit/personas.md +++ b/docs/orm-docs-audit/personas.md @@ -1,6 +1,6 @@ -# Who reads the Prisma 8 docs +# Who reads the Prisma ORM docs -Four readers arrive at the docs. The first two produce almost all the complaints. The docs outside `orm/` are built for the third. The fourth never complains. +Four readers arrive. The first two produce almost all the complaints (Discord, GitHub, and support, August and September 2026). The docs outside `orm/` are built for the third. The fourth never complains. ## The Newcomer @@ -12,9 +12,9 @@ How they judge the docs: can I copy the example and does it run. ## The Upgrader -Has used Prisma 5, 6, or 7. Has a running app, a database with data in it, and a migration history. Arrived because `npx prisma` installed Prisma 8 without them choosing it, or because they saw the announcement. Most of the Discord complaints are from this reader. +Has used Prisma ORM 5, 6, or 7. Has a running app, a database with data in it, and a migration history. Arrived because `npx prisma` installed Prisma ORM 8 without them choosing it, or because they saw the announcement. Most of the complaints are from this reader. -What they need: first, a straight answer on whether to move now and how to stay on 7 if not. Second, the Prisma 8 name for every Prisma 7 thing they know, or a plain statement that it does not exist yet. Third, the exact sequence to bring an existing database under Prisma 8 control and make the next migration work. +What they need: first, a straight answer on whether to move now and how to stay on 7 if not. Second, the Prisma ORM 8 name for every Prisma ORM 7 thing they know, or a plain statement that it does not exist yet. Third, the exact sequence to bring an existing database under Prisma ORM 8 control and make the next migration work. How they judge the docs: against the mental model they already have. Every page that explains contracts before answering "where did `findMany` go" costs trust. @@ -22,12 +22,12 @@ How they judge the docs: against the mental model they already have. Every page Wants to ship a product on the Prisma platform: Composer, Compute, Postgres, Storage. May be technical, may lean on a coding agent. The ORM is one component. Happy to have tools scaffold the app and happy to hand a prompt to an agent. -The docs root, the framework guides, the agent prompts, and the full-stack tutorial serve this reader well. They are not the problem, but their content occupies the entry points the Newcomer and the Upgrader land on. +The docs root, the framework guides, the agent prompts, and the full-stack tutorial serve this reader well. The problem is that their content occupies the entry points the Newcomer and the Upgrader land on. ## The Agent -Reads the shipped skill, `llms.txt`, and the `.md` version of any page. Never complains. The skill is out of scope for this audit except where the human pages feed into it. +Reads the shipped `prisma-8` skill, `llms.txt`, and the `.md` rendition of any page. Never complains. The skill is out of scope for the docs work except where the human pages feed into it; its own defects are in `brief-skill-staleness.md`. -## What this means for the audit +## What this means for the docs -The ORM entry points must serve the Newcomer and the Upgrader before the Builder. Today the order is reversed: the root page is the Builder's, the ORM landing opens with an Agent prompt, and the Upgrader gets a two-line note saying Prisma 7 still exists. +The ORM entry points must serve the Newcomer and the Upgrader before the Builder. Today the order is reversed: the root page is the Builder's, the ORM landing opens with an agent prompt, and the Upgrader gets a two-line note saying Prisma ORM 7 still exists. diff --git a/docs/orm-docs-audit/slice-corrections.md b/docs/orm-docs-audit/slice-corrections.md index e7d5d50e5a..a439e4b7bf 100644 --- a/docs/orm-docs-audit/slice-corrections.md +++ b/docs/orm-docs-audit/slice-corrections.md @@ -1,83 +1,22 @@ -# Slice 1: corrections to published pages +# The corrections slice: what shipped, and the decisions behind it -Scope: fix what is wrong on pages that exist today, without moving, adding, or removing pages. Everything in `changes.md` section B, plus A4 (two label edits). Sections A, C, D are out of scope and come after the IA discussion. Each fix cites the rc.9 source line it was verified against; the audit files under `audit/` hold the line lists. +Before any restructure, every factual error on the published Prisma ORM 8 pages was fixed in place. Three PRs to `prisma/web`, each reviewed independently against the rc.9 source, each commit citing the line it was verified against: -## Proposed batches - -Three PRs to `prisma/web`, in this order. Each is reviewable on its own and does not depend on the others. - -### PR 1: mechanical renames (about 350 lines, 20 pages) - -Search-and-replace with a known correct form. Low judgement, high volume. Reviewer checks the diff is uniform. - -| Item | What changes | Pages | +| PR | What | Size | |---|---|---| -| B11 | `execute(plan)` to `query(plan)` for row reads; Mongo `db.execute(plan)` to `(await db.runtime()).query(plan)`; `ps.execute` to `ps.query`; drop `executePrepared`. Writes with no returned rows stay on `execute`. | 14 | -| B1 | `.take()`/`.skip()` to `.limit()`/`.offset()`; keep Mongo pipeline `skip` stages | 8 | -| B2 | `createCount` and siblings to `createAndCount` and siblings, including headings | 2 | -| B12 | drop the `sha256:` prefix on every hash | 9 | -| B13 | `extensionPacks` to `extensions` | 2 | -| B14 | migration directory listing and `migration.ts` imports to the `migrations/snapshots//` layout | 3 | -| B4 | remove `@db.Uuid`; re-point the named-types example at a real alias | 1 | -| B21 | stale flags, codes, command names, and printed output (`--skip-skills`, `CLI.INIT_SKILL_INSTALL_FAILED`, bare `ref set`, `prisma-cli` hints, `PN-RUN-3000`, `from: null`, the "Applied 1 migration(s)" line, `cd prisma`, top-level `migrate`, hyphenated slugs, `--db` shown as required) | 10 | -| B23 | `db.runtime().close()` to `db.close()` | 4 | -| B26 | enum ordering note updated for rc.9 | 1 | - -### PR 2: page rewrites (about 12 pages) - -Sentences change, not just names. Each page gets one commit so the reviewer can read it as prose. - -| Item | Page | What changes | -|---|---|---| -| B15 + B3 + B10 | both `add-to-existing-project` pages | default path is `src/prisma/`; `orm init` writes no skills; `.env` is a prompt; show `db.ts` once; one `DATABASE_URL` story; Temporal polyfill note; `--write-env` / `--schema-path`; `db.orm.public.User` | -| B16 | six `orm/migrations/*`, `cli/migration-plan`, `cli/db-init`, `cli/db-update`, `cli/migration-ref`, `cli/index`, upgrade guide | `migration plan` refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN`; `db init` / `db update` advance the ref only without `--db`; `NO_TARGET` belongs to `migration new`; the automatic baseline and `--from @empty` | -| B17 | five `orm/middleware/*` | two lifecycles, no `intercept`; rewrite the logger example on `afterQuery`; fix lint keys, budgets latency, cache hooks; drop "permissive mode" on Postgres | -| B18 | `orm/reference/raw-queries`, `advanced-queries` | whole-query raw SQL exists; `db.raw.sql`; drop the "unversioned ids" callout | -| B19 | `relations-and-joins`, `data-modeling/relational-databases` | 1:1 back side, N:M include and nested writes, referential actions, `.variant()` all work; stop sending readers to the SQL builder | -| B20 | `sql-query-builder`, `advanced-queries`, `orm-client` | aggregates return numbers; the `BigInt` / `Decimal` variants; `min` / `max` typing | -| B22 | `editing-a-migration` | add `rawCodecInferer` so the data-transform example typechecks | -| B24 | `writing-data` | upsert needs `conflictOn` | -| B27 | `transactions-and-runtime`, `pipeline-builder` | structured error codes, not plain `Error`; fix the `prepare` then `connect()` sample | -| B31 | `data-modeling/index` | scalar table: `Json` vs `Jsonb`, add `Decimal`, `Bytes` | -| B35 | `using-extensions` | the recipe does not fit Supabase; catalog links lead to `@internal` install commands | - -### PR 3: start pages and guides, small facts (about 20 pages) - -One-line or one-paragraph facts on the getting-started pages and guides. - -| Item | What changes | -|---|---| -| B5 | SQLite ships; `orm/index` and `sql-query-builder` | -| B6 | upgrade guides: version pins, `Database signed` output, the CREATE TABLE symptom that no longer appears | -| B8 | one Node floor, stated once (needs decision 2) | -| B9 | explain `// use prisma-next` where the contract is introduced | -| B28 | `create-prisma` page: `minimal` template, no `.env` for Postgres, `--force`, deploy defaults, Deno flag, script list | -| B29 | MongoDB pages: replica set is not required | -| B30 | Bun guide build and dev scripts; NestJS `@Inject` note; TypeScript authoring paths; Deno page staleness | -| B32 + A4 | guides index and the upgrade guide's sidebar label | -| B33 | `ai/tools/skills` page: one skill, no `--skip-skills`, `orm init` does not install | -| B34 | full-stack tutorial: `TimestamptzString`, no `postinstall` | -| B7 | the agent-files line on four pages (needs decision 1) | -| B25 | streaming claim on `reading-data` (needs decision 3) | - -## What this slice does not do - -- It does not touch the sixteen Prisma 7 guides under Prisma ORM 8 paths (A7). They are wrong for a Prisma ORM 8 reader, but fixing them means moving or rewriting whole pages, which is the IA discussion. If you want something now, the smallest honest change is a one-line banner at the top of each saying it is written for Prisma ORM 7; say so and I will add it to PR 3. -- It does not add missing content (C). Where a fix would leave a hole (for example B18 removes "raw SQL does not exist" but the page still needs a section on what does), the fix states the fact in one paragraph and stops. -- It does not touch the skill (D14) or the monorepo docs (D17). -- It does not rename "Prisma 8" to "Prisma ORM" (naming.md). That is a site-wide pass and cleaner as its own PR after this slice; mixing it in would bury the corrections in a 700-line diff. +| #8236 | Names, flags, paths, codes, and printed output that no longer exist at rc.9, replaced by the form that does | 12 commits, 39 files | +| #8237 | Pages whose explanations were wrong (the `db` ref, middleware, raw SQL, relations, aggregates, the existing-project pages) | 12 commits, 30 files | +| #8238 | Facts on the getting-started pages and guides (Node floor, MongoDB replica set, create-prisma flags and scripts, the skills page, the tutorial, streaming, `npm create prisma@latest`) | 18 commits, 40 files | -## Decisions before PR 3 +Out of scope by design: the sixteen Prisma 7 guides under Prisma ORM 8 paths (A7, now with Ankur), new content (C), the agent skill (D14), the monorepo docs (D17), and the "Prisma 8" to "Prisma ORM" rename. -Will answered on 2026-09-10: 1 and 4 as proposed; 2 and 3 checked as below. +## Four decisions taken along the way -1. **B7, agent files.** Write the `skills: { agents: [] }` workaround now; replace it when the opt-out brief lands. -2. **B8, Node floor.** Checked by running rc.9 end to end (`contract emit`, `db init`, ORM create and read, `for await`, SQL builder) in a scratch project under Node 22.12.0, 22.18.0, and 22.22.3: all pass. Node release schedule (`nodejs/Release/schedule.json`): 22 "Jod" is Maintenance LTS until 2027-04-30; 23 reached end of life 2025-06-01; 24 "Krypton" is Active LTS, Maintenance from 2026-10-20, end of life 2028-04-30; 26 becomes LTS 2026-10-28. So Node 22 is supported and in LTS for another seven months, and 23 is dead. The scaffold's `engines` range `^22.18.0 || >=24.11.0` is what `create-prisma` enforces; the excluded 24.0 to 24.10 band is odd and worth asking the create-prisma owner about, but the site should not contradict what the scaffold refuses. Site wording: "Node.js 22.18 or newer; Node.js 24 recommended." The monorepo's `Supported Versions.md` says 24 and is wrong about what runs. -3. **B25, streaming.** What the page says: `for await` over `.all()` "streams" rows with a "steady, flat memory footprint" for millions of rows, you "start working on the first record before the last one has arrived", and on early exit "unprocessed records are never buffered". What the implementation does: `postgres()` creates its driver with `cursor: { disabled: true }` (`packages/3-extensions/postgres/src/runtime/postgres.ts:245`), and the driver's own comment calls that "buffered execution": the whole result set is fetched into memory before iteration starts; only decoding through the codecs happens per row as your loop pulls. Cursor batches (`batchSize`, default 100) exist in the driver and are only reachable through the serverless facade's `cursor` option. Measured on a 400,006-row table under Node 22.18: `for await` that breaks after the first row took 186 ms and grew the heap by 64 MB (every row was fetched), versus 824 ms for `await ...all()` (fetch plus decode of every row). So `for await` saves the decode work and the decoded array, not the fetch. The page's three claims about memory and arrival order are false on `postgres()`; the "read once" rule and the per-row hand-off are true. Fix for this slice: rewrite the section to say what actually happens (rows are fetched in full, decoded one at a time as you iterate, use `limit()` or the serverless facade with cursors for genuinely large results). Whether `postgres()` should expose `cursor` is D8 and is out of this slice. -4. **B16, the `--db` quirk.** Document the current behaviour as-is, with `--advance-ref db` shown in every example that passes `--db`. +1. **Agent files.** The scaffold pages carry one line saying Prisma writes skill files for coding agents and that `skills: { agents: [] }` in `prisma.config.ts` stops it. That is the only correct answer until create-prisma grows an opt-out flag (D3), at which point the line is replaced. +2. **Node floor.** The site says "Node.js 22.18 or newer (on the 24 line, 24.11 or newer); 24 recommended". Checked by running rc.9 end to end (`contract emit`, `db init`, ORM create and read, `for await`, SQL builder) under Node 22.12.0, 22.18.0, and 22.22.3: all pass. Node 22 is Maintenance LTS until 2027-04-30; 23 reached end of life 2025-06-01; 24 is Active LTS until 2028-04-30. The `prisma` CLI and create-prisma both declare `>=22.18.0`; only the `package.json` create-prisma writes into a project narrows to `^22.18.0 || >=24.11.0`, which is why the 24 sub-range is stated. The monorepo's `docs/Supported Versions.md` says 24 and is wrong about what runs. +3. **Streaming.** The reading-data page promised that `for await` streams rows with a flat memory footprint. It does not on `postgres()`: the facade creates its driver with `cursor: { disabled: true }`, so the whole result is fetched before iteration and only decoding is per row. Measured on a 400,006-row table under Node 22.18: `for await` that breaks after the first row took 186 ms and grew the heap by 64 MB (every row fetched), against 824 ms for `await ...all()` (fetch plus decode). The page now says what happens and points large-result readers at `limit()` or the serverless facade, which reads through a cursor in batches of 100. Whether `postgres()` should expose cursors is D8. +4. **The `--db` quirk.** `db init` and `db update` advance the `db` ref only when the URL comes from config; with `--db` they do not unless `--advance-ref db` is also passed. Documented as-is, with the flag shown on every dev-loop example that passes `--db`; deploy and CI examples are left without it on purpose. Whether the rule should change is D9. -## How the work runs +## Two audit claims the source overruled -- One implementer per PR, working from the audit files and `changes.md`, in this worktree on a branch off `main`. Every changed code sample cites the source line in the commit message. Where a sample can be typechecked against `wip/prisma-src/examples/prisma-8-demo`, it is. -- I review each PR against the source before it goes to you. You do the prose pass. -- No push and no PR until you say so; the branches sit here until then. +Left as the pages had them: `migration plan` can raise `MIGRATION.NO_TARGET` after a rollback cycle (the planner does resolve a leaf), and `min` / `max` over a `DateTime` column type-checks at rc.9 (there is no `pg/timestamptz@1` codec; `DateTime` is the temporal codec, which `min`/`max` accept). From 328bcf1be6f366a0a251576c27149b880e75b0e4 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 16:02:17 +0200 Subject: [PATCH 06/28] docs: state the real reason for the naming rule, brand separation Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/naming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/orm-docs-audit/naming.md b/docs/orm-docs-audit/naming.md index c7de792279..2b67920647 100644 --- a/docs/orm-docs-audit/naming.md +++ b/docs/orm-docs-audit/naming.md @@ -10,7 +10,7 @@ - The release status page says "Prisma ORM 8 is a release candidate; Prisma ORM 7 is supported until ...". - The Prisma 7 docs trees (`orm/v7`, `(index)/v7`, `guides/v7`, `cli/v7`) keep their version label in the nav, because that is what they are. -"Prisma 8" as a bare product name reads as a different product from "Prisma ORM", which is the Upgrader's fear stated back to them. It also collides with the platform, where "Prisma" alone means the whole stack. +Why: the Prisma brand identity is being separated from the ORM. Prisma is the company and the platform; the ORM is one product on it. Calling the ORM "Prisma 8" ties the whole brand to one product's release cycle, and it leaves no name for the platform, where "Prisma" alone already means the stack. So the ORM is never "Prisma" plus a version; it is "Prisma ORM", and that name is what gets a version number. ## How to do it From 476adee8587715caf4109f8594a44753f05cd2d0 Mon Sep 17 00:00:00 2001 From: "reviewer (Program)" Date: Fri, 11 Sep 2026 14:24:26 +0000 Subject: [PATCH 07/28] docs: reconcile the ORM docs audit with #8242 and make the naming counts reproducible changes.md, ia.md, README.md: A7 landed as #8242 on 2026-09-11 in a different shape (fifteen guides rewritten for Prisma ORM 8 in place with Prisma 7 copies under guides/v7, Cloudflare D1 moved to v7 only), so the status, the A7 item, and C9/C11/C12 no longer describe main; record what landed and mark those items for re-scoping. naming.md: the scope table mixed corpora, occurrences counted with the v6/v7 trees included (690/198/2816) while the file counts and the heading excluded them. Restate both from one corpus with the method and the commit: 679/135/487, by area 221/196/131/77, 96 titles = 7 title + 89 metaTitle. changes.md carries the same number. journeys.md, changes.md: the Prisma 7 mapping is fourteen inline diff blocks across six orm/ pages (twelve led by 'For Prisma 7 users'), not sixteen across nine. ia.md: the Prisma 7 note box is on all four getting-started pages, /prisma-orm/create-prisma, /prisma-orm (titled 'Prisma 7'), /orm and /cli (titled 'Prisma 7 users'), not only the PostgreSQL pages. README.md: only audit/ still uses the wip/ citation prefixes. --- docs/orm-docs-audit/README.md | 4 ++-- docs/orm-docs-audit/changes.md | 20 +++++++++++--------- docs/orm-docs-audit/ia.md | 6 ++++-- docs/orm-docs-audit/journeys.md | 2 +- docs/orm-docs-audit/naming.md | 10 ++++++---- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md index b41a63e6f8..1081ba2e4d 100644 --- a/docs/orm-docs-audit/README.md +++ b/docs/orm-docs-audit/README.md @@ -2,7 +2,7 @@ Working documents behind the Prisma ORM 8 docs corrections (prisma/web #8236, #8237, #8238) and the proposed restructure. Written September 2026 against `@prisma/orm-postgres@8.0.0-rc.9`; source paths refer to the prisma/orm monorepo at that tag (`packages/`, `docs/releases/`, `examples/`, `skills/prisma-8/`) and to prisma/create-prisma. Site paths are relative to `apps/docs/content/docs/`. -Citations in `audit/`, `changes.md`, and the briefs use the worktree layout the audit was run in: `wip/prisma-src/` is prisma/orm (formerly prisma/prisma; the old name still redirects) at `v8.0.0-rc.9`, `wip/create-prisma-src/` is prisma/create-prisma, `wip/web/` is this repository, and `wip/docs-audit/` is this directory. Strip the prefix to get the path in the named repository. +Citations in `audit/` use the worktree layout the audit was run in: `wip/prisma-src/` is prisma/orm (formerly prisma/prisma; the old name still redirects) at `v8.0.0-rc.9`, `wip/create-prisma-src/` is prisma/create-prisma, and `wip/docs-audit/` is this directory. Strip the prefix to get the path in the named repository. Read in this order: @@ -14,6 +14,6 @@ Read in this order: 6. `naming.md` — the "Prisma ORM" naming rule. 7. `slice-corrections.md` — how the section B corrections were sliced, and the decisions taken. 8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). -9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. +9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. The audit is a snapshot of the site on 2026-09-10; the guides pages it flags as Prisma 7 content were rewritten for Prisma ORM 8 in #8242 on 2026-09-11. Prose is a draft throughout; the structure and the cited facts are what has been verified. diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 347e6b4cf7..448ba7770f 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -10,17 +10,19 @@ Status as of 2026-09-11. **Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -**In progress.** A7 (moving the sixteen Prisma 7 guides out of the Latest tree) is with Ankur. D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. +**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect; thirteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. + +**In progress.** D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. **Not started.** The naming pass, the restructure (A1 to A3, A5, A6, A8), every new page (C), and the rest of D. ## Recommended order for the open work -1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (691 occurrences in 109 files). Mechanical, one PR, done after A7 lands so the two do not conflict. +1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (679 occurrences in 109 files). Mechanical, one PR. A7 has landed (#8242), so nothing blocks it. 2. **C4, release status page.** Half a page; unblocks J4 (the reader who got upgraded by accident). Needs the GA window and the Prisma ORM 7 support policy from Will. 3. **C2, add Prisma ORM to an app you already started.** The J1 page and the complaint that started this work. One page, written from `mental-model.md`. 4. **C1, coming from Prisma 7.** The mapping table and the "not yet" list. Unblocks J3. -5. **C9, deployment.** The largest hole: zero Prisma ORM 8 coverage for any host, and the six pages A7 removes had been standing in for it. +5. **C9, deployment.** Was the largest hole; #8242 shipped Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces. What remains is what those pages do not cover (see C9). 6. **The restructure** (A1, A2, A3, A5, A6) as one piece of work, after the pages above exist to be organised. 7. **Everything else in C** as its dependency in D clears. @@ -42,11 +44,11 @@ Status as of 2026-09-11. The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These are the moves that tree implies. - **A1. Give the ORM its own front door, organised by starting state.** Replace the quickstart-versus-existing-project split with four doors on `/prisma-orm` and `/orm`: new app from scratch; app already started with an empty database; existing database with data; existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. -- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. +- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The fourteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. - **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. - **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. -- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** In progress (Ankur). `guides/frameworks/react-router-7`, `solid-start`, all of `guides/deployment/*`, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` are Prisma 7 end to end and have no copy under `guides/v7/`. Move with the same slugs and redirects; the Latest sidebar loses those labels until C9, C11, and C12 replace them. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Thirteen further pages stay in Latest with a "This guide uses Prisma 7" note; #8242 says which are blocked on third-party adapters and which are portable follow-ups. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. - **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. @@ -84,9 +86,9 @@ Grouped by where the page lives. Each says what the page is for, what it must co ### Guides -- **C9. Deploying Prisma ORM 8.** Zero coverage today for any host. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. -- **C11. CI.** `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. -- **C12. Switching from another ORM; team schema workflow.** Replaces the six Prisma 7 guides A7 removes. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. +- **C9. Deploying Prisma ORM 8.** Partly overtaken by #8242, which added Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces; re-scope against those pages before writing. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. +- **C11. CI.** #8242 rewrote `guides/integrations/github-actions.mdx` for Prisma ORM 8; check it against this before writing. `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. +- **C12. Switching from another ORM; team schema workflow.** #8242 rewrote the three `guides/switch-to-prisma-orm/*` and three `guides/database/*` pages for Prisma ORM 8; re-scope against them. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. - **C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, `supabase({ contractJson, url, jwksUrl | jwtSecret })`, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*`, and the `SUPABASE.*` errors. Source: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. ### Reference completeness @@ -142,7 +144,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ## Naming -The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR after A7. +The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR (A7 has landed, so nothing blocks it). ## Open questions diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index f0652d4328..2844c9898f 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -49,7 +49,7 @@ Upgrade Prisma ORM GitHub Actions, AI SDK, React Router 7, SolidStart ``` -The six Guides labels that leave come back as Prisma ORM 8 pages when C9 (deployment), C11 (CI), and C12 (switching, team workflow) are written. +The Prisma ORM 8 replacements for those labels sit at the same slugs; C9 (deployment), C11 (CI), and C12 (switching, team workflow) in `changes.md` say what they must cover. ### The ORM root page (`/orm`) @@ -162,6 +162,8 @@ Reference ### Guides (ORM-relevant parts) +Snapshot of 2026-09-10. On 2026-09-11, #8242 rewrote the Deployment, Database, Switch to Prisma ORM, GitHub Actions, AI SDK, React Router 7, and SolidStart pages for Prisma ORM 8 at the same slugs, moved their Prisma 7 versions (and Cloudflare D1) under `guides/v7`, and gave the overview an Upgrading section. + ``` Overview /guides says "Upgrading: moving from Prisma 7" is coming v7 @@ -180,5 +182,5 @@ Making guides ### Where Prisma 7 readers are pointed today - Root page: one line, "Here for the ORM? Jump straight to Prisma 7 or Prisma 8". -- A "Using Prisma 7?" note box on `/orm`, `/prisma-orm`, both PostgreSQL getting-started pages, and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. +- A note box ("Using Prisma 7?", "Prisma 7", or "Prisma 7 users") on `/orm`, `/prisma-orm`, `/prisma-orm/create-prisma`, all four getting-started pages (PostgreSQL and MongoDB), and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. - Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides, where the label is "PostgreSQL". diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md index ca47fac543..c4682668e7 100644 --- a/docs/orm-docs-audit/journeys.md +++ b/docs/orm-docs-audit/journeys.md @@ -34,7 +34,7 @@ Done: for every Prisma ORM 7 call in their code, they know the Prisma ORM 8 call What the docs must provide: one mapping page in four sections (schema and types, CLI commands, client API, not-yet list with a status per item), reachable from every ORM entry point. The not-yet list is the part readers ask for most: `createMany` and `skipDuplicates`, `findUniqueOrThrow`, atomic `increment`/`decrement`, case-insensitive filters, JSON path filters, `$transaction` arrays, the payload types. -Where the structure fails: there is no node. The mapping exists as sixteen inline "For Prisma 7 users" blocks across nine pages, so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. +Where the structure fails: there is no node. The mapping exists as fourteen inline diff blocks across six `orm/` pages (twelve of them introduced with "For Prisma 7 users"), so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. Verdict: **red**. IA node: "Coming from Prisma 7" (C1, placed by A2); the not-yet list depends on D4. diff --git a/docs/orm-docs-audit/naming.md b/docs/orm-docs-audit/naming.md index 2b67920647..c85cd0bead 100644 --- a/docs/orm-docs-audit/naming.md +++ b/docs/orm-docs-audit/naming.md @@ -24,12 +24,14 @@ One pass over the whole site, as its own PR. Not a global replace: each of the 1 ## Scope on the site (2026-09-10, outside the v6 and v7 trees) +Counted with `git grep -o` over the `.mdx` and `meta.json` files under `apps/docs/content/docs/`, excluding every `v6/` and `v7/` directory, on `main` as of 2026-09-10 (`684dcbf6`). + | Term | Occurrences | Files | | --- | --- | --- | -| "Prisma 8" | 691 | 109 | -| "Prisma 7" | 198 | 33 | -| "Prisma ORM" | 2816 | 95 | +| "Prisma 8" | 679 | 109 | +| "Prisma 7" | 135 | 33 | +| "Prisma ORM" | 487 | 95 | -By area: `orm/` 225, `guides/` 196, `(index)/` 135, `cli/` 81. 96 page titles or meta titles contain "Prisma 8". No sidebar label does; the labels come from titles. +By area: `orm/` 221, `guides/` 196, `(index)/` 131, `cli/` 77. 96 frontmatter titles contain "Prisma 8": 7 `title:` values, which are also the sidebar labels of those pages, and 89 `metaTitle:` values. No `meta.json` group title does. The common sentence shapes ("Add Prisma 8 to an ...", "Prisma 8 is the ...", "Prisma 8 app with ...", "Prisma 8 skills for ...") all take "Prisma ORM" as a drop-in replacement. The contrast sentences keep the number and add "ORM". From dc1ca337312516a531291aad8d106afc656448d5 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 16:28:50 +0200 Subject: [PATCH 08/28] docs: correct the Temporal-by-Node.js-version fact Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 448ba7770f..ef0458832d 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -8,21 +8,19 @@ Status as of 2026-09-11. ## Where things stand -**Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. +**Shipped.** Every correction to an existing page (section B, 35 items) went out in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist), #8237 (pages whose explanations were wrong), and #8238 (facts on the getting-started pages and guides). Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect; thirteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. - -**In progress.** D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. +**In progress.** A7 (moving the sixteen Prisma 7 guides out of the Latest tree) is with Ankur. D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. **Not started.** The naming pass, the restructure (A1 to A3, A5, A6, A8), every new page (C), and the rest of D. ## Recommended order for the open work -1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (679 occurrences in 109 files). Mechanical, one PR. A7 has landed (#8242), so nothing blocks it. +1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (691 occurrences in 109 files). Mechanical, one PR, done after A7 lands so the two do not conflict. 2. **C4, release status page.** Half a page; unblocks J4 (the reader who got upgraded by accident). Needs the GA window and the Prisma ORM 7 support policy from Will. 3. **C2, add Prisma ORM to an app you already started.** The J1 page and the complaint that started this work. One page, written from `mental-model.md`. 4. **C1, coming from Prisma 7.** The mapping table and the "not yet" list. Unblocks J3. -5. **C9, deployment.** Was the largest hole; #8242 shipped Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces. What remains is what those pages do not cover (see C9). +5. **C9, deployment.** The largest hole: zero Prisma ORM 8 coverage for any host, and the six pages A7 removes had been standing in for it. 6. **The restructure** (A1, A2, A3, A5, A6) as one piece of work, after the pages above exist to be organised. 7. **Everything else in C** as its dependency in D clears. @@ -44,17 +42,17 @@ Status as of 2026-09-11. The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These are the moves that tree implies. - **A1. Give the ORM its own front door, organised by starting state.** Replace the quickstart-versus-existing-project split with four doors on `/prisma-orm` and `/orm`: new app from scratch; app already started with an empty database; existing database with data; existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. -- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The fourteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. +- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. - **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. - **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. -- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Thirteen further pages stay in Latest with a "This guide uses Prisma 7" note; #8242 says which are blocked on third-party adapters and which are portable follow-ups. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** In progress (Ankur). `guides/frameworks/react-router-7`, `solid-start`, all of `guides/deployment/*`, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` are Prisma 7 end to end and have no copy under `guides/v7/`. Move with the same slugs and redirects; the Latest sidebar loses those labels until C9, C11, and C12 replace them. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. -- **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. +- **A4** (sidebar labels and the guides index) shipped in #8238. -## B. Corrections to existing pages (#8236 and #8237 merged; #8238 open) +## B. Corrections to existing pages (shipped) -Thirty-five items, all verified against rc.9 source, in #8236 and #8237 (merged) and #8238 (open as of 2026-09-11). What they fixed, in order of how many readers they hit: +Thirty-five items, all verified against rc.9 source and shipped in #8236, #8237, #8238. What they fixed, in order of how many readers they hit: | Theme | What was wrong | Items | |---|---|---| @@ -86,16 +84,16 @@ Grouped by where the page lives. Each says what the page is for, what it must co ### Guides -- **C9. Deploying Prisma ORM 8.** Partly overtaken by #8242, which added Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces; re-scope against those pages before writing. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. -- **C11. CI.** #8242 rewrote `guides/integrations/github-actions.mdx` for Prisma ORM 8; check it against this before writing. `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. -- **C12. Switching from another ORM; team schema workflow.** #8242 rewrote the three `guides/switch-to-prisma-orm/*` and three `guides/database/*` pages for Prisma ORM 8; re-scope against them. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. +- **C9. Deploying Prisma ORM 8.** Zero coverage today for any host. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. +- **C11. CI.** `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. +- **C12. Switching from another ORM; team schema workflow.** Replaces the six Prisma 7 guides A7 removes. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. - **C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, `supabase({ contractJson, url, jwksUrl | jwtSecret })`, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*`, and the `SUPABASE.*` errors. Source: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. ### Reference completeness - **C7. Advanced Postgres.** All of it ships and none of it is documented: RLS and policies in PSL and the TypeScript builder; expression and partial indexes (`@@index(expression:, where:, unique:, type:)`); `@@check`; `@noCheck`; `installExtension` / `createExtension` migration factories; `@@control` for how much of a table Prisma manages. Unblocks J8. Source: `skills/prisma-8/references/contract.md:101-108,265-367`, `packages/2-sql/2-authoring/contract-psl/README.md`. Waits on the product call about how to label these. - **C8. Money and Decimal.** Cents as integers (already there), `Numeric(p, s)` in type position, what `@default` accepts, `avgDecimal`, and that a decimal string avoids float loss while the declared scale still rounds. Answers an open Discord question. -- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on prisma/orm `main` (#30231 and #30236 merged 2026-09-10); publish when the first tagged release after rc.9 ships them. #30158 (reusable where filter types) is already in rc.9. Also what `contract.d.ts` already exports today. Unblocks J9. +- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch; publish when prisma/orm#30231, #30236, #30158 ship. Also what `contract.d.ts` already exports today. Unblocks J9. - **C13. Migration factory reference.** The site shows six factories; the `Migration` base class has about thirty (indexes, foreign keys, uniques, checks, column changes, native enums, `installExtension`, RLS and policies), plus free factories and the `node migration.ts --dry-run` / `--config` self-emit CLI. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. - **C14. PSL and TypeScript builder completeness.** A rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. The PSL page lacks native types in type position, the `@default` generator list, the `temporal.*` presets, scalar lists, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks, `native_enum`, `@relation("Name")`, `onDelete`/`onUpdate`, inline extension types, MongoDB index options, `.variant()`. The TypeScript page lacks most field helpers, composite keys (`.attributes()`), indexes and checks, `foreignKeyDefaults`, the `output` option, and the MongoDB builder's value objects, indexes, enums, vectors, and polymorphism. The full list is in `audit/contract.md` under Missing. Source: the two `contract-psl` and `contract-ts` READMEs. - **C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute`; `verifyMarker`; `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat `db.orm.User` accessor for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the `configure(meta)` callback and `meta.annotate(...)` (how cache opt-in works); `distinctOn`'s capability; MongoDB `mode` and the extra filter classes; the SQLite facade; the static client; `db.prepare`; `ctx.signal` and `MongoMiddleware`; `createInMemoryCacheStore`. Full list in `audit/orm-client.md` and `audit/builders.md` under Missing. @@ -124,7 +122,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ### Product decisions -- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work is merged: the where filter types (#30158) are in rc.9; `Models` and `Shape<>` (#30231, #30236) are on `main` awaiting a tagged release. +- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work (`Models`, `Shape<>`) is in PRs. - **D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Move the release candidate to `next` until GA, or state the policy on C4. ### create-prisma @@ -144,7 +142,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ## Naming -The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR (A7 has landed, so nothing blocks it). +The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR after A7. ## Open questions From 5ed9a9a26c4d45f6a6ddf2099bfa120f8b18aca8 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 16:29:39 +0200 Subject: [PATCH 09/28] docs: restore the change list's A7 and C6 updates; keep the Temporal correction The previous commit replaced the branch copy of changes.md with an older working copy and lost the notes that #8242 landed A7 by rewriting the guides rather than moving them. Restored, with only the Temporal wording changed on top. Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/brief-skill-staleness.md | 2 +- docs/orm-docs-audit/changes.md | 32 +++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/orm-docs-audit/brief-skill-staleness.md b/docs/orm-docs-audit/brief-skill-staleness.md index a93628008e..52641b656e 100644 --- a/docs/orm-docs-audit/brief-skill-staleness.md +++ b/docs/orm-docs-audit/brief-skill-staleness.md @@ -30,7 +30,7 @@ Line numbers are from the rc.9 tag. "Source" is the file that proves the correct 18. **Streaming.** `queries.md:146` says there is no streaming surface and recommends holding a `pg.Client`. The read terminals return an `AsyncIterableResult` you can `for await`; but on the long-lived `postgres()` facade the driver runs with cursors disabled, so the full result is fetched before iteration and only decoding is per row. The serverless facade (`@prisma/orm-postgres/serverless`) reads through a cursor in batches of 100. Say exactly that. Source: `packages/3-extensions/sql-orm-client/src/collection.ts:998-1022`, `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`, `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:39-53`, `postgres-serverless.ts:28-42`. 19. **`migration show` with no argument.** `migrations.md:189` runs it bare; the `` positional is required. Source: `cli/src/orm/migration/show.ts:3-6`. 20. **`--from` grammar.** `migration-model.md:67` lists `@contract | @db | @empty` for `migration plan --from`. The command is offline: only `@empty` resolves there (`@db` needs the live marker, `@contract` needs a contract hash the plan resolver does not pass). Source: `cli/src/control-api/operations/plan-resolution.ts:224-229`, `packages/1-framework/3-tooling/migration/src/refs/contract-ref.ts:39-56`. -21. **Node.js floor for Temporal.** Wherever the skill says Temporal-backed types need a polyfill "on Node", say: Node.js 26.8.2 and later ship `globalThis.Temporal`; 26.8.1 and earlier, including every 22 and 24, do not, so `temporal-polyfill/full/global` must be imported before the first read or the column authored as a `*String` type. Checked empirically on 22.22.3, 24.16.0, 26.8.1, 26.8.2. +21. **Node.js floor for Temporal.** Wherever the skill says Temporal-backed types need a polyfill "on Node", say: Node.js 26 and later ship `globalThis.Temporal` (Homebrew's Node.js 26 build omits it); 25 and earlier, including every 22 and 24, do not, so `temporal-polyfill/full/global` must be imported before the first read or the column authored as a `*String` type. Checked empirically on 22.22.3, 24.16.0, 25.8.0, 26.0.0, 26.8.1 (official and Homebrew), 26.8.2. Things the skill gets right that the site had wrong (keep them): `db.raw.sql` as the raw tag and whole-query raw SQL with `.returnsRow()` / `.affectedCount()` (`queries.md:143`, `queries-postgres.md:392, 415`); `extensions` not `extensionPacks` in `defineContract` (`contract.md:51, 386`); the five lint severity keys (`runtime.md`); `../../snapshots//contract.json` imports (`migrations.md:225, 253`); `db.close()` for teardown (`runtime.md:66-78`); the `prebuild` emit for Next.js (`build.md:466`). diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index ef0458832d..448ba7770f 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -8,19 +8,21 @@ Status as of 2026-09-11. ## Where things stand -**Shipped.** Every correction to an existing page (section B, 35 items) went out in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist), #8237 (pages whose explanations were wrong), and #8238 (facts on the getting-started pages and guides). Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. +**Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -**In progress.** A7 (moving the sixteen Prisma 7 guides out of the Latest tree) is with Ankur. D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. +**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect; thirteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. + +**In progress.** D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. **Not started.** The naming pass, the restructure (A1 to A3, A5, A6, A8), every new page (C), and the rest of D. ## Recommended order for the open work -1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (691 occurrences in 109 files). Mechanical, one PR, done after A7 lands so the two do not conflict. +1. **Naming pass**: "Prisma 8" to "Prisma ORM" everywhere (679 occurrences in 109 files). Mechanical, one PR. A7 has landed (#8242), so nothing blocks it. 2. **C4, release status page.** Half a page; unblocks J4 (the reader who got upgraded by accident). Needs the GA window and the Prisma ORM 7 support policy from Will. 3. **C2, add Prisma ORM to an app you already started.** The J1 page and the complaint that started this work. One page, written from `mental-model.md`. 4. **C1, coming from Prisma 7.** The mapping table and the "not yet" list. Unblocks J3. -5. **C9, deployment.** The largest hole: zero Prisma ORM 8 coverage for any host, and the six pages A7 removes had been standing in for it. +5. **C9, deployment.** Was the largest hole; #8242 shipped Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces. What remains is what those pages do not cover (see C9). 6. **The restructure** (A1, A2, A3, A5, A6) as one piece of work, after the pages above exist to be organised. 7. **Everything else in C** as its dependency in D clears. @@ -42,17 +44,17 @@ Status as of 2026-09-11. The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These are the moves that tree implies. - **A1. Give the ORM its own front door, organised by starting state.** Replace the quickstart-versus-existing-project split with four doors on `/prisma-orm` and `/orm`: new app from scratch; app already started with an empty database; existing database with data; existing Prisma 7 app. Each door is one page that carries the whole path. Today three of the four starting states share one page written for the third. Unblocks J1, J2, J5. -- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The sixteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. +- **A2. "Coming from Prisma 7" at the top level of the ORM sidebar**, linked from the root page, `/getting-started`, `/orm`, and reading-data. The fourteen inline diff blocks stay but point at it. Unblocks J3, J4. The page itself is C1. - **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. - **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. -- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** In progress (Ankur). `guides/frameworks/react-router-7`, `solid-start`, all of `guides/deployment/*`, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` are Prisma 7 end to end and have no copy under `guides/v7/`. Move with the same slugs and redirects; the Latest sidebar loses those labels until C9, C11, and C12 replace them. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Thirteen further pages stay in Latest with a "This guide uses Prisma 7" note; #8242 says which are blocked on third-party adapters and which are portable follow-ups. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. -- **A4** (sidebar labels and the guides index) shipped in #8238. +- **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. -## B. Corrections to existing pages (shipped) +## B. Corrections to existing pages (#8236 and #8237 merged; #8238 open) -Thirty-five items, all verified against rc.9 source and shipped in #8236, #8237, #8238. What they fixed, in order of how many readers they hit: +Thirty-five items, all verified against rc.9 source, in #8236 and #8237 (merged) and #8238 (open as of 2026-09-11). What they fixed, in order of how many readers they hit: | Theme | What was wrong | Items | |---|---|---| @@ -84,16 +86,16 @@ Grouped by where the page lives. Each says what the page is for, what it must co ### Guides -- **C9. Deploying Prisma ORM 8.** Zero coverage today for any host. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. -- **C11. CI.** `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. -- **C12. Switching from another ORM; team schema workflow.** Replaces the six Prisma 7 guides A7 removes. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. +- **C9. Deploying Prisma ORM 8.** Partly overtaken by #8242, which added Prisma ORM 8 guides for Docker, Cloudflare Workers, Turborepo, pnpm workspaces, and Bun workspaces; re-scope against those pages before writing. What a deploy needs: `prisma contract emit` as a `prebuild` step, `db migrate` (or `db init`) from the pipeline before the app starts, `db.close()` on shutdown, and for edge runtimes the per-request facade `@prisma/orm-postgres/serverless` (`postgresServerless({ contractJson })` at module scope, `await using runtime = await db.connect({ url })` per request). Sections or pages for Docker, Vercel, Cloudflare Workers, monorepos. The monorepo's `docs/Serverless Deployment Guide.md` is the source for the Cloudflare path (Hyperdrive, `nodejs_compat`, migrations against the origin URL never through Hyperdrive, one runtime per `connect()`, the 128 MiB isolate limit) and carries a production caveat with no site presence: against real Hyperdrive the serverless facade's default cursor path hangs (SQLSTATE 58000, request killed at 30 s); the workaround is `cursor: { disabled: true }`. Source: `skills/prisma-8/references/build.md:421-435`, `packages/3-extensions/postgres/README.md:41-60`, `docs/Serverless Deployment Guide.md:97,274`. +- **C11. CI.** #8242 rewrote `guides/integrations/github-actions.mdx` for Prisma ORM 8; check it against this before writing. `prisma migration status --to --db "$URL" --json`, fail the job on any `diagnostics[]` entry (the process exits 0 on warnings, so exit codes alone miss `MIGRATION.DIVERGED` and friends), then `prisma db migrate --to --db "$URL"`. Source: `skills/prisma-8/references/migration-review.md:172-197`. D16 would make this one line. +- **C12. Switching from another ORM; team schema workflow.** #8242 rewrote the three `guides/switch-to-prisma-orm/*` and three `guides/database/*` pages for Prisma ORM 8; re-scope against them. The brownfield flow (`orm init`, `contract infer`, review, `contract emit`, `db sign`, `db verify`) and the team loop (`migration plan`, refs, `db update` for local iteration, `db verify`, `migration status` in CI). Reuses C3 and C11. - **C10. Supabase and row level security.** The Supabase extension is one table row on the site. What ships: `@@rls` on a model, the five `policy_*` block kinds with `target` / `roles` / `using` / `withCheck`, the cross-space foreign key `supabase:auth.AuthUser`, `supabase({ contractJson, url, jwksUrl | jwtSecret })`, `db.asUser(jwt)` / `db.asAnon()` / `db.asServiceRole()`, the session-pooler requirement, the one-time `GRANT` for `auth.*`, and the `SUPABASE.*` errors. Source: `packages/9-public/@prisma/orm-extension-supabase/`, `skills/prisma-8/references/supabase.md`. ### Reference completeness - **C7. Advanced Postgres.** All of it ships and none of it is documented: RLS and policies in PSL and the TypeScript builder; expression and partial indexes (`@@index(expression:, where:, unique:, type:)`); `@@check`; `@noCheck`; `installExtension` / `createExtension` migration factories; `@@control` for how much of a table Prisma manages. Unblocks J8. Source: `skills/prisma-8/references/contract.md:101-108,265-367`, `packages/2-sql/2-authoring/contract-psl/README.md`. Waits on the product call about how to label these. - **C8. Money and Decimal.** Cents as integers (already there), `Numeric(p, s)` in type position, what `@default` accepts, `avgDecimal`, and that a decimal string avoids float loss while the declared scale still rounds. Answers an open Discord question. -- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on the PR branch; publish when prisma/orm#30231, #30236, #30158 ship. Also what `contract.d.ts` already exports today. Unblocks J9. +- **C6. Types.** Model, result, where, and input types with the Prisma 7 names beside each. Written from `docs/reference/model-and-result-types.md` on prisma/orm `main` (#30231 and #30236 merged 2026-09-10); publish when the first tagged release after rc.9 ships them. #30158 (reusable where filter types) is already in rc.9. Also what `contract.d.ts` already exports today. Unblocks J9. - **C13. Migration factory reference.** The site shows six factories; the `Migration` base class has about thirty (indexes, foreign keys, uniques, checks, column changes, native enums, `installExtension`, RLS and policies), plus free factories and the `node migration.ts --dry-run` / `--config` self-emit CLI. Source: `packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts:159-506`. - **C14. PSL and TypeScript builder completeness.** A rewrite of `psl-syntax.mdx` and `typescript-schema-builder.mdx` large enough to plan as one. The PSL page lacks native types in type position, the `@default` generator list, the `temporal.*` presets, scalar lists, `@@unique`, `@@index` options, `@@check`, `@noCheck`, `@@control`, `namespace` blocks, `native_enum`, `@relation("Name")`, `onDelete`/`onUpdate`, inline extension types, MongoDB index options, `.variant()`. The TypeScript page lacks most field helpers, composite keys (`.attributes()`), indexes and checks, `foreignKeyDefaults`, the `output` option, and the MongoDB builder's value objects, indexes, enums, vectors, and polymorphism. The full list is in `audit/contract.md` under Missing. Source: the two `contract-psl` and `contract-ts` READMEs. - **C15. Runtime reference completeness.** Additions to `transactions-and-runtime.mdx` and `orm-client.mdx`: `query` vs `execute`; `verifyMarker`; `binding`; `db.raw`, `db.nativeEnums`, `db.context`, `db.contract`, `db.stack`; the flat `db.orm.User` accessor for single-namespace contracts; `AsyncIterableResult.first()` / `.firstOrThrow()`; the `configure(meta)` callback and `meta.annotate(...)` (how cache opt-in works); `distinctOn`'s capability; MongoDB `mode` and the extra filter classes; the SQLite facade; the static client; `db.prepare`; `ctx.signal` and `MongoMiddleware`; `createInMemoryCacheStore`. Full list in `audit/orm-client.md` and `audit/builders.md` under Missing. @@ -122,7 +124,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ### Product decisions -- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work (`Models`, `Shape<>`) is in PRs. +- **D4. Missing client API.** Verified absent: `firstOrThrow` on the collection (it exists on the result, so `.all().firstOrThrow()` works), atomic `increment`/`decrement`, case-insensitive string filters, insert with on-conflict-do-nothing (`skipDuplicates`), JSON path or containment filters (the `jsonb` codec has only the `equality` trait). Also not supported: soft delete, validations, lifecycle callbacks, custom `Collection` subclasses, read replicas, MongoDB referential actions. Each needs a decision: build it, or document the workaround and say it is not planned. The types work is merged: the where filter types (#30158) are in rc.9; `Models` and `Shape<>` (#30231, #30236) are on `main` awaiting a tagged release. - **D6. The npm `latest` tag.** `prisma@latest` is 8.0.0-rc.13 while `@prisma/client@latest` is 7.10.0, so a Prisma 7 project's routine `npx prisma` picks up the 8 CLI against a 7 client. Move the release candidate to `next` until GA, or state the policy on C4. ### create-prisma @@ -142,7 +144,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. ## Naming -The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR after A7. +The product is "Prisma ORM". A version number appears only when two versions are contrasted ("Prisma ORM 7 to 8"). Never "Prisma 8" as a product name. Rule, counts, and exceptions in `naming.md`. Applies to every item above and to the proposed nodes in `ia.md`. Not started; planned as its own PR (A7 has landed, so nothing blocks it). ## Open questions From b46e8988e14dc370579d8e19c45dd7768774a878 Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 16:29:55 +0200 Subject: [PATCH 10/28] docs: Temporal ships in Node.js 26; the polyfill is for 25 and earlier Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 448ba7770f..d43d02a0d3 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -119,7 +119,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. - **D8. Streaming does not stream on `postgres()`.** The facade creates its driver with `cursor: { disabled: true }`, so `for await` iterates an already-fetched result; only the serverless facade exposes cursor batches. Measured: breaking after the first row of a 400,000-row table still grew the heap by 64 MB. Expose `cursor` on `postgres()` or keep the docs' new wording. Source: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`. - **D12. Permissive mode is unreachable on Postgres.** `postgres()` never forwards `mode`, so every "warn in permissive mode" branch in lints and budgets is dead on Postgres; only `mongo()` accepts it. Expose it or remove the branches. Source: `postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. - **D7. `db.connect()` vs `db.runtime()`, `db.close()` vs `db.runtime().close()`.** Two names for adjacent things, a Mongo-only `await`, and `db.prepare` then `db.connect()` throwing `DRIVER.ALREADY_CONNECTED`. One call on both targets would simplify every page that shows a script. -- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js before 26.8.2 every read throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported. `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. +- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js 25 and earlier every read throws (official Node.js 26 ships `globalThis.Temporal`; Homebrew's Node.js 26 build omits it) `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported. `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. - **D5. `contract infer` on Prisma 7 databases.** Users report inferred contracts that fail to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether rc.9 still emits removed syntax and whether `Decimal @default(0.00)` is a bug. See D10. ### Product decisions From f4266e719ce69067a7ffae7383cdc2234a3e182e Mon Sep 17 00:00:00 2001 From: "reviewer (Program)" Date: Fri, 11 Sep 2026 14:53:33 +0000 Subject: [PATCH 11/28] docs: reconcile the audit's counts with the tree and the same PR's Temporal fact ia.md still said the Prisma 7 mapping was spread over nine pages after journeys.md was corrected to fourteen diff blocks on six orm/ pages; naming.md's prisma-next count (40) only reproduces with the v6/v7 trees included, the stated corpus gives 39. changes.md counted thirteen pages kept with the 'This guide uses Prisma 7' note, from the #8242 description; the tree on main has fourteen, and the two Accelerate integration guides moved to guides/v7 alongside Cloudflare D1. slice-corrections.md carried pre-merge PR sizes and said A7 was still with Ankur. audit/start-guides.md said no stable Node ships Temporal, which brief-skill-staleness.md and D10 in the same PR now contradict; Node.js 26 does. D10's parenthetical was moved so it no longer splits 'throws' from the error code. --- docs/orm-docs-audit/audit/start-guides.md | 2 +- docs/orm-docs-audit/changes.md | 6 +++--- docs/orm-docs-audit/ia.md | 2 +- docs/orm-docs-audit/naming.md | 2 +- docs/orm-docs-audit/slice-corrections.md | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/orm-docs-audit/audit/start-guides.md b/docs/orm-docs-audit/audit/start-guides.md index 7c3dfa0291..9732217a85 100644 --- a/docs/orm-docs-audit/audit/start-guides.md +++ b/docs/orm-docs-audit/audit/start-guides.md @@ -32,7 +32,7 @@ Monorepo paths below are relative to `wip/prisma-src/` unless they start with `w ## Missing -- Temporal requirement for inferred contracts — `contract infer` maps `timestamp`/`timestamptz` columns to `Timestamp`/`Timestamptz`, which are Temporal-backed; on a runtime without a global `Temporal` (no stable Node ships one) every read of such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported first or the type is changed to `TimestamptzString`. create-prisma installs the polyfill for this reason; `orm init` does not. Neither existing-project page nor the Prisma 7 upgrade guide (whose real-world schemas have `DateTime` columns) mentions it — evidence: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`, `packages/3-targets/3-targets/postgres/src/core/errors.ts:74-86`, `skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md:38-47`, `wip/create-prisma-src/src/constants/dependencies.ts:21-23`, `wip/create-prisma-src/templates/create/_shared/src/prisma/db.ts.hbs:15` — belongs on `add-to-existing-project/postgresql.mdx` step 4 and `guides/upgrade-prisma-orm/postgresql.mdx` section 2.4 +- Temporal requirement for inferred contracts — `contract infer` maps `timestamp`/`timestamptz` columns to `Timestamp`/`Timestamptz`, which are Temporal-backed; on a runtime without a global `Temporal` (Node.js 25 and earlier ship none; 26 does) every read of such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported first or the type is changed to `TimestamptzString`. create-prisma installs the polyfill for this reason; `orm init` does not. Neither existing-project page nor the Prisma 7 upgrade guide (whose real-world schemas have `DateTime` columns) mentions it — evidence: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`, `packages/3-targets/3-targets/postgres/src/core/errors.ts:74-86`, `skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md:38-47`, `wip/create-prisma-src/src/constants/dependencies.ts:21-23`, `wip/create-prisma-src/templates/create/_shared/src/prisma/db.ts.hbs:15` — belongs on `add-to-existing-project/postgresql.mdx` step 4 and `guides/upgrade-prisma-orm/postgresql.mdx` section 2.4 - `create-prisma --json` — non-interactive machine-readable mode for agents; not in the flag table — evidence: `wip/create-prisma-src/src/index.ts:73-76`, `wip/create-prisma-src/README.md:66-81` — belongs in the `create-prisma.mdx` flag table and the agent prompts on `getting-started.mdx` / `index.mdx` - The full set of generated package scripts — the scaffold adds `db:update`, `db:verify`, `migration:status`, `migration:show`, `skills:sync`, `composer:dev`, `composer:deploy`, and `deploy` alongside the four the site mentions — evidence: `wip/create-prisma-src/src/tasks/install.ts:47-70` — belongs in `create-prisma.mdx` "Start the app" - `orm init` flags — `--schema-path`, `--write-env`, `--probe-db`, `--strict-probe`, `--skip-install`, `--keep-previous-facade`, plus `--confirm ` for re-running init in an already scaffolded directory — evidence: `packages/1-framework/3-tooling/cli/src/orm/init.ts:87-112`, `packages/1-framework/3-tooling/cli/src/orm/init-inputs.ts:218-227` — `--write-env` and `--schema-path` belong on both add-to-existing-project pages, which currently rely on the defaults they describe wrongly diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index d43d02a0d3..ef1fe3f717 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -10,7 +10,7 @@ Status as of 2026-09-11. **Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect; thirteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. +**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect (the Neon and Supabase Accelerate guides moved with it); fourteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. **In progress.** D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. @@ -48,7 +48,7 @@ The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These a - **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. - **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. -- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Thirteen further pages stay in Latest with a "This guide uses Prisma 7" note; #8242 says which are blocked on third-party adapters and which are portable follow-ups. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Fourteen further pages stay in Latest with a "This guide uses Prisma 7" note (the #8242 description counts thirteen; the tree has fourteen); #8242 says which are blocked on third-party adapters and which are portable follow-ups. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. - **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. @@ -119,7 +119,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. - **D8. Streaming does not stream on `postgres()`.** The facade creates its driver with `cursor: { disabled: true }`, so `for await` iterates an already-fetched result; only the serverless facade exposes cursor batches. Measured: breaking after the first row of a 400,000-row table still grew the heap by 64 MB. Expose `cursor` on `postgres()` or keep the docs' new wording. Source: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`. - **D12. Permissive mode is unreachable on Postgres.** `postgres()` never forwards `mode`, so every "warn in permissive mode" branch in lints and budgets is dead on Postgres; only `mongo()` accepts it. Expose it or remove the branches. Source: `postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. - **D7. `db.connect()` vs `db.runtime()`, `db.close()` vs `db.runtime().close()`.** Two names for adjacent things, a Mongo-only `await`, and `db.prepare` then `db.connect()` throwing `DRIVER.ALREADY_CONNECTED`. One call on both targets would simplify every page that shows a script. -- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js 25 and earlier every read throws (official Node.js 26 ships `globalThis.Temporal`; Homebrew's Node.js 26 build omits it) `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported. `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. +- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js 25 and earlier every read throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported (official Node.js 26 ships `globalThis.Temporal`; Homebrew's Node.js 26 build omits it). `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. - **D5. `contract infer` on Prisma 7 databases.** Users report inferred contracts that fail to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether rc.9 still emits removed syntax and whether `Decimal @default(0.00)` is a bug. See D10. ### Product decisions diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index 2844c9898f..884d509638 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -96,7 +96,7 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | --- | --- | --- | | J1 existing app, empty database | Add to Existing Project > PostgreSQL | page assumes tables exist; no node for this state | | J2 existing database with data | Add to Existing Project > PostgreSQL | right node, page stops before the ref step | -| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; content spread over nine pages | +| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; fourteen diff blocks spread over six pages | | J4 should I move now | root, `/prisma-orm` | no node; note box only says 7 is supported | | J5 incremental upgrade | Guides > Upgrade Prisma ORM > PostgreSQL | not linked from any ORM node; label hides it | | J6 data types | Data Modeling > Overview | right node; one stale example | diff --git a/docs/orm-docs-audit/naming.md b/docs/orm-docs-audit/naming.md index c85cd0bead..c288bf19c8 100644 --- a/docs/orm-docs-audit/naming.md +++ b/docs/orm-docs-audit/naming.md @@ -18,7 +18,7 @@ One pass over the whole site, as its own PR. Not a global replace: each of the 1 ## What stays as is -- Identifiers: `prisma-next.md`, `// use prisma-next`, `@prisma/orm-postgres`, `/studio/prisma-next`, package names, error codes. 40 occurrences of `prisma-next` as an identifier; none as prose. +- Identifiers: `prisma-next.md`, `// use prisma-next`, `@prisma/orm-postgres`, `/studio/prisma-next`, package names, error codes. 39 occurrences of `prisma-next` as an identifier; none as prose. - The "Prisma 7" group at the bottom of Getting Started and the v7 doc trees. - Release notes and changelogs, which name versions by nature. diff --git a/docs/orm-docs-audit/slice-corrections.md b/docs/orm-docs-audit/slice-corrections.md index a439e4b7bf..b283c636cb 100644 --- a/docs/orm-docs-audit/slice-corrections.md +++ b/docs/orm-docs-audit/slice-corrections.md @@ -4,11 +4,11 @@ Before any restructure, every factual error on the published Prisma ORM 8 pages | PR | What | Size | |---|---|---| -| #8236 | Names, flags, paths, codes, and printed output that no longer exist at rc.9, replaced by the form that does | 12 commits, 39 files | -| #8237 | Pages whose explanations were wrong (the `db` ref, middleware, raw SQL, relations, aggregates, the existing-project pages) | 12 commits, 30 files | -| #8238 | Facts on the getting-started pages and guides (Node floor, MongoDB replica set, create-prisma flags and scripts, the skills page, the tutorial, streaming, `npm create prisma@latest`) | 18 commits, 40 files | +| #8236 | Names, flags, paths, codes, and printed output that no longer exist at rc.9, replaced by the form that does | 40 files, merged 2026-09-10 | +| #8237 | Pages whose explanations were wrong (the `db` ref, middleware, raw SQL, relations, aggregates, the existing-project pages) | 31 files, merged 2026-09-11 | +| #8238 | Facts on the getting-started pages and guides (Node floor, MongoDB replica set, create-prisma flags and scripts, the skills page, the tutorial, streaming, `npm create prisma@latest`) | 32 files, open as of 2026-09-11 | -Out of scope by design: the sixteen Prisma 7 guides under Prisma ORM 8 paths (A7, now with Ankur), new content (C), the agent skill (D14), the monorepo docs (D17), and the "Prisma 8" to "Prisma ORM" rename. +Out of scope by design: the sixteen Prisma 7 guides under Prisma ORM 8 paths (A7, since landed as #8242), new content (C), the agent skill (D14), the monorepo docs (D17), and the "Prisma 8" to "Prisma ORM" rename. ## Four decisions taken along the way From 5dce14b6ad0a80da6709020e3effaef30892cd16 Mon Sep 17 00:00:00 2001 From: "reviewer (Program)" Date: Fri, 11 Sep 2026 15:09:03 +0000 Subject: [PATCH 12/28] docs: mark the audit's overruled streaming claim and fix the upgrade-guide label and A4 facts - audit/extras.md: Missing item 9 and the skill-vs-site bullet concluded streaming on postgres() is cursor-backed; orm-client.md, slice-corrections decision 3 (measured) and D8 say the facade disables the cursor. Note the overruling in place instead of leaving the two audit files contradicting. - ia.md: the PostgreSQL upgrade guide's sidebar label on main is its title, "Migrate from Prisma 7 to Prisma 8", not "PostgreSQL"; only the MongoDB twin is labelled by database name. Corrected the proposal, the why table, the current-state tree and the pointer list; added the '-' legend entry. - changes.md A4: the label changes are in #8238; the guides index part (Upgrading section replacing the coming-as-they-land list) landed in #8242. - audit/gaps.md: create-prisma dependencies.ts citation is lines 8-10 at 0.11.7, matching D11 and start-guides.md. --- docs/orm-docs-audit/audit/extras.md | 6 +++--- docs/orm-docs-audit/audit/gaps.md | 2 +- docs/orm-docs-audit/changes.md | 2 +- docs/orm-docs-audit/ia.md | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/orm-docs-audit/audit/extras.md b/docs/orm-docs-audit/audit/extras.md index 1aeeb54ed2..9acb7d2303 100644 --- a/docs/orm-docs-audit/audit/extras.md +++ b/docs/orm-docs-audit/audit/extras.md @@ -32,7 +32,7 @@ Ranked by how likely a user is to need it, most likely first. Items marked (know 6. `Decimal` (known) — PSL `Decimal` maps to Postgres `numeric` with optional `precision` (1..1000) and `scale` params; runtime value is a decimal string (`CANONICAL_NUMERIC_TEXT`); `@default` accepts numeric text; aggregates: `sum` over `numeric` returns a decimal `string | null`, `avgDecimal(field)` gives an exact decimal string, `sumBigInt` / `countBigInt` for integers, and `count()` / `sum` over integers throw `RUNTIME.DECODE_FAILED` past 2^53-1 — evidence: `packages/3-targets/3-targets/postgres/src/core/codecs.ts:121-175,547`; `codec-type-map.ts:73`; `default-normalizer.ts:18,221`; `psl-infer/infer-enum-blocks.ts:19`; `skills/prisma-8/references/queries-postgres.md:233-255,386,407` — `orm/data-modeling/index.mdx:152-160` omits `Decimal` from the scalar table and `:182` says to store money as integer minor units; nothing documents `avgDecimal` / `sumBigInt` / the overflow error — belongs on `orm/data-modeling/index.mdx` and `orm/fundamentals/advanced-queries.mdx` (aggregates). 7. SQLite target (known) — `@prisma/orm-sqlite` ships at rc.9 with `sqlite(...)` runtime, `[Symbol.asyncDispose]`, and its own capability limits (no `checkConstraint`, no `scalarList`, no `enums`, no `lateral`, no `avgDecimal`); the skill routes to it throughout — evidence: `packages/9-public/@prisma/orm-sqlite/package.json`; `packages/3-extensions/sqlite/src/runtime/sqlite.ts:85,354`; `skills/prisma-8/references/runtime.md:333`, `queries-postgres.md:255`, `contract.md` (`@@check` on SQLite) — site mentions are only `orm/reference/error-reference.mdx:598`, `cli/skills.mdx:38` and capability examples in `orm/contract-authoring/capabilities.mdx:46-70`; there is no getting-started, quickstart, or runtime section for SQLite — belongs in `(index)/prisma-orm/quickstart/`, `orm/reference/transactions-and-runtime.mdx`, `orm/index.mdx`. 8. Enabling a Postgres extension that has no pack (`pg_trgm`, `citext`, …) (known) — the migration authoring API has a structured `createExtension('')` op (renders `CREATE EXTENSION IF NOT EXISTS`), so a user can add it to a hand-written or edited `migration.ts`; there is no contract-level "requires extension" declaration, and no `pg_trgm` pack ships even though `docs/reference/capabilities.md:97-103` reserves a `pg_trgm` capability namespace — evidence: `packages/3-targets/3-targets/postgres/src/core/migrations/op-factory-call.ts:1443-1465` (`CreateExtensionCall`, `renderTypeScript` → `createExtension("...")`); `migrations/operations/dependencies.ts:7-22`; `packages/3-extensions/` has no `pg_trgm` — the site only mentions `CREATE EXTENSION` for packs that ship their own migration (`orm/extensions/using-extensions.mdx:76`) — belongs on `orm/migrations/editing-a-migration.mdx`. -9. Streaming is cursor-backed on Postgres — the site documents `for await` over `.all()` (`orm/fundamentals/reading-data.mdx:280-313`) but never says the Postgres driver reads through a server-side cursor in batches (`pg-cursor`, `cursorBatchSize`) nor that the serverless client takes `cursor` options; the skill wrongly says "No `.stream()` cursor today" — evidence: `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:24,374-384`, `named-cursor.ts`; `packages/3-extensions/postgres/src/runtime/postgres-serverless.ts:31` (`PostgresServerlessCursorOptions`); `packages/2-sql/5-runtime/src/sql-runtime.ts:387-399` — belongs on `orm/fundamentals/reading-data.mdx` and `orm/reference/transactions-and-runtime.mdx`. +9. Streaming is cursor-backed on Postgres — the site documents `for await` over `.all()` (`orm/fundamentals/reading-data.mdx:280-313`) but never says the Postgres driver reads through a server-side cursor in batches (`pg-cursor`, `cursorBatchSize`) nor that the serverless client takes `cursor` options; the skill wrongly says "No `.stream()` cursor today" — evidence: `packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:24,374-384`, `named-cursor.ts`; `packages/3-extensions/postgres/src/runtime/postgres-serverless.ts:31` (`PostgresServerlessCursorOptions`); `packages/2-sql/5-runtime/src/sql-runtime.ts:387-399` — belongs on `orm/fundamentals/reading-data.mdx` and `orm/reference/transactions-and-runtime.mdx`. Overruled: the driver has the cursor, but the `postgres()` facade constructs it with `cursor: { disabled: true }`, so on the long-lived client the whole result is fetched before iteration; only the serverless facade reads through a cursor. See `orm-client.md` (Misleading, first bullet), `slice-corrections.md` decision 3 (measured), and D8 in `changes.md`. 10. `create-prisma` flags used by the tutorial — the tutorial uses `create ... --template hono --provider postgres --yes`, and `--authoring`, `--package-manager`, `--deploy`, `--workspace`, `--force`, `--json`, `--verbose` also exist; the tutorial says "Answer the prompts for contract authoring style and package manager" without naming the flags that skip them — evidence: `wip/create-prisma-src/src/index.ts:39-86` — belongs on `(index)/full-stack-tutorial.mdx:45` (one line) and `(index)/prisma-orm/create-prisma.mdx`. ## Unverified @@ -45,7 +45,7 @@ Ranked by how likely a user is to need it, most likely first. Items marked (know ## Skill vs site -- `skills/prisma-8/references/queries.md:146` says "Streaming large result sets. No `.stream()` cursor today" and recommends holding a `pg.Client` to stream; the site (`orm/fundamentals/reading-data.mdx:280-313`) says `for await` over `.all()` streams without buffering. The source matches the site: `collection.ts:998-1022` exposes the async-iterable read terminal and the Postgres driver iterates via `pg-cursor` (`packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:374-384`). The skill is stale. +- `skills/prisma-8/references/queries.md:146` says "Streaming large result sets. No `.stream()` cursor today" and recommends holding a `pg.Client` to stream; the site (`orm/fundamentals/reading-data.mdx:280-313`) says `for await` over `.all()` streams without buffering. The source matches the site: `collection.ts:998-1022` exposes the async-iterable read terminal and the Postgres driver iterates via `pg-cursor` (`packages/3-targets/7-drivers/postgres/src/postgres-driver.ts:374-384`). The skill is stale. Overruled on the memory claim: `postgres()` disables the driver cursor (`packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`), so the result is buffered before `for await` starts; the skill is closer to the truth there. See `orm-client.md` and `slice-corrections.md` decision 3; the reading-data page was corrected in #8238. - `skills/prisma-8/references/runtime.md:11,135-158,315,322` tells users to import `createTelemetryMiddleware` from `@internal/middleware-telemetry`; no such package exists in the rc.9 tree (only comments and old plan docs mention it). The site's "Three middleware ship with Prisma 8 today" (`orm/middleware/how-middleware-works.mdx:82`: lints, budgets, cache) matches the source (`packages/2-sql/5-runtime/src/middleware/{lints,budgets}.ts`, `packages/3-extensions/middleware-cache/`). The skill is stale; also `runtime.md` never mentions the cache middleware the site documents. - `skills/prisma-8/references/contract.md:25,29,49` uses `cipherstash.EncryptedString(...)` as a canonical extension example; no cipherstash package exists in the rc.9 tree (`wip/prisma-src/CHANGELOG.md:1040` records `@prisma-next/extension-cipherstash` being dropped in favour of CipherStash's own `@cipherstash/prisma-next`, `README.md:82`). The site does not mention cipherstash, which is correct. - `skills/prisma-8/references/contract.md:179` writes `pgvector.Vector(length: 1536)`; the site (`orm/extensions/using-extensions.mdx`) and `examples/prisma-8-demo/src/prisma/contract.prisma:4` use positional `pgvector.Vector(1536)`. The examples compile against rc.9, so the site matches. @@ -65,7 +65,7 @@ Each item: is it supported at rc.9, where the evidence is, and whether the ORM 8 - SQLite target — ships (Missing item 7). Site: `orm/index.mdx:36` still says planned (known); no runtime or quickstart coverage. - Vite plugin — ships (Missing item 5). Site: none. - `@@control` policies — supported (Missing item 4). Site: none. -- Streaming — supported and documented; the cursor mechanics are not (Missing item 9). +- Streaming — `for await` is supported and documented, but on `postgres()` it does not stream: the facade disables the driver cursor and the result is buffered first (Missing item 9, overruled note; `slice-corrections.md` decision 3). ### Supported and documented diff --git a/docs/orm-docs-audit/audit/gaps.md b/docs/orm-docs-audit/audit/gaps.md index dff1ea2ff6..f4815723ff 100644 --- a/docs/orm-docs-audit/audit/gaps.md +++ b/docs/orm-docs-audit/audit/gaps.md @@ -55,7 +55,7 @@ Ten of the twenty-one pages in this area are Prisma ORM 7 content sitting under - `guides/runtimes/deno.mdx:29,65` — `npx create-db@latest --env .env --ttl 24h` — the `create-db` source is not in the worktree; flags not checked. - `guides/runtimes/deno.mdx:17` "Deno 2.0 or later" and `guides/frameworks/elysia.mdx:17` "Bun 1.1 or later" — no engine constraint for Deno or Bun in `create-prisma-src` or `prisma-src`. - `orm/contract-authoring/psl-syntax.mdx:39` and the framework guides' starter contract — the site writes `createdAt DateTime` while the rc.9 starter contract writes `createdAt TimestamptzString @default(now())` (`code-templates.ts:180`); I could not find the PSL scalar-name table in `packages/2-sql/2-authoring/contract-psl/src` by grep (`'DateTime'` and `TimestamptzString` have no hits there), so whether `DateTime` still parses is not confirmed. Another area owns `psl-syntax.mdx`. -- The scaffold pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` (`create-prisma-src/src/constants/dependencies.ts:9-11`, "Must match @prisma/composer-prisma-cloud's exact peerDependency") while this audit is against rc.9; whether the published `create-prisma@latest` has moved could not be checked offline. Any rc.9-only behaviour the framework pages describe would not hold on a fresh scaffold until it does. +- The scaffold pins `@prisma/orm-postgres` and `@prisma/orm-mongo` to `8.0.0-rc.8` (`create-prisma-src/src/constants/dependencies.ts:8-10`, "Must match @prisma/composer-prisma-cloud's exact peerDependency") while this audit is against rc.9; whether the published `create-prisma@latest` has moved could not be checked offline. Any rc.9-only behaviour the framework pages describe would not hold on a fresh scaffold until it does. ## Skill vs site diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index ef1fe3f717..0df707144f 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -50,7 +50,7 @@ The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These a - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. - **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Fourteen further pages stay in Latest with a "This guide uses Prisma 7" note (the #8242 description counts thirteen; the tree has fourteen); #8242 says which are blocked on third-party adapters and which are portable follow-ups. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. -- **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. +- **A4** (sidebar labels and the guides index). The two upgrade-guide labels ("Prisma 7 to 8 (PostgreSQL)", "Prisma 6 to 8 (MongoDB)") are in #8238, open as of 2026-09-11. The guides index part landed in #8242, which replaced the "Coming as they land" list with an Upgrading section linking both guides. ## B. Corrections to existing pages (#8236 and #8237 merged; #8238 open) diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index 884d509638..b90a783a0d 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -4,7 +4,7 @@ Proposal first, then why, then the current state it changes. Source: the `meta.j ## Proposed -Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. +Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, `-` is content leaving the tree, unmarked is unchanged. ### Getting Started > Prisma ORM @@ -42,7 +42,7 @@ Introduction ``` Overview no "coming soon" line for upgrading; it exists Upgrade Prisma ORM - ~ Prisma 7 to 8 (PostgreSQL) was "PostgreSQL" + ~ Prisma 7 to 8 (PostgreSQL) was "Migrate from Prisma 7 to Prisma 8" ~ Prisma 6 to 8 (MongoDB) was "MongoDB" v7, v6, v5, v4, v3, v1 - Deployment, Database, Switch to Prisma ORM, Prisma 7 content; lives under guides/v7 @@ -98,7 +98,7 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | J2 existing database with data | Add to Existing Project > PostgreSQL | right node, page stops before the ref step | | J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; fourteen diff blocks spread over six pages | | J4 should I move now | root, `/prisma-orm` | no node; note box only says 7 is supported | -| J5 incremental upgrade | Guides > Upgrade Prisma ORM > PostgreSQL | not linked from any ORM node; label hides it | +| J5 incremental upgrade | Guides > Upgrade Prisma ORM > Migrate from Prisma 7 to Prisma 8 | not linked from any ORM node; three levels down, and the MongoDB twin is labelled only "MongoDB" | | J6 data types | Data Modeling > Overview | right node; one stale example | | J7 editor setup | none | no node | | J8 advanced Postgres | none | no node; needs product answers | @@ -109,7 +109,7 @@ Two observations follow from the table. First, the Getting Started > Prisma ORM subtree is organised by the tool that runs (`create-prisma` for Quickstart, `orm init` for Add to Existing Project) and then by database. The reader does not know those tools yet. The failures in J1 and J2 both happen at the point where the reader's situation differs from the page's assumption about it. The reader knows their situation: do I have an app, do I have a database, does it have data, was it Prisma 7. That is why I proposed organising this subtree by starting state. The database split (PostgreSQL / MongoDB) stays inside each. -Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides with a database name as its label. +Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides, three levels down, and its MongoDB twin carries only a database name as its label. ## Current state @@ -173,7 +173,7 @@ Deployment, Authentication, Integrations, Postgres Database (Expand-and-contract migrations, Multiple databases, Schema management in teams) Switch to Prisma ORM, Switch to Prisma Postgres Upgrade Prisma ORM - PostgreSQL /guides/upgrade-prisma-orm/postgresql title: "Migrate from Prisma 7 to Prisma 8" + Migrate from Prisma 7 to Prisma 8 /guides/upgrade-prisma-orm/postgresql Prisma 7 to 8 MongoDB /guides/upgrade-prisma-orm/mongodb v6 Mongo to 8 v7, v6, v5, v4, v3, v1 older version-to-version guides Making guides @@ -183,4 +183,4 @@ Making guides - Root page: one line, "Here for the ORM? Jump straight to Prisma 7 or Prisma 8". - A note box ("Using Prisma 7?", "Prisma 7", or "Prisma 7 users") on `/orm`, `/prisma-orm`, `/prisma-orm/create-prisma`, all four getting-started pages (PostgreSQL and MongoDB), and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. -- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides, where the label is "PostgreSQL". +- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides > Upgrade Prisma ORM, where the PostgreSQL page is labelled "Migrate from Prisma 7 to Prisma 8" and the MongoDB page just "MongoDB" (#8238 relabels both). From df980a34cc338fafdc3695d5530126e93e42ea9c Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 18:09:41 +0200 Subject: [PATCH 13/28] docs: the release status facts are decided; drop the C4 decision row Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 0df707144f..8be8185247 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -10,7 +10,7 @@ Status as of 2026-09-11. **Shipped, or nearly.** Every correction to an existing page (section B, 35 items) is in three PRs: prisma/web #8236 (API names, flags, and paths that no longer exist) and #8237 (pages whose explanations were wrong) are merged; #8238 (facts on the getting-started pages and guides) is open as of 2026-09-11. Each commit cites the source line it was verified against. Section B below is a summary of what changed; the details are in the PRs. -**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect (the Neon and Supabase Accelerate guides moved with it); fourteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. +**Landed since the audit.** A7 shipped as prisma/web #8242 (merged 2026-09-11), in a different shape from the move proposed below: fifteen of the sixteen Prisma 7 guides were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only, with a redirect; thirteen other pages (authentication, some integrations, some Prisma Postgres guides) stay in the Latest tree with a "This guide uses Prisma 7" note. C9, C11, and C12 need re-scoping against the pages #8242 added. **In progress.** D1 (adoption sets the `db` ref) and D3 (a skills opt-out in create-prisma) have briefs and are with ORM-side agents. D14 (the agent skill) has a brief ready to hand over. @@ -30,7 +30,6 @@ Status as of 2026-09-11. | Item | Decision | Who | |---|---|---| -| C4 | GA window to state publicly; Prisma ORM 7 support policy | Will | | D6 | Keep the release candidate on npm `latest`, or move it to `next` until GA | Will, with whoever owns publishing | | D4 | For each missing client API: build it, or document the workaround and say it is not planned | ORM product | | D1 | Which of the two designs for one-step adoption | ORM (brief in `brief-db-ref-on-adoption.md`) | @@ -48,9 +47,9 @@ The proposed sidebar trees and the `/orm` page structure are in `ia.md`. These a - **A3. Human content first, agent prompts last.** `/prisma-orm`, `/getting-started`, and every framework guide open with a copyable agent prompt before any human instruction. Move the prompt to the end or into a collapsed block. This is the direct answer to the "written for AI" complaint. - **A5. Root page: give the ORM a section**, not one line ("Here for the ORM? Jump to Prisma 7 or Prisma 8"). The four doors from A1 in one row. File: `(index)/index.mdx`. - **A6. Rewrite `orm/core-concepts.mdx` as a narrative** from `mental-model.md`. The current page is a glossary; the mental model explains why, in the order a reader meets each piece. Keep the glossary as a closing section. -- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Fourteen further pages stay in Latest with a "This guide uses Prisma 7" note (the #8242 description counts thirteen; the tree has fourteen); #8242 says which are blocked on third-party adapters and which are portable follow-ups. +- **A7. Move the sixteen Prisma 7 guides out of the Latest tree.** Landed as #8242 (2026-09-11), in a different shape. `guides/frameworks/react-router-7`, `solid-start`, `guides/deployment/*` except Cloudflare D1, `guides/integrations/github-actions`, `ai-sdk`, all of `guides/switch-to-prisma-orm/*` and `guides/database/*` were rewritten for Prisma ORM 8 at the same slugs, each with its Prisma 7 page preserved under `guides/v7/`; Cloudflare D1 moved to `guides/v7/` only (there is no Prisma ORM 8 D1 driver). The Latest sidebar keeps those labels. Thirteen further pages stay in Latest with a "This guide uses Prisma 7" note; #8242 says which are blocked on third-party adapters and which are portable follow-ups. - **A8. One error reference, or two that link.** `cli/error-reference.mdx` claims to list every CLI code but carries only the platform namespaces; every `MIGRATION.*`, `CONTRACT.*`, `CONFIG.*` code is on `orm/reference/error-reference.mdx`, and the structured errors' `docsUrl` points there. Merge them, or state the split on both and cross-link. -- **A4** (sidebar labels and the guides index). The two upgrade-guide labels ("Prisma 7 to 8 (PostgreSQL)", "Prisma 6 to 8 (MongoDB)") are in #8238, open as of 2026-09-11. The guides index part landed in #8242, which replaced the "Coming as they land" list with an Upgrading section linking both guides. +- **A4** (sidebar labels and the guides index) is in #8238, open as of 2026-09-11. ## B. Corrections to existing pages (#8236 and #8237 merged; #8238 open) @@ -80,7 +79,7 @@ Grouped by where the page lives. Each says what the page is for, what it must co - **C2. Add Prisma ORM to an app you already started.** Starts from "you have a project directory and an empty or absent database": `orm init`, edit the contract, `contract emit`, `db init`, one query, with `db.ts` shown. Bun as the worked example, since that is the case reported, with a note for Node. Unblocks J1. Source: `mental-model.md`; the scaffold in `create-prisma`. - **C1. Coming from Prisma 7.** The mapping table from `mental-model.md` in four sections: schema and types, CLI commands, client API, and "not in Prisma ORM 8 yet" with a status per item. The last section is the one readers ask for most and no page has: `skipDuplicates`, `increment`/`decrement`, `findUniqueOrThrow`, case-insensitive filters, `$transaction` arrays, model and payload types, `@updatedAt` (rejected; use `temporal.updatedAt()`), `cuid()` (rejected; use `cuid(2)`), JSON path filtering, soft delete, validations, callbacks, read replicas. Unblocks J3. Placement is A2; content of the "not yet" list depends on D4. - **C3. Adopt an existing database.** Split from the existing-project page so it has room: what `contract infer` produces (SQL-only; captures indexes, checks, RLS, 1:1 relations; emits Temporal-backed timestamp types that need the polyfill, D10), what `db sign` checks and what exit code 4 means, the baseline migration, the `db` ref, the second migration with `--advance-ref db`. Unblocks J2. Waits on D1, which decides how short it can be. -- **C4. Release status.** One short page: release candidate; GA window; Prisma ORM 7 gets bug fixes and security updates for twelve months; `npx prisma` and `npm install prisma` resolve to Prisma ORM 8; to stay on 7, pin `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. Waits on Will (facts) and D6 (whether the tag stays). +- **C4. Release status.** One short page: release candidate; GA window; Prisma ORM 7 gets bug fixes and security updates for 18 months from GA; `npx prisma` and `npm install prisma` resolve to Prisma ORM 8; to stay on 7, pin `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. GA is expected in October 2026 and Prisma ORM 7 is supported for 18 months from GA; waits on D6 (whether the tag stays). - **C18. Supported versions.** No page states the floors. Candidates: Node (see the decision above), Bun 1.2 (site says 1.1), Deno 2.0, PostgreSQL 15 (stated nowhere), MongoDB 8.0, TypeScript 5.9, `tsconfig` with `moduleResolution: "bundler"` and `strict: true`, ESM-only. The monorepo's `docs/Supported Versions.md` is the draft but is wrong about Node and documents a `--merge-tsconfig` flag that does not exist, so confirm each number. One page under getting started, linked from every quickstart. - **C5. Editor setup.** Where the VS Code extension lives (open-vsx), that Prisma ORM 8 does not bundle a language server and uses the locally installed CLI, that `// use prisma-next` on line one is what the language server keys on, and `prisma contract format` as the fallback. Unblocks J7. Waits on Serhii. @@ -119,7 +118,7 @@ Places where the docs are hard because the tool is. Grouped by who owns the fix. - **D8. Streaming does not stream on `postgres()`.** The facade creates its driver with `cursor: { disabled: true }`, so `for await` iterates an already-fetched result; only the serverless facade exposes cursor batches. Measured: breaking after the first row of a 400,000-row table still grew the heap by 64 MB. Expose `cursor` on `postgres()` or keep the docs' new wording. Source: `packages/3-extensions/postgres/src/runtime/postgres.ts:245-247`. - **D12. Permissive mode is unreachable on Postgres.** `postgres()` never forwards `mode`, so every "warn in permissive mode" branch in lints and budgets is dead on Postgres; only `mongo()` accepts it. Expose it or remove the branches. Source: `postgres.ts:86-94,276-282`, `sql-runtime.ts:187`. - **D7. `db.connect()` vs `db.runtime()`, `db.close()` vs `db.runtime().close()`.** Two names for adjacent things, a Mongo-only `await`, and `db.prepare` then `db.connect()` throwing `DRIVER.ALREADY_CONNECTED`. One call on both targets would simplify every page that shows a script. -- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js 25 and earlier every read throws `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported (official Node.js 26 ships `globalThis.Temporal`; Homebrew's Node.js 26 build omits it). `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. +- **D10. Inferred contracts fail at read time without the Temporal polyfill.** `contract infer` maps timestamp columns to Temporal-backed types; on Node.js 25 and earlier every read throws (official Node.js 26 ships `globalThis.Temporal`; Homebrew's Node.js 26 build omits it) `RUNTIME.TEMPORAL_UNAVAILABLE` unless `temporal-polyfill/full/global` is imported. `create-prisma` installs the polyfill; `orm init` does not. Options: infer to `TimestamptzString` by default, have `orm init` install and import the polyfill, or fail at emit with a clear message. Source: `packages/3-targets/3-targets/postgres/src/core/psl-infer/postgres-type-map.ts:30-33`. - **D5. `contract infer` on Prisma 7 databases.** Users report inferred contracts that fail to emit: `@db.*` attributes, `Decimal` defaults, non-`public` schemas. Check whether rc.9 still emits removed syntax and whether `Decimal @default(0.00)` is a bug. See D10. ### Product decisions From 63e942023952c8c42ca62bda3dd5b92e64136bdd Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 18:21:21 +0200 Subject: [PATCH 14/28] docs: add the plain-language rule and reader-review process Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/README.md | 2 +- docs/orm-docs-audit/plain-language.md | 63 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 docs/orm-docs-audit/plain-language.md diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md index 1081ba2e4d..35a2f7372e 100644 --- a/docs/orm-docs-audit/README.md +++ b/docs/orm-docs-audit/README.md @@ -11,7 +11,7 @@ Read in this order: 3. `mental-model.md` — the standalone explanation of Prisma ORM 8 (contract, emit, signature, plans, migrations and refs) that pages get written from. 4. `ia.md` — the proposed sidebar trees and `/orm` page structure, then the current state and the reasons. 5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B; #8236 and #8237 are merged, #8238 is open as of 2026-09-11), new pages (C), ORM changes (D). Leads with the suggested order. -6. `naming.md` — the "Prisma ORM" naming rule. +6. `naming.md` — the "Prisma ORM" naming rule. `plain-language.md` — the rule every page must follow so it reads as written by a person for an ordinary user, with the banned-word list and the reader-review step. 7. `slice-corrections.md` — how the section B corrections were sliced, and the decisions taken. 8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). 9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. The audit is a snapshot of the site on 2026-09-10; the guides pages it flags as Prisma 7 content were rewritten for Prisma ORM 8 in #8242 on 2026-09-11. diff --git a/docs/orm-docs-audit/plain-language.md b/docs/orm-docs-audit/plain-language.md new file mode 100644 index 0000000000..4f8ae3498c --- /dev/null +++ b/docs/orm-docs-audit/plain-language.md @@ -0,0 +1,63 @@ +# Plain language: the rule for every page + +The reader is an ordinary developer who has used Prisma ORM before and has never seen the Prisma ORM 8 source code. Every sentence must be one they could restate in their own words on first reading. This is the largest complaint about the current docs and it overrides any other style preference. + +## The rule + +1. Say what the reader does and what happens. Not what the system is. +2. One idea per sentence. If a sentence needs a parenthetical, split it. +3. Use the reader's words for things: "the command-line tool", "the library your app imports", "your schema file", "the call that runs the query", "an error with a code". +4. A term from the source code may appear on a page only if the docs glossary already defines it for readers, or the sentence that first uses it says what it means in plain words. Otherwise use the plain words and drop the term. +5. Explain a mechanism only when the reader needs it to act. If they do not, cut it. +6. No sentence is finished if the reader has to guess what a word refers to. + +## Banned words and their replacements + +These come from `packages/` and the release notes and mean nothing to readers. Do not use them in prose; the replacement is the meaning. + +| Do not write | Write | +| --- | --- | +| terminal, terminal call, terminal method | the call that runs the query (`.all()`, `.first()`, `.create(...)`) | +| codec | how the value is stored and read; or just name the type | +| envelope, structured envelope, structured error | an error with a code (`RUNTIME.NO_ROWS`) | +| type position, "in type position" | written as the type (`VarChar(255)` instead of `@db.VarChar(255)`) | +| runtime (as a noun for the library) | the library your app imports; or `db` | +| release line, release cycle, runs ahead | released separately, on its own schedule | +| lane (SQL lane, raw lane) | the raw SQL API; the query builder | +| facade | the client; `postgres(...)` | +| junction model, join model | the model for the join table | +| plan, query plan | the query, before it runs; or the built query | +| emit, emitted artifacts (unexplained) | `prisma contract emit` writes `contract.json` and `contract.d.ts` | +| signature, marker (unexplained) | the record in the database of which contract it matches | +| ref (unexplained) | a named pointer to a migration state; explain on first use | +| capability | which database features the contract needs | +| buffers, buffered, materializes | loads every row into memory first | +| surface, API surface | the methods; the commands | +| lowered, lowering | turned into SQL | +| namespace-qualified, namespace coordinate | `db.orm.public.User` (`public` is the PostgreSQL schema) | +| reducer, refinement callback | a way to count or sum related records; a way to filter related records | +| dotted codes | a code such as `RUNTIME.NO_ROWS` | +| envelope config, CLI envelope | the config file | +| dev loop | while you are iterating | +| brownfield, greenfield | an existing database; a new project | +| deterministic | the same input always produces the same output | +| idempotent | safe to run more than once | +| topology, graph (for migrations, unexplained) | the chain of migrations | + +Also banned: "unblocks", "surfaces", "carries", "wires up", "sits", "lives at" (say "is at"), "spells", "hands back", "rides on", "routes on", "keys on", "the shape", "story" (as in "the `DATABASE_URL` story"). + +## Sentence shapes to avoid + +- A noun with three or more modifiers: "per-request cursor-enabled serverless facade". +- "X, so Y, which Z": three claims chained; split. +- A caveat in parentheses mid-sentence; make it its own sentence or cut it. +- Passive voice for what the reader does: "the version is pinned" becomes "lock the version". +- Starting with the mechanism: "Because emit is deterministic, hashing..." becomes what the reader sees. + +## Process + +1. Write the page from the facts. +2. Fact review against the source (as today). +3. Reader review: an agent with the persona above and only this file reads the page and marks every sentence it cannot restate and every word it had to guess. Fix every mark. Repeat until clean. +4. Run `check-plain.sh` on the changed files before pushing. +5. Will does the final pass. From babb53fdda1917926a7e53fbcb615afcb888b2ad Mon Sep 17 00:00:00 2001 From: willbot Date: Fri, 11 Sep 2026 18:23:02 +0200 Subject: [PATCH 15/28] docs: add the plain-language pass over the reference pages to the change list Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 8be8185247..6e7a3e800e 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -101,6 +101,7 @@ Grouped by where the page lives. Each says what the page is for, what it must co - **C16. Build integration.** The Vite plugin `@prisma/orm-postgres/vite-plugin-contract-emit` (re-emits on save; dev server only) and the `"prebuild": "prisma contract emit"` pattern for every other bundler. Zero hits on the site; the Vite-based framework guides tell readers to run emit by hand. Source: `packages/1-framework/3-tooling/vite-plugin-contract-emit/README.md`. - **C19. Extension pages beyond pgvector.** PostGIS (`Geometry`, seven operations, the `pg/geometry@1` JSON round-trip exemption), ParadeDB (`key_field`-only), arktype-json (`arktypeJson(schema)`) each have one catalog row. - **C20. Telemetry page.** `cli/telemetry.mdx` omits `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file, that CI never sends, the first-run notice, and the event fields. The rc.9 first-run notice links to `prisma-next.dev/docs/cli/telemetry`, which is not this page. Source: `packages/1-framework/3-tooling/cli-telemetry/src/`. +- **C21. Plain-language pass over the reference and fundamentals pages.** 66 Prisma ORM 8 pages use vocabulary from the source code that readers do not have ("terminal", "codec", "reducer", "refinement callback", "namespace-qualified", "facade", "lane", "surface"). This is the largest complaint about the docs. Every page gets the reader review in `plain-language.md`: an agent with only the Prisma ORM 7 user's knowledge marks every sentence it cannot restate, and each mark is rewritten. Start with `orm/fundamentals/*` and `orm/reference/orm-client.mdx`, which every reader hits. The check script `check-plain.sh` catches the banned words before push; the review catches the rest. - **C17. CLI page additions.** `configuration.mdx`: `migrations.dir`, `formatter`, the `composer` section, the telemetry variables. `orm-init.mdx`: full flag list, exit codes 4 and 5, `prisma-next.md`. `db-update.mdx`: never plans `data`-class operations. `migration-ref.mdx`: the refusals. `migration-new.mdx`: default origin rules. `migration-status.mdx`: `--json` diagnostics. `db-migrate.mdx`: `MIGRATION.MARKER_MISMATCH`, `PATH_UNREACHABLE`. `contract-emit.mdx`: `--json` output, the `output` option. `cli/index.mdx`: `@prisma/orm-toolchain`, `@prisma/orm-framework`. ## D. Change the ORM and its tooling From e1506b30ce88a4d6d6ae513e91377b4267d3d2ab Mon Sep 17 00:00:00 2001 From: willbot Date: Sat, 12 Sep 2026 08:52:00 +0200 Subject: [PATCH 16/28] docs: local database and runnable-example journeys, IA node, and change items C22 and C23 Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/changes.md | 2 ++ docs/orm-docs-audit/ia.md | 24 ++++++++++++----------- docs/orm-docs-audit/journeys.md | 34 +++++++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 6e7a3e800e..28f9cd1806 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -81,6 +81,8 @@ Grouped by where the page lives. Each says what the page is for, what it must co - **C3. Adopt an existing database.** Split from the existing-project page so it has room: what `contract infer` produces (SQL-only; captures indexes, checks, RLS, 1:1 relations; emits Temporal-backed timestamp types that need the polyfill, D10), what `db sign` checks and what exit code 4 means, the baseline migration, the `db` ref, the second migration with `--advance-ref db`. Unblocks J2. Waits on D1, which decides how short it can be. - **C4. Release status.** One short page: release candidate; GA window; Prisma ORM 7 gets bug fixes and security updates for 18 months from GA; `npx prisma` and `npm install prisma` resolve to Prisma ORM 8; to stay on 7, pin `prisma@7` and `@prisma/client@7`. Linked from the root page and every "Using Prisma 7?" note. Unblocks J4. GA is expected in October 2026 and Prisma ORM 7 is supported for 18 months from GA; waits on D6 (whether the tag stays). - **C18. Supported versions.** No page states the floors. Candidates: Node (see the decision above), Bun 1.2 (site says 1.1), Deno 2.0, PostgreSQL 15 (stated nowhere), MongoDB 8.0, TypeScript 5.9, `tsconfig` with `moduleResolution: "bundler"` and `strict: true`, ESM-only. The monorepo's `docs/Supported Versions.md` is the draft but is wrong about Node and documents a `--merge-tsconfig` flag that does not exist, so confirm each number. One page under getting started, linked from every quickstart. +- **C22. A database on your machine.** One page in the Getting Started > Prisma ORM subtree for the reader with no hosted database: `prisma dev` first (a local Prisma Postgres, no install; the page under Local development already exists, link it), then the Composer local stack (`dev`), then a PostgreSQL you run yourself, with a Docker Compose file and the connection string for it. Ends with how to look at the rows: Studio against the local instance (check whether `prisma dev` serves Studio, and which command opens it in Prisma ORM 8), or a Postgres client such as pgAdmin. Linked from every quickstart at the point where `DATABASE_URL` first appears. Unblocks J11. Source: `local-development/postgres.mdx`, `composer/local-development.mdx`, the Docker deployment guide for the Compose file shape. +- **C23. Example repositories.** One small runnable repository per starting state, each with a README that lists which files the reader writes, which files Prisma generates, and the command that produces each, and with comments in `db.ts`, `prisma.config.ts`, and the query file. Linked from the matching quickstart or starting-state page. Seed: `examples/prisma-8-demo` in the monorepo. Needs a home (a `prisma/examples`-style repository or a folder in `prisma/orm`) and an owner on the ORM side. Unblocks J12. - **C5. Editor setup.** Where the VS Code extension lives (open-vsx), that Prisma ORM 8 does not bundle a language server and uses the locally installed CLI, that `// use prisma-next` on line one is what the language server keys on, and `prisma contract format` as the fallback. Unblocks J7. Waits on Serhii. ### Guides diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index b90a783a0d..2d5362ea9e 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -4,7 +4,7 @@ Proposal first, then why, then the current state it changes. Source: the `meta.j ## Proposed -Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, `-` is content leaving the tree, unmarked is unchanged. +Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. ### Getting Started > Prisma ORM @@ -22,12 +22,15 @@ Prisma ORM PostgreSQL MongoDB + Coming from Prisma 7 link to the ORM page below, so the Upgrader finds it from here + + A database on your machine prisma dev (no install) first; Composer's local stack; your own Postgres (Docker Compose); how to look at the rows + Editor setup create-prisma reference; moved to last ``` Four starting states, one group each. "Coming from Prisma 7" is a link node here because the page itself belongs with the API it maps. +"A database on your machine" answers the question every starting state runs into on the first page: where does `DATABASE_URL` come from when I have no hosted database. The site already has the answers, `prisma dev` under Local development and the Composer local stack, but a reader inside the ORM subtree never meets them; the quickstart's "Path A" is the only mention. The node names the three options in order of effort (`prisma dev`, Composer, a Postgres you run yourself with Docker Compose), links to the pages that already exist for the first two, gives the Docker Compose file and connection string for the third, and ends with how to look at the data (Studio against the local instance, or any Postgres client). + ### ORM > Introduction ``` @@ -42,14 +45,14 @@ Introduction ``` Overview no "coming soon" line for upgrading; it exists Upgrade Prisma ORM - ~ Prisma 7 to 8 (PostgreSQL) was "Migrate from Prisma 7 to Prisma 8" + ~ Prisma 7 to 8 (PostgreSQL) was "PostgreSQL" ~ Prisma 6 to 8 (MongoDB) was "MongoDB" v7, v6, v5, v4, v3, v1 - Deployment, Database, Switch to Prisma ORM, Prisma 7 content; lives under guides/v7 GitHub Actions, AI SDK, React Router 7, SolidStart ``` -The Prisma ORM 8 replacements for those labels sit at the same slugs; C9 (deployment), C11 (CI), and C12 (switching, team workflow) in `changes.md` say what they must cover. +The six Guides labels that leave come back as Prisma ORM 8 pages when C9 (deployment), C11 (CI), and C12 (switching, team workflow) are written. ### The ORM root page (`/orm`) @@ -80,6 +83,7 @@ The ORM line becomes a short row with the four starting states, linking into the | Add to an app you already have | J1 | | Adopt an existing database (rewritten) | J2 | | Coming from Prisma 7 | J3, J5 (links to the incremental guide), J6 (attribute map) | +| A database on your machine | J1, J11 | | Editor setup | J7 | | Guides labels and overview line | J5 | | Core concepts rewritten | the "written for AI" complaint, by giving the Newcomer a why-first page | @@ -96,9 +100,9 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | --- | --- | --- | | J1 existing app, empty database | Add to Existing Project > PostgreSQL | page assumes tables exist; no node for this state | | J2 existing database with data | Add to Existing Project > PostgreSQL | right node, page stops before the ref step | -| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; fourteen diff blocks spread over six pages | +| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; content spread over nine pages | | J4 should I move now | root, `/prisma-orm` | no node; note box only says 7 is supported | -| J5 incremental upgrade | Guides > Upgrade Prisma ORM > Migrate from Prisma 7 to Prisma 8 | not linked from any ORM node; three levels down, and the MongoDB twin is labelled only "MongoDB" | +| J5 incremental upgrade | Guides > Upgrade Prisma ORM > PostgreSQL | not linked from any ORM node; label hides it | | J6 data types | Data Modeling > Overview | right node; one stale example | | J7 editor setup | none | no node | | J8 advanced Postgres | none | no node; needs product answers | @@ -109,7 +113,7 @@ Two observations follow from the table. First, the Getting Started > Prisma ORM subtree is organised by the tool that runs (`create-prisma` for Quickstart, `orm init` for Add to Existing Project) and then by database. The reader does not know those tools yet. The failures in J1 and J2 both happen at the point where the reader's situation differs from the page's assumption about it. The reader knows their situation: do I have an app, do I have a database, does it have data, was it Prisma 7. That is why I proposed organising this subtree by starting state. The database split (PostgreSQL / MongoDB) stays inside each. -Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides, three levels down, and its MongoDB twin carries only a database name as its label. +Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides with a database name as its label. ## Current state @@ -162,8 +166,6 @@ Reference ### Guides (ORM-relevant parts) -Snapshot of 2026-09-10. On 2026-09-11, #8242 rewrote the Deployment, Database, Switch to Prisma ORM, GitHub Actions, AI SDK, React Router 7, and SolidStart pages for Prisma ORM 8 at the same slugs, moved their Prisma 7 versions (and Cloudflare D1) under `guides/v7`, and gave the overview an Upgrading section. - ``` Overview /guides says "Upgrading: moving from Prisma 7" is coming v7 @@ -173,7 +175,7 @@ Deployment, Authentication, Integrations, Postgres Database (Expand-and-contract migrations, Multiple databases, Schema management in teams) Switch to Prisma ORM, Switch to Prisma Postgres Upgrade Prisma ORM - Migrate from Prisma 7 to Prisma 8 /guides/upgrade-prisma-orm/postgresql Prisma 7 to 8 + PostgreSQL /guides/upgrade-prisma-orm/postgresql title: "Migrate from Prisma 7 to Prisma 8" MongoDB /guides/upgrade-prisma-orm/mongodb v6 Mongo to 8 v7, v6, v5, v4, v3, v1 older version-to-version guides Making guides @@ -182,5 +184,5 @@ Making guides ### Where Prisma 7 readers are pointed today - Root page: one line, "Here for the ORM? Jump straight to Prisma 7 or Prisma 8". -- A note box ("Using Prisma 7?", "Prisma 7", or "Prisma 7 users") on `/orm`, `/prisma-orm`, `/prisma-orm/create-prisma`, all four getting-started pages (PostgreSQL and MongoDB), and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. -- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides > Upgrade Prisma ORM, where the PostgreSQL page is labelled "Migrate from Prisma 7 to Prisma 8" and the MongoDB page just "MongoDB" (#8238 relabels both). +- A "Using Prisma 7?" note box on `/orm`, `/prisma-orm`, both PostgreSQL getting-started pages, and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. +- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides, where the label is "PostgreSQL". diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md index c4682668e7..080be2b752 100644 --- a/docs/orm-docs-audit/journeys.md +++ b/docs/orm-docs-audit/journeys.md @@ -1,14 +1,14 @@ # Jobs readers come to the docs to do -Ten jobs. Each names who does it, what "done" looks like, what the docs must provide for it, and where the site's structure fails it. The jobs are the design input for `ia.md` (which node serves each job) and `changes.md` (which page or ORM change supplies what is missing). Verdicts describe the structure, not the state of any one sentence: **green** a page exists for the job and carries it end to end, **amber** the job can be done but the reader has to assemble it from several places or work around a gap, **red** no page is written for the job. +Twelve jobs. Each names who does it, what "done" looks like, what the docs must provide for it, and where the site's structure fails it. The jobs are the design input for `ia.md` (which node serves each job) and `changes.md` (which page or ORM change supplies what is missing). Verdicts describe the structure, not the state of any one sentence: **green** a page exists for the job and carries it end to end, **amber** the job can be done but the reader has to assemble it from several places or work around a gap, **red** no page is written for the job. ## J1. Add Prisma ORM to an app I already started, with an empty database Who: Newcomer, sometimes Upgrader. The most common Discord complaint is this job. -Done: models defined, tables created, one query returns rows, from inside the app they already have. +Done: models defined, tables created, one query returns rows, from inside the app they already have, and they can open the database and see those rows. -What the docs must provide: one page that starts from "you have a project directory and no tables", runs `orm init`, edit the contract, `contract emit`, `db init`, one query, and shows `db.ts` and where `DATABASE_URL` comes from. +What the docs must provide: one page that starts from "you have a project directory and no tables", runs `orm init`, edit the contract, `contract emit`, `db init`, one query, and shows `db.ts` and where `DATABASE_URL` comes from (linking J11 for a database on the reader's machine). It ends by showing the rows in the database, with Studio or a Postgres client, because that is how a beginner confirms the page worked. Where the structure fails: the getting-started subtree is organised by which tool runs (`create-prisma` for new apps, `orm init` for "existing project"). The reader's situation, an app with no database yet, falls between the two: the scaffold page creates a new app, and the existing-project page assumes tables exist and starts with `contract infer`. The three commands that fit exist only as a snippet on the CLI overview. @@ -34,7 +34,7 @@ Done: for every Prisma ORM 7 call in their code, they know the Prisma ORM 8 call What the docs must provide: one mapping page in four sections (schema and types, CLI commands, client API, not-yet list with a status per item), reachable from every ORM entry point. The not-yet list is the part readers ask for most: `createMany` and `skipDuplicates`, `findUniqueOrThrow`, atomic `increment`/`decrement`, case-insensitive filters, JSON path filters, `$transaction` arrays, the payload types. -Where the structure fails: there is no node. The mapping exists as fourteen inline diff blocks across six `orm/` pages (twelve of them introduced with "For Prisma 7 users"), so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. +Where the structure fails: there is no node. The mapping exists as sixteen inline "For Prisma 7 users" blocks across nine pages, so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. Verdict: **red**. IA node: "Coming from Prisma 7" (C1, placed by A2); the not-yet list depends on D4. @@ -122,6 +122,30 @@ Where the structure fails: the reader meets the files on the scaffold pages and Verdict: docs **amber**, tool **red**. Tool change D3. +## J11. Run Prisma ORM against a database on my machine + +Who: Newcomer, often a junior or a learner who does not want a hosted database yet. Reported on Discord by a reader who spent several days getting a local setup running and ended up reading example repositories on GitHub instead of the site. + +Done: a database runs locally, `DATABASE_URL` points at it, the first migration or `db init` has run, and the reader can see the tables and rows. + +What the docs must provide: one page in the ORM subtree that names the three ways to get a local database, in order of effort, and links or shows each: `prisma dev` (a local Prisma Postgres, no install), the Composer local stack (`dev`, which also runs the app), and a PostgreSQL the reader runs themselves, with a Docker Compose file and the matching connection string. It ends with how to look at the data: Studio against the local instance, or any Postgres client such as pgAdmin. + +Where the structure fails: the answers exist on the site, under Local development and Composer, but those are top-level platform sections. Nothing in the ORM subtree points at them except the quickstart's "Path A", which a reader who arrived at the ORM section from a search result never sees. A reader who wants Docker Compose finds only the Docker deployment guide, which is about shipping, not developing. + +Verdict: **red**. IA node: "A database on your machine". + +## J12. Learn from a runnable example + +Who: Newcomer. The same Discord reader: "I would recommend tutorials which can be cloned, run locally, and have a lot of comments in the code to understand what files need to be created and coded, which files are generated and why." + +Done: the reader has cloned a repository, run it against a local database, and can tell from comments in the code which files they wrote, which files Prisma generated, and what each command in `package.json` does. + +What the docs must provide: one small example repository per starting state (new app, app you already have, existing database), each with a README that says which files are yours (`contract.prisma`, `db.ts`, `prisma.config.ts`, your queries), which are generated (`contract.json`, `contract.d.ts`, `migrations/`), and the command that produces each generated file. Every quickstart and starting-state page links the matching repository. The monorepo's `examples/prisma-8-demo` is the seed. + +Where the structure fails: no page links a runnable repository. The quickstarts are copy-and-paste sequences with no way to check a broken local setup against a known-good one. + +Verdict: **red**. IA node: links from every starting-state page; no new node. + ## Summary | Job | Verdict | What serves it | @@ -136,3 +160,5 @@ Verdict: docs **amber**, tool **red**. Tool change D3. | J8 advanced Postgres | red | Advanced Postgres (C7) | | J9 types | red | Types (C6) on the next tagged release | | J10 agent files | amber / red | the line on scaffold pages; D3 | +| J11 local database | red | A database on your machine (C22) | +| J12 runnable example | red | example repositories linked from every starting state (C23) | From f0996aae528ef1bd4104951e61fcc3eac39663dd Mon Sep 17 00:00:00 2001 From: willbot Date: Sat, 12 Sep 2026 08:52:34 +0200 Subject: [PATCH 17/28] docs: keep the branch's newer ia and journeys text; add only J11, J12, the IA node, C22 and C23 Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/ia.md | 20 +++++++++++--------- docs/orm-docs-audit/journeys.md | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/orm-docs-audit/ia.md b/docs/orm-docs-audit/ia.md index 2d5362ea9e..8a7585f142 100644 --- a/docs/orm-docs-audit/ia.md +++ b/docs/orm-docs-audit/ia.md @@ -4,7 +4,7 @@ Proposal first, then why, then the current state it changes. Source: the `meta.j ## Proposed -Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, unmarked is unchanged. +Scope: the Getting Started > Prisma ORM subtree, the ORM > Introduction group, and the Guides tree (two labels, and the Prisma 7 pages leaving it). Nothing else moves. `+` is a new node, `~` is a renamed or rewritten node, `-` is content leaving the tree, unmarked is unchanged. ### Getting Started > Prisma ORM @@ -45,14 +45,14 @@ Introduction ``` Overview no "coming soon" line for upgrading; it exists Upgrade Prisma ORM - ~ Prisma 7 to 8 (PostgreSQL) was "PostgreSQL" + ~ Prisma 7 to 8 (PostgreSQL) was "Migrate from Prisma 7 to Prisma 8" ~ Prisma 6 to 8 (MongoDB) was "MongoDB" v7, v6, v5, v4, v3, v1 - Deployment, Database, Switch to Prisma ORM, Prisma 7 content; lives under guides/v7 GitHub Actions, AI SDK, React Router 7, SolidStart ``` -The six Guides labels that leave come back as Prisma ORM 8 pages when C9 (deployment), C11 (CI), and C12 (switching, team workflow) are written. +The Prisma ORM 8 replacements for those labels sit at the same slugs; C9 (deployment), C11 (CI), and C12 (switching, team workflow) in `changes.md` say what they must cover. ### The ORM root page (`/orm`) @@ -100,9 +100,9 @@ No change to the top-level section list, to Data Modeling, Contract Authoring, F | --- | --- | --- | | J1 existing app, empty database | Add to Existing Project > PostgreSQL | page assumes tables exist; no node for this state | | J2 existing database with data | Add to Existing Project > PostgreSQL | right node, page stops before the ref step | -| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; content spread over nine pages | +| J3 Prisma 7 query mapping | Fundamentals > Reading data | no node; fourteen diff blocks spread over six pages | | J4 should I move now | root, `/prisma-orm` | no node; note box only says 7 is supported | -| J5 incremental upgrade | Guides > Upgrade Prisma ORM > PostgreSQL | not linked from any ORM node; label hides it | +| J5 incremental upgrade | Guides > Upgrade Prisma ORM > Migrate from Prisma 7 to Prisma 8 | not linked from any ORM node; three levels down, and the MongoDB twin is labelled only "MongoDB" | | J6 data types | Data Modeling > Overview | right node; one stale example | | J7 editor setup | none | no node | | J8 advanced Postgres | none | no node; needs product answers | @@ -113,7 +113,7 @@ Two observations follow from the table. First, the Getting Started > Prisma ORM subtree is organised by the tool that runs (`create-prisma` for Quickstart, `orm init` for Add to Existing Project) and then by database. The reader does not know those tools yet. The failures in J1 and J2 both happen at the point where the reader's situation differs from the page's assumption about it. The reader knows their situation: do I have an app, do I have a database, does it have data, was it Prisma 7. That is why I proposed organising this subtree by starting state. The database split (PostgreSQL / MongoDB) stays inside each. -Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides with a database name as its label. +Second, the Upgrader has no node anywhere in Getting Started or ORM. Every Prisma 7 pointer is for staying on 7. The one page written for moving to 8 is filed under Guides, three levels down, and its MongoDB twin carries only a database name as its label. ## Current state @@ -166,6 +166,8 @@ Reference ### Guides (ORM-relevant parts) +Snapshot of 2026-09-10. On 2026-09-11, #8242 rewrote the Deployment, Database, Switch to Prisma ORM, GitHub Actions, AI SDK, React Router 7, and SolidStart pages for Prisma ORM 8 at the same slugs, moved their Prisma 7 versions (and Cloudflare D1) under `guides/v7`, and gave the overview an Upgrading section. + ``` Overview /guides says "Upgrading: moving from Prisma 7" is coming v7 @@ -175,7 +177,7 @@ Deployment, Authentication, Integrations, Postgres Database (Expand-and-contract migrations, Multiple databases, Schema management in teams) Switch to Prisma ORM, Switch to Prisma Postgres Upgrade Prisma ORM - PostgreSQL /guides/upgrade-prisma-orm/postgresql title: "Migrate from Prisma 7 to Prisma 8" + Migrate from Prisma 7 to Prisma 8 /guides/upgrade-prisma-orm/postgresql Prisma 7 to 8 MongoDB /guides/upgrade-prisma-orm/mongodb v6 Mongo to 8 v7, v6, v5, v4, v3, v1 older version-to-version guides Making guides @@ -184,5 +186,5 @@ Making guides ### Where Prisma 7 readers are pointed today - Root page: one line, "Here for the ORM? Jump straight to Prisma 7 or Prisma 8". -- A "Using Prisma 7?" note box on `/orm`, `/prisma-orm`, both PostgreSQL getting-started pages, and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. -- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides, where the label is "PostgreSQL". +- A note box ("Using Prisma 7?", "Prisma 7", or "Prisma 7 users") on `/orm`, `/prisma-orm`, `/prisma-orm/create-prisma`, all four getting-started pages (PostgreSQL and MongoDB), and `/cli`. It says Prisma 7 remains supported and links to `/orm/v7` and `/v7/getting-started`. Both links are for staying on 7. +- Nothing under Getting Started or ORM links to the upgrade guide. It is reachable only through Guides > Upgrade Prisma ORM, where the PostgreSQL page is labelled "Migrate from Prisma 7 to Prisma 8" and the MongoDB page just "MongoDB" (#8238 relabels both). diff --git a/docs/orm-docs-audit/journeys.md b/docs/orm-docs-audit/journeys.md index 080be2b752..f8ef9eb5c4 100644 --- a/docs/orm-docs-audit/journeys.md +++ b/docs/orm-docs-audit/journeys.md @@ -8,7 +8,7 @@ Who: Newcomer, sometimes Upgrader. The most common Discord complaint is this job Done: models defined, tables created, one query returns rows, from inside the app they already have, and they can open the database and see those rows. -What the docs must provide: one page that starts from "you have a project directory and no tables", runs `orm init`, edit the contract, `contract emit`, `db init`, one query, and shows `db.ts` and where `DATABASE_URL` comes from (linking J11 for a database on the reader's machine). It ends by showing the rows in the database, with Studio or a Postgres client, because that is how a beginner confirms the page worked. +What the docs must provide: one page that starts from "you have a project directory and no tables", runs `orm init`, edit the contract, `contract emit`, `db init`, one query, and shows `db.ts` and where `DATABASE_URL` comes from. Where the structure fails: the getting-started subtree is organised by which tool runs (`create-prisma` for new apps, `orm init` for "existing project"). The reader's situation, an app with no database yet, falls between the two: the scaffold page creates a new app, and the existing-project page assumes tables exist and starts with `contract infer`. The three commands that fit exist only as a snippet on the CLI overview. @@ -34,7 +34,7 @@ Done: for every Prisma ORM 7 call in their code, they know the Prisma ORM 8 call What the docs must provide: one mapping page in four sections (schema and types, CLI commands, client API, not-yet list with a status per item), reachable from every ORM entry point. The not-yet list is the part readers ask for most: `createMany` and `skipDuplicates`, `findUniqueOrThrow`, atomic `increment`/`decrement`, case-insensitive filters, JSON path filters, `$transaction` arrays, the payload types. -Where the structure fails: there is no node. The mapping exists as sixteen inline "For Prisma 7 users" blocks across nine pages, so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. +Where the structure fails: there is no node. The mapping exists as fourteen inline diff blocks across six `orm/` pages (twelve of them introduced with "For Prisma 7 users"), so the reader finds it by luck, and nothing admits what does not exist. The accessor change (`prisma.user` to `db.orm.public.User`) is stated once. Verdict: **red**. IA node: "Coming from Prisma 7" (C1, placed by A2); the not-yet list depends on D4. From c02aa1533b125c94d914dacc68d52a1978b9b658 Mon Sep 17 00:00:00 2001 From: willbot Date: Sat, 12 Sep 2026 09:04:43 +0200 Subject: [PATCH 18/28] docs: handover brief for the next agent Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/orm-docs-audit/HANDOVER.md diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md new file mode 100644 index 0000000000..2cc0fa14a2 --- /dev/null +++ b/docs/orm-docs-audit/HANDOVER.md @@ -0,0 +1,55 @@ +# Handover: Prisma ORM 8 docs audit and plain-language pass + +Written 2026-09-12 by the previous agent for the next one. Read this first, then `changes.md` in this directory. + +## Transcript of the previous session + +`/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` + +Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a page name. The session was compacted once; the first user message after compaction carries a summary of everything before it. + +## Where things are + +- `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). +- Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. +- Draft PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 in progress on `apps/docs/content/docs/orm/reference/orm-client.mdx`. See "Current task". +- The Prisma ORM 8 source used for every fact check is `prisma/orm` at tag `8.0.0-rc.9` (`f889eeb89e`). The previous worktree had it at `wip/prisma-src/`; in a fresh worktree, `git -C /Users/will/Projects/prisma/prisma worktree add f889eeb89e`. The published CLI is newer than that tree: `prisma@8.0.0-rc.13` exists, `npx prisma skills sync` exists, and `prisma/config` is the config import. ORM packages are still rc.9. + +## How to work (rules Will has given, in his words where possible) + +- Act as the `wmadden-electric` bot: commit with `git commit -s --trailer "Signed-off-by: Will Madden "`, end the message with `Co-Authored-By: Claude Fable 5.1 `, push only through the `bot` remote. +- "NOT EVERY FUCKING CHANGE NEEDS A SEPARATE PR": follow-ups go on the open PR. +- Address every review comment and every CI failure without being asked. Resolve CodeRabbit threads via GraphQL `resolveReviewThread` after replying. CodeRabbit's "changes requested" verdict blocks the merge even when all threads are resolved; dismissing it is blocked for the agent, so Will dismisses it or merges with `--admin`. +- PR descriptions: a grounding before/after example first, then the decision, then how it was checked, then what a reviewer should know, alternatives considered last. +- Plain English, no invented jargon, short sentences. Never use the question UI. +- The design docs carry no status ("they are not a fucking to do list"). Progress lives in PRs. +- The product is "Prisma ORM"; a version number only when contrasting ("Prisma ORM 7 to 8"). The reason is separating the Prisma brand from the ORM. +- Use Opus for implementer and reviewer subagents. +- Do not paste the readers' reports into pages; extract each agent's final message from its task output with the small script in `c21-orm-client/` (`extract.py` in the previous scratchpad; it prints the last assistant text block of a task JSONL). + +## The C21 method (what worked on the fundamentals pages) + +The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: + +1. Run `scripts/check-plain.sh` and fix hits. +2. Dispatch a fresh Opus reader with `references/reader-persona.md` verbatim and only the page (a long page in slices by `##` heading, 400 to 700 lines each). Save its report with the extract script. +3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; in `c21-orm-client/` on #8260), the page's own conventions file if any, the report, and the rc.9 source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. +4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a "no longer than it is now" budget, because pages grow and readers then trip on the additions. +5. Fact re-check by a separate Opus agent against the source, claim by claim, before the PR. On the fundamentals pages this caught seven real errors that the wording rounds had introduced or left standing. Do not skip it. +6. Commit each round. Link check: `cd apps/docs && node_modules/.bin/fumadocs-mdx && node_modules/.bin/tsx ./scripts/lint-links.ts`. Spelling: `node_modules/.bin/cspell "content/docs/orm/**/*.mdx"` (random sample ids fail it; use `cuid2000...` style). Revert any `meta.json` the formatter touches. + +Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. + +## Current task: C21 on `orm/reference/orm-client.mdx` (draft PR #8260) + +Done: banned terms replaced (headings "Read terminals" and "Mutation terminals" are now "Read methods" and "Write methods" with the old anchors pinned); round one read in four slices; round one fixes applied to all four slices and reassembled (2,058 lines; plain check, cspell, and link check pass). + +Not done, and the reason it matters: the four fixer agents were stopped before they reported, so their factual changes are unverified. The page rules gave them a list of facts to look up (see `c21-orm-client/page-conventions.md`, last bullet). Start with a full fact re-check of the reassembled page against rc.9, apply corrections, then rounds two to four, then the final fact re-check, then take #8260 out of draft with a description in Will's format. Delete `docs/orm-docs-audit/c21-orm-client/` from the branch before it merges. + +## After that, in order + +1. The other seven pages under `orm/reference/`, one PR for the section. +2. `orm/contract-authoring/`, `orm/data-modeling/`, `orm/migrations/`, `orm/middleware/`, `orm/extensions/` (20 pages), one PR per section. +3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. +4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. +5. Briefs waiting for an ORM-side owner: `brief-skill-staleness.md` (D14), D17 in `changes.md`. Add to D14: the scorecard marks `contains`/`startsWith`/`endsWith` as reachable when they are not, and the skill still says N:M includes fail when they work. From 35d116861054b9fb395c73a28ead96dd7cb120b3 Mon Sep 17 00:00:00 2001 From: willbot Date: Sat, 12 Sep 2026 11:13:26 +0200 Subject: [PATCH 19/28] docs: handover brief, orm-client page finished, next is the rest of orm/reference Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index 2cc0fa14a2..ec639f609c 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -12,7 +12,7 @@ Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a pa - `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). - Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. -- Draft PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 in progress on `apps/docs/content/docs/orm/reference/orm-client.mdx`. See "Current task". +- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, finished on 2026-09-12 and out of draft: two fact re-checks against rc.9 and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5; they were removed from the tree before review. - The Prisma ORM 8 source used for every fact check is `prisma/orm` at tag `8.0.0-rc.9` (`f889eeb89e`). The previous worktree had it at `wip/prisma-src/`; in a fresh worktree, `git -C /Users/will/Projects/prisma/prisma worktree add f889eeb89e`. The published CLI is newer than that tree: `prisma@8.0.0-rc.13` exists, `npx prisma skills sync` exists, and `prisma/config` is the config import. ORM packages are still rc.9. ## How to work (rules Will has given, in his words where possible) @@ -40,15 +40,16 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. -## Current task: C21 on `orm/reference/orm-client.mdx` (draft PR #8260) +## Current task: the other seven pages under `orm/reference/` -Done: banned terms replaced (headings "Read terminals" and "Mutation terminals" are now "Read methods" and "Write methods" with the old anchors pinned); round one read in four slices; round one fixes applied to all four slices and reassembled (2,058 lines; plain check, cspell, and link check pass). +`orm-client.mdx` is done (PR #8260). Next is item 1 below. Two things learned on the orm-client page that the fundamentals pages did not show: -Not done, and the reason it matters: the four fixer agents were stopped before they reported, so their factual changes are unverified. The page rules gave them a list of facts to look up (see `c21-orm-client/page-conventions.md`, last bullet). Start with a full fact re-check of the reassembled page against rc.9, apply corrections, then rounds two to four, then the final fact re-check, then take #8260 out of draft with a description in Will's format. Delete `docs/orm-docs-audit/c21-orm-client/` from the branch before it merges. +- On a reference page, readers keep asking for getting-started material (installing, `prisma orm init`, creating tables). Answer with one sentence and a link; do not add it. +- From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts after four wording rounds, so do not skip it. ## After that, in order -1. The other seven pages under `orm/reference/`, one PR for the section. +1. The other seven pages under `orm/reference/`, one PR for the section (the current task). 2. `orm/contract-authoring/`, `orm/data-modeling/`, `orm/migrations/`, `orm/middleware/`, `orm/extensions/` (20 pages), one PR per section. 3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. 4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. From cfbf40650512a760cf733f9b6d284e202544bbee Mon Sep 17 00:00:00 2001 From: willbot Date: Sun, 13 Sep 2026 09:29:37 +0200 Subject: [PATCH 20/28] docs: brief for documenting intermediate contracts in data transform migrations (C25) Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/README.md | 2 +- .../brief-intermediate-contracts.md | 47 +++++++++++++++++++ docs/orm-docs-audit/changes.md | 1 + 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 docs/orm-docs-audit/brief-intermediate-contracts.md diff --git a/docs/orm-docs-audit/README.md b/docs/orm-docs-audit/README.md index 35a2f7372e..0c54744868 100644 --- a/docs/orm-docs-audit/README.md +++ b/docs/orm-docs-audit/README.md @@ -13,7 +13,7 @@ Read in this order: 5. `changes.md` — every proposed change by kind: restructure (A), corrections to existing pages (B; #8236 and #8237 are merged, #8238 is open as of 2026-09-11), new pages (C), ORM changes (D). Leads with the suggested order. 6. `naming.md` — the "Prisma ORM" naming rule. `plain-language.md` — the rule every page must follow so it reads as written by a person for an ordinary user, with the banned-word list and the reader-review step. 7. `slice-corrections.md` — how the section B corrections were sliced, and the decisions taken. -8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). +8. `brief-db-ref-on-adoption.md`, `brief-skills-opt-out.md`, `brief-skill-staleness.md` — three ORM-side changes handed to other agents; `brief-intermediate-contracts.md` — a docs page to write (C25) (adoption sets the `db` ref; a skills opt-out in create-prisma; bringing the `prisma-8` agent skill up to rc.9). 9. `audit/` — the page-by-page audit findings that section B and much of C and D were built from. `INSTRUCTIONS.md` and `AREAS.md` describe how the audit was run; the seven area files hold the findings with source citations. The audit is a snapshot of the site on 2026-09-10; the guides pages it flags as Prisma 7 content were rewritten for Prisma ORM 8 in #8242 on 2026-09-11. Prose is a draft throughout; the structure and the cited facts are what has been verified. diff --git a/docs/orm-docs-audit/brief-intermediate-contracts.md b/docs/orm-docs-audit/brief-intermediate-contracts.md new file mode 100644 index 0000000000..50920cebaa --- /dev/null +++ b/docs/orm-docs-audit/brief-intermediate-contracts.md @@ -0,0 +1,47 @@ +# Docs update for intermediate contracts in data transform migrations + +Recorded 2026-09-13 from a brief written on another branch. Target page: `apps/docs/content/docs/orm/migrations/editing-a-migration.mdx`, next to `dataTransform`. Change item C25 in `changes.md`. + +# For the docs site: data transforms that need an intermediate contract + +Audience: an agent writing or extending the Prisma 8 migrations documentation. This describes a technique that exists in the ORM today and is specified in ADR 197 ("Migration packages snapshot their own contract", section "Intermediate contracts") in `prisma/orm`. It should be documented next to `dataTransform`, because it answers the first question anyone hits when a migration both changes a column and has to move data through it. + +## The problem the reader has + +A migration in Prisma 8 is an edge between two contracts: the start contract and the end contract. Its `dataTransform` step runs typed ORM queries, and those queries are typed and planned against a contract the author hands in. The natural choice is the end contract, and for a pure backfill it is right: add a nullable column, fill it, the end contract has the column. + +It stops working the moment the transform has to read something the migration removes. Example: replacing a boolean `needsReply` with an enum column `state`. The transform must read `needsReply` to decide each row's `state`, but the end contract no longer has `needsReply`, so a query against it cannot name that column; the planner rejects it (`PN-MIG-2005`, a reference to something not in the contract). The start contract has `needsReply` but not `state`, so a query against it cannot write the new column either. Neither contract describes the database at the moment the transform runs. + +Authors who hit this reach for raw SQL inside the migration, which throws away the typing the contract-first design exists to give them. + +## The technique + +Describe the in-between state as a contract of its own, inside the migration directory, and type the transform against it. + +1. Copy the schema authoring file (the `.prisma` file, or the TypeScript builder) into the migration directory as `intermediate.prisma`. +2. Edit it to the shape the database has at the moment the transform runs: in the example, `ConversationReplyState` carries both `needsReply Boolean` and `state reply_state?` (nullable, because it is not yet filled). +3. Emit it: `prisma contract emit` pointed at that file, producing `intermediate.json` and `intermediate.d.ts` next to it. These are snapshots; they never change after the migration is written, which is the same rule ADR 197 applies to the migration's own `contract.json`. +4. In `migration.ts`, import both the end contract snapshot and the intermediate one, and order the operations as: schema steps that reach the intermediate state (add the nullable `state` column), then `this.dataTransform(intermediateContract, 'fill reply state', { run: () => })`, then the schema steps that reach the end state (set `state` not null, drop `needsReply`, drop anything else the migration removes). + +The transform's queries are now typed: `needsReply` and `state` both exist in the contract they are built from, the plan's storage hash matches the contract the transform was handed (the runner checks this and refuses a mismatch with `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`), and nothing is raw text. + +Multiple intermediate contracts are allowed; the author names and emits each one. Every migration directory is self-contained: it never reaches outside itself for type information, so it keeps type-checking however the project's schema evolves afterwards. + +## A trap the page must warn about + +A column declared with `temporal.updatedAtString()` makes the query builder set it on every update, and it does so by putting the current time into the plan as a parameter. A migration's transform is lowered into `ops.json` when the migration is planned, not when it is applied, so that timestamp is baked into `ops.json`, and every re-emit of the migration produces different bytes while `migration.json` keeps the same hash. `migration status` then reports `MIGRATION.CONTRACT_SPACE_VIOLATION` and the author has no idea why. In the intermediate contract, declare such columns as a plain timestamp type (`TimestamptzString`) rather than the auto-updating form; the intermediate contract only types the transform, so the end contract's `updatedAt` behaviour is untouched. Found while writing the first such migration in `prisma/asks` (2026-09-12). + +## What the docs page should show + +- A worked example with three files: `intermediate.prisma` (the relevant model only), `migration.ts` with the imports and the operation order, and the directory listing after `contract emit`. +- The rule of thumb: type a transform against the end contract when the transform only writes columns the end contract has and reads columns it keeps; use an intermediate contract when the transform reads anything the migration removes or renames, or writes a column before its final constraints are applied. +- The failure the reader sees without it (`PN-MIG-2005` against the end contract) and why raw SQL is the wrong fix. +- The alternative of two migrations (add and fill in the first, drop in the second), when a team prefers not to keep an intermediate snapshot, with its cost: an extra contract version that exists only to make the transform expressible. + +## References for the writer + +- `prisma/orm`, `docs/architecture docs/adrs/ADR 197 - Migration packages snapshot their own contract.md`, section "Intermediate contracts" (the directory layout and the import pattern are there, written for Mongo; the Postgres form is identical apart from the builder). +- `prisma/orm`, `packages/3-targets/3-targets/postgres/src/core/migrations/operations/data-transform.ts`, the Postgres `dataTransform(contract, name, { run, check })` signature and its contract-mismatch check. +- `prisma/orm`, `examples/retail-store/migrations/app/20260513T0508_backfill_product_status/migration.ts`, a backfill transform (Mongo) showing the operation order and the snapshot imports. +- ADR 028 ("Migration Structure & Operations") for migrations as edges between contract hashes, and ADR 192 for why no TypeScript runs at apply time: the intermediate contract matters at plan time only; the runner executes the lowered `ops.json`. +- Status note from ADR 197: the scaffolder's automatic snapshot copy is target state; the intermediate-contract workflow itself is done by hand with `contract emit` and works with the current CLI. Verify against the release the page documents. diff --git a/docs/orm-docs-audit/changes.md b/docs/orm-docs-audit/changes.md index 28f9cd1806..f677c29f5e 100644 --- a/docs/orm-docs-audit/changes.md +++ b/docs/orm-docs-audit/changes.md @@ -104,6 +104,7 @@ Grouped by where the page lives. Each says what the page is for, what it must co - **C19. Extension pages beyond pgvector.** PostGIS (`Geometry`, seven operations, the `pg/geometry@1` JSON round-trip exemption), ParadeDB (`key_field`-only), arktype-json (`arktypeJson(schema)`) each have one catalog row. - **C20. Telemetry page.** `cli/telemetry.mdx` omits `DO_NOT_TRACK=1`, `PRISMA_NEXT_DISABLE_TELEMETRY=1`, the per-user config file, that CI never sends, the first-run notice, and the event fields. The rc.9 first-run notice links to `prisma-next.dev/docs/cli/telemetry`, which is not this page. Source: `packages/1-framework/3-tooling/cli-telemetry/src/`. - **C21. Plain-language pass over the reference and fundamentals pages.** 66 Prisma ORM 8 pages use vocabulary from the source code that readers do not have ("terminal", "codec", "reducer", "refinement callback", "namespace-qualified", "facade", "lane", "surface"). This is the largest complaint about the docs. Every page gets the reader review in `plain-language.md`: an agent with only the Prisma ORM 7 user's knowledge marks every sentence it cannot restate, and each mark is rewritten. Start with `orm/fundamentals/*` and `orm/reference/orm-client.mdx`, which every reader hits. The check script `check-plain.sh` catches the banned words before push; the review catches the rest. +- **C25. Data transforms that need an intermediate contract.** A migration that both removes a column and has to read it in `dataTransform` cannot type the transform against either the start or the end contract; the planner rejects the query with `PN-MIG-2005`, and authors fall back to raw SQL. The technique that exists today: emit an `intermediate.prisma` inside the migration directory describing the in-between shape, and type the transform against it. Goes on `orm/migrations/editing-a-migration.mdx` next to `dataTransform`, with the `updatedAtString()` trap that makes `ops.json` non-deterministic. Brief: `brief-intermediate-contracts.md`. - **C17. CLI page additions.** `configuration.mdx`: `migrations.dir`, `formatter`, the `composer` section, the telemetry variables. `orm-init.mdx`: full flag list, exit codes 4 and 5, `prisma-next.md`. `db-update.mdx`: never plans `data`-class operations. `migration-ref.mdx`: the refusals. `migration-new.mdx`: default origin rules. `migration-status.mdx`: `--json` diagnostics. `db-migrate.mdx`: `MIGRATION.MARKER_MISMATCH`, `PATH_UNREACHABLE`. `contract-emit.mdx`: `--json` output, the `output` option. `cli/index.mdx`: `@prisma/orm-toolchain`, `@prisma/orm-framework`. ## D. Change the ORM and its tooling From 82ddf61a48a82c18b2953ba6715b6d67b4644b4d Mon Sep 17 00:00:00 2001 From: willbot Date: Sun, 13 Sep 2026 14:27:47 +0200 Subject: [PATCH 21/28] docs: handover after the orm/reference section (#8267) Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index ec639f609c..c18dac26d4 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -1,6 +1,6 @@ # Handover: Prisma ORM 8 docs audit and plain-language pass -Written 2026-09-12 by the previous agent for the next one. Read this first, then `changes.md` in this directory. +Written 2026-09-12, updated 2026-09-13, by the previous agent for the next one. Read this first, then `changes.md` in this directory. ## Transcript of the previous session @@ -12,8 +12,9 @@ Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a pa - `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). - Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. -- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, finished on 2026-09-12 and out of draft: two fact re-checks against rc.9 and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5; they were removed from the tree before review. -- The Prisma ORM 8 source used for every fact check is `prisma/orm` at tag `8.0.0-rc.9` (`f889eeb89e`). The previous worktree had it at `wip/prisma-src/`; in a fresh worktree, `git -C /Users/will/Projects/prisma/prisma worktree add f889eeb89e`. The published CLI is newer than that tree: `prisma@8.0.0-rc.13` exists, `npx prisma skills sync` exists, and `prisma/config` is the config import. ORM packages are still rc.9. +- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5. +- PR #8267 (branch `docs/orm8-plain-language-orm-reference`) is C21 on the rest of `orm/reference/` (`sql-query-builder`, `raw-queries`, `pipeline-builder`, `transactions-and-runtime`, `index`), merged 2026-09-13: a fact check against rc.10, four reader rounds, a final fact re-check, and CodeRabbit's six comments. The reports are in the branch history at 13f900ad2. The error reference page is generated from prisma/orm and out of scope. +- The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`), since #8261 moved the docs to rc.10. The previous worktree had it at `wip/prisma-src/`; in a fresh worktree, `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Check whether a newer rc has landed before starting a section. ## How to work (rules Will has given, in his words where possible) @@ -25,6 +26,10 @@ Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a pa - The design docs carry no status ("they are not a fucking to do list"). Progress lives in PRs. - The product is "Prisma ORM"; a version number only when contrasting ("Prisma ORM 7 to 8"). The reason is separating the Prisma brand from the ORM. - Use Opus for implementer and reviewer subagents. +- Never fix one sentence Will points at in isolation. Reread the whole page and check the claims around it; a bad sentence has always meant more was wrong nearby ("NEVER REWRITE SENTENCES IN ISOLATION. REREAD THE WHOLE DOCUMENT"). +- No commentary about the docs inside the docs: no "this page documents", no "each method has a Remarks list", no "examples carry over between pages". Write the reference itself. +- Never interleave PostgreSQL and MongoDB sentence by sentence. Give each database its own example and its own paragraph. +- Resolving CodeRabbit threads: zsh does not word-split `$ids`, so loop with `while read -r id`, and keep the GraphQL query in a file under `wip/` and pass it with `-f query="$(cat file)"`. - Do not paste the readers' reports into pages; extract each agent's final message from its task output with the small script in `c21-orm-client/` (`extract.py` in the previous scratchpad; it prints the last assistant text block of a task JSONL). ## The C21 method (what worked on the fundamentals pages) @@ -33,24 +38,26 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: 1. Run `scripts/check-plain.sh` and fix hits. 2. Dispatch a fresh Opus reader with `references/reader-persona.md` verbatim and only the page (a long page in slices by `##` heading, 400 to 700 lines each). Save its report with the extract script. -3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; in `c21-orm-client/` on #8260), the page's own conventions file if any, the report, and the rc.9 source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. +3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; in `c21-orm-client/` on #8260), the page's own conventions file if any, the report, and the source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. 4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a "no longer than it is now" budget, because pages grow and readers then trip on the additions. 5. Fact re-check by a separate Opus agent against the source, claim by claim, before the PR. On the fundamentals pages this caught seven real errors that the wording rounds had introduced or left standing. Do not skip it. 6. Commit each round. Link check: `cd apps/docs && node_modules/.bin/fumadocs-mdx && node_modules/.bin/tsx ./scripts/lint-links.ts`. Spelling: `node_modules/.bin/cspell "content/docs/orm/**/*.mdx"` (random sample ids fail it; use `cuid2000...` style). Revert any `meta.json` the formatter touches. Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. -## Current task: the other seven pages under `orm/reference/` +## Current task: `orm/contract-authoring/` -`orm-client.mdx` is done (PR #8260). Next is item 1 below. Two things learned on the orm-client page that the fundamentals pages did not show: +`orm/reference/` is done (#8260, #8267). Next is item 1 below, one PR per section. Things learned on the reference pages that the fundamentals pages did not show: - On a reference page, readers keep asking for getting-started material (installing, `prisma orm init`, creating tables). Answer with one sentence and a link; do not add it. -- From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts after four wording rounds, so do not skip it. +- From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts on the orm-client page and twenty-six on the other reference pages after four wording rounds, so do not skip it. +- Fact checkers infer motives and defaults the source does not state (why a helper was renamed, what a driver returns). Trim to what a source line says. +- When a section's pages run in parallel, a `page-conventions.md` beside `conventions.md` keeps them agreeing on setup lines, the example schema, and phrasing such as "PostgreSQL only". ## After that, in order -1. The other seven pages under `orm/reference/`, one PR for the section (the current task). -2. `orm/contract-authoring/`, `orm/data-modeling/`, `orm/migrations/`, `orm/middleware/`, `orm/extensions/` (20 pages), one PR per section. +1. `orm/contract-authoring/` (the current task), then `orm/data-modeling/`, `orm/migrations/`, `orm/middleware/`, `orm/extensions/` (20 pages in all), one PR per section. +2. C25, `brief-intermediate-contracts.md`: intermediate contracts in data transform migrations. Fits the `orm/migrations/` section pass. 3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. 4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. 5. Briefs waiting for an ORM-side owner: `brief-skill-staleness.md` (D14), D17 in `changes.md`. Add to D14: the scorecard marks `contains`/`startsWith`/`endsWith` as reachable when they are not, and the skill still says N:M includes fail when they work. From 056dcc62ef7d727ea1e63e129fb8b89af0fc2623 Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 14 Sep 2026 16:15:34 +0200 Subject: [PATCH 22/28] docs: handover after the contract-authoring section (#8271) Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index c18dac26d4..3ac82862bb 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -1,20 +1,23 @@ # Handover: Prisma ORM 8 docs audit and plain-language pass -Written 2026-09-12, updated 2026-09-13, by the previous agent for the next one. Read this first, then `changes.md` in this directory. +Written 2026-09-12, updated 2026-09-14, by the previous agent for the next one. Read this first, then `changes.md` in this directory. ## Transcript of the previous session -`/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` +`/Users/wmadden/.claude/projects/-Users-wmadden-Projects-prisma-web--claude-worktrees-error-reference-follow-ups-81a8e7/29b9a58b-bb9f-48f4-8639-597b84cf76f8.jsonl` (about 15 MB; 2026-09-13 to 2026-09-14, the orm/reference and contract-authoring passes). If your sandbox cannot read it, tell Will straight away and wait: he will copy it into your worktree. Do not continue without it. The session before that one is at `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` (the audit and the fundamentals pass). -Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a page name. The session was compacted once; the first user message after compaction carries a summary of everything before it. +Search the transcript for `C21`, `reader review`, `fact re-check`, `factcheck2`, `conventions.md`, or a page name. It was compacted once; the first user message after compaction carries a summary of everything before it. ## Where things are - `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). - Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. - PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5. +- PR #8271 (branch `docs/orm8-plain-language-contract-authoring`) is C21 on `orm/contract-authoring/` (the data contract, PSL, TypeScript builder, the two emitted files, and the page now titled Supported database features), plus three things Will asked for while it ran: the Supported databases page at `/prisma-orm/supported-databases` (PostgreSQL release candidate, MongoDB early access, everything else coming soon; it replaces the database section of prisma/orm#25843), the upgrade guides linked from the ORM section's Introduction and the v7 guides nav, and a sidebar fix (folders in the version-filtered Guides tree never opened for their own page; they now match by id). It is approved on GitHub and green; the agent could not merge it because the tool refused a merge, so Will merges it. The reports are in the branch history at 40c5394e3. The plain-language checker (`check-plain.sh`) now skips link targets, pinned anchors, `href` attributes, and the front-matter `url` line. - PR #8267 (branch `docs/orm8-plain-language-orm-reference`) is C21 on the rest of `orm/reference/` (`sql-query-builder`, `raw-queries`, `pipeline-builder`, `transactions-and-runtime`, `index`), merged 2026-09-13: a fact check against rc.10, four reader rounds, a final fact re-check, and CodeRabbit's six comments. The reports are in the branch history at 13f900ad2. The error reference page is generated from prisma/orm and out of scope. -- The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`), since #8261 moved the docs to rc.10. The previous worktree had it at `wip/prisma-src/`; in a fresh worktree, `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Check whether a newer rc has landed before starting a section. +- The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. +- The published `prisma` package (8.0.0-rc.15 on 2026-09-14) exports `./config`, so the docs import `definePrismaConfig` from `prisma/config`. The rc.10 source tree only has `@prisma/cli-engine` and every fact checker "corrects" it; revert them. Check with `npm view prisma@latest exports`. +- The design branch is checked out in the previous worktree at `wip/design/` (a git worktree under the gitignored `wip/`). In a fresh worktree, `git worktree add wip/design docs/orm8-docs-audit-design` after `git fetch bot` and `git branch -f docs/orm8-docs-audit-design bot/docs/orm8-docs-audit-design`. ## How to work (rules Will has given, in his words where possible) @@ -29,6 +32,8 @@ Search it for `C21`, `reader review`, `fact re-check`, `conventions.md`, or a pa - Never fix one sentence Will points at in isolation. Reread the whole page and check the claims around it; a bad sentence has always meant more was wrong nearby ("NEVER REWRITE SENTENCES IN ISOLATION. REREAD THE WHOLE DOCUMENT"). - No commentary about the docs inside the docs: no "this page documents", no "each method has a Remarks list", no "examples carry over between pages". Write the reference itself. - Never interleave PostgreSQL and MongoDB sentence by sentence. Give each database its own example and its own paragraph. +- Merging: when Will says "approved" in chat, squash-merge with `gh pr merge N --squash --delete-branch`. Auto-merge is off for the repo. On 2026-09-14 the tool refused a merge on a GitHub approval alone; ask Will. +- The dev server in a worktree needs `pnpm turbo run build --filter=@prisma/eclipse` first and `rm -rf apps/docs/.next`; the launch config is `docs` on port 3105. Verify nav changes by reading the sidebar without clicking anything open, and check the live site with the folder collapsed as a reader sees it. Do not report "it is in the nav" from the presence of text in the HTML. - Resolving CodeRabbit threads: zsh does not word-split `$ids`, so loop with `while read -r id`, and keep the GraphQL query in a file under `wip/` and pass it with `-f query="$(cat file)"`. - Do not paste the readers' reports into pages; extract each agent's final message from its task output with the small script in `c21-orm-client/` (`extract.py` in the previous scratchpad; it prints the last assistant text block of a task JSONL). @@ -45,9 +50,9 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. -## Current task: `orm/contract-authoring/` +## Current task: `orm/data-modeling/` -`orm/reference/` is done (#8260, #8267). Next is item 1 below, one PR per section. Things learned on the reference pages that the fundamentals pages did not show: +`orm/reference/` (#8260, #8267) and `orm/contract-authoring/` (#8271) are done. Next is item 1 below, one PR per section. The contract-authoring pass is the model for a section of explanation pages: `docs/orm-docs-audit/c21-contract-authoring/` at 40c5394e3 on the #8271 branch has its `conventions.md`, `page-conventions.md`, the checker brief (`wip/c21/ca/factcheck-brief.md` in the old worktree; its text is quoted in the transcript), and every report. Copy `page-conventions.md` and adapt it: it bans commentary about the docs, interleaved PostgreSQL and MongoDB sentences, and the words capability, gate, codec, canonical, deterministic, pure, source of truth. Things learned on the reference pages that the fundamentals pages did not show: - On a reference page, readers keep asking for getting-started material (installing, `prisma orm init`, creating tables). Answer with one sentence and a link; do not add it. - From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts on the orm-client page and twenty-six on the other reference pages after four wording rounds, so do not skip it. @@ -56,8 +61,17 @@ Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggreg ## After that, in order -1. `orm/contract-authoring/` (the current task), then `orm/data-modeling/`, `orm/migrations/`, `orm/middleware/`, `orm/extensions/` (20 pages in all), one PR per section. +1. `orm/data-modeling/` (the current task, 3 pages), then `orm/migrations/` (6 pages, where C25 fits), `orm/middleware/`, `orm/extensions/`, one PR per section. 2. C25, `brief-intermediate-contracts.md`: intermediate contracts in data transform migrations. Fits the `orm/migrations/` section pass. 3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. 4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. 5. Briefs waiting for an ORM-side owner: `brief-skill-staleness.md` (D14), D17 in `changes.md`. Add to D14: the scorecard marks `contains`/`startsWith`/`endsWith` as reachable when they are not, and the skill still says N:M includes fail when they work. + +## Open questions from the last session, for Will + +- **SQLite.** `@prisma/orm-sqlite` is published at the same version as the PostgreSQL and MongoDB packages and the source has a SQLite target, but Will's brief for the Supported databases page said everything except PostgreSQL and MongoDB is coming soon, so the page lists SQLite as coming soon and the Release status page no longer names the SQLite library. Will decides whether SQLite gets a status. +- **A JavaScript `Date` codec.** Will and Serhii are discussing one beside the Temporal codecs. There is no real-user evidence logged anywhere in this project; the evidence is D10 in `changes.md` (inferred contracts throw at read time without a global `Temporal`, which Node.js 22 and 24 lack), the raw-queries readers stumbling on `Temporal.Instant` in four rounds, raw SQL rejecting a `Date` outright, MongoDB returning a `Date` while PostgreSQL returns Temporal, and the `DateString` family being the only escape hatch. Discord and GitHub issues were not searched. +- **Implicit many-to-many** is not supported at rc.10 or rc.11: two bare list fields raise `PSL_ORPHANED_BACKRELATION` and the message says to write a join model. The docs say so correctly. Serhii read the upgrade guide as saying many-to-many is unsupported; only the implicit form is. +- **Operating contexts.** The Supported databases page covers only the database section of prisma/orm#25843. Runtimes, frameworks, deployment platforms, and languages have no Prisma ORM 8 page. +- A team-facing summary of the whole project is published at https://claude.ai/code/artifact/3516e640-e939-4c4a-9db6-ff858027cf93 (Will's private artifact). + From 07800c515251d3fbba9139b2fdc944085916c77b Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 14 Sep 2026 16:40:02 +0200 Subject: [PATCH 23/28] docs: absolute paths in the handover Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index 3ac82862bb..91a995de70 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -8,11 +8,22 @@ Written 2026-09-12, updated 2026-09-14, by the previous agent for the next one. Search the transcript for `C21`, `reader review`, `fact re-check`, `factcheck2`, `conventions.md`, or a page name. It was compacted once; the first user message after compaction carries a summary of everything before it. +## Absolute paths + +The previous agent's worktree is `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7`. It still exists and holds everything below that is not in git: + +- This file: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/design/docs/orm-docs-audit/HANDOVER.md` (the design branch checked out at `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/design/`). +- The rc.10 source checkout: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/prisma-src/` (a worktree of `/Users/wmadden/Projects/prisma/prisma` at `cfccb09be2`). +- The contract-authoring briefs: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck-brief.md`, `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck2-brief.md`, `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/fixer-brief.md`, and the PR body `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/pr-body.md`. The reference-section briefs are beside them in `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/`. +- The report extractor: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/extract.py`. +- The reports of every round, as files: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/r1/` to `r4/` and `fc2/` hold the page copies; the reader and checker reports are in git at commit 40c5394e3 of `docs/orm8-plain-language-contract-authoring` under `docs/orm-docs-audit/c21-contract-authoring/`, and at 13f900ad2 of `docs/orm8-plain-language-orm-reference` under `docs/orm-docs-audit/c21-orm-reference/`. Read them with `git show :` from any worktree of prisma/web. +- The docs-reader-review skill: `.claude/skills/docs-reader-review/` at the root of any prisma/web checkout, on `main`. + ## Where things are - `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). - Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. -- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5. +- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5 under `docs/orm-docs-audit/c21-orm-client/`. - PR #8271 (branch `docs/orm8-plain-language-contract-authoring`) is C21 on `orm/contract-authoring/` (the data contract, PSL, TypeScript builder, the two emitted files, and the page now titled Supported database features), plus three things Will asked for while it ran: the Supported databases page at `/prisma-orm/supported-databases` (PostgreSQL release candidate, MongoDB early access, everything else coming soon; it replaces the database section of prisma/orm#25843), the upgrade guides linked from the ORM section's Introduction and the v7 guides nav, and a sidebar fix (folders in the version-filtered Guides tree never opened for their own page; they now match by id). It is approved on GitHub and green; the agent could not merge it because the tool refused a merge, so Will merges it. The reports are in the branch history at 40c5394e3. The plain-language checker (`check-plain.sh`) now skips link targets, pinned anchors, `href` attributes, and the front-matter `url` line. - PR #8267 (branch `docs/orm8-plain-language-orm-reference`) is C21 on the rest of `orm/reference/` (`sql-query-builder`, `raw-queries`, `pipeline-builder`, `transactions-and-runtime`, `index`), merged 2026-09-13: a fact check against rc.10, four reader rounds, a final fact re-check, and CodeRabbit's six comments. The reports are in the branch history at 13f900ad2. The error reference page is generated from prisma/orm and out of scope. - The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. @@ -35,7 +46,7 @@ Search the transcript for `C21`, `reader review`, `fact re-check`, `factcheck2`, - Merging: when Will says "approved" in chat, squash-merge with `gh pr merge N --squash --delete-branch`. Auto-merge is off for the repo. On 2026-09-14 the tool refused a merge on a GitHub approval alone; ask Will. - The dev server in a worktree needs `pnpm turbo run build --filter=@prisma/eclipse` first and `rm -rf apps/docs/.next`; the launch config is `docs` on port 3105. Verify nav changes by reading the sidebar without clicking anything open, and check the live site with the folder collapsed as a reader sees it. Do not report "it is in the nav" from the presence of text in the HTML. - Resolving CodeRabbit threads: zsh does not word-split `$ids`, so loop with `while read -r id`, and keep the GraphQL query in a file under `wip/` and pass it with `-f query="$(cat file)"`. -- Do not paste the readers' reports into pages; extract each agent's final message from its task output with the small script in `c21-orm-client/` (`extract.py` in the previous scratchpad; it prints the last assistant text block of a task JSONL). +- Do not paste the readers' reports into pages; extract each agent's final message from its task output with `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/extract.py` (usage: `python3 extract.py `; it prints the last assistant text block of a task JSONL). ## The C21 method (what worked on the fundamentals pages) @@ -43,7 +54,7 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: 1. Run `scripts/check-plain.sh` and fix hits. 2. Dispatch a fresh Opus reader with `references/reader-persona.md` verbatim and only the page (a long page in slices by `##` heading, 400 to 700 lines each). Save its report with the extract script. -3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; in `c21-orm-client/` on #8260), the page's own conventions file if any, the report, and the source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. +3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; the latest is `docs/orm-docs-audit/c21-contract-authoring/conventions.md` at commit 40c5394e3), the page's own conventions file if any, the report, and the source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. 4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a "no longer than it is now" budget, because pages grow and readers then trip on the additions. 5. Fact re-check by a separate Opus agent against the source, claim by claim, before the PR. On the fundamentals pages this caught seven real errors that the wording rounds had introduced or left standing. Do not skip it. 6. Commit each round. Link check: `cd apps/docs && node_modules/.bin/fumadocs-mdx && node_modules/.bin/tsx ./scripts/lint-links.ts`. Spelling: `node_modules/.bin/cspell "content/docs/orm/**/*.mdx"` (random sample ids fail it; use `cuid2000...` style). Revert any `meta.json` the formatter touches. @@ -52,7 +63,7 @@ Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggreg ## Current task: `orm/data-modeling/` -`orm/reference/` (#8260, #8267) and `orm/contract-authoring/` (#8271) are done. Next is item 1 below, one PR per section. The contract-authoring pass is the model for a section of explanation pages: `docs/orm-docs-audit/c21-contract-authoring/` at 40c5394e3 on the #8271 branch has its `conventions.md`, `page-conventions.md`, the checker brief (`wip/c21/ca/factcheck-brief.md` in the old worktree; its text is quoted in the transcript), and every report. Copy `page-conventions.md` and adapt it: it bans commentary about the docs, interleaved PostgreSQL and MongoDB sentences, and the words capability, gate, codec, canonical, deterministic, pure, source of truth. Things learned on the reference pages that the fundamentals pages did not show: +`orm/reference/` (#8260, #8267) and `orm/contract-authoring/` (#8271) are done. Next is item 1 below, one PR per section. The contract-authoring pass is the model for a section of explanation pages: `docs/orm-docs-audit/c21-contract-authoring/` at 40c5394e3 on the #8271 branch has its `conventions.md`, `page-conventions.md`, the checker brief (`/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck-brief.md`), and every report. Copy `page-conventions.md` and adapt it: it bans commentary about the docs, interleaved PostgreSQL and MongoDB sentences, and the words capability, gate, codec, canonical, deterministic, pure, source of truth. Things learned on the reference pages that the fundamentals pages did not show: - On a reference page, readers keep asking for getting-started material (installing, `prisma orm init`, creating tables). Answer with one sentence and a link; do not add it. - From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts on the orm-client page and twenty-six on the other reference pages after four wording rounds, so do not skip it. From 4613d6f1301b72a2d4d86c3ab3abac81ea3a4fa4 Mon Sep 17 00:00:00 2001 From: willbot Date: Tue, 15 Sep 2026 15:59:01 +0200 Subject: [PATCH 24/28] docs: handover after the data-modeling section Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index 91a995de70..b5647ff956 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -1,10 +1,12 @@ # Handover: Prisma ORM 8 docs audit and plain-language pass -Written 2026-09-12, updated 2026-09-14, by the previous agent for the next one. Read this first, then `changes.md` in this directory. +Written 2026-09-12, updated 2026-09-15, by the previous agent for the next one. Read this first, then `changes.md` in this directory. ## Transcript of the previous session -`/Users/wmadden/.claude/projects/-Users-wmadden-Projects-prisma-web--claude-worktrees-error-reference-follow-ups-81a8e7/29b9a58b-bb9f-48f4-8639-597b84cf76f8.jsonl` (about 15 MB; 2026-09-13 to 2026-09-14, the orm/reference and contract-authoring passes). If your sandbox cannot read it, tell Will straight away and wait: he will copy it into your worktree. Do not continue without it. The session before that one is at `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` (the audit and the fundamentals pass). +The most recent session (2026-09-14 to 2026-09-15, the data-modeling pass and the Supported databases consolidation) is `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-pr-conflicts-review-fb93f7/ce65cd59-a425-4754-9e75-9f9f740b388b.jsonl` (about 6 MB). Its worktree is `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7`, which holds `wip/c21/dm/` (the data-modeling briefs, page copies per round, and `extract.py` in `wip/c21/`), `wip/prisma-src/` (a plain `git archive` export of rc.10, not a worktree, because that session only had read access to `/Users/wmadden/Projects/prisma/prisma`), `wip/orm/` (a shallow clone of prisma/orm through the bot remote), and `wip/migrations-before-queries.md` (a brief for the ORM team, see below). Note that the two transcripts belong to two macOS users, `will` and `wmadden`, who are both Will; if a path is unreadable, tell Will and he grants access with an ACL. + +The session before that is `/Users/wmadden/.claude/projects/-Users-wmadden-Projects-prisma-web--claude-worktrees-error-reference-follow-ups-81a8e7/29b9a58b-bb9f-48f4-8639-597b84cf76f8.jsonl` (about 15 MB; 2026-09-13 to 2026-09-14, the orm/reference and contract-authoring passes). If your sandbox cannot read it, tell Will straight away and wait: he will copy it into your worktree. Do not continue without it. The session before that one is at `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` (the audit and the fundamentals pass). Search the transcript for `C21`, `reader review`, `fact re-check`, `factcheck2`, `conventions.md`, or a page name. It was compacted once; the first user message after compaction carries a summary of everything before it. @@ -26,8 +28,13 @@ The previous agent's worktree is `/Users/wmadden/Projects/prisma/web/.claude/wor - PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5 under `docs/orm-docs-audit/c21-orm-client/`. - PR #8271 (branch `docs/orm8-plain-language-contract-authoring`) is C21 on `orm/contract-authoring/` (the data contract, PSL, TypeScript builder, the two emitted files, and the page now titled Supported database features), plus three things Will asked for while it ran: the Supported databases page at `/prisma-orm/supported-databases` (PostgreSQL release candidate, MongoDB early access, everything else coming soon; it replaces the database section of prisma/orm#25843), the upgrade guides linked from the ORM section's Introduction and the v7 guides nav, and a sidebar fix (folders in the version-filtered Guides tree never opened for their own page; they now match by id). It is approved on GitHub and green; the agent could not merge it because the tool refused a merge, so Will merges it. The reports are in the branch history at 40c5394e3. The plain-language checker (`check-plain.sh`) now skips link targets, pinned anchors, `href` attributes, and the front-matter `url` line. - PR #8267 (branch `docs/orm8-plain-language-orm-reference`) is C21 on the rest of `orm/reference/` (`sql-query-builder`, `raw-queries`, `pipeline-builder`, `transactions-and-runtime`, `index`), merged 2026-09-13: a fact check against rc.10, four reader rounds, a final fact re-check, and CodeRabbit's six comments. The reports are in the branch history at 13f900ad2. The error reference page is generated from prisma/orm and out of scope. +- PR #8279 (branch `docs/orm8-plain-language-data-modeling`) is C21 on `orm/data-modeling/` (`index`, `relational-databases`, `mongodb`), merged 2026-09-15: a fact check against rc.10, four reader rounds, a final fact re-check (five drifts), seven CodeRabbit threads. The reports, `conventions.md`, and `page-conventions.md` are in the branch history at 19138ba09. The same PR moved Release status and Supported databases from the Getting Started tree into the ORM section (`/orm/release-status`, `/orm/supported-databases`, old URLs redirect, Getting Started keeps link entries), and merged the older `orm/reference/supported-databases` page into `/orm/supported-databases` (Ankur's feature table, hosted-provider table, and community-package note kept; SQLite is Experimental with `@prisma/orm-sqlite`, MySQL is coming soon and planned next, MongoDB is early access; Will decided all three). +- Two things learned on the data-modeling pages: on MongoDB, `@map` renames the field in TypeScript as well as in the database, so the primary key is always `_id` in code. That is filed as a bug, TML-3247 on the Terminal team in Linear, related to TML-2961. And the `prisma-8` skill's `contract.md` says the default referential action is `Restrict`; the code writes no clause at all. Add that to D14. +- prisma/orm#30296 (branch `docs/readme-v7-support-window`) fixes the README, CONTRIBUTING, and SECURITY to say Prisma 7 gets bug fixes and security updates for eighteen months after `8.0.0` final, matching the Release status page. Approved, auto-merge armed behind the merge queue as of 2026-09-15. +- prisma/orm#30287 (open) makes `schema.prisma` a Prisma ORM 8 contract source (`prisma7Schema('prisma/schema.prisma')` in `prisma.config.ts`), so a Prisma 7 app runs `contract emit`, `db sign`, and `db verify` on the file it already has, with zero findings. When it ships (rc.12), the upgrade guide and Coming from Prisma ORM 7 are wrong where they describe `contract infer` plus hand edits, and the migrations section pass should know it is coming. `wip/migrations-before-queries.md` in the worktree above is the brief Will shared with the team on the route it enables (hand migrations to Prisma ORM 8 first, keep Prisma 7 queries); it lists what is still missing, including a `migrations: false` option for the Prisma 7 config. - The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. - The published `prisma` package (8.0.0-rc.15 on 2026-09-14) exports `./config`, so the docs import `definePrismaConfig` from `prisma/config`. The rc.10 source tree only has `@prisma/cli-engine` and every fact checker "corrects" it; revert them. Check with `npm view prisma@latest exports`. +- pnpm on Will's machine (user `will`) could not switch to the pinned 12.3.4 because its managed install under `~/Library/pnpm/.tools/pnpm/12.3.4` was a placeholder; running that package's `install.js` fixed it. If `pnpm` prints `ENOEXEC`, that is the cause. - The design branch is checked out in the previous worktree at `wip/design/` (a git worktree under the gitignored `wip/`). In a fresh worktree, `git worktree add wip/design docs/orm8-docs-audit-design` after `git fetch bot` and `git branch -f docs/orm8-docs-audit-design bot/docs/orm8-docs-audit-design`. ## How to work (rules Will has given, in his words where possible) @@ -61,18 +68,19 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. -## Current task: `orm/data-modeling/` +## Current task: `orm/migrations/` -`orm/reference/` (#8260, #8267) and `orm/contract-authoring/` (#8271) are done. Next is item 1 below, one PR per section. The contract-authoring pass is the model for a section of explanation pages: `docs/orm-docs-audit/c21-contract-authoring/` at 40c5394e3 on the #8271 branch has its `conventions.md`, `page-conventions.md`, the checker brief (`/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck-brief.md`), and every report. Copy `page-conventions.md` and adapt it: it bans commentary about the docs, interleaved PostgreSQL and MongoDB sentences, and the words capability, gate, codec, canonical, deterministic, pure, source of truth. Things learned on the reference pages that the fundamentals pages did not show: +`orm/reference/` (#8260, #8267), `orm/contract-authoring/` (#8271), and `orm/data-modeling/` (#8279) are done. Next is `orm/migrations/` (six pages: `how-migrations-work`, `generating-a-migration`, `applying-a-migration`, `editing-a-migration`, `rollbacks-and-recovery`, `the-migration-graph`), one PR for the section, where C25 (intermediate contracts, `brief-intermediate-contracts.md`) fits. The data-modeling pass is the closest model: `docs/orm-docs-audit/c21-data-modeling/` at 19138ba09 on the #8279 branch has its `conventions.md`, `page-conventions.md`, and every report, and the briefs are at `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/dm/` (`factcheck-brief.md`, `fixer-brief.md`, `factcheck2-brief.md`). Copy `page-conventions.md` and adapt it. Things learned on the data-modeling pages: -- On a reference page, readers keep asking for getting-started material (installing, `prisma orm init`, creating tables). Answer with one sentence and a link; do not add it. -- From round three on, fixers add answers and readers then trip on the additions. Give every fixer from round three a "no longer than now" budget, and tell round four's fixers to prefer cutting. The final fact re-check found thirteen drifts on the orm-client page and twenty-six on the other reference pages after four wording rounds, so do not skip it. -- Fact checkers infer motives and defaults the source does not state (why a helper was renamed, what a driver returns). Trim to what a source line says. -- When a section's pages run in parallel, a `page-conventions.md` beside `conventions.md` keeps them agreeing on setup lines, the example schema, and phrasing such as "PostgreSQL only". +- Readers ask for setup material (the config file, `prisma orm init`, the command loop) in every round. Answer with one sentence and a link each time; do not add a setup section. The one exception that paid off: naming the command sequence once, in a Next steps bullet, without flags (`apps/docs/CLAUDE.md` forbids flags on guide pages, and CodeRabbit enforces it). +- Error codes are noise to a first reader. Keep the one a Prisma ORM 7 reader will hit from habit (`PSL_ORPHANED_BACKRELATION`) and state the rule before the code; cut the rest. +- Prisma ORM 7 comparisons ("Prisma ORM 7 called this the back-relation") are facts the rc.10 source cannot confirm. State them as Prisma ORM 7 facts and tell the final checker so. +- On the migrations pages specifically: the `db` ref, `migrate dev` versus `db migrate`, `db sign` versus `db init`, and what `migration plan` writes (a directory, not a file) are the claims that drifted on other pages. Check them first. +- From round three on, no-growth budgets and "prefer cutting". The section ended seven lines shorter than it started and the final re-check still found five drifts. ## After that, in order -1. `orm/data-modeling/` (the current task, 3 pages), then `orm/migrations/` (6 pages, where C25 fits), `orm/middleware/`, `orm/extensions/`, one PR per section. +1. `orm/migrations/` (the current task, 6 pages, where C25 fits), then `orm/middleware/`, `orm/extensions/`, one PR per section. 2. C25, `brief-intermediate-contracts.md`: intermediate contracts in data transform migrations. Fits the `orm/migrations/` section pass. 3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. 4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. @@ -80,7 +88,11 @@ Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggreg ## Open questions from the last session, for Will -- **SQLite.** `@prisma/orm-sqlite` is published at the same version as the PostgreSQL and MongoDB packages and the source has a SQLite target, but Will's brief for the Supported databases page said everything except PostgreSQL and MongoDB is coming soon, so the page lists SQLite as coming soon and the Release status page no longer names the SQLite library. Will decides whether SQLite gets a status. +- **SQLite** is decided: Experimental, with `@prisma/orm-sqlite`, on the Supported databases page. The Release status page still does not name the SQLite library; make them agree when that page is next touched. +- **Default referential action.** When `onDelete` and `onUpdate` are both omitted, Prisma ORM writes no clause. The relational data-modeling page says "the database decides" and does not name PostgreSQL's `NO ACTION`. Will has not said whether to name it. +- **MongoDB before the first write.** The skill says `db migrate` writes a marker document in `_prisma_migrations`, but no marker check was found in the MongoDB runtime, so no page says whether an unmigrated database rejects a write. +- **`namespace` blocks** exist in the PSL interpreter (`interpreter.ts:197-231`) and no page documents them; the relational page mentions them in one clause without a link. +- **Node.js floor for `Temporal`.** The source and the raw-queries page say 26.8.2; `coming-from-prisma-orm-7.mdx` line 65 says "26 and later". Fix the latter when that page is next touched. - **A JavaScript `Date` codec.** Will and Serhii are discussing one beside the Temporal codecs. There is no real-user evidence logged anywhere in this project; the evidence is D10 in `changes.md` (inferred contracts throw at read time without a global `Temporal`, which Node.js 22 and 24 lack), the raw-queries readers stumbling on `Temporal.Instant` in four rounds, raw SQL rejecting a `Date` outright, MongoDB returning a `Date` while PostgreSQL returns Temporal, and the `DateString` family being the only escape hatch. Discord and GitHub issues were not searched. - **Implicit many-to-many** is not supported at rc.10 or rc.11: two bare list fields raise `PSL_ORPHANED_BACKRELATION` and the message says to write a join model. The docs say so correctly. Serhii read the upgrade guide as saying many-to-many is unsupported; only the implicit form is. - **Operating contexts.** The Supported databases page covers only the database section of prisma/orm#25843. Runtimes, frameworks, deployment platforms, and languages have no Prisma ORM 8 page. From dc7b37f2b1955887191de22fa179937c313c49f4 Mon Sep 17 00:00:00 2001 From: willbot Date: Tue, 15 Sep 2026 18:55:56 +0200 Subject: [PATCH 25/28] docs: handover after the migrations section Co-Authored-By: Claude Opus 5 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 71 ++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index b5647ff956..b570122872 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -4,7 +4,7 @@ Written 2026-09-12, updated 2026-09-15, by the previous agent for the next one. ## Transcript of the previous session -The most recent session (2026-09-14 to 2026-09-15, the data-modeling pass and the Supported databases consolidation) is `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-pr-conflicts-review-fb93f7/ce65cd59-a425-4754-9e75-9f9f740b388b.jsonl` (about 6 MB). Its worktree is `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7`, which holds `wip/c21/dm/` (the data-modeling briefs, page copies per round, and `extract.py` in `wip/c21/`), `wip/prisma-src/` (a plain `git archive` export of rc.10, not a worktree, because that session only had read access to `/Users/wmadden/Projects/prisma/prisma`), `wip/orm/` (a shallow clone of prisma/orm through the bot remote), and `wip/migrations-before-queries.md` (a brief for the ORM team, see below). Note that the two transcripts belong to two macOS users, `will` and `wmadden`, who are both Will; if a path is unreadable, tell Will and he grants access with an ACL. +The most recent session (2026-09-14 to 2026-09-15, the data-modeling pass, the Supported databases consolidation, and the migrations pass) is `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-pr-conflicts-review-fb93f7/ce65cd59-a425-4754-9e75-9f9f740b388b.jsonl` (about 6 MB). Its worktree is `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7`, which holds `wip/c21/dm/` and `wip/c21/mig/` (the data-modeling and migrations briefs, shared answers, page copies per round, and reports; `extract.py` is in `wip/c21/`), `wip/prisma-src-rc11/` (a plain export of prisma/orm at rc.11, `ff47560c9f`), `wip/prisma-src/` (a plain `git archive` export of rc.10, not a worktree, because that session only had read access to `/Users/wmadden/Projects/prisma/prisma`), `wip/orm/` (a shallow clone of prisma/orm through the bot remote), and `wip/migrations-before-queries.md` (a brief for the ORM team, see below). Note that the two transcripts belong to two macOS users, `will` and `wmadden`, who are both Will; if a path is unreadable, tell Will and he grants access with an ACL. The session before that is `/Users/wmadden/.claude/projects/-Users-wmadden-Projects-prisma-web--claude-worktrees-error-reference-follow-ups-81a8e7/29b9a58b-bb9f-48f4-8639-597b84cf76f8.jsonl` (about 15 MB; 2026-09-13 to 2026-09-14, the orm/reference and contract-authoring passes). If your sandbox cannot read it, tell Will straight away and wait: he will copy it into your worktree. Do not continue without it. The session before that one is at `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` (the audit and the fundamentals pass). @@ -32,7 +32,7 @@ The previous agent's worktree is `/Users/wmadden/Projects/prisma/web/.claude/wor - Two things learned on the data-modeling pages: on MongoDB, `@map` renames the field in TypeScript as well as in the database, so the primary key is always `_id` in code. That is filed as a bug, TML-3247 on the Terminal team in Linear, related to TML-2961. And the `prisma-8` skill's `contract.md` says the default referential action is `Restrict`; the code writes no clause at all. Add that to D14. - prisma/orm#30296 (branch `docs/readme-v7-support-window`) fixes the README, CONTRIBUTING, and SECURITY to say Prisma 7 gets bug fixes and security updates for eighteen months after `8.0.0` final, matching the Release status page. Approved, auto-merge armed behind the merge queue as of 2026-09-15. - prisma/orm#30287 (open) makes `schema.prisma` a Prisma ORM 8 contract source (`prisma7Schema('prisma/schema.prisma')` in `prisma.config.ts`), so a Prisma 7 app runs `contract emit`, `db sign`, and `db verify` on the file it already has, with zero findings. When it ships (rc.12), the upgrade guide and Coming from Prisma ORM 7 are wrong where they describe `contract infer` plus hand edits, and the migrations section pass should know it is coming. `wip/migrations-before-queries.md` in the worktree above is the brief Will shared with the team on the route it enables (hand migrations to Prisma ORM 8 first, keep Prisma 7 queries); it lists what is still missing, including a `migrations: false` option for the Prisma 7 config. -- The Prisma ORM 8 source used for every fact check is `prisma/orm` at `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. +- The Prisma ORM 8 source for the migrations pass was `prisma/orm` at `8.0.0-rc.11` (`ff47560c9f`), exported at `wip/prisma-src-rc11/` in the worktree above; use rc.11 for the next section unless Will says otherwise. Earlier sections used `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. - The published `prisma` package (8.0.0-rc.15 on 2026-09-14) exports `./config`, so the docs import `definePrismaConfig` from `prisma/config`. The rc.10 source tree only has `@prisma/cli-engine` and every fact checker "corrects" it; revert them. Check with `npm view prisma@latest exports`. - pnpm on Will's machine (user `will`) could not switch to the pinned 12.3.4 because its managed install under `~/Library/pnpm/.tools/pnpm/12.3.4` was a placeholder; running that package's `install.js` fixed it. If `pnpm` prints `ENOEXEC`, that is the cause. - The design branch is checked out in the previous worktree at `wip/design/` (a git worktree under the gitignored `wip/`). In a fresh worktree, `git worktree add wip/design docs/orm8-docs-audit-design` after `git fetch bot` and `git branch -f docs/orm8-docs-audit-design bot/docs/orm8-docs-audit-design`. @@ -62,26 +62,59 @@ The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: 1. Run `scripts/check-plain.sh` and fix hits. 2. Dispatch a fresh Opus reader with `references/reader-persona.md` verbatim and only the page (a long page in slices by `##` heading, 400 to 700 lines each). Save its report with the extract script. 3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; the latest is `docs/orm-docs-audit/c21-contract-authoring/conventions.md` at commit 40c5394e3), the page's own conventions file if any, the report, and the source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. -4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a "no longer than it is now" budget, because pages grow and readers then trip on the additions. +4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a word budget counted with `wc -w` (not lines: on the migrations pages fixers met line budgets by writing longer lines), because pages grow and readers then trip on the additions. 5. Fact re-check by a separate Opus agent against the source, claim by claim, before the PR. On the fundamentals pages this caught seven real errors that the wording rounds had introduced or left standing. Do not skip it. 6. Commit each round. Link check: `cd apps/docs && node_modules/.bin/fumadocs-mdx && node_modules/.bin/tsx ./scripts/lint-links.ts`. Spelling: `node_modules/.bin/cspell "content/docs/orm/**/*.mdx"` (random sample ids fail it; use `cuid2000...` style). Revert any `meta.json` the formatter touches. Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. -## Current task: `orm/migrations/` - -`orm/reference/` (#8260, #8267), `orm/contract-authoring/` (#8271), and `orm/data-modeling/` (#8279) are done. Next is `orm/migrations/` (six pages: `how-migrations-work`, `generating-a-migration`, `applying-a-migration`, `editing-a-migration`, `rollbacks-and-recovery`, `the-migration-graph`), one PR for the section, where C25 (intermediate contracts, `brief-intermediate-contracts.md`) fits. The data-modeling pass is the closest model: `docs/orm-docs-audit/c21-data-modeling/` at 19138ba09 on the #8279 branch has its `conventions.md`, `page-conventions.md`, and every report, and the briefs are at `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/dm/` (`factcheck-brief.md`, `fixer-brief.md`, `factcheck2-brief.md`). Copy `page-conventions.md` and adapt it. Things learned on the data-modeling pages: - -- Readers ask for setup material (the config file, `prisma orm init`, the command loop) in every round. Answer with one sentence and a link each time; do not add a setup section. The one exception that paid off: naming the command sequence once, in a Next steps bullet, without flags (`apps/docs/CLAUDE.md` forbids flags on guide pages, and CodeRabbit enforces it). -- Error codes are noise to a first reader. Keep the one a Prisma ORM 7 reader will hit from habit (`PSL_ORPHANED_BACKRELATION`) and state the rule before the code; cut the rest. -- Prisma ORM 7 comparisons ("Prisma ORM 7 called this the back-relation") are facts the rc.10 source cannot confirm. State them as Prisma ORM 7 facts and tell the final checker so. -- On the migrations pages specifically: the `db` ref, `migrate dev` versus `db migrate`, `db sign` versus `db init`, and what `migration plan` writes (a directory, not a file) are the claims that drifted on other pages. Check them first. -- From round three on, no-growth budgets and "prefer cutting". The section ended seven lines shorter than it started and the final re-check still found five drifts. +## Done: `orm/migrations/` (PR #8281) + +PR #8281 (branch `docs/orm8-plain-language-migrations`) is C21 on the six `orm/migrations/` pages, plus C25, a new section in Editing a migration: "When a backfill reads a column the migration removes". Open as of 2026-09-15. + +The pass ran these steps: +1. A banned-term pass and a fact check against rc.11. +2. A real run of the pages' commands with `prisma` 8.0.0-rc.15 and a local PostgreSQL. +3. Four reader rounds. +4. A final fact re-check, which made 28 corrections. + +The briefs, shared answers, page copies per round, and every report are in `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/mig/`. None is in the PR, because Will said not to add dispatches to PRs. The most useful files there: +- `round2-notes.md`, which holds every final-check item and its resolution. +- `round1-shared-answers.md` to `round4-shared-answers.md`, which are sourced facts about migrations. +- `real-run-transcript.md`. +- `notes-for-handover.md`, which lists the product bugs. +- `fc2-drifts.md`, what the final check corrected. + +Things learned on this pass: +- **Budget in words, not lines.** Round three's fixers met line budgets by writing longer lines, and four pages grew by up to 13%. +- **Run the commands.** The real run caught several things that reading the source did not: + - a wrong rollback end state; + - an `updatedAt` column makes a backfill impossible to apply; + - the unfilled-placeholder failure was blamed on the wrong cause; + - the literal `{bin}` in CLI hints; + - `node migration.ts` works only from the project root. + + Do the same for any section whose pages show commands. +- **Shared answers every round.** Readers on all six pages asked the same questions. One shared-answers file per round kept the pages consistent. When a fact turns up while fixers run, send it to the affected fixer. +- **Cross-check one checker's finding on the other pages.** The How migrations work checker found that a MongoDB re-run stops at a collection the failed run created. Three other pages said the opposite, and their checkers had confirmed it. +- **Length.** The section went from 9997 words on `main` to 13749. Most of the growth answers questions readers asked every round, and C25 adds about 60 lines. Will has not said whether he wants a cutting round. ## After that, in order -1. `orm/migrations/` (the current task, 6 pages, where C25 fits), then `orm/middleware/`, `orm/extensions/`, one PR per section. -2. C25, `brief-intermediate-contracts.md`: intermediate contracts in data transform migrations. Fits the `orm/migrations/` section pass. +1. Handle review on #8281 (the migrations section), then `orm/middleware/`, `orm/extensions/`, one PR per section. +2. File the product bugs from the migrations pass, listed in `wip/c21/mig/notes-for-handover.md`, wherever Will decides. The list: + - `{bin}` is never replaced. + - Planner-written migrations don't type-check. + - An `updatedAt` backfill can never be applied. + - `migration new --from` writes a no-op migration that breaks planning. + - `node migration.ts` works only from the project root. + - `contract emit --config` misreports its output file names. + - The `db migrate` summary count is off. + - `npx prisma dev` needs an entry argument. + - `migration log` sorts rows applied in the same second by name. + - A MongoDB re-run after a partial failure stops at a collection the failed run created. + + Outside the section: `studio/prisma-next.mdx` line 112 describes `migration plan` with no `db` ref wrongly. Also add to D14: the `prisma-8` skill says an un-recompiled `migration.ts` edit causes a hash mismatch, and it does not. 3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. 4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. 5. Briefs waiting for an ORM-side owner: `brief-skill-staleness.md` (D14), D17 in `changes.md`. Add to D14: the scorecard marks `contains`/`startsWith`/`endsWith` as reachable when they are not, and the skill still says N:M includes fail when they work. @@ -97,4 +130,12 @@ Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggreg - **Implicit many-to-many** is not supported at rc.10 or rc.11: two bare list fields raise `PSL_ORPHANED_BACKRELATION` and the message says to write a join model. The docs say so correctly. Serhii read the upgrade guide as saying many-to-many is unsupported; only the implicit form is. - **Operating contexts.** The Supported databases page covers only the database section of prisma/orm#25843. Runtimes, frameworks, deployment platforms, and languages have no Prisma ORM 8 page. - A team-facing summary of the whole project is published at https://claude.ai/code/artifact/3516e640-e939-4c4a-9db6-ff858027cf93 (Will's private artifact). - +- **Migrations pass: committing refs.** Should `migrations/app/refs/db.json` be committed? The same question applies to a `prod` ref. The source is silent, and no migrations page says. +- **Migrations pass: `--advance-ref db`.** Why is it not the default in development? The source gives no reason. +- **Migrations pass: the `prod` ref.** Does it mean what is deployed or what should be deployed, and should deploys move it? +- **Migrations pass: merge workflow.** The graph page shows the diamond from the e2e test, with two merge migrations after both branches merge. `skills/prisma-8/references/migration-review.md` 116-130 recommends rebasing and replanning instead. +- **Migrations pass: adoption order.** Generating a migration says sign, then plan, then migrate. The PostgreSQL upgrade guide says plan a baseline, sign, then set the `db` ref. Both work. +- **Migrations pass: `db sign` failing on production.** Its error suggests running `db update` and then signing again. The pages do not recommend that on production. +- **Migrations pass: Discord.** Should the pages name the `#prisma-next` channel? They now say only "ask on Discord". +- **Migrations pass: Node.js version.** The published `prisma` 8.0.0-rc.15 declares `node >=22.18.0`, but the rc.11 monorepo declares `>=24`. The pages say 22.18. +- **Migrations pass: concurrent PostgreSQL runs.** After waiting for the lock, the second run fails with a marker mismatch. The page says only that one waits for the other. From a5eeb8f5c0ecfcf4b38df1a7ca9b9adbef8b68d8 Mon Sep 17 00:00:00 2001 From: willbot Date: Wed, 16 Sep 2026 10:09:20 +0200 Subject: [PATCH 26/28] docs(audit): record the migrations cutting round and terminology decisions Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index b570122872..ad61ededba 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -77,6 +77,7 @@ The pass ran these steps: 2. A real run of the pages' commands with `prisma` 8.0.0-rc.15 and a local PostgreSQL. 3. Four reader rounds. 4. A final fact re-check, which made 28 corrections. +5. A language review by the operator, then a cutting round: one Opus fixer per page, a word ceiling, and the rule that facts stay fixed. Brief in `wip/c21/mig/cut-brief.md`. The briefs, shared answers, page copies per round, and every report are in `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/mig/`. None is in the PR, because Will said not to add dispatches to PRs. The most useful files there: - `round2-notes.md`, which holds every final-check item and its resolution. @@ -97,7 +98,9 @@ Things learned on this pass: Do the same for any section whose pages show commands. - **Shared answers every round.** Readers on all six pages asked the same questions. One shared-answers file per round kept the pages consistent. When a fact turns up while fixers run, send it to the affected fixer. - **Cross-check one checker's finding on the other pages.** The How migrations work checker found that a MongoDB re-run stops at a collection the failed run created. Three other pages said the opposite, and their checkers had confirmed it. -- **Length.** The section went from 9997 words on `main` to 13749. Most of the growth answers questions readers asked every round, and C25 adds about 60 lines. Will has not said whether he wants a cutting round. +- **Reader rounds bloat pages.** Each round answered readers by adding sentences, and each page ended up defining every term as if the reader arrived cold. The same eight facts were restated on every page. Plan a cutting round after the reader rounds, with the rule: define each term once per page at first use, link elsewhere, facts stay fixed. Fixers refuse ceilings they can only meet by deleting facts, which is right, so set ceilings as ceilings and accept the report. +- **Length.** The section went from 9997 words on `main` to 13749 after the reader rounds and 12606 after the cutting round. +- **Terminology.** Will banned movement metaphors for migrations (the database moves, the marker moves, the ref moves, the database is behind or catches up, where the database is). Say what a command changes and what the database ends up matching. "Database schema" is fine; only PostgreSQL namespaces make it ambiguous, and Will rejected reserving the word. Rules in `.claude/skills/docs-reader-review/references/banned-terms.md`, "Migration vocabulary". ## After that, in order From 414eaa85cd78be8415b07ca7dc41bfe1aebb6cfc Mon Sep 17 00:00:00 2001 From: willbot Date: Wed, 16 Sep 2026 10:25:33 +0200 Subject: [PATCH 27/28] docs(audit): record the explanation round and the explain-not-state rule Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md index ad61ededba..2be939ce2b 100644 --- a/docs/orm-docs-audit/HANDOVER.md +++ b/docs/orm-docs-audit/HANDOVER.md @@ -78,6 +78,7 @@ The pass ran these steps: 3. Four reader rounds. 4. A final fact re-check, which made 28 corrections. 5. A language review by the operator, then a cutting round: one Opus fixer per page, a word ceiling, and the rule that facts stay fixed. Brief in `wip/c21/mig/cut-brief.md`. +6. An explanation round after Will rejected the prose: one Opus fixer per page, no ceiling, rewriting against `.claude/skills/docs-reader-review/references/explain-not-state.md`. Brief in `wip/c21/mig/explain-brief.md`. The briefs, shared answers, page copies per round, and every report are in `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/mig/`. None is in the PR, because Will said not to add dispatches to PRs. The most useful files there: - `round2-notes.md`, which holds every final-check item and its resolution. @@ -99,7 +100,8 @@ Things learned on this pass: - **Shared answers every round.** Readers on all six pages asked the same questions. One shared-answers file per round kept the pages consistent. When a fact turns up while fixers run, send it to the affected fixer. - **Cross-check one checker's finding on the other pages.** The How migrations work checker found that a MongoDB re-run stops at a collection the failed run created. Three other pages said the opposite, and their checkers had confirmed it. - **Reader rounds bloat pages.** Each round answered readers by adding sentences, and each page ended up defining every term as if the reader arrived cold. The same eight facts were restated on every page. Plan a cutting round after the reader rounds, with the rule: define each term once per page at first use, link elsewhere, facts stay fixed. Fixers refuse ceilings they can only meet by deleting facts, which is right, so set ceilings as ceilings and accept the report. -- **Length.** The section went from 9997 words on `main` to 13749 after the reader rounds and 12606 after the cutting round. +- **Explain, do not state.** Will's biggest correction on this pass. The pages stated facts in short correct sentences and never said what they meant for the reader, with counting lead-ins ("Four things change it:") and fragment openers ("One name is special."). His model rewrite and the rules are in `.claude/skills/docs-reader-review/references/explain-not-state.md`, and `check-staccato.py` now flags the mechanical signs. Run that reference on every future section before the reader rounds, not after. Word ceilings make this habit worse: use them only against repetition. +- **Length.** The section went from 9997 words on `main` to 13749 after the reader rounds, 12606 after the cutting round, and 15875 after the explanation round. Will has not objected to the length, only to the prose. - **Terminology.** Will banned movement metaphors for migrations (the database moves, the marker moves, the ref moves, the database is behind or catches up, where the database is). Say what a command changes and what the database ends up matching. "Database schema" is fine; only PostgreSQL namespaces make it ambiguous, and Will rejected reserving the word. Rules in `.claude/skills/docs-reader-review/references/banned-terms.md`, "Migration vocabulary". ## After that, in order From 93bba1b0f5bdf29a9ef452dd0814b6bf1e66da5f Mon Sep 17 00:00:00 2001 From: willbot Date: Wed, 16 Sep 2026 11:20:17 +0200 Subject: [PATCH 28/28] docs(audit): delete HANDOVER.md Co-Authored-By: Claude Fable 5.1 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/orm-docs-audit/HANDOVER.md | 146 -------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 docs/orm-docs-audit/HANDOVER.md diff --git a/docs/orm-docs-audit/HANDOVER.md b/docs/orm-docs-audit/HANDOVER.md deleted file mode 100644 index 2be939ce2b..0000000000 --- a/docs/orm-docs-audit/HANDOVER.md +++ /dev/null @@ -1,146 +0,0 @@ -# Handover: Prisma ORM 8 docs audit and plain-language pass - -Written 2026-09-12, updated 2026-09-15, by the previous agent for the next one. Read this first, then `changes.md` in this directory. - -## Transcript of the previous session - -The most recent session (2026-09-14 to 2026-09-15, the data-modeling pass, the Supported databases consolidation, and the migrations pass) is `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-pr-conflicts-review-fb93f7/ce65cd59-a425-4754-9e75-9f9f740b388b.jsonl` (about 6 MB). Its worktree is `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7`, which holds `wip/c21/dm/` and `wip/c21/mig/` (the data-modeling and migrations briefs, shared answers, page copies per round, and reports; `extract.py` is in `wip/c21/`), `wip/prisma-src-rc11/` (a plain export of prisma/orm at rc.11, `ff47560c9f`), `wip/prisma-src/` (a plain `git archive` export of rc.10, not a worktree, because that session only had read access to `/Users/wmadden/Projects/prisma/prisma`), `wip/orm/` (a shallow clone of prisma/orm through the bot remote), and `wip/migrations-before-queries.md` (a brief for the ORM team, see below). Note that the two transcripts belong to two macOS users, `will` and `wmadden`, who are both Will; if a path is unreadable, tell Will and he grants access with an ACL. - -The session before that is `/Users/wmadden/.claude/projects/-Users-wmadden-Projects-prisma-web--claude-worktrees-error-reference-follow-ups-81a8e7/29b9a58b-bb9f-48f4-8639-597b84cf76f8.jsonl` (about 15 MB; 2026-09-13 to 2026-09-14, the orm/reference and contract-authoring passes). If your sandbox cannot read it, tell Will straight away and wait: he will copy it into your worktree. Do not continue without it. The session before that one is at `/Users/will/.claude/projects/-Users-will-Projects-prisma-web--claude-worktrees-prisma-orm-8-docs-audit-5bdfd9/7636eb55-44f8-408f-b81e-481bd0140ea6.jsonl` (the audit and the fundamentals pass). - -Search the transcript for `C21`, `reader review`, `fact re-check`, `factcheck2`, `conventions.md`, or a page name. It was compacted once; the first user message after compaction carries a summary of everything before it. - -## Absolute paths - -The previous agent's worktree is `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7`. It still exists and holds everything below that is not in git: - -- This file: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/design/docs/orm-docs-audit/HANDOVER.md` (the design branch checked out at `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/design/`). -- The rc.10 source checkout: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/prisma-src/` (a worktree of `/Users/wmadden/Projects/prisma/prisma` at `cfccb09be2`). -- The contract-authoring briefs: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck-brief.md`, `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/factcheck2-brief.md`, `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/fixer-brief.md`, and the PR body `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/pr-body.md`. The reference-section briefs are beside them in `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/`. -- The report extractor: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/extract.py`. -- The reports of every round, as files: `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/ca/r1/` to `r4/` and `fc2/` hold the page copies; the reader and checker reports are in git at commit 40c5394e3 of `docs/orm8-plain-language-contract-authoring` under `docs/orm-docs-audit/c21-contract-authoring/`, and at 13f900ad2 of `docs/orm8-plain-language-orm-reference` under `docs/orm-docs-audit/c21-orm-reference/`. Read them with `git show :` from any worktree of prisma/web. -- The docs-reader-review skill: `.claude/skills/docs-reader-review/` at the root of any prisma/web checkout, on `main`. - -## Where things are - -- `prisma/web` on `main` has, merged this week: the three correction PRs (#8236, #8237, #8238), the naming pass (#8246), Release status and Coming from Prisma ORM 7 (#8245), the `docs-reader-review` skill (#8247), and the plain-language rewrite of the five `orm/fundamentals` pages (#8251). -- Draft PR #8243 (branch `docs/orm8-docs-audit-design`) holds the design docs in `docs/orm-docs-audit/`: `personas.md`, `journeys.md`, `mental-model.md`, `ia.md`, `naming.md`, `changes.md`, `plain-language.md`, the briefs, and this file. It is not meant to merge; it is the shared copy Will links people to. Other people edit this branch: always `git fetch bot` and start from the branch head, and merge your additions rather than copying files over. -- PR #8260 (branch `docs/orm8-plain-language-orm-client`) is C21 on `apps/docs/content/docs/orm/reference/orm-client.mdx`, merged 2026-09-12: two fact re-checks and four reader rounds. The reader and checker reports for that page are in the branch history at d104536a5 under `docs/orm-docs-audit/c21-orm-client/`. -- PR #8271 (branch `docs/orm8-plain-language-contract-authoring`) is C21 on `orm/contract-authoring/` (the data contract, PSL, TypeScript builder, the two emitted files, and the page now titled Supported database features), plus three things Will asked for while it ran: the Supported databases page at `/prisma-orm/supported-databases` (PostgreSQL release candidate, MongoDB early access, everything else coming soon; it replaces the database section of prisma/orm#25843), the upgrade guides linked from the ORM section's Introduction and the v7 guides nav, and a sidebar fix (folders in the version-filtered Guides tree never opened for their own page; they now match by id). It is approved on GitHub and green; the agent could not merge it because the tool refused a merge, so Will merges it. The reports are in the branch history at 40c5394e3. The plain-language checker (`check-plain.sh`) now skips link targets, pinned anchors, `href` attributes, and the front-matter `url` line. -- PR #8267 (branch `docs/orm8-plain-language-orm-reference`) is C21 on the rest of `orm/reference/` (`sql-query-builder`, `raw-queries`, `pipeline-builder`, `transactions-and-runtime`, `index`), merged 2026-09-13: a fact check against rc.10, four reader rounds, a final fact re-check, and CodeRabbit's six comments. The reports are in the branch history at 13f900ad2. The error reference page is generated from prisma/orm and out of scope. -- PR #8279 (branch `docs/orm8-plain-language-data-modeling`) is C21 on `orm/data-modeling/` (`index`, `relational-databases`, `mongodb`), merged 2026-09-15: a fact check against rc.10, four reader rounds, a final fact re-check (five drifts), seven CodeRabbit threads. The reports, `conventions.md`, and `page-conventions.md` are in the branch history at 19138ba09. The same PR moved Release status and Supported databases from the Getting Started tree into the ORM section (`/orm/release-status`, `/orm/supported-databases`, old URLs redirect, Getting Started keeps link entries), and merged the older `orm/reference/supported-databases` page into `/orm/supported-databases` (Ankur's feature table, hosted-provider table, and community-package note kept; SQLite is Experimental with `@prisma/orm-sqlite`, MySQL is coming soon and planned next, MongoDB is early access; Will decided all three). -- Two things learned on the data-modeling pages: on MongoDB, `@map` renames the field in TypeScript as well as in the database, so the primary key is always `_id` in code. That is filed as a bug, TML-3247 on the Terminal team in Linear, related to TML-2961. And the `prisma-8` skill's `contract.md` says the default referential action is `Restrict`; the code writes no clause at all. Add that to D14. -- prisma/orm#30296 (branch `docs/readme-v7-support-window`) fixes the README, CONTRIBUTING, and SECURITY to say Prisma 7 gets bug fixes and security updates for eighteen months after `8.0.0` final, matching the Release status page. Approved, auto-merge armed behind the merge queue as of 2026-09-15. -- prisma/orm#30287 (open) makes `schema.prisma` a Prisma ORM 8 contract source (`prisma7Schema('prisma/schema.prisma')` in `prisma.config.ts`), so a Prisma 7 app runs `contract emit`, `db sign`, and `db verify` on the file it already has, with zero findings. When it ships (rc.12), the upgrade guide and Coming from Prisma ORM 7 are wrong where they describe `contract infer` plus hand edits, and the migrations section pass should know it is coming. `wip/migrations-before-queries.md` in the worktree above is the brief Will shared with the team on the route it enables (hand migrations to Prisma ORM 8 first, keep Prisma 7 queries); it lists what is still missing, including a `migrations: false` option for the Prisma 7 config. -- The Prisma ORM 8 source for the migrations pass was `prisma/orm` at `8.0.0-rc.11` (`ff47560c9f`), exported at `wip/prisma-src-rc11/` in the worktree above; use rc.11 for the next section unless Will says otherwise. Earlier sections used `8.0.0-rc.10` (`cfccb09be2`). In a fresh worktree: `git -C /Users/wmadden/Projects/prisma/prisma worktree add cfccb09be2`. Tag `v8.0.0-rc.11` exists upstream as of 2026-09-14 (`git -C /Users/wmadden/Projects/prisma/prisma fetch origin --tags`; tags are `v8.0.0-rc.N`), and npm `latest` for the three ORM packages is rc.11; the docs still say rc.10. Ask Will whether to move the source to rc.11 before the next section. -- The published `prisma` package (8.0.0-rc.15 on 2026-09-14) exports `./config`, so the docs import `definePrismaConfig` from `prisma/config`. The rc.10 source tree only has `@prisma/cli-engine` and every fact checker "corrects" it; revert them. Check with `npm view prisma@latest exports`. -- pnpm on Will's machine (user `will`) could not switch to the pinned 12.3.4 because its managed install under `~/Library/pnpm/.tools/pnpm/12.3.4` was a placeholder; running that package's `install.js` fixed it. If `pnpm` prints `ENOEXEC`, that is the cause. -- The design branch is checked out in the previous worktree at `wip/design/` (a git worktree under the gitignored `wip/`). In a fresh worktree, `git worktree add wip/design docs/orm8-docs-audit-design` after `git fetch bot` and `git branch -f docs/orm8-docs-audit-design bot/docs/orm8-docs-audit-design`. - -## How to work (rules Will has given, in his words where possible) - -- Act as the `wmadden-electric` bot: commit with `git commit -s --trailer "Signed-off-by: Will Madden "`, end the message with `Co-Authored-By: Claude Fable 5.1 `, push only through the `bot` remote. -- "NOT EVERY FUCKING CHANGE NEEDS A SEPARATE PR": follow-ups go on the open PR. -- Address every review comment and every CI failure without being asked. Resolve CodeRabbit threads via GraphQL `resolveReviewThread` after replying. CodeRabbit's "changes requested" verdict blocks the merge even when all threads are resolved; dismissing it is blocked for the agent, so Will dismisses it or merges with `--admin`. -- PR descriptions: a grounding before/after example first, then the decision, then how it was checked, then what a reviewer should know, alternatives considered last. -- Plain English, no invented jargon, short sentences. Never use the question UI. -- The design docs carry no status ("they are not a fucking to do list"). Progress lives in PRs. -- The product is "Prisma ORM"; a version number only when contrasting ("Prisma ORM 7 to 8"). The reason is separating the Prisma brand from the ORM. -- Use Opus for implementer and reviewer subagents. -- Never fix one sentence Will points at in isolation. Reread the whole page and check the claims around it; a bad sentence has always meant more was wrong nearby ("NEVER REWRITE SENTENCES IN ISOLATION. REREAD THE WHOLE DOCUMENT"). -- No commentary about the docs inside the docs: no "this page documents", no "each method has a Remarks list", no "examples carry over between pages". Write the reference itself. -- Never interleave PostgreSQL and MongoDB sentence by sentence. Give each database its own example and its own paragraph. -- Merging: when Will says "approved" in chat, squash-merge with `gh pr merge N --squash --delete-branch`. Auto-merge is off for the repo. On 2026-09-14 the tool refused a merge on a GitHub approval alone; ask Will. -- The dev server in a worktree needs `pnpm turbo run build --filter=@prisma/eclipse` first and `rm -rf apps/docs/.next`; the launch config is `docs` on port 3105. Verify nav changes by reading the sidebar without clicking anything open, and check the live site with the folder collapsed as a reader sees it. Do not report "it is in the nav" from the presence of text in the HTML. -- Resolving CodeRabbit threads: zsh does not word-split `$ids`, so loop with `while read -r id`, and keep the GraphQL query in a file under `wip/` and pass it with `-f query="$(cat file)"`. -- Do not paste the readers' reports into pages; extract each agent's final message from its task output with `/Users/wmadden/Projects/prisma/web/.claude/worktrees/error-reference-follow-ups-81a8e7/wip/c21/extract.py` (usage: `python3 extract.py `; it prints the last assistant text block of a task JSONL). - -## The C21 method (what worked on the fundamentals pages) - -The skill is `.claude/skills/docs-reader-review/` on `main`. Per page: - -1. Run `scripts/check-plain.sh` and fix hits. -2. Dispatch a fresh Opus reader with `references/reader-persona.md` verbatim and only the page (a long page in slices by `##` heading, 400 to 700 lines each). Save its report with the extract script. -3. Dispatch an Opus fixer per page or slice with: the skill's step 3 rules, `conventions.md` (shared verified facts and wording; the latest is `docs/orm-docs-audit/c21-contract-authoring/conventions.md` at commit 40c5394e3), the page's own conventions file if any, the report, and the source paths. Tell it which facts to look up before writing, a line budget, and to put `Q` markers in its report, not the page. -4. Repeat. Four rounds was the point of diminishing returns on the fundamentals pages; from round three on, give the fixer a word budget counted with `wc -w` (not lines: on the migrations pages fixers met line budgets by writing longer lines), because pages grow and readers then trip on the additions. -5. Fact re-check by a separate Opus agent against the source, claim by claim, before the PR. On the fundamentals pages this caught seven real errors that the wording rounds had introduced or left standing. Do not skip it. -6. Commit each round. Link check: `cd apps/docs && node_modules/.bin/fumadocs-mdx && node_modules/.bin/tsx ./scripts/lint-links.ts`. Spelling: `node_modules/.bin/cspell "content/docs/orm/**/*.mdx"` (random sample ids fail it; use `cuid2000...` style). Revert any `meta.json` the formatter touches. - -Readers keep asking for MongoDB depth on every page (fewer examples, no `.aggregate`, no cursor). That is a content gap, not wording; it is logged as C24 in `changes.md` and is out of scope for C21. - -## Done: `orm/migrations/` (PR #8281) - -PR #8281 (branch `docs/orm8-plain-language-migrations`) is C21 on the six `orm/migrations/` pages, plus C25, a new section in Editing a migration: "When a backfill reads a column the migration removes". Open as of 2026-09-15. - -The pass ran these steps: -1. A banned-term pass and a fact check against rc.11. -2. A real run of the pages' commands with `prisma` 8.0.0-rc.15 and a local PostgreSQL. -3. Four reader rounds. -4. A final fact re-check, which made 28 corrections. -5. A language review by the operator, then a cutting round: one Opus fixer per page, a word ceiling, and the rule that facts stay fixed. Brief in `wip/c21/mig/cut-brief.md`. -6. An explanation round after Will rejected the prose: one Opus fixer per page, no ceiling, rewriting against `.claude/skills/docs-reader-review/references/explain-not-state.md`. Brief in `wip/c21/mig/explain-brief.md`. - -The briefs, shared answers, page copies per round, and every report are in `/Users/will/Projects/prisma/web/.claude/worktrees/pr-conflicts-review-fb93f7/wip/c21/mig/`. None is in the PR, because Will said not to add dispatches to PRs. The most useful files there: -- `round2-notes.md`, which holds every final-check item and its resolution. -- `round1-shared-answers.md` to `round4-shared-answers.md`, which are sourced facts about migrations. -- `real-run-transcript.md`. -- `notes-for-handover.md`, which lists the product bugs. -- `fc2-drifts.md`, what the final check corrected. - -Things learned on this pass: -- **Budget in words, not lines.** Round three's fixers met line budgets by writing longer lines, and four pages grew by up to 13%. -- **Run the commands.** The real run caught several things that reading the source did not: - - a wrong rollback end state; - - an `updatedAt` column makes a backfill impossible to apply; - - the unfilled-placeholder failure was blamed on the wrong cause; - - the literal `{bin}` in CLI hints; - - `node migration.ts` works only from the project root. - - Do the same for any section whose pages show commands. -- **Shared answers every round.** Readers on all six pages asked the same questions. One shared-answers file per round kept the pages consistent. When a fact turns up while fixers run, send it to the affected fixer. -- **Cross-check one checker's finding on the other pages.** The How migrations work checker found that a MongoDB re-run stops at a collection the failed run created. Three other pages said the opposite, and their checkers had confirmed it. -- **Reader rounds bloat pages.** Each round answered readers by adding sentences, and each page ended up defining every term as if the reader arrived cold. The same eight facts were restated on every page. Plan a cutting round after the reader rounds, with the rule: define each term once per page at first use, link elsewhere, facts stay fixed. Fixers refuse ceilings they can only meet by deleting facts, which is right, so set ceilings as ceilings and accept the report. -- **Explain, do not state.** Will's biggest correction on this pass. The pages stated facts in short correct sentences and never said what they meant for the reader, with counting lead-ins ("Four things change it:") and fragment openers ("One name is special."). His model rewrite and the rules are in `.claude/skills/docs-reader-review/references/explain-not-state.md`, and `check-staccato.py` now flags the mechanical signs. Run that reference on every future section before the reader rounds, not after. Word ceilings make this habit worse: use them only against repetition. -- **Length.** The section went from 9997 words on `main` to 13749 after the reader rounds, 12606 after the cutting round, and 15875 after the explanation round. Will has not objected to the length, only to the prose. -- **Terminology.** Will banned movement metaphors for migrations (the database moves, the marker moves, the ref moves, the database is behind or catches up, where the database is). Say what a command changes and what the database ends up matching. "Database schema" is fine; only PostgreSQL namespaces make it ambiguous, and Will rejected reserving the word. Rules in `.claude/skills/docs-reader-review/references/banned-terms.md`, "Migration vocabulary". - -## After that, in order - -1. Handle review on #8281 (the migrations section), then `orm/middleware/`, `orm/extensions/`, one PR per section. -2. File the product bugs from the migrations pass, listed in `wip/c21/mig/notes-for-handover.md`, wherever Will decides. The list: - - `{bin}` is never replaced. - - Planner-written migrations don't type-check. - - An `updatedAt` backfill can never be applied. - - `migration new --from` writes a no-op migration that breaks planning. - - `node migration.ts` works only from the project root. - - `contract emit --config` misreports its output file names. - - The `db migrate` summary count is off. - - `npx prisma dev` needs an entry argument. - - `migration log` sorts rows applied in the same second by name. - - A MongoDB re-run after a partial failure stops at a collection the failed run created. - - Outside the section: `studio/prisma-next.mdx` line 112 describes `migration plan` with no `db` ref wrongly. Also add to D14: the `prisma-8` skill says an un-recompiled `migration.ts` edit causes a hash mismatch, and it does not. -3. C2, "Add Prisma ORM to an app you already started": scaffold a Prisma 7 app with an older `npm create prisma`, add ORM 8, write the page from what happens. -4. C22 (a database on your machine: `prisma dev` first, Composer, Docker Compose) and C23 (runnable example repositories), both from a Discord user's feedback; see `journeys.md` J11 and J12. -5. Briefs waiting for an ORM-side owner: `brief-skill-staleness.md` (D14), D17 in `changes.md`. Add to D14: the scorecard marks `contains`/`startsWith`/`endsWith` as reachable when they are not, and the skill still says N:M includes fail when they work. - -## Open questions from the last session, for Will - -- **SQLite** is decided: Experimental, with `@prisma/orm-sqlite`, on the Supported databases page. The Release status page still does not name the SQLite library; make them agree when that page is next touched. -- **Default referential action.** When `onDelete` and `onUpdate` are both omitted, Prisma ORM writes no clause. The relational data-modeling page says "the database decides" and does not name PostgreSQL's `NO ACTION`. Will has not said whether to name it. -- **MongoDB before the first write.** The skill says `db migrate` writes a marker document in `_prisma_migrations`, but no marker check was found in the MongoDB runtime, so no page says whether an unmigrated database rejects a write. -- **`namespace` blocks** exist in the PSL interpreter (`interpreter.ts:197-231`) and no page documents them; the relational page mentions them in one clause without a link. -- **Node.js floor for `Temporal`.** The source and the raw-queries page say 26.8.2; `coming-from-prisma-orm-7.mdx` line 65 says "26 and later". Fix the latter when that page is next touched. -- **A JavaScript `Date` codec.** Will and Serhii are discussing one beside the Temporal codecs. There is no real-user evidence logged anywhere in this project; the evidence is D10 in `changes.md` (inferred contracts throw at read time without a global `Temporal`, which Node.js 22 and 24 lack), the raw-queries readers stumbling on `Temporal.Instant` in four rounds, raw SQL rejecting a `Date` outright, MongoDB returning a `Date` while PostgreSQL returns Temporal, and the `DateString` family being the only escape hatch. Discord and GitHub issues were not searched. -- **Implicit many-to-many** is not supported at rc.10 or rc.11: two bare list fields raise `PSL_ORPHANED_BACKRELATION` and the message says to write a join model. The docs say so correctly. Serhii read the upgrade guide as saying many-to-many is unsupported; only the implicit form is. -- **Operating contexts.** The Supported databases page covers only the database section of prisma/orm#25843. Runtimes, frameworks, deployment platforms, and languages have no Prisma ORM 8 page. -- A team-facing summary of the whole project is published at https://claude.ai/code/artifact/3516e640-e939-4c4a-9db6-ff858027cf93 (Will's private artifact). -- **Migrations pass: committing refs.** Should `migrations/app/refs/db.json` be committed? The same question applies to a `prod` ref. The source is silent, and no migrations page says. -- **Migrations pass: `--advance-ref db`.** Why is it not the default in development? The source gives no reason. -- **Migrations pass: the `prod` ref.** Does it mean what is deployed or what should be deployed, and should deploys move it? -- **Migrations pass: merge workflow.** The graph page shows the diamond from the e2e test, with two merge migrations after both branches merge. `skills/prisma-8/references/migration-review.md` 116-130 recommends rebasing and replanning instead. -- **Migrations pass: adoption order.** Generating a migration says sign, then plan, then migrate. The PostgreSQL upgrade guide says plan a baseline, sign, then set the `db` ref. Both work. -- **Migrations pass: `db sign` failing on production.** Its error suggests running `db update` and then signing again. The pages do not recommend that on production. -- **Migrations pass: Discord.** Should the pages name the `#prisma-next` channel? They now say only "ask on Discord". -- **Migrations pass: Node.js version.** The published `prisma` 8.0.0-rc.15 declares `node >=22.18.0`, but the rc.11 monorepo declares `>=24`. The pages say 22.18. -- **Migrations pass: concurrent PostgreSQL runs.** After waiting for the lock, the second run fails with a marker mismatch. The page says only that one waits for the other.