Skip to content

TML-2693: include adapter + driver capabilities in createExecutionContext (parity with CLI emit)#602

Merged
wmadden merged 6 commits into
mainfrom
tml-2693-merge-stack-component-capabilities-into-the-runtime-contract
May 28, 2026
Merged

TML-2693: include adapter + driver capabilities in createExecutionContext (parity with CLI emit)#602
wmadden merged 6 commits into
mainfrom
tml-2693-merge-stack-component-capabilities-into-the-runtime-contract

Conversation

@wmadden
Copy link
Copy Markdown
Contributor

@wmadden wmadden commented May 28, 2026

At a glance

In-process consumers building a contract via defineContract(...) and handing it to createExecutionContext now see the same capability matrix the CLI-emitted contract carries. The integration tests for sql-builder had been working around the gap by pre-enriching test-side; the workaround is gone:

- import { enrichContract } from '@prisma-next/cli/control-api';
- // Mirror CLI emit-time enrichment: in-memory `defineContract` only folds in
- // target + extension-pack capabilities; adapter and driver contributions
- // land via `enrichContract` at emit time. Tests that exercise the runtime
- // builder against an in-memory contract need the same merged matrix.
- const enrichedContract = enrichContract(contract, [postgresTarget, postgresAdapter, pgvector]);
- const sqlContract = new SqlContractSerializer().deserializeContract(enrichedContract);
+ const sqlContract = new SqlContractSerializer().deserializeContract(contract);
  ...
- context = createExecutionContext({ contract: sqlContract, stack });
+ context = createExecutionContext({ contract: sqlContract, stack, driver: postgresDriver });

The change

createExecutionContext (in @prisma-next/sql-runtime) now folds the stack's capability contributions into the contract before exposing it to the runtime — using the same merge primitive enrichContract already uses at CLI emit time. Both callers go through the shared helper, so the matrix the runtime sees is byte-identical to the matrix the CLI emits. createExecutionContext's options gain an optional driver? field so in-memory consumers can pass { adapter, driver } and get the full match.

Why the gap existed

PR #574 (TML-2653) removed capabilities from defineContract. Capability authoring moved out of the contract and into the stack components — target, adapter, driver, extension packs — each contributing through their descriptor's optional capabilities field. The CLI's enrichContract folds those contributions together at emit time and writes the merged matrix into contract.json.

The runtime had no equivalent fold. An in-process consumer building a contract via defineContract({ family, target, extensionPacks }, …) and handing it to createExecutionContext saw only target + extension-pack capabilities. The adapter's and driver's contributions never reached the matrix runtime gates check against, so calls like sql.returning or postgres.distinctOn were rejected for operations the adapter actually supports.

Structured for review

Three commits, dependency-ordered for a reviewer who wants to walk it:

  1. 6ddac1795 — extract mergeCapabilityMatrices into @prisma-next/framework-components/components. Pure refactor; enrichContract's public output is byte-identical (the existing contract-enrichment.test.ts stayed green unchanged).
  2. 990956bff — call the helper from createExecutionContext. Adds the optional driver? option; rebinds the local contract so all downstream construction and the returned ExecutionContext.contract carry the merged matrix.
  3. 74454e508 — delete the test-side workaround in test/integration/test/sql-builder/setup.ts.

Things to scrutinize

  • Helper signature is structural, not nominal. mergeCapabilityMatrices takes ReadonlyArray<{ capabilities?: unknown }> rather than TargetBoundComponentDescriptor[]. The runtime caller's SqlExecutionStack descriptors satisfy the structural shape directly; enrichContract keeps its own TargetBoundComponentDescriptor[] parameter and narrows internally.
  • Defensive base handling in the helper. A malformed runtime base (only reachable via unsafe casts) returns the empty matrix rather than throwing on Object.entries(undefined). Pinned by an explicit "tolerates a malformed base" test so the tolerance isn't load-bearing on accident.
  • Three pre-existing toBe(contract) assertions relaxed to toEqual(contract) in sql-context.test.ts, execution-stack.test.ts, and parameterized-types.test.ts. createExecutionContext now always returns a fresh contract object carrying the merged matrix, even when no contributor adds anything — identity equality is structurally false. None of the three tests were about contract identity; they used .toBe incidentally. The identical assertion in Mongo's mongo-execution-stack.test.ts is deliberately untouched (Mongo runtime is out of scope).

Out of scope

  • Mongo runtime — same gap may apply; separate ticket if so.
  • enrichContract's shape (the extensionPacksMeta fold; sortDeep of the rest of the contract) — left as-is.
  • extensionPacksMeta at runtime — emit-time-only metadata; runtime doesn't gate on it.
  • profileHash / capability-hash regeneration — emit-time concern; in-memory merge doesn't replay hashing.
  • The three CLI-emit-parity tests under test/integration/test/authoring/ that legitimately call enrichContract to assert emit shape.

Alternatives considered

Wiring driver capabilities into the runtime. Three options were on the table:

  • (A) Read the driver off a SqlExecutionStackWithDriver variant. Either pass the WithDriver shape into createExecutionContext, or widen SqlExecutionStack itself. Rejected because the driver is only a capability source here — its lifecycle is wired separately via instantiateExecutionStack + runtime.connect. Reading it off the stack would leak a structural quirk into the function's input shape and make the capability-source intent implicit rather than documented.
  • (B) Scope the runtime fold to target + adapter + extension packs. Driver capabilities would continue to land via CLI emit only. Rejected because it fails the literal AC3 wording — an in-memory consumer with { adapter, driver } would still see only adapter and target capabilities at runtime.
  • (C, chosen) Add an optional driver? field to createExecutionContext's options. Strictly additive — every existing caller compiles unchanged. The driver is consulted only as a capability source; runtime driver lifecycle is unchanged. Matches AC3's wording literally.

Helper home — framework-components/components vs contract. The helper takes contributor-shaped input. framework-components is where TargetBoundComponentDescriptor lives and is already a foundation layer that both CLI tooling and SQL runtime depend on; @prisma-next/contract is type-only.

Parity test against enrichContract directly vs against the shared helper. Asserting enrichContract(contract, …).capabilities === createExecutionContext(...).contract.capabilities in sql-runtime's package-local tests would import @prisma-next/cli/control-api — upward-layer for sql-runtime, and would either trip lint:deps or require a layering exception. The chosen approach asserts both sides against the shared helper; byte-equality follows by transitivity (the helper extraction commit pins enrichContract ↔ helper; the runtime-fold commit pins createExecutionContext ↔ helper).

@wmadden wmadden requested a review from a team as a code owner May 28, 2026 12:31
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Warning

Review limit reached

@wmadden, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 31 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 6fc838b9-95be-45a1-bf4d-0c9d88f44a47

📥 Commits

Reviewing files that changed from the base of the PR and between bd5d3eb and e1f4cf8.

📒 Files selected for processing (1)
  • test/integration/test/sql-builder/setup.ts
📝 Walkthrough

Walkthrough

This PR centralizes capability-matrix merging via a new export mergeCapabilityMatrices, replaces local merges in CLI, folds driver and extension capabilities into SQL execution contexts, and adds tests and integration updates verifying deterministic, non-mutating merges.

Changes

Capability Matrix Merge Implementation and Adoption

Layer / File(s) Summary
Foundation: mergeCapabilityMatrices primitive
packages/1-framework/1-core/framework-components/src/shared/capabilities.ts, packages/1-framework/1-core/framework-components/src/exports/components.ts, packages/1-framework/1-core/framework-components/test/capabilities.test.ts
Implements mergeCapabilityMatrices with plain-object extraction, boolean-leaf filtering, later-wins merge semantics, non-mutation, and deep lexicographic sorting. Adds tests covering merging, edge cases, idempotency, ordering, and non-mutation; re-exports the function.
CLI Contract Enrichment Refactoring
packages/1-framework/3-tooling/cli/src/control-api/contract-enrichment.ts
Refactors enrichContract to call mergeCapabilityMatrices(ir.capabilities, components) and removes the local CapabilityMatrix type and helper functions.
SQL Runtime Context Integration
packages/2-sql/5-runtime/src/sql-context.ts
Extends createExecutionContext to accept an optional driver descriptor, builds capability contributors from stack.target, stack.adapter, optional driver, and stack.extensionPacks, merges them, and returns a contract with the merged capabilities.
Runtime Context Test Coverage
packages/2-sql/5-runtime/test/sql-context.test.ts, packages/2-sql/5-runtime/test/execution-stack.test.ts, packages/2-sql/5-runtime/test/parameterized-types.test.ts
Updates assertions from reference equality to deep equality for context.contract. Adds helper constructors and a capability folding test suite that verifies folding order, collision precedence, non-mutation, equivalence with mergeCapabilityMatrices, and idempotency.
Integration Test Setup Update
test/integration/test/sql-builder/setup.ts
Removes enrichContract usage in setup, deserializes base contract directly, and now passes driver: stack.driver explicitly to createExecutionContext.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • prisma/prisma-next#574: Introduces the "merge capabilities from stack/components instead of author capabilities" refactor that this PR implements in the framework and runtime layers.

Poem

🐰
Matrices fold where contributors meet,
Later keys prevail, sorted and neat,
Plain objects pruned to boolean song,
Merged without breaking what came along,
A rabbit cheers: one primitive, strong.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: including adapter and driver capabilities in createExecutionContext to achieve parity with CLI emit behavior.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2693-merge-stack-component-capabilities-into-the-runtime-contract

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 28, 2026

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@602

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@602

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@602

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@602

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@602

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@602

@prisma-next/extension-cipherstash

npm i https://pkg.pr.new/@prisma-next/extension-cipherstash@602

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@602

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@602

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@602

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@602

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@602

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@602

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@602

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@602

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@602

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@602

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@602

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@602

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@602

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@602

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@602

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@602

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@602

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@602

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@602

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@602

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@602

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@602

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@602

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@602

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@602

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@602

prisma-next

npm i https://pkg.pr.new/prisma-next@602

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@602

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@602

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@602

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@602

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@602

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@602

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@602

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@602

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@602

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@602

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@602

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@602

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@602

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@602

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@602

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@602

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@602

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@602

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@602

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@602

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@602

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@602

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@602

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@602

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@602

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@602

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@602

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@602

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@602

commit: e1f4cf8

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
test/integration/test/sql-builder/setup.ts (1)

116-116: ⚡ Quick win

Use the stack’s driver descriptor for capability folding to avoid drift.

Line 116 passes postgresDriver, but the stack was created with a wrapped driver descriptor. Reusing stack.driver keeps merged capabilities aligned with the exact descriptor used to instantiate runtime.

Proposed change
-    context = createExecutionContext({ contract: sqlContract, stack, driver: postgresDriver });
+    context = createExecutionContext({ contract: sqlContract, stack, driver: stack.driver });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/integration/test/sql-builder/setup.ts` at line 116, The test is
instantiating the execution context with the raw postgresDriver which can
desynchronize capability folding from the wrapped driver used to create the
stack; update the call to createExecutionContext to pass the stack's actual
driver descriptor (use stack.driver) instead of postgresDriver so that merged
capabilities remain consistent with the runtime that instantiated the stack
(keep sqlContract and stack the same).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/1-framework/1-core/framework-components/src/shared/capabilities.ts`:
- Around line 16-29: Replace the unsafe "as" casts in sortDeep: import blindCast
from "`@prisma-next/utils/casts`" (or named import blindCast) and use blindCast<T,
"sortDeep preserves runtime shape, but the recursive generic type relationship
can’t be expressed to TS">(...) to cast the mapped array result and the final
next object instead of using "as unknown as T" and "as T"; alternatively, change
sortDeep to operate on unknown internally and perform a single
blindCast<T,...>(result) at the function boundary so only one explicit cast
remains.

In `@packages/2-sql/5-runtime/test/sql-context.test.ts`:
- Line 928: The test currently compares serialized JSON strings —
expect(JSON.stringify(context.contract.capabilities)).toBe(JSON.stringify(expected))
— which is brittle; change it to a structural deep equality assertion such as
expect(context.contract.capabilities).toEqual(expected) (or toStrictEqual if you
want strict matching) so the test compares the actual objects
(context.contract.capabilities vs expected) directly for clearer diffs and more
robust comparisons.

In `@test/integration/test/sql-builder/setup.ts`:
- Line 24: The unsafe cast using "as Contract" on the result of new
SqlContractSerializer().deserializeContract(contract) should be replaced with
the repository's cast helper to make the unsafe boundary explicit; locate the
deserialization call that assigns to sqlContract and replace the bare cast with
the repo's cast/assert helper (e.g., castToContract or similar) so the value
returned by SqlContractSerializer.deserializeContract is validated/annotated via
the central cast utility rather than a raw TypeScript assertion.

---

Nitpick comments:
In `@test/integration/test/sql-builder/setup.ts`:
- Line 116: The test is instantiating the execution context with the raw
postgresDriver which can desynchronize capability folding from the wrapped
driver used to create the stack; update the call to createExecutionContext to
pass the stack's actual driver descriptor (use stack.driver) instead of
postgresDriver so that merged capabilities remain consistent with the runtime
that instantiated the stack (keep sqlContract and stack the same).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 762f10e4-4022-483a-878d-bd0f7d9bd5bd

📥 Commits

Reviewing files that changed from the base of the PR and between bc310d2 and 74454e5.

📒 Files selected for processing (9)
  • packages/1-framework/1-core/framework-components/src/exports/components.ts
  • packages/1-framework/1-core/framework-components/src/shared/capabilities.ts
  • packages/1-framework/1-core/framework-components/test/capabilities.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/contract-enrichment.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/execution-stack.test.ts
  • packages/2-sql/5-runtime/test/parameterized-types.test.ts
  • packages/2-sql/5-runtime/test/sql-context.test.ts
  • test/integration/test/sql-builder/setup.ts

Comment thread packages/1-framework/1-core/framework-components/src/shared/capabilities.ts Outdated
Comment thread packages/2-sql/5-runtime/test/sql-context.test.ts Outdated
Comment thread test/integration/test/sql-builder/setup.ts Outdated
…untime + emit reuse (TML-2693)

The CLI emit path (`enrichContract`) and the SQL runtime (`createExecutionContext`) both need to fold a stack of component descriptors capabilities into a single matrix. Until now the primitive lived inline in `contract-enrichment.ts`, so the runtime had no way to call it without dragging the CLI into its dependency graph.

This change lifts the inline `mergeCapabilities` + `extractCapabilityMatrix` logic out of `contract-enrichment.ts` into a new shared helper `mergeCapabilityMatrices` in `@prisma-next/framework-components/components`, with its own unit tests. `enrichContract` now delegates to it; its public output is unchanged for any type-valid Contract (`Contract.capabilities` is non-optional `Record<string, Record<string, boolean>>`). The helper also treats a non-object `base` as the empty matrix rather than throwing, which keeps `enrichContract` byte-identical for the existing CLI tests that pass an unsafely-cast mock contract.

D1 of TML-2693: lays the substrate. D2 wires `createExecutionContext` to call the same helper; D3 removes the test-side `enrichContract` workaround in `test/integration/test/sql-builder/setup.ts`.

Signed-off-by: Will Madden <madden@prisma.io>
wmadden added a commit that referenced this pull request May 28, 2026
…up (TML-2693)

Addresses CodeRabbit review on #602:

- `capabilities.ts`: refactor `sortDeep` to operate on `unknown` internally and
  blindCast only once at the `mergeCapabilityMatrices` return boundary, replacing
  three bare `as` casts. Restores the lint:casts delta to 0.
- `sql-context.test.ts`: swap the `JSON.stringify(...).toBe(JSON.stringify(...))`
  full-stack equality assertion for a direct `.toEqual` — both compare the same
  structurally sorted matrix, but the structural assertion gives clearer diffs.
- `test/integration/test/sql-builder/setup.ts`: replace the bare
  `as Contract` cast on the deserializer boundary with `blindCast<Contract, "…">`
  so the unsafe boundary is named at the call site.

No behaviour change.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden force-pushed the tml-2693-merge-stack-component-capabilities-into-the-runtime-contract branch from 74454e5 to 4ccf24e Compare May 28, 2026 13:01
wmadden added 4 commits May 28, 2026 15:01
…t (TML-2693)

In-process consumers that build a contract via `defineContract({ family, target, extensionPacks }, …)` and hand it to `createExecutionContext` previously saw only the target + extension-pack capabilities baked into the IR; adapter and driver contributions landed only via the CLI emit path through `enrichContract`. Runtime capability gates (`sql.returning`, `postgres.distinctOn`, …) therefore rejected operations the adapter actually supported.

This change folds the same merge that `enrichContract` performs at emit time into the runtime by reusing the shared `mergeCapabilityMatrices` helper (extracted in the preceding refactor). After the existing requirements check, the runtime computes the merged matrix from target + adapter + (optional) driver + extension packs and rebinds the local contract so the entire downstream pipeline — codec / queryOperation / mutationDefault collection and the returned `ExecutionContext.contract` — observes the merged matrix.

`createExecutionContext` gains a new optional `driver?: RuntimeDriverDescriptor<…>` field on its options. The driver is consulted *only* as a capability source here; its lifecycle (connect/close) stays where it is, on `instantiateExecutionStack` + `runtime`. Existing callers that do not pass `driver` continue to work unchanged. Three pre-existing tests that asserted referential equality of `context.contract` to the input were relaxed to structural equality, since the returned contract is now always a fresh object carrying the merged matrix.

TML-2693 D2. D1 (commit 6ddac17) extracted the shared helper; D3 will drop the test-side `enrichContract` workaround in `test/integration/test/sql-builder/setup.ts` and feed the driver descriptor to `createExecutionContext` via the new option.

Signed-off-by: Will Madden <madden@prisma.io>
…p (TML-2693)

With createExecutionContext now folding stack capabilities at runtime
(990956b, building on the shared mergeCapabilityMatrices helper from
6ddac17), the in-memory contract path no longer needs the CLI emit-time
enrichment as a test-side workaround.

Pass the unenriched in-memory contract directly to SqlContractSerializer
.deserializeContract and supply postgresDriver via the new options.driver
field so the runtime fold sees the driver capabilities the same way
enrichContract did.

Removes the only test-side consumer of @prisma-next/cli/control-api as a
runtime workaround. The remaining authoring/ usages of enrichContract are
legitimate CLI-emit-parity tests and are out of scope here.

Signed-off-by: Will Madden <madden@prisma.io>
…up (TML-2693)

Addresses CodeRabbit review on #602:

- `capabilities.ts`: refactor `sortDeep` to operate on `unknown` internally and
  blindCast only once at the `mergeCapabilityMatrices` return boundary, replacing
  three bare `as` casts. Restores the lint:casts delta to 0.
- `sql-context.test.ts`: swap the `JSON.stringify(...).toBe(JSON.stringify(...))`
  full-stack equality assertion for a direct `.toEqual` — both compare the same
  structurally sorted matrix, but the structural assertion gives clearer diffs.
- `test/integration/test/sql-builder/setup.ts`: replace the bare
  `as Contract` cast on the deserializer boundary with `blindCast<Contract, "…">`
  so the unsafe boundary is named at the call site.

No behaviour change.

Signed-off-by: Will Madden <madden@prisma.io>
Replace bare casts in mergeCapabilityMatrices, use structural equality in
capability folding tests, and pass stack.driver for integration setup so
capability folding matches the instantiated stack descriptor.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden force-pushed the tml-2693-merge-stack-component-capabilities-into-the-runtime-contract branch from 4ccf24e to bd5d3eb Compare May 28, 2026 13:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@wmadden wmadden changed the title TML-2693: fold stack capabilities into the runtime contract at createExecutionContext TML-2693: include adapter + driver capabilities in createExecutionContext (parity with CLI emit) May 28, 2026
…-2693)

`stack.driver` is typed as `RuntimeDriverDescriptor<…> | undefined` because the
field is optional on `SqlExecutionStack`, which trips `exactOptionalPropertyTypes`
when passed to `createExecutionContext`. Bind the (cursor-disabled) driver
descriptor to a local variable and feed the same value to both
`createSqlExecutionStack` and `createExecutionContext` so both observe a narrow
non-optional type without a non-null assertion.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden merged commit 96318b7 into main May 28, 2026
17 checks passed
wmadden added a commit that referenced this pull request May 28, 2026
…up (TML-2693)

Addresses CodeRabbit review on #602:

- `capabilities.ts`: refactor `sortDeep` to operate on `unknown` internally and
  blindCast only once at the `mergeCapabilityMatrices` return boundary, replacing
  three bare `as` casts. Restores the lint:casts delta to 0.
- `sql-context.test.ts`: swap the `JSON.stringify(...).toBe(JSON.stringify(...))`
  full-stack equality assertion for a direct `.toEqual` — both compare the same
  structurally sorted matrix, but the structural assertion gives clearer diffs.
- `test/integration/test/sql-builder/setup.ts`: replace the bare
  `as Contract` cast on the deserializer boundary with `blindCast<Contract, "…">`
  so the unsafe boundary is named at the call site.

No behaviour change.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden deleted the tml-2693-merge-stack-component-capabilities-into-the-runtime-contract branch May 28, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant