contract infer signs the database: full-fidelity indexes, policy blocks, @@rls — scenario A complete#1052
contract infer signs the database: full-fidelity indexes, policy blocks, @@rls — scenario A complete#1052wmadden-electric wants to merge 15 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@prisma-next/extension-author-tools
@prisma-next/mongo-runtime
@prisma-next/family-mongo
@prisma-next/sql-runtime
@prisma-next/family-sql
@prisma-next/extension-arktype-json
@prisma-next/middleware-cache
@prisma-next/mongo
@prisma-next/extension-paradedb
@prisma-next/extension-pgvector
@prisma-next/extension-postgis
@prisma-next/postgres
@prisma-next/sql-orm-client
@prisma-next/sqlite
@prisma-next/extension-supabase
@prisma-next/target-mongo
@prisma-next/adapter-mongo
@prisma-next/driver-mongo
@prisma-next/contract
@prisma-next/utils
@prisma-next/config
@prisma-next/errors
@prisma-next/framework-components
@prisma-next/operations
@prisma-next/ts-render
@prisma-next/contract-authoring
@prisma-next/ids
@prisma-next/psl-parser
@prisma-next/psl-printer
@prisma-next/cli
@prisma-next/cli-telemetry
@prisma-next/config-loader
@prisma-next/emitter
@prisma-next/language-server
@prisma-next/migration-tools
prisma-next
@prisma-next/vite-plugin-contract-emit
@prisma-next/mongo-codec
@prisma-next/mongo-contract
@prisma-next/mongo-value
@prisma-next/mongo-contract-psl
@prisma-next/mongo-contract-ts
@prisma-next/mongo-emitter
@prisma-next/mongo-schema-ir
@prisma-next/mongo-query-ast
@prisma-next/mongo-orm
@prisma-next/mongo-query-builder
@prisma-next/mongo-lowering
@prisma-next/mongo-wire
@prisma-next/sql-contract
@prisma-next/sql-errors
@prisma-next/sql-operations
@prisma-next/sql-schema-ir
@prisma-next/sql-contract-psl
@prisma-next/sql-contract-ts
@prisma-next/sql-contract-emitter
@prisma-next/sql-lane-query-builder
@prisma-next/sql-relational-core
@prisma-next/sql-builder
@prisma-next/target-postgres
@prisma-next/target-sqlite
@prisma-next/adapter-postgres
@prisma-next/adapter-sqlite
@prisma-next/driver-postgres
@prisma-next/driver-sqlite
commit: |
size-limit report 📦
|
365daa2 to
1c06c92
Compare
6fa9c82 to
cbd291d
Compare
1c06c92 to
9e7cffb
Compare
cbd291d to
f64b82d
Compare
9e7cffb to
962cf64
Compare
a0072e3 to
abc1ea9
Compare
962cf64 to
e788c6c
Compare
abc1ea9 to
d72b6af
Compare
e788c6c to
fb75a23
Compare
bc9617b to
b35b685
Compare
…plicate guard The duplicate-index rejection keyed every entry by content signature, which rejects a legally-twinned database: two content-identical indexes under different physical names, which a signed (adopted) contract may carry. Exact-mode entries (no prefix) now skip the content key — their identity is the name, and name collisions are already rejected by the named-object check. Managed entries keep the content key: two managed twins would share the content hash and collide on the wire name anyway, and the content key additionally rejects same-content different-prefix pairs, which could never both converge. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…managed re-detection The slice-1 skip guard (expression and partial indexes) and the unique gate (unique non-constraint indexes silently dropped) are deleted — every non-constraint index emits. A new buildIndexAttribute re-detects identity: when the live name parses as a wire name AND its hash recomputes from the introspected content, the index is managed and emits name: with the prefix; otherwise it adopts exactly with map: and the content verbatim (expression:, where:, unique: true, type:, options: as introspected — options only alongside type, the pair the PSL surface requires). The btree edge is documented: an index authored type: 'btree' hashed the method into its suffix but introspects type-normalized, so it re-infers as map: — a clean round trip, just exact rather than managed. Constraint-backed uniques keep flowing to @@unique through the untouched id/unique builder. Fidelity journey seeds gain expression, partial, and unique indexes with one test per new emission, and the full infer -> emit -> verify round trip stays zero-issue. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… an explicit btree type The dispatch-1 narrowing left scenario A holed: a btree index with reloptions (fillfactor) had no emission, so it signed with perpetual options drift. The builder now emits an explicit type: 'btree' beside options: when the introspected node carries options with the type normalized away — the pair the PSL surface requires — and the expected node's constructor normalizes btree back to undefined, so verify compares clean. Round-trip pinned at unit level and in the fidelity journey (fillfactor index infers, emits, and verifies zero-issue). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The five policy_* block descriptors gain an optional permissive boolean parameter (pg/bool codec, default true), threaded through lowerRlsPolicyFromBlock and buildRlsPolicyEntity into the hash-tuple slot and entity field that always existed — a managed permissive: true policy's wire name is byte-unchanged (pinned), a RESTRICTIVE twin gets a different hash, and an @@Map policy carries permissive: false verbatim. This is D8's minimal enabler: a RESTRICTIVE live policy can now infer and round-trip. The TS entity-handle path stays defaulted permissive. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Every introspected policy emits a policy_<operation> block in its namespace: the head is the parsed wire prefix (else the physical name) sanitized to the PSL identifier grammar, within-namespace collisions numeric-suffixed deterministically by sorted physical name; @@Map ALWAYS carries the physical name (a body reprint never reliably re-hashes, so every adopted policy is exact); bodies and roles emit verbatim, and a RESTRICTIVE row emits permissive = false. A policy referencing a role whose name fails the identifier grammar skips with a comment note on its target model — the honest leftover a strict verify then names. @@rls emits from the table node's rlsEnabled, replacing the Supabase harness's out-of-band appender shape exactly. Policy-bearing output namespace-wraps like enum-bearing output. Emitting RESTRICTIVE policies exposed a canonicalization hole: the default-omission walk dropped permissive: false, so the emitted contract failed its own validation on the next read. PostgresContractSerializer now preserves the policy permissive path, the same class of preservation the SQL family declares for an index's unique: false. Fidelity and infer-workflow journeys cover permissive + RESTRICTIVE policies, multi-role, withCheck, @@rls, and re-infer stability; two pre-existing assertions were namespace-wrap-adjusted (indentation-tolerant regex, field-precise name match). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…and full index fidelity applyRlsEnablement is deleted — @@rls now comes from infer natively, line-for-line identical. The regen (checked-in generator only) ends the slice-1 transitional omission: the reference's partial unique indexes, partial non-unique indexes, expression indexes, and unique non-constraint indexes all adopt as exact-named map: entries. The movement is purely additive — zero removals, zero map:-to-name: flips (no real Supabase index name is wire-shaped), and no policy blocks (the reference fixture seeds none). CONTRACT-FIDELITY's partial-index omission passage is replaced by the full-fidelity statement, and the oauth_consents.client_id FK note now reflects its declared partial backing index. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…es shipped behavior A byte-identical reprint re-hashes to the authored suffix, so a simple expression index re-detects managed — equally sound, proven by test. Policies remain always-exact by design, not by hash impossibility. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…(project DoD-2/3) A database created by another tool — an expression index, a partial index, a unique expression index, and PERMISSIVE + RESTRICTIVE policies on an RLS-enabled table — signs through contract infer -> emit -> db verify with zero issues, and db update --dry-run plans zero operations (both asserted on the --json outputs). From that signed contract, one index and one policy transition from map: to the managed spelling with bodies verbatim; the widening plan is exactly two ops, an ALTER INDEX RENAME and an ALTER POLICY RENAME, byte-asserted against the recomputed wire names; applying it verifies clean. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
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>
…t an exact twin S4-2 review observation: the reference pair differs in unique, so the exact-twin guard rests on its unit tests, not a live fixture. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…rable, name-identified, adoptable Adds the functional-indexes entry to requirement 4 as Landed: expression/partial/unique index authoring in PSL and TypeScript (the Cipherstash EQL shape), name-identified indexes and RLS policies with content-hashed wire names, and full-fidelity contract infer so live databases adopt cleanly and convert to managed naming by renames. Aggregates updated (35 tasks, 7 done; requirement-4 minibar 2 done) and the header legend corrected to match the caption. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…behavior The journey header, describe title, and step comments describe what each step does — sign a foreign database as-is, then transition one index and one policy to managed naming via exactly two renames — instead of pointing at planning checklist coordinates. Behavior and assertions unchanged. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… is derived
SqlObjectNaming — { kind: "exact", name } | { kind: "managed", prefix,
hash } — is the naming input for all four name-identified classes
(contract Index, SqlIndexIR, PostgresRlsPolicy,
PostgresPolicySchemaNode). The flat fields stay exactly as stored:
`name` is DERIVED (formatWireName(prefix, hash) for managed, verbatim
for exact) and the optional `prefix` property is retained, so canonical
JSON, storage hashes, emitters, validators, and every fixture are
byte-identical. The hash is input-only — never a stored field.
A mismatched name/prefix pair is now unconstructable from the union, so
the constructor parse-back checks delete; flat data still arrives at
load boundaries (contract JSON via indexInputFromSerialized and the
policy entity-kind descriptor, the migration API literal via
rlsPolicyInputFromFlat, entity/node rebuilds via namingFromFlat), and
the pair is validated exactly there. parseWireName returns the managed
arm directly, so introspection reads
`parseWireName(name) ?? { kind: "exact", name }`.
Producers migrate to the union: lowerAuthoredIndex,
buildRlsPolicyEntity, the @@Map exact policy, both introspection sites,
the family and Postgres tree derivations, policyNodeToContractPolicy,
and the test corpus (constructor-invariant tests retarget at the flat
load boundaries, where the checks now live).
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
7939a8c to
f8738ab
Compare
b35b685 to
72ef213
Compare
At a glance
Sign a database this toolchain has never seen:
— proven end-to-end on a raw-SQL database carrying an expression index, a partial index, a unique expression index, and PERMISSIVE + RESTRICTIVE RLS policies. And the second step, adopting it into management: flip one index's
map:toname:and delete one policy's@@map, and the widening plan is exactly twoALTER … RENAMEstatements. The emitted contract is the database's signature. This closes scenario A and the functional-indexes project's build phase.Decision
Slice 4 of the functional-indexes project (spec
projects/functional-indexes/specs/infer-round-trip.spec.mdon the base branch):contract inferemits everything the identity model can hold.where-carrying nodes) and the silent drop of unique non-constraint indexes are gone. For each index, infer recomputes the content hash from the introspected node: if the live name is<prefix>_<that hash>, it emitsname: "<prefix>"— databases this toolchain created re-infer to managed contracts byte-identically. Otherwisemap: "<live name>"with content verbatim. (A simple expression whose reprint equals the authored text re-detects managed too — equally sound, pinned by test; the spec's over-general side-claim was corrected.) A default-method index carrying storage parameters emitstype: "btree"besideoptions:so it round-trips clean — the PSL surface requires the pair, and the constructor normalization from slice 2 makes the comparison exact.@@rls. Everypg_policiesrow emits apolicy_*block: head identifier derived from the name and sanitized to the PSL grammar (collisions numeric-suffixed deterministically),@@mapalways — policy re-detection is not attempted by design — with verbatim reprinted bodies. Tables with row security emit@@rlsnatively; the Supabase harness's bolt-on appender is deleted.permissivebecame authorable — a falsified spec assumption resolved: D8 commits to capturingpermissivefrom the row, but RESTRICTIVE had no authoring surface. The fivepolicy_*blocks gain an optionalpermissiveproperty (defaulttrue; the hash tuple already carried the slot, so managed hashes are byte-unchanged). En route this exposed the third instance of the false-literal canonicalization class:permissive: falsewas dropped on emit — fixed target-side (shouldPreserveEmptyoverride), with a sweep confirming no other target-entity boolean is droppable.@@rlscomes from infer, zero removals or flips.CONTRACT-FIDELITY.md's transitional-omission passage is retired.The scenario matrix is complete
Every row of the project spec's normative A–J table now has named green tests — A (this PR's sign-the-database journey + slice 1's fields-only round-trip), B/D/E/G/H (slice 2), C/F (slice 3 + this PR's transition), I/J (slice 1, J extended by the twin-guard tests and the live Supabase pair). The full walk is in the review ledger and the slice spec.
Verification
Full standing gate green at every dispatch (build · typecheck · whole Lint surface ·
fixtures:check·check:upgrade-coverage· all three suites ·test:examples). The DoD journeys assert on real--jsonCLI outputs with byte-asserted plans; upgrade entries extended for both audiences (infer fidelity,permissive, twin legality, themap:→name:re-detection consequence). Release notes are deliberately deferred to release-cut per repo convention (draft-release-notesenumerates all merged PRs); the deviation is recorded in plan.md.Base
Stacked:
slice/rls-exact-names(#1050) → #1048 → #1047 → #1046. Merge in stack order, retargeting as bases land. After this merges, one final close-out PR promotes the ADR, stripsprojects/functional-indexes/**references, and deletes the project folder.Skill update
Both 0.16-to-0.17 skill clusters extended: user entry covers infer's full-fidelity capture and consequences; extension entry
contract-infer-emits-full-fidelitycovers regen expectations and appender deletion.Checklist
git commit -s) per the DCO.🤖 Generated with Claude Code