Skip to content

Commit f294bbd

Browse files
docs: infer full-fidelity capture in the user docs and upgrade entries
The contract and quickstart skills' brownfield sections state what infer now captures (the full index matrix with managed re-detection, @@rls, policy blocks with @@Map and verbatim bodies, the RESTRICTIVE spelling, the skip-with-note case). Upgrade entries, both audiences: the user skill's newly-available note covers infer fidelity, the map:-to-name: re-detection on wire-shaped names, authorable permissive, and the legal exact twins; the extension skill gains contract-infer-emits-full- fidelity for packs whose contract-space generators run infer (additive regen movement, delete out-of-band @@rls appenders). plan.md marks the two slice-4 carry-overs landed with their commits and records the release-notes deviation (authored at release-cut per repo convention). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
1 parent 9dd7b1f commit f294bbd

5 files changed

Lines changed: 28 additions & 5 deletions

File tree

projects/functional-indexes/plan.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ The identity switch, done entirely beneath the authoring surface (existing `@@in
4949
### 4 — `infer-round-trip`
5050

5151
- D8 in full: index managed re-detection (recompute-and-match), `map:` fallback, policy block emission (head sanitization + dedup, `@@map` always, verbatim bodies), `@@rls` emission.
52-
- Slice-1 carry-over (dispatch-3 review): the authoring-time duplicate-content index guard (`validateStorageSemantics`) rejects byte-identical twins under different names. Legal in Postgres, so a database carrying them must still be signable — key the guard by name for exact-mode indexes (or equivalent) when infer starts emitting them.
53-
- Slice-1 carry-over: infer currently skips expression-carrying AND `where`-carrying index nodes (self-consistency — no authoring surface could hold the bodies); both skip sites are comment-marked for this slice. The Supabase reference contract re-adopts its partial indexes here.
52+
- Slice-1 carry-over (dispatch-3 review): the authoring-time duplicate-content index guard (`validateStorageSemantics`) rejects byte-identical twins under different names. Legal in Postgres, so a database carrying them must still be signable — key the guard by name for exact-mode indexes (or equivalent) when infer starts emitting them. **Landed** in `74117e56f` (exact entries name-identified; the named-object check carries name collisions).
53+
- Slice-1 carry-over: infer currently skips expression-carrying AND `where`-carrying index nodes (self-consistency — no authoring surface could hold the bodies); both skip sites are comment-marked for this slice. The Supabase reference contract re-adopts its partial indexes here. **Landed** in `8951c1345` (gates deleted, full-matrix emission) and `d4fe1f5eb` (Supabase re-adoption).
5454
- DoD-2 sign-the-database e2e, DoD-3 transition e2e, DoD-4 upgrade e2e; scenario A coverage completes the A–J matrix (DoD-5 sweep test list checked off here).
55-
- Release-notes draft for the breaking change + upgrade instructions (per the `record-upgrade-instructions` skill).
55+
- Release-notes draft for the breaking change + upgrade instructions (per the `record-upgrade-instructions` skill). **Deviation record:** the upgrade-instruction entries are complete (both skill clusters, 0.16-to-0.17); the committed `docs/releases/v0.17.0.md` is deliberately NOT authored in this slice — repo convention authors it at release-cut time via the `draft-release-notes` skill, which enumerates all merged PRs (spec § 7).
5656

5757
## Close-out (required)
5858

skills/extension-author/prisma-next-extension-upgrade/upgrades/0.16-to-0.17/instructions.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,27 @@ changes:
312312
- "PostgresPolicySchemaNode"
313313
- "policy_select"
314314
anyMatch: true
315+
- id: contract-infer-emits-full-fidelity
316+
summary: |
317+
`contract infer` emits every non-constraint index (expression, partial `where:`,
318+
unique, `type:`/`options:`) and the RLS surface (`@@rls` natively, every policy as a
319+
`policy_<operation>` block with `@@map` and verbatim reprinted bodies, `permissive =
320+
false` for RESTRICTIVE rows). A pack whose contract-space generator runs infer (the
321+
supabase pattern) sees ADDITIVE movement on its next regeneration: previously omitted
322+
partial/expression/unique indexes adopt as exact `map:` entries, and `@@rls` no longer
323+
needs an out-of-band appender — delete any `applyRlsEnablement`-style post-processing
324+
and regenerate through the checked-in generator; re-emit moves the storage hash. The
325+
duplicate-index validation keys exact-mode entries by name, so a reference database's
326+
content-identical twin indexes now validate. An index whose live name is wire-shaped
327+
and whose hash recomputes re-infers as managed `name:` (real third-party names are not
328+
wire-shaped, so adopted contracts stay `map:`).
329+
detection:
330+
glob: "**/*.{ts,mts,cts,prisma}"
331+
contains:
332+
- "inferPslContract"
333+
- "contract infer"
334+
- "@@rls"
335+
anyMatch: true
315336
---
316337

317338
# 0.16 → 0.17 — Extension-author upgrade instructions

skills/prisma-next-contract/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ pnpm prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contrac
354354
pnpm prisma-next contract emit
355355
```
356356

357+
Infer captures indexes at full fidelity — expression, partial (`where:`), unique non-constraint, `type:`/`options:` — adopting each under `map:` with the live name, except that a name shaped like a managed wire name whose hash recomputes from the content re-detects as managed and emits `name:` with the prefix. RLS surfaces too: `@@rls` on RLS-enabled models, and every policy as a `policy_<operation>` block with `@@map("<live name>")`, verbatim predicate reprints, and `permissive = false` for RESTRICTIVE rows (a policy whose role name can't be spelled as a PSL identifier is skipped with a comment note). Replacing an adopted `map:` with the plain managed spelling later converges via a single rename migration.
358+
357359
## Common Pitfalls
358360

359361
1. **Forgetting to re-emit after an edit.** `contract.json` and `contract.d.ts` go stale; downstream typecheck and `migration plan` see the old shape. Re-emit, or install the Vite plugin (`prisma-next-build`).

skills/prisma-next-quickstart/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ Then run the snippet from *Your first arc* above against the `User` model. When
244244

245245
## Workflow — Brownfield-DB (existing database, no contract)
246246

247-
The concept: against an existing database with no PN contract, `contract infer` walks the live schema (tables, columns, indexes, constraints) and writes a PSL contract that describes it. The result is a *starting point*, not the final contract — review and clean it up, then `db sign` to record the current contract hash as the marker (instead of letting `db init` try to recreate the schema from scratch).
247+
The concept: against an existing database with no PN contract, `contract infer` walks the live schema (tables, columns, indexes — including expression and partial ones — constraints, and RLS enablement + policies) and writes a PSL contract that describes it. The result is a *starting point*, not the final contract — review and clean it up, then `db sign` to record the current contract hash as the marker (instead of letting `db init` try to recreate the schema from scratch).
248248

249249
```bash
250250
mkdir my-app && cd my-app

skills/upgrade/prisma-next-upgrade/upgrades/0.16-to-0.17/instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ Each entry in a table's `indexes` array in `contract.json` / `contract.d.ts` now
344344
- `prefix` — present when the name is toolchain-managed: the physical name is then `<prefix>_<8hex>`, where the suffix is a content hash of the index definition.
345345
- `columns` — now optional; an index carries either `columns` or an opaque `expression` string, never both.
346346

347-
Newly available in 0.17 (additive — no migration needed): RLS policy blocks (`policy_select` etc.) accept `@@map("physical name")` to adopt an existing live policy under its exact name — no wire-name hash, drift detection byte-compares the body against Postgres's reprint (hand-authoring the text warns with `PN_EXACT_NAME_BODY_COMPARISON`), and replacing `@@map` with the plain head later converges via a single `ALTER POLICY … RENAME`. Also newly available: both authoring surfaces accept the full index parameter matrix. PSL `@@index` and TS `constraints.index` take `expression:` (instead of a fields list; requires `name:` or `map:`), `where:` (partial-index predicate), `unique:`, `type:`/`options:` (target-registered access method), and `name:` xor `map:`. Combining `map:` with a SQL body emits the `PN_EXACT_NAME_BODY_COMPARISON` warning at build time — drift detection byte-compares hand-authored text against Postgres's reprint, so prefer `name:` unless the text was captured by `contract infer`. SQLite contracts reject `expression:`/`where:` with `CONTRACT.ARGUMENT_INVALID` (the target does not support them).
347+
Newly available in 0.17 (additive — no migration needed): `contract infer` captures the full index matrix (expression, partial `where:`, unique non-constraint, `type:`/`options:`) and the RLS surface (`@@rls`, every policy as a `policy_<operation>` block with `@@map` and verbatim reprinted bodies, `permissive = false` for RESTRICTIVE rows), so `infer → emit → db verify` is zero-issue on databases carrying those objects. Re-running `contract infer` therefore rewrites `contract.prisma` with more entries than 0.16 emitted; an index whose live name is wire-shaped (`<prefix>_<8hex>`, created by this toolchain) and whose hash recomputes now re-infers as managed `name:` instead of exact `map:` — both spellings verify clean, the managed one keeps renames first-class. `permissive` is an authorable policy-block property (default `true`; managed wire names for `permissive = true` policies are byte-unchanged). Contracts may also now carry two content-identical exact-named (`map:`) indexes under different names — legal twins a signed database can have. RLS policy blocks (`policy_select` etc.) accept `@@map("physical name")` to adopt an existing live policy under its exact name — no wire-name hash, drift detection byte-compares the body against Postgres's reprint (hand-authoring the text warns with `PN_EXACT_NAME_BODY_COMPARISON`), and replacing `@@map` with the plain head later converges via a single `ALTER POLICY … RENAME`. Also newly available: both authoring surfaces accept the full index parameter matrix. PSL `@@index` and TS `constraints.index` take `expression:` (instead of a fields list; requires `name:` or `map:`), `where:` (partial-index predicate), `unique:`, `type:`/`options:` (target-registered access method), and `name:` xor `map:`. Combining `map:` with a SQL body emits the `PN_EXACT_NAME_BODY_COMPARISON` warning at build time — drift detection byte-compares hand-authored text against Postgres's reprint, so prefer `name:` unless the text was captured by `contract infer`. SQLite contracts reject `expression:`/`where:` with `CONTRACT.ARGUMENT_INVALID` (the target does not support them).
348348

349349
A contract emitted by 0.16 fails validation when a 0.17 toolchain loads it — a `Contract structural validation failed: storage.namespaces.<ns> …` error whose message contains `indexes[0].name must be a string (was missing)` and `indexes[0].unique must be boolean (was missing)` — and the storage hash moves for every contract that declares indexes. Re-emit:
350350

0 commit comments

Comments
 (0)