Skip to content

feat(sql): compose mutation defaults via registries#214

Merged
wmadden merged 40 commits intomainfrom
tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl
Mar 23, 2026
Merged

feat(sql): compose mutation defaults via registries#214
wmadden merged 40 commits intomainfrom
tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl

Conversation

@wmadden
Copy link
Copy Markdown
Contributor

@wmadden wmadden commented Mar 4, 2026

closes TML-2025

Key snippet(s)

Runtime execution: resolve default handler by contract id

// Runtime: resolve execution default handler by id from the composed runtime registry
const generator = generatorRegistry.get(spec.id);
if (!generator) {
  throw runtimeError(
    'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
    `Contract references mutation default generator '${spec.id}' but no runtime component provides it.`,
    { id: spec.id },
  );
}
return generator.generate(spec.params);

Intent

Make mutation default behavior component-composable end-to-end across two distinct seams: control-time PSL lowering composes a default-function vocabulary plus generator applicability descriptors, and runtime mutation-default application composes generator implementations that resolve emitted id references (with stable missing-id errors).

Change map

The story

  1. Define an explicit control-plane vocabulary + applicability model. A ControlMutationDefaults contribution bundles a default-function lowering registry and generator descriptors that declare applicable codecIds, plus assembly rules that fail on duplicates.
  2. Make PSL lowering consume composed registries. The PSL interpreter lowers @default(...) calls via the registry, then validates declared applicability by comparing the column’s codecId to the generator descriptor’s applicableCodecIds.
  3. Make control-plane assembly deterministic and testable. The SQL family assembly collects contributions deterministically and rejects collisions, so CLI/control-plane consumers can build the same registry given the same component composition.
  4. Resolve runtime default handlers by generator id via composition. SQL runtime execution context construction collects mutationDefaultGenerators() from target/adapter/packs, and applyMutationDefaults resolves each emitted generator id from that runtime registry with a stable missing-id error.
  5. Prove pack extensibility in parity fixtures and focused unit tests. New tests demonstrate both lowering-time pack vocabulary contributions and runtime generator resolution behavior.

Behavior changes & evidence

Compatibility / migration / risk

  • API surface: PSL interpretation/provider now requires explicit target + scalarTypeDescriptors inputs, and accepts composed controlMutationDefaults as an optional input; there is no default target or provider-local assembly.
  • Runtime: contracts that reference execution default generator ids not provided by the composed runtime stack now fail early and clearly (RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING).

Non-goals / intentionally out of scope

  • Expanding PSL default-function syntax beyond what’s needed to prove the registry seam.
  • Adding predicate-based applicability (v1 is codecId-only).

Summary by CodeRabbit

  • New Features

    • Composed mutation-default system: mutation defaults and generators can be contributed by packs/adapters and composed into the build/runtime.
    • Pack-provided authoring helpers: type constructors and field presets available from packs.
    • Generator applicability descriptors: generators declare which column codecs they support.
  • Documentation

    • Added ADRs describing mutation-default composition, pack-provided helpers, and parameterized native types.
  • Breaking Changes

    • Generator IDs validated by pattern (not a fixed list).
    • Authoring/contract tooling now requires explicit target and scalar-type descriptors; duplicate contributions are hard errors.

@linear
Copy link
Copy Markdown

linear Bot commented Mar 4, 2026

TML-2025 Follow-up: pack-provided mutation default functions registry (remove PSL hardcoding)

Context

Milestone 5 (TML-2020) locks in Option 2: PSL default functions are interpreted via an injected registry, and v1 ships with a provider-supplied built-in registry.

That solves parity, but the default-function vocabulary and per-column applicability are still effectively hard-coded (even if moved out of the interpreter).

Canonical spec + plan

  • Spec: projects/psl-contract-authoring/specs/Follow-up - Pack-provided mutation default functions registry.spec.md
  • Plan: projects/psl-contract-authoring/plans/Follow-up - Pack-provided mutation default functions registry-plan.md

Goal

Design and implement a framework-component contribution surface so targets/adapters/extension packs can provide:

  • a mutation-default generator vocabulary (names + argument rules → generator spec), and
  • applicability rules keyed by column type (codecId/nativeType/typeParams / facets).

Then wire PSL provider and TS authoring surfaces to consume this vocabulary as the single source of truth.

Acceptance criteria

  • Packs can contribute default-function / generator handlers without modifying the PSL provider.
  • PSL validation errors for unknown/invalid defaults remain stable and span-based.
  • The runtime generator registry can execute referenced generators (or errors clearly when missing).
  • A migration path exists from built-in v1 registry to pack-assembled registry (no breaking changes for existing fixtures).

References

  • ADR 164: docs/architecture docs/adrs/ADR 164 - Registry-driven PSL default function lowering.md
  • Milestone 5 ticket: TML-2020

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 6945abf0-6375-442c-ba16-2c60bfcdf5eb

📥 Commits

Reviewing files that changed from the base of the PR and between cfb9fb4 and dce82b6.

📒 Files selected for processing (1)
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
✅ Files skipped from review due to trivial changes (1)
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json

📝 Walkthrough

Walkthrough

An extensible mutation-defaults system was introduced: default-function handlers and generator descriptors are composed from contributors and passed into the PSL interpreter. Generator IDs moved from enumerated literals to regex-constrained flat strings validated at runtime and resolved from composed registries; runtime now enforces generator ownership and uniqueness.

Changes

Cohort / File(s) Summary
Generator ID System
packages/1-framework/1-core/shared/contract/src/types.ts, packages/1-framework/2-authoring/ids/src/generator-ids.ts, packages/1-framework/2-authoring/ids/src/..., packages/2-sql/2-authoring/contract-ts/schemas/..., packages/2-sql/1-core/contract/src/validators.ts
Replaced literal generator-id union with regex-constrained flat string; added builtinGeneratorIds/BuiltinGeneratorId; updated validators and JSON schema to accept flat IDs.
Builtin Generator Metadata & Resolution
packages/1-framework/2-authoring/ids/src/index.ts, .../generators.ts, .../runtime.ts
Added builtin metadata registry, per-generator descriptor resolvers, exported resolver API, and runtime type-guard that errors on unknown builtin ids.
Control / Default-Function Registry Shape
packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts, packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
Reworked registry entries to include { lower, usageSignatures? }; introduced ControlMutationDefaults, ControlMutationDefaultRegistry, and mutation-generator descriptor types; removed in-file builtin implementations.
PSL Interpreter & Provider API
packages/2-sql/2-authoring/contract-psl/src/interpreter.ts, .../provider.ts, .../README.md
Made target and scalarTypeDescriptors required; added optional controlMutationDefaults; removed implicit builtin wiring; threaded generator/codec context through lowering and applicability checks.
Family-level Composition
packages/2-sql/3-tooling/family/src/core/assembly.ts, .../migrations/types.ts, .../exports/control.ts, .../README.md
Added assemblers assembleControlMutationDefaultContributions and assemblePslInterpretationContributions; new types for function entries, generator descriptors, and PSL scalar descriptors; enforce uniqueness across contributors.
Postgres Adapter Contributions
packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts, .../exports/control.ts, .../exports/runtime.ts, package.json
Added Postgres lowering, generator descriptors, PSL scalar descriptors; wired into adapter descriptor and runtime; added runtime generator factory and two package deps.
Runtime Registry & Resolution
packages/2-sql/5-runtime/src/sql-context.ts, .../exports/index.ts, .../README.md
Introduced RuntimeMutationDefaultGenerator, collectMutationDefaultGenerators(); generator resolution moved to composed registry; added runtime errors for duplicates/missing ids and threaded registry into execution flows.
Tests & Fixtures
packages/2-sql/2-authoring/contract-psl/test/*, packages/2-sql/3-tooling/family/test/*, packages/2-sql/5-runtime/test/*, packages/1-framework/2-authoring/ids/test/*, packages/3-targets/6-adapters/postgres/test/*, test/integration/..., packages/*/test/fixtures.ts
Added fixtures to create builtin-like control mutation defaults and PSL scalar descriptors; updated many tests to pass required interpreter inputs; added tests for assembly, applicability, runtime composition, and generator behaviors; added timeouts helper usage in several tests.
Integration & Examples
test/integration/test/authoring/parity/default-pack-slugid/*, examples/prisma-next-demo/prisma-next.config.ts, test/integration/.../prisma-next.config.parity-psl.ts
Added slugid extension pack, expected contract fixtures, and updated example/config templates to assemble and pass PSL interpretation contributions into contract creation.
Docs & ADRs
docs/architecture/docs/adrs/ADR 169*.md, ADR 170*.md, ADR 171*.md, docs/architecture/docs/ADR-INDEX.md, .cursor/rules/use-timeouts-helper-in-tests.mdc
Added ADRs describing declared applicability and pack-provided helpers; updated ADR index; adjusted test-timeout guidance to require shared helper import.
CI
.github/workflows/pr-code-security.yml
Replaced reusable code-scanning workflow with inline Semgrep + SARIF + Reviewdog steps and adjusted trigger/permissions.

Sequence Diagram(s)

sequenceDiagram
    participant PSL as PSL Document
    participant Interp as PSL Interpreter
    participant Scalars as Scalar Descriptors<br/>(composed)
    participant Defaults as Default-Function Registry<br/>(composed)
    participant Generators as Generator Registry<br/>(composed)
    participant IR as Contract IR

    PSL->>Interp: provide document + target + scalar descriptors + controlMutationDefaults
    Interp->>Scalars: resolve field scalar -> ColumnDescriptor
    Interp->>Defaults: lower default function calls (if any)
    Defaults-->>Interp: returns storage default OR execution generator spec
    alt execution generator produced
        Interp->>Generators: lookup generator by id
        Generators-->>Interp: GeneratorDescriptor (or missing)
        Interp->>Generators: check applicableCodecIds vs field.codecId
        Generators-->>Interp: optionally resolveGeneratedColumnDescriptor
    end
    Interp->>IR: emit resolved fields, storage defaults, execution defaults
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hop, hop, the defaults now flow,

Through composed packs and registries they go,
Generators named, unique and bright,
Scalars mapped and lowering right,
A rabbit cheers: composed systems glow! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(sql): compose mutation defaults via registries' accurately describes the main change—implementing a registry-driven composition model for mutation default functions across control-time and runtime as the primary objective of the PR.

✏️ 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-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl

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

Comment thread packages/2-sql/5-runtime/src/sql-context.ts
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 4, 2026

Open in StackBlitz

@prisma-next/runtime-executor

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/runtime-executor@214

@prisma-next/sql-runtime

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

@prisma-next/extension-paradedb

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

@prisma-next/extension-pgvector

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

@prisma-next/postgres

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

@prisma-next/sql-orm-client

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

@prisma-next/contract-authoring

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

@prisma-next/contract-ts

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

@prisma-next/ids

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

@prisma-next/psl-parser

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

@prisma-next/cli

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

@prisma-next/emitter

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

@prisma-next/eslint-plugin

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/eslint-plugin@214

@prisma-next/migration-tools

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

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

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

@prisma-next/sql-contract

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

@prisma-next/sql-errors

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

@prisma-next/sql-operations

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

@prisma-next/sql-schema-ir

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

@prisma-next/sql-contract-psl

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

@prisma-next/sql-contract-ts

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

@prisma-next/sql-contract-emitter

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

@prisma-next/family-sql

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

@prisma-next/sql-kysely-lane

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-kysely-lane@214

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

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

@prisma-next/sql-relational-core

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

@prisma-next/sql-lane

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-lane@214

@prisma-next/target-postgres

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

@prisma-next/adapter-postgres

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

@prisma-next/driver-postgres

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

@prisma-next/core-control-plane

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/core-control-plane@214

@prisma-next/core-execution-plane

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/core-execution-plane@214

@prisma-next/config

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

@prisma-next/contract

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

@prisma-next/operations

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

@prisma-next/plan

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

@prisma-next/utils

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

commit: dce82b6

Copy link
Copy Markdown

@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: 8

🧹 Nitpick comments (4)
docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md (1)

49-49: Clarify "For this slice".

The phrase "For this slice" is ambiguous. Consider specifying whether this means "in this initial implementation", "for this architectural aspect", or "in this PR scope". Clearer wording would help readers understand the scope and any planned evolution.

Suggested alternatives
-For this slice, applicability is keyed by `codecId` only.
+In this initial implementation, applicability is keyed by `codecId` only.

Or, if referring to architectural scope:

-For this slice, applicability is keyed by `codecId` only.
+For mutation default applicability, the key is `codecId` only.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture` docs/adrs/ADR 169 - Declared applicability for mutation
default generators.md at line 49, The phrase "For this slice" is ambiguous;
update the sentence containing "For this slice, applicability is keyed by
`codecId` only." to explicitly state the scope—e.g., "In this ADR, applicability
is keyed by `codecId` only." or "In this initial implementation, applicability
is keyed by `codecId` only."—so readers know whether the statement refers to the
ADR, the initial implementation, or the PR scope; pick the most accurate scope
and apply that wording consistently throughout the document.
packages/2-sql/2-authoring/contract-ts/src/contract.ts (1)

80-82: Consider extracting the generator ID pattern to avoid duplication.

This regex pattern is duplicated in packages/2-sql/1-core/contract/src/validators.ts (lines 25-27). Both use the same pattern for validating flat generator IDs.

♻️ Suggested approach

Extract the pattern to a shared constant in @prisma-next/sql-contract that both validators can import:

// In `@prisma-next/sql-contract/validators` or a shared constants file
export const GENERATOR_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;

This ensures the validation logic stays in sync across both packages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts` around lines 80 - 82,
Duplicate regex for generator IDs is used in GeneratorIdSchema and the
validators in packages/2-sql/1-core/contract/src/validators.ts; extract it to a
shared exported constant (e.g., GENERATOR_ID_PATTERN) in the
`@prisma-next/sql-contract` package and import it from both places. Replace the
inline regex in GeneratorIdSchema and the other validator with a reference to
GENERATOR_ID_PATTERN, keeping the existing narrow(...) logic (use the
pattern.test(value) call) so behavior is unchanged. Update exports so the
constant is available to both packages and adjust import statements in files
that used the inline regex.
packages/2-sql/3-tooling/family/src/core/assembly.ts (1)

261-290: Avoid multi-pass controlMutationDefaults() evaluation in assembly.

The current flow evaluates descriptor contributions in separate passes (generator map helper + function loop). If a descriptor computes contributions dynamically, this can drift across passes. Prefer one pass that collects both generators and functions from the same snapshot.

♻️ Proposed refactor (single-pass collection)
 export function assembleControlMutationDefaultContributions(
   descriptors: ReadonlyArray<SqlControlDescriptorWithContributions>,
 ): AssembledControlMutationDefaultContributions {
   const defaultFunctionRegistry = new Map<string, ControlMutationDefaultFunctionEntry>();
   const functionOwners = new Map<string, string>();
-  const generatorMap = createControlMutationDefaultGeneratorDescriptorMap(descriptors);
+  const generatorMap = new Map<string, ControlMutationDefaultGeneratorDescriptor>();
+  const generatorOwners = new Map<string, string>();

   for (const descriptor of descriptors) {
     const contributions = descriptor.controlMutationDefaults?.();
     if (!contributions) {
       continue;
     }
+
+    for (const generatorDescriptor of contributions.generatorDescriptors) {
+      const owner = generatorOwners.get(generatorDescriptor.id);
+      if (owner) {
+        throw new Error(
+          `Duplicate mutation default generator id "${generatorDescriptor.id}". Descriptor "${descriptor.id}" conflicts with "${owner}".`,
+        );
+      }
+      generatorMap.set(generatorDescriptor.id, generatorDescriptor);
+      generatorOwners.set(generatorDescriptor.id, descriptor.id);
+    }

     for (const [functionName, handler] of contributions.defaultFunctionRegistry) {
       const owner = functionOwners.get(functionName);
       if (owner) {
         throw new Error(
           `Duplicate mutation default function "${functionName}". Descriptor "${descriptor.id}" conflicts with "${owner}".`,
         );
       }
       defaultFunctionRegistry.set(functionName, handler);
       functionOwners.set(functionName, descriptor.id);
     }
   }

   return {
     defaultFunctionRegistry,
     generatorDescriptors: Array.from(generatorMap.values()),
   };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/3-tooling/family/src/core/assembly.ts` around lines 261 - 290,
The assembly currently calls
createControlMutationDefaultGeneratorDescriptorMap(descriptors) and then
iterates descriptors again calling descriptor.controlMutationDefaults() a second
time, which can yield different results for dynamic contributions; change
assembleControlMutationDefaultContributions to perform a single-pass: for each
descriptor call descriptor.controlMutationDefaults() once, add its generator
descriptors into a local generatorMap (mirroring the shape
createControlMutationDefaultGeneratorDescriptorMap produces) and simultaneously
merge its defaultFunctionRegistry entries into defaultFunctionRegistry while
checking duplicates via functionOwners; finally return defaultFunctionRegistry
and Array.from(generatorMap.values())—remove the separate
createControlMutationDefaultGeneratorDescriptorMap call and ensure you reference
descriptor.id when reporting conflicts.
packages/1-framework/2-authoring/ids/src/index.ts (1)

115-118: Use ifDefined() instead of inline conditional spread for params.

This segment should follow the repo’s standardized conditional spread helper.

♻️ Proposed refactor
   const resolvedDescriptor = resolveBuiltinGeneratedColumnDescriptor({
     id,
-    ...(params ? { params } : {}),
+    ...ifDefined('params', params),
   });

As per coding guidelines: "Use ifDefined() from @prisma-next/utils/defined for conditional object spreads instead of inline conditional spread patterns."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/2-authoring/ids/src/index.ts` around lines 115 - 118,
Replace the inline conditional spread used when building the args for
resolveBuiltinGeneratedColumnDescriptor: instead of spreading ...(params ? {
params } : {}), use the repository helper ifDefined from
`@prisma-next/utils/defined` and spread ...ifDefined({ params }) so the call
becomes resolveBuiltinGeneratedColumnDescriptor({ id, ...ifDefined({ params })
}); ensure you import ifDefined if it's not already present and adjust the
import list accordingly; keep references to resolvedDescriptor,
resolveBuiltinGeneratedColumnDescriptor, id, and params.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/1-framework/2-authoring/ids/src/index.ts`:
- Line 143: The file is re-exporting builtinGeneratorIds from src/index.ts which
violates the rule against cross-file re-exports outside an exports/ surface;
locate the original definition of builtinGeneratorIds (the module that defines
that symbol) and either (a) add the export there or (b) create/declare it under
this package's exports/ surface and export it from that file, then remove the
cross-file re-export line "export { builtinGeneratorIds };" from src/index.ts so
the package API only exposes symbols via the designated exports/ surface.

In `@packages/1-framework/2-authoring/ids/src/runtime.ts`:
- Around line 5-8: Replace the cast lookup that uses (spec.id as
BuiltinGeneratorId) with a type guard using Object.hasOwn to safely narrow the
key before accessing idGenerators: check Object.hasOwn(idGenerators, spec.id)
(or equivalent predicate) and only then read idGenerators[spec.id] into
generator; if the guard fails, throw the same Error for unknown built-in ID.
This removes the blind cast while keeping the same behavior around idGenerators,
BuiltinGeneratorId, and spec.id.

In `@packages/2-sql/2-authoring/contract-psl/src/interpreter.ts`:
- Line 800: The current double-cast on the builder variable bypasses type
safety; replace "as unknown as DynamicContractBuilder" with the concrete
SqlContractBuilder type (or remove the cast entirely) so builder is
declared/initialized as the SqlContractBuilder returned by
defineContract().target(input.target); update the builder declaration to use
SqlContractBuilder (or let TypeScript infer it) so you can call storageType(),
table(), model(), and build() without blind casts and preserve type safety.

In `@packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts`:
- Around line 32-35: Add a short inline comment explaining the intentional
double-cast on the InterpretPslDocumentToSqlContractIRInput argument to
interpretPslDocumentToSqlContractIRInternal: state that the double-cast (as
unknown as InterpretPslDocumentToSqlContractIRInput) is used only in this test
to bypass stricter typing for test setup/mocking and is permitted per the
“test-only escapes” guideline; place the comment directly above or beside the
double-cast to make intent explicit.

In `@packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts`:
- Line 96: The test case named "collects ColumnRefs from nested OperationExpr"
uses a raw numeric timeout ({ timeout: 1_000 }) which violates the project's
guideline; replace the numeric literal with the shared test timeout constant
from `@prisma-next/test-utils` (e.g., use timeouts.unit or another appropriate
timeouts.* constant) in the it(...) options so the test reads the timeout from
the shared helper rather than a raw number.

In `@packages/2-sql/5-runtime/README.md`:
- Around line 23-24: The Architecture section in README.md omits the new
mutation default generator concept, causing inconsistency with the earlier lines
that add "Mutation Default Generator Composition" and "No Implicit Generator
Baseline"; update the Architecture list (referencing SqlStaticContributions) to
include mutation default generators and explain that SqlStaticContributions now
aggregates composed default generators from target/adapter/extension
contributors and that the runtime resolves generator ids only from those
composed contributors (no builtin fallback). Keep the wording concise, follow
the project's doc guideline to describe the current state (not history), and
ensure the new entry references "mutation default generators" and "generator
ids" so readers can map it to the earlier points.

In `@packages/3-targets/3-targets/postgres/package.json`:
- Around line 29-30: Remove the invalid "uniku" dependency from package.json
(the entry "uniku": "^0.0.12") so installs no longer fail; if a different
package was intended, replace "uniku" with the correct npm package name and
update any import/use sites accordingly (search for references to "uniku" in the
postgres target). Ensure package.json only contains valid dependencies needed by
the postgres target, then run npm/yarn install to verify.

In
`@packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts`:
- Line 52: The test "stores raw default expressions from database" should not
use the hardcoded timeout 1_000; import and use the shared test timeout helper
instead (e.g., the exported timeouts constant from the test helpers) and replace
the inline 1_000 in the it(...) timeout option with the appropriate shared value
(for example timeouts.short or timeouts.default), ensuring you add the import of
the timeouts helper at the top and update the it(...) invocation that contains
the literal 1_000.

---

Nitpick comments:
In `@docs/architecture` docs/adrs/ADR 169 - Declared applicability for mutation
default generators.md:
- Line 49: The phrase "For this slice" is ambiguous; update the sentence
containing "For this slice, applicability is keyed by `codecId` only." to
explicitly state the scope—e.g., "In this ADR, applicability is keyed by
`codecId` only." or "In this initial implementation, applicability is keyed by
`codecId` only."—so readers know whether the statement refers to the ADR, the
initial implementation, or the PR scope; pick the most accurate scope and apply
that wording consistently throughout the document.

In `@packages/1-framework/2-authoring/ids/src/index.ts`:
- Around line 115-118: Replace the inline conditional spread used when building
the args for resolveBuiltinGeneratedColumnDescriptor: instead of spreading
...(params ? { params } : {}), use the repository helper ifDefined from
`@prisma-next/utils/defined` and spread ...ifDefined({ params }) so the call
becomes resolveBuiltinGeneratedColumnDescriptor({ id, ...ifDefined({ params })
}); ensure you import ifDefined if it's not already present and adjust the
import list accordingly; keep references to resolvedDescriptor,
resolveBuiltinGeneratedColumnDescriptor, id, and params.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts`:
- Around line 80-82: Duplicate regex for generator IDs is used in
GeneratorIdSchema and the validators in
packages/2-sql/1-core/contract/src/validators.ts; extract it to a shared
exported constant (e.g., GENERATOR_ID_PATTERN) in the `@prisma-next/sql-contract`
package and import it from both places. Replace the inline regex in
GeneratorIdSchema and the other validator with a reference to
GENERATOR_ID_PATTERN, keeping the existing narrow(...) logic (use the
pattern.test(value) call) so behavior is unchanged. Update exports so the
constant is available to both packages and adjust import statements in files
that used the inline regex.

In `@packages/2-sql/3-tooling/family/src/core/assembly.ts`:
- Around line 261-290: The assembly currently calls
createControlMutationDefaultGeneratorDescriptorMap(descriptors) and then
iterates descriptors again calling descriptor.controlMutationDefaults() a second
time, which can yield different results for dynamic contributions; change
assembleControlMutationDefaultContributions to perform a single-pass: for each
descriptor call descriptor.controlMutationDefaults() once, add its generator
descriptors into a local generatorMap (mirroring the shape
createControlMutationDefaultGeneratorDescriptorMap produces) and simultaneously
merge its defaultFunctionRegistry entries into defaultFunctionRegistry while
checking duplicates via functionOwners; finally return defaultFunctionRegistry
and Array.from(generatorMap.values())—remove the separate
createControlMutationDefaultGeneratorDescriptorMap call and ensure you reference
descriptor.id when reporting conflicts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Lite

Run ID: a5303313-8592-47a0-b73b-32b7eeaf71b5

📥 Commits

Reviewing files that changed from the base of the PR and between 2140353 and 70d2b6d.

⛔ Files ignored due to path filters (17)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/psl-contract-authoring/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/Follow-up - Pack-provided mutation default functions registry-plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/references/authoring-surface-gap-inventory.md is excluded by !projects/**
  • projects/psl-contract-authoring/spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Follow-up - Pack-provided mutation default functions registry.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 1 - Pluggable contract sources.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 2 - PSL parser.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 3 - Fixture-driven parity harness.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 4 - Parameterized attributes and pgvector parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 5 - ID variants and default function parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 6 - Close-out.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 7 - PSL sql template literal syntax.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/code-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/system-design-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/walkthrough.md is excluded by !projects/**
📒 Files selected for processing (46)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/1-core/contract/test/validate.test.ts
  • packages/2-sql/2-authoring/contract-psl/README.md
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/3-targets/postgres/package.json
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
  • test/integration/test/authoring/parity/default-pack-slugid/packs.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • test/integration/test/authoring/templates/prisma-next.config.parity-psl.ts
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts

Comment thread packages/1-framework/2-authoring/ids/src/index.ts Outdated
Comment thread packages/1-framework/2-authoring/ids/src/runtime.ts Outdated
Comment thread packages/2-sql/2-authoring/contract-psl/src/interpreter.ts Outdated
Comment thread packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
Comment thread packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts Outdated
Comment thread packages/2-sql/5-runtime/README.md
Comment thread packages/3-targets/3-targets/postgres/package.json Outdated
Comment thread packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts Outdated
@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from 1d1f33c to f275c8a Compare March 5, 2026 06:04
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
packages/2-sql/5-runtime/README.md (1)

23-24: Use one term for generator concept across the README.

Line 23 says “execution default generators,” but the rest of this README uses “mutation default generators.” Consider standardizing this bullet to the latter for consistency and easier scanning.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/5-runtime/README.md` around lines 23 - 24, Update the README
phrase "execution default generators" to use the same term as the rest of the
document: "mutation default generators". Locate the bullet containing "execution
default generators" (the first bullet under the feature list) and replace that
phrase so the bullet reads "Mutation Default Generator Composition: Assemble
mutation default generators from composed target/adapter/extension contributors"
to keep terminology consistent across the README.
packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts (1)

231-231: Use expect.not.objectContaining() for absence checks.

Please align this assertion with the repo matcher convention for “field must be absent”.

♻️ Suggested matcher update
-      expect(columns['no_default']).not.toHaveProperty('default');
+      expect(columns['no_default']).toEqual(
+        expect.not.objectContaining({ default: expect.anything() }),
+      );

As per coding guidelines, "Use expect.not.objectContaining() for absence checks".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts`
at line 231, Replace the assertion that uses .not.toHaveProperty for the
"no_default" column with the repo convention using expect.not.objectContaining:
change the assertion on columns['no_default'] to use
expect(...).toEqual(expect.not.objectContaining({ default: expect.anything() }))
so the test asserts absence of the default field via expect.not.objectContaining
rather than .not.toHaveProperty.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/2-sql/5-runtime/README.md`:
- Around line 23-24: Update the README phrase "execution default generators" to
use the same term as the rest of the document: "mutation default generators".
Locate the bullet containing "execution default generators" (the first bullet
under the feature list) and replace that phrase so the bullet reads "Mutation
Default Generator Composition: Assemble mutation default generators from
composed target/adapter/extension contributors" to keep terminology consistent
across the README.

In
`@packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts`:
- Line 231: Replace the assertion that uses .not.toHaveProperty for the
"no_default" column with the repo convention using expect.not.objectContaining:
change the assertion on columns['no_default'] to use
expect(...).toEqual(expect.not.objectContaining({ default: expect.anything() }))
so the test asserts absence of the default field via expect.not.objectContaining
rather than .not.toHaveProperty.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: c4481c6c-7bb9-4f6a-9d79-b6ed47ca4f8d

📥 Commits

Reviewing files that changed from the base of the PR and between 70d2b6d and 1d1f33c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts

Copy link
Copy Markdown

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/2-sql/2-authoring/contract-psl/test/provider.test.ts (1)

87-112: ⚠️ Potential issue | 🔴 Critical

Missing required options parameter in calls to prismaContract.

The function signature requires options: PrismaContractOptions as a non-optional parameter. Lines 87 and 173 call prismaContract('./schema.prisma') without passing any options. Both calls need baseOptions passed as the second argument, consistent with other tests in the file (e.g., line 131, 211, 250, 289, 348, 388, 413).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/test/provider.test.ts` around lines
87 - 112, The tests call prismaContract('./schema.prisma') without the required
options argument; update those calls to pass the shared baseOptions (of type
PrismaContractOptions) as the second parameter so they match other tests (e.g.,
change prismaContract('./schema.prisma') to prismaContract('./schema.prisma',
baseOptions)); find usages by searching for prismaContract and ensure both
occurrences in this test file receive baseOptions.
🧹 Nitpick comments (9)
packages/3-targets/6-adapters/postgres/test/adapter.test.ts (1)

1039-1042: Use timeouts.default instead of timeouts.databaseOperation.

This test performs pure in-memory AST lowering with no actual database operations. The databaseOperation timeout is documented for "database operations (queries, setup, teardown)" including table creation and data insertion, none of which occur here. Use timeouts.default for general transformation tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-targets/6-adapters/postgres/test/adapter.test.ts` around lines
1039 - 1042, The test titled 'lowers SELECT with operation expression in include
ORDER BY' is using timeouts.databaseOperation but performs only in-memory AST
lowering (no DB work); change the timeout argument in the it(...) call from
timeouts.databaseOperation to timeouts.default to reflect that this is a general
transformation test rather than a database operation test.
packages/2-sql/1-core/contract/test/validate.test.ts (2)

65-107: Split these new cases into a dedicated test file.

This suite is already large; adding more scenarios here makes it harder to navigate and maintain. Move the execution-default generator-id cases into a focused file (for example, validate.execution-defaults.test.ts).

As per coding guidelines, **/*.test.ts files should stay under 500 lines and be split by logical boundaries with descriptive names.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/test/validate.test.ts` around lines 65 - 107,
Split the two tests that cover execution default generator ids out of
validate.test.ts into a new focused test file (e.g.,
validate.execution-defaults.test.ts): copy the two it(...) blocks referencing
validateContract<SqlContract<SqlStorage>>(...) and the
execution.mutations.defaults scenarios into the new file, keep or add any
necessary shared fixtures (baseContract) imports or recreations, update imports
to reference validateContract, SqlContract and SqlStorage, and remove the copied
blocks from the original validate.test.ts so both files stay under the 500-line
guideline and tests run unchanged.

104-106: Assert the specific generator-id failure reason.

Line 104 currently accepts any structural validation error. Consider also asserting /a flat generator id/ so the test proves this exact rule.

Suggested assertion tightening
-    expect(() => validateContract<SqlContract<SqlStorage>>(contract)).toThrow(
-      /Contract structural validation failed/,
-    );
+    expect(() => validateContract<SqlContract<SqlStorage>>(contract)).toThrow(
+      /a flat generator id/,
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/test/validate.test.ts` around lines 104 - 106,
The test currently asserts any structural validation error from
validateContract<SqlContract<SqlStorage>>(contract); tighten it to assert the
specific generator-id failure by matching the error message for "a flat
generator id" as well (e.g., change the toThrow regex to include /a flat
generator id/ or add a separate expect that the thrown error message matches /a
flat generator id/), referencing the validateContract call and the
SqlContract/SqlStorage types so the test ensures this exact rule is enforced.
packages/2-sql/2-authoring/contract-ts/src/contract.ts (1)

80-87: Centralize generator-id schema to avoid validation drift.

GeneratorIdSchema here duplicates the same regex rule in packages/2-sql/1-core/contract/src/validators.ts (Line 25-27). Reuse a shared exported schema/helper so both validation paths stay aligned.

Refactor direction
-import { ColumnDefaultSchema, ForeignKeySchema } from '@prisma-next/sql-contract/validators';
+import {
+  ColumnDefaultSchema,
+  ForeignKeySchema,
+  generatorIdSchema,
+} from '@prisma-next/sql-contract/validators';

-const GeneratorIdSchema = type('string').narrow((value, ctx) => {
-  return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value) ? true : ctx.mustBe('a flat generator id');
-});
-
 const ExecutionMutationDefaultValueSchema = type({
   kind: "'generator'",
-  id: GeneratorIdSchema,
+  id: generatorIdSchema,
   'params?': 'Record<string, unknown>',
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts` around lines 80 - 87,
Replace the local duplicated GeneratorIdSchema with the shared exported
generator-id schema from the core validators module: remove the local const
GeneratorIdSchema and import the shared exported symbol (the generator id schema
exported from the core validators file) and use that in the
ExecutionMutationDefaultValueSchema id field; ensure the import name matches the
exported identifier and update any references to GeneratorIdSchema in this file
to use the imported symbol so both packages share the same validation logic.
packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts (2)

133-160: Test for duplicate generator IDs is under the wrong describe block.

This test calls createControlMutationDefaultGeneratorDescriptorMap but is nested under describe('assembleControlMutationDefaultContributions'). Consider moving it to a separate describe block or renaming the parent describe to reflect it covers both functions.

Suggested structure
+describe('createControlMutationDefaultGeneratorDescriptorMap', () => {
   it('throws for duplicate generator ids', () => {
     // ...existing test...
   });
+});

Or rename the parent describe block to cover all assembly functions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts`
around lines 133 - 160, The test asserting duplicate generator ids is misplaced
under the describe('assembleControlMutationDefaultContributions') block; move
that it(...) into a new or existing describe that pertains to
createControlMutationDefaultGeneratorDescriptorMap (or rename the parent
describe to cover both assembly helpers) so tests are grouped by the function
they exercise; specifically relocate the test referencing
createControlMutationDefaultGeneratorDescriptorMap (and the duplicated generator
fixtures) into a describe block named for
createControlMutationDefaultGeneratorDescriptorMap (or update the parent
describe title) to keep organization consistent.

162-208: Scalar type descriptor tests are also under the wrong describe block.

Lines 162-208 test assemblePslInterpretationContributions but are nested under describe('assembleControlMutationDefaultContributions').

Suggested structure
+describe('assemblePslInterpretationContributions', () => {
   it('collects scalar type descriptor contributions', () => {
     // ...existing test...
   });
+
   it('throws for duplicate scalar type descriptors', () => {
     // ...existing test...
   });
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts`
around lines 162 - 208, The two "it" cases that exercise
assemblePslInterpretationContributions are currently nested inside the
describe('assembleControlMutationDefaultContributions') block; move those tests
so they live under the appropriate describe for
assemblePslInterpretationContributions (or a new describe with that name) so the
specs reference assemblePslInterpretationContributions directly; ensure the test
names remain the same and keep the test bodies invoking createDescriptor and
assemblePslInterpretationContributions unchanged.
packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts (2)

221-228: Normalize usage signatures before formatting diagnostics.

" " currently passes the filter. Trimming first avoids noisy/blank signature entries in error messages.

Small cleanup
-      const usageSignatures = entry.usageSignatures?.filter((signature) => signature.length > 0);
+      const usageSignatures = entry.usageSignatures
+        ?.map((signature) => signature.trim())
+        .filter((signature) => signature.length > 0);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`
around lines 221 - 228, The code building signatures from registry entries
allows whitespace-only usage signatures through the filter; update the logic
that computes usageSignatures in default-function-registry.ts (the
Array.from(registry.entries()) .flatMap block) to trim each signature before
filtering — e.g. map each entry.usageSignatures to signature.trim() and then
filter by trimmed.length>0, and then fall back to [`${functionName}()`] when the
resulting array is empty; ensure you reference the existing variables (registry,
entry, usageSignatures, signatures) so the change is localized.

17-22: Require columnCodecId in lowering context for stronger applicability guarantees.

Keeping this optional allows call sites to omit codec context and accidentally bypass intended applicability checks.

Proposed tightening
 export interface DefaultFunctionLoweringContext {
   readonly sourceId: string;
   readonly modelName: string;
   readonly fieldName: string;
-  readonly columnCodecId?: string;
+  readonly columnCodecId: string;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`
around lines 17 - 22, The DefaultFunctionLoweringContext currently makes
columnCodecId optional which allows callers to omit codec info; change the
interface so columnCodecId is required (remove the ? on columnCodecId) in
DefaultFunctionLoweringContext and then update all call sites, implementations,
and tests that construct or receive a DefaultFunctionLoweringContext (search for
uses of DefaultFunctionLoweringContext, functions like anyLowering/ lower*
implementations, and places that pass sourceId/modelName/fieldName) to supply a
concrete columnCodecId value; ensure any helper builders or factories that
create this context are updated to accept/propagate columnCodecId and adjust
types/signatures accordingly so the compiler enforces the presence of the codec
id.
packages/2-sql/5-runtime/src/sql-context.ts (1)

381-400: Add an explicit fallback in computeExecutionDefaultValue.

Making unsupported kinds fail explicitly avoids silent/ambiguous behavior when contract data is invalid or evolves.

Suggested hardening
 function computeExecutionDefaultValue(
   spec: ExecutionMutationDefaultValue,
   generatorRegistry: ReadonlyMap<string, RuntimeMutationDefaultGenerator>,
 ): unknown {
   switch (spec.kind) {
     case 'generator': {
       const generator = generatorRegistry.get(spec.id);
       if (!generator) {
         throw runtimeError(
           'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
           `Contract references mutation default generator '${spec.id}' but no runtime component provides it.`,
           {
             id: spec.id,
           },
         );
       }
       return generator.generate(spec.params);
     }
+    default: {
+      throw runtimeError(
+        'RUNTIME.MUTATION_DEFAULT_KIND_UNSUPPORTED',
+        'Unsupported execution mutation default kind.',
+        { spec },
+      );
+    }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/5-runtime/src/sql-context.ts` around lines 381 - 400,
computeExecutionDefaultValue currently handles only spec.kind === 'generator'
and can return undefined for unknown kinds; add an explicit fallback branch for
unsupported spec.kind values that throws a runtimeError (similar style to the
existing error) so invalid or evolved contract data fail loudly. Locate the
computeExecutionDefaultValue function and the switch over spec.kind and add a
default/case for other kinds that throws a clear runtimeError referencing
spec.kind and spec (or spec.id when available) so callers never get an ambiguous
undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/2-sql/2-authoring/contract-psl/test/provider.test.ts`:
- Around line 87-112: The tests call prismaContract('./schema.prisma') without
the required options argument; update those calls to pass the shared baseOptions
(of type PrismaContractOptions) as the second parameter so they match other
tests (e.g., change prismaContract('./schema.prisma') to
prismaContract('./schema.prisma', baseOptions)); find usages by searching for
prismaContract and ensure both occurrences in this test file receive
baseOptions.

---

Nitpick comments:
In `@packages/2-sql/1-core/contract/test/validate.test.ts`:
- Around line 65-107: Split the two tests that cover execution default generator
ids out of validate.test.ts into a new focused test file (e.g.,
validate.execution-defaults.test.ts): copy the two it(...) blocks referencing
validateContract<SqlContract<SqlStorage>>(...) and the
execution.mutations.defaults scenarios into the new file, keep or add any
necessary shared fixtures (baseContract) imports or recreations, update imports
to reference validateContract, SqlContract and SqlStorage, and remove the copied
blocks from the original validate.test.ts so both files stay under the 500-line
guideline and tests run unchanged.
- Around line 104-106: The test currently asserts any structural validation
error from validateContract<SqlContract<SqlStorage>>(contract); tighten it to
assert the specific generator-id failure by matching the error message for "a
flat generator id" as well (e.g., change the toThrow regex to include /a flat
generator id/ or add a separate expect that the thrown error message matches /a
flat generator id/), referencing the validateContract call and the
SqlContract/SqlStorage types so the test ensures this exact rule is enforced.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`:
- Around line 221-228: The code building signatures from registry entries allows
whitespace-only usage signatures through the filter; update the logic that
computes usageSignatures in default-function-registry.ts (the
Array.from(registry.entries()) .flatMap block) to trim each signature before
filtering — e.g. map each entry.usageSignatures to signature.trim() and then
filter by trimmed.length>0, and then fall back to [`${functionName}()`] when the
resulting array is empty; ensure you reference the existing variables (registry,
entry, usageSignatures, signatures) so the change is localized.
- Around line 17-22: The DefaultFunctionLoweringContext currently makes
columnCodecId optional which allows callers to omit codec info; change the
interface so columnCodecId is required (remove the ? on columnCodecId) in
DefaultFunctionLoweringContext and then update all call sites, implementations,
and tests that construct or receive a DefaultFunctionLoweringContext (search for
uses of DefaultFunctionLoweringContext, functions like anyLowering/ lower*
implementations, and places that pass sourceId/modelName/fieldName) to supply a
concrete columnCodecId value; ensure any helper builders or factories that
create this context are updated to accept/propagate columnCodecId and adjust
types/signatures accordingly so the compiler enforces the presence of the codec
id.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts`:
- Around line 80-87: Replace the local duplicated GeneratorIdSchema with the
shared exported generator-id schema from the core validators module: remove the
local const GeneratorIdSchema and import the shared exported symbol (the
generator id schema exported from the core validators file) and use that in the
ExecutionMutationDefaultValueSchema id field; ensure the import name matches the
exported identifier and update any references to GeneratorIdSchema in this file
to use the imported symbol so both packages share the same validation logic.

In `@packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts`:
- Around line 133-160: The test asserting duplicate generator ids is misplaced
under the describe('assembleControlMutationDefaultContributions') block; move
that it(...) into a new or existing describe that pertains to
createControlMutationDefaultGeneratorDescriptorMap (or rename the parent
describe to cover both assembly helpers) so tests are grouped by the function
they exercise; specifically relocate the test referencing
createControlMutationDefaultGeneratorDescriptorMap (and the duplicated generator
fixtures) into a describe block named for
createControlMutationDefaultGeneratorDescriptorMap (or update the parent
describe title) to keep organization consistent.
- Around line 162-208: The two "it" cases that exercise
assemblePslInterpretationContributions are currently nested inside the
describe('assembleControlMutationDefaultContributions') block; move those tests
so they live under the appropriate describe for
assemblePslInterpretationContributions (or a new describe with that name) so the
specs reference assemblePslInterpretationContributions directly; ensure the test
names remain the same and keep the test bodies invoking createDescriptor and
assemblePslInterpretationContributions unchanged.

In `@packages/2-sql/5-runtime/src/sql-context.ts`:
- Around line 381-400: computeExecutionDefaultValue currently handles only
spec.kind === 'generator' and can return undefined for unknown kinds; add an
explicit fallback branch for unsupported spec.kind values that throws a
runtimeError (similar style to the existing error) so invalid or evolved
contract data fail loudly. Locate the computeExecutionDefaultValue function and
the switch over spec.kind and add a default/case for other kinds that throws a
clear runtimeError referencing spec.kind and spec (or spec.id when available) so
callers never get an ambiguous undefined.

In `@packages/3-targets/6-adapters/postgres/test/adapter.test.ts`:
- Around line 1039-1042: The test titled 'lowers SELECT with operation
expression in include ORDER BY' is using timeouts.databaseOperation but performs
only in-memory AST lowering (no DB work); change the timeout argument in the
it(...) call from timeouts.databaseOperation to timeouts.default to reflect that
this is a general transformation test rather than a database operation test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8ee8d5be-1920-4d95-8841-71bd7d094858

📥 Commits

Reviewing files that changed from the base of the PR and between 1d1f33c and f275c8a.

⛔ Files ignored due to path filters (17)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/psl-contract-authoring/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/Follow-up - Pack-provided mutation default functions registry-plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/references/authoring-surface-gap-inventory.md is excluded by !projects/**
  • projects/psl-contract-authoring/spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Follow-up - Pack-provided mutation default functions registry.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 1 - Pluggable contract sources.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 2 - PSL parser.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 3 - Fixture-driven parity harness.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 4 - Parameterized attributes and pgvector parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 5 - ID variants and default function parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 6 - Close-out.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 7 - PSL sql template literal syntax.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/code-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/system-design-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/walkthrough.md is excluded by !projects/**
📒 Files selected for processing (45)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/1-core/contract/test/validate.test.ts
  • packages/2-sql/2-authoring/contract-psl/README.md
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
  • test/integration/test/authoring/parity/default-pack-slugid/packs.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • test/integration/test/authoring/templates/prisma-next.config.parity-psl.ts
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts
🚧 Files skipped from review as they are similar to previous changes (17)
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/packs.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • docs/architecture docs/ADR-INDEX.md
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • packages/2-sql/2-authoring/contract-psl/README.md
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts

@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from f275c8a to 70d3b9e Compare March 7, 2026 17:43
Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (4)
packages/2-sql/2-authoring/contract-psl/test/fixtures.ts (1)

24-35: Switch the optional params spread to ifDefined().

This helper currently uses inline conditional spreading for params, which the repo bans in package/test code. Please rewrite this with ifDefined() so the fixtures stay aligned with the shared object-construction convention. As per coding guidelines, "Use ifDefined() from @prisma-next/utils/defined for conditional object spreads instead of inline conditional spread patterns".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts` around lines 24 -
35, Replace the inline conditional spread in executionGenerator with the shared
helper: import ifDefined from '@prisma-next/utils/defined' and change the
generated object spread from ...(params ? { params } : {}) to ...ifDefined({
params }, params) so that executionGenerator uses ifDefined for the optional
params property.
packages/2-sql/1-core/contract/test/validate.test.ts (1)

65-107: Move these cases into a dedicated execution-defaults test file.

This file is already well past the repository's 500-line limit, and adding more scenarios here makes it harder to navigate and maintain. Please move the new generator-id coverage into a focused validate.execution-defaults*.test.ts split instead of extending this catch-all file further. As per coding guidelines, "Keep test files under 500 lines ... split test files when they exceed 500 lines, contain multiple distinct concerns that can be logically separated, or have multiple top-level describe blocks that can be split by functionality".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/test/validate.test.ts` around lines 65 - 107,
Move the two test cases that exercise execution default generator ids out of the
large validate.test.ts into a new focused test file (e.g.
validate.execution-defaults.test.ts); copy the two it(...) blocks that reference
validateContract, SqlContract, and SqlStorage into that new file, keep the same
imports/setup used in the original (baseContract, validateContract, types), and
remove them from the original file so validate.test.ts stays under the 500-line
guideline and concerns remain separated.
packages/2-sql/2-authoring/contract-ts/src/contract.ts (1)

78-85: Reuse the shared generator-id validator here.

This regex now exists in both packages/2-sql/2-authoring/contract-ts/src/contract.ts and packages/2-sql/1-core/contract/src/validators.ts, so authoring-side and core validation can drift independently on the next rule change. Please export the TypeScript validator from the shared contract package and consume it here instead of keeping a second copy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts` around lines 78 - 85,
Replace the duplicated regex validator by importing the shared generator-id
validator from the common contract validators and use it in place of the local
GeneratorIdSchema; specifically, remove the local GeneratorIdSchema declaration,
add an import for the shared generator-id validator (the exported symbol from
the shared validators package) at the top of this file, and update
ExecutionMutationDefaultValueSchema to reference that imported validator instead
of the inline regex; ensure the import name matches the exported symbol from the
shared package and run types/tsc to confirm no type breaks.
packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts (1)

1-863: Consider splitting this test file.

At 863 lines, this file exceeds the 500-line guideline. The tests naturally group into distinct concerns that could be split:

  • Basic PSL-to-IR mapping (models, types, mappings)
  • Relation handling
  • Default function lowering
  • Extension/namespace handling
  • Diagnostics/error cases

This would improve navigability and align with the test file size guideline.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts` around
lines 1 - 863, The test file is too long (863 lines) and should be split into
smaller, focused test files grouped by concern; create multiple files (e.g.,
basic-mapping.test.ts, relations.test.ts, defaults.test.ts, extensions.test.ts,
diagnostics.test.ts) and move the corresponding it blocks into them by locating
tests under the top-level describe('interpretPslDocumentToSqlContractIR') and
using helpers like interpretPslDocumentToSqlContractIR (the wrapper),
interpretPslDocumentToSqlContractIRInternal,
createBuiltinLikeControlMutationDefaults, postgresScalarTypeDescriptors, and
postgresTarget to maintain shared setup; extract any shared fixtures/imports
into a small test-utils or fixtures module and update imports in each new test
file so assertions and helper usage remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/2-sql/3-tooling/family/src/core/assembly.ts`:
- Around line 234-320: Materialize each descriptor's controlMutationDefaults()
once and reuse it: in assembleControlMutationDefaultContributions, first loop
descriptors and call descriptor.controlMutationDefaults?.(), storing results
(e.g., an array of {descriptor, contributions} or a Map from descriptor.id to
contributions) and skip nulls; then use that cached collection both to build the
generator descriptors (rather than calling
createControlMutationDefaultGeneratorDescriptorMap(descriptors) which triggers a
second evaluation) and to register defaultFunctionRegistry entries. Either
change createControlMutationDefaultGeneratorDescriptorMap to accept the cached
contributions collection or call its logic inline using the cached
contributions; reference controlMutationDefaults,
assembleControlMutationDefaultContributions, and
createControlMutationDefaultGeneratorDescriptorMap. Also add a regression test
that asserts controlMutationDefaults() is invoked exactly once per descriptor.

---

Nitpick comments:
In `@packages/2-sql/1-core/contract/test/validate.test.ts`:
- Around line 65-107: Move the two test cases that exercise execution default
generator ids out of the large validate.test.ts into a new focused test file
(e.g. validate.execution-defaults.test.ts); copy the two it(...) blocks that
reference validateContract, SqlContract, and SqlStorage into that new file, keep
the same imports/setup used in the original (baseContract, validateContract,
types), and remove them from the original file so validate.test.ts stays under
the 500-line guideline and concerns remain separated.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts`:
- Around line 24-35: Replace the inline conditional spread in executionGenerator
with the shared helper: import ifDefined from '@prisma-next/utils/defined' and
change the generated object spread from ...(params ? { params } : {}) to
...ifDefined({ params }, params) so that executionGenerator uses ifDefined for
the optional params property.

In `@packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts`:
- Around line 1-863: The test file is too long (863 lines) and should be split
into smaller, focused test files grouped by concern; create multiple files
(e.g., basic-mapping.test.ts, relations.test.ts, defaults.test.ts,
extensions.test.ts, diagnostics.test.ts) and move the corresponding it blocks
into them by locating tests under the top-level
describe('interpretPslDocumentToSqlContractIR') and using helpers like
interpretPslDocumentToSqlContractIR (the wrapper),
interpretPslDocumentToSqlContractIRInternal,
createBuiltinLikeControlMutationDefaults, postgresScalarTypeDescriptors, and
postgresTarget to maintain shared setup; extract any shared fixtures/imports
into a small test-utils or fixtures module and update imports in each new test
file so assertions and helper usage remain unchanged.

In `@packages/2-sql/2-authoring/contract-ts/src/contract.ts`:
- Around line 78-85: Replace the duplicated regex validator by importing the
shared generator-id validator from the common contract validators and use it in
place of the local GeneratorIdSchema; specifically, remove the local
GeneratorIdSchema declaration, add an import for the shared generator-id
validator (the exported symbol from the shared validators package) at the top of
this file, and update ExecutionMutationDefaultValueSchema to reference that
imported validator instead of the inline regex; ensure the import name matches
the exported symbol from the shared package and run types/tsc to confirm no type
breaks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 68bde77d-7f42-4281-b1c7-583dda879f33

📥 Commits

Reviewing files that changed from the base of the PR and between f275c8a and 70d3b9e.

⛔ Files ignored due to path filters (17)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/psl-contract-authoring/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/Follow-up - Pack-provided mutation default functions registry-plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/references/authoring-surface-gap-inventory.md is excluded by !projects/**
  • projects/psl-contract-authoring/spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Follow-up - Pack-provided mutation default functions registry.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 1 - Pluggable contract sources.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 2 - PSL parser.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 3 - Fixture-driven parity harness.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 4 - Parameterized attributes and pgvector parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 5 - ID variants and default function parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 6 - Close-out.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 7 - PSL sql template literal syntax.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/code-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/system-design-review.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/reviews/walkthrough.md is excluded by !projects/**
📒 Files selected for processing (47)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/1-core/contract/test/validate.test.ts
  • packages/2-sql/2-authoring/contract-psl/README.md
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
  • test/integration/test/authoring/parity/default-pack-slugid/packs.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • test/integration/test/authoring/templates/prisma-next.config.parity-psl.ts
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • docs/architecture docs/ADR-INDEX.md
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/2-sql/5-runtime/src/exports/index.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts

Comment thread packages/2-sql/3-tooling/family/src/core/assembly.ts Outdated
Copy link
Copy Markdown

@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: 1

♻️ Duplicate comments (1)
packages/1-framework/2-authoring/ids/src/index.ts (1)

7-7: ⚠️ Potential issue | 🟡 Minor

Move builtinGeneratorIds to the package's real export surface.

Importing the symbol first and then re-exporting it from src/index.ts is still a cross-file re-export. Please expose it from the designated exports/ surface instead of forwarding it here.

As per coding guidelines: "Do not reexport things from one file in another, except in the exports/ folders."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/2-authoring/ids/src/index.ts` at line 7, The file is
re-exporting builtinGeneratorIds from src/index.ts which violates the rule
against cross-file re-exports; instead export builtinGeneratorIds from the
package's official export surface under exports/ (create or add to the
appropriate exports file in exports/ and export the symbol there, e.g. export {
builtinGeneratorIds } from './path/to/original/module'), remove the
re-export/import forwarding from src/index.ts, and update any internal import
sites if needed to import from the package's public export path rather than
src/index.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/1-framework/2-authoring/ids/src/index.ts`:
- Around line 22-34: The resolver resolveNanoidColumnDescriptor must not
silently coerce invalid sizes to 21; validate params?.['size'] and if it exists
but is not an integer between 2 and 255, throw a clear error (e.g., "nanoid size
must be an integer between 2 and 255") so generated.params cannot diverge from
the descriptor. If params.size is undefined, keep the default length 21;
otherwise use the validated value for typeParams.length and ensure
generated.params matches that validated size. Target
resolveNanoidColumnDescriptor, the generated.params handling, and
typeParams.length when implementing this change.

---

Duplicate comments:
In `@packages/1-framework/2-authoring/ids/src/index.ts`:
- Line 7: The file is re-exporting builtinGeneratorIds from src/index.ts which
violates the rule against cross-file re-exports; instead export
builtinGeneratorIds from the package's official export surface under exports/
(create or add to the appropriate exports file in exports/ and export the symbol
there, e.g. export { builtinGeneratorIds } from './path/to/original/module'),
remove the re-export/import forwarding from src/index.ts, and update any
internal import sites if needed to import from the package's public export path
rather than src/index.ts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 781d0de8-adb4-44cc-921b-a0e5acae8061

📥 Commits

Reviewing files that changed from the base of the PR and between 70d3b9e and e172608.

📒 Files selected for processing (5)
  • packages/1-framework/2-authoring/ids/src/generator-ids.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/test/ids.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-mutation-defaults.test.ts

Comment thread packages/1-framework/2-authoring/ids/src/index.ts
Comment thread packages/2-sql/5-runtime/src/sql-context.ts
@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from 8d3e462 to ad6722f Compare March 8, 2026 20:11
Comment thread packages/1-framework/2-authoring/ids/test/ids.test.ts
@jkomyno
Copy link
Copy Markdown
Contributor

jkomyno commented Mar 11, 2026

Code Review — PR #214: feat(sql): compose mutation defaults via registries

Branch: tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl
Stats: 68 files, +4,242 / -1,023 lines, 33 commits


Findings Summary

  • Total Findings: 12
  • 🔴 P1 (Critical): 1 — should fix before merge
  • 🟡 P2 (Important): 5 — should fix
  • 🔵 P3 (Nice-to-Have): 6 — enhancements

🔴 P1 — Critical

1. ControlMutationDefaultFunctionHandler returns unknown instead of a structured result type

  • File: packages/2-sql/3-tooling/family/src/core/migrations/types.ts:58-61
  • Why: The family-layer handler type returns unknown while the authoring-layer equivalent (DefaultFunctionLoweringHandler) returns LoweredDefaultResult. This erases type safety at the composition boundary — a handler returning 42 compiles fine. The current code works because satisfies on the Postgres adapter preserves narrow types, but this is fragile: anyone explicitly annotating the return type would silently lose type checking.
  • Fix: Define a structurally equivalent result discriminated union ({ ok: true; value: ... } | { ok: false; diagnostic: ... }) in the family layer, rather than erasing to unknown. This matches how ControlMutationDefaultSpan and ControlMutationDefaultFunctionCall already duplicate structure across layers.

🟡 P2 — Important

2. Assembly-layer errors are unstructured throw new Error(...) instead of structured envelopes

  • File: packages/2-sql/3-tooling/family/src/core/assembly.ts:251-253, 264-266, 296-299
  • Why: The runtime layer uses runtimeError() with stable codes and structured details ({ id, existingOwner, incomingOwner }). The assembly layer throws plain Error strings for the same duplicate-detection scenarios. This inconsistency makes agent consumption harder and breaks the structured-error convention.

3. Generator params passed without runtime schema validation

  • File: packages/2-sql/5-runtime/src/sql-context.ts:398
  • Why: spec.params (typed Record<string, unknown> | undefined) flows directly to generator.generate() without shape validation. Authoring-time validation exists but doesn't run at runtime. A hand-crafted contract.json with { size: "malicious" } would bypass validation. The codebase already has a paramsSchema pattern on RuntimeParameterizedCodecDescriptor — the same pattern should apply here.

4. Test fixture duplicates ~230 lines of production code

  • File: packages/2-sql/2-authoring/contract-psl/test/fixtures.ts (321 lines)
  • Why: createBuiltinLikeControlMutationDefaults() re-implements the entire Postgres adapter's lowering handlers line-for-line. This creates a maintenance trap: changes to production code must be mirrored manually. The composed-mutation-defaults.test.ts already demonstrates an inline-stub approach that avoids this. Most interpreter tests only need 2-3 handlers, not all 7.

5. Redundant runtime guards on required interface fields

  • File: packages/2-sql/2-authoring/contract-psl/src/interpreter.ts:1070-1093
  • Why: InterpretPslDocumentToSqlContractIRInput declares target and scalarTypeDescriptors as required. Yet the function checks if (!input.target) and emits diagnostics. The only test exercising this path uses as unknown as to bypass TypeScript. Either make the fields optional (if JS callers exist) or remove the guards and test.

6. Removed user-friendly suggestions for mistyped generator names

  • File: packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • Why: The old unknownFunctionSuggestionsByName provided targeted hints like "cuid2" → "Use cuid(2)". The registry approach dropped these. The usageSignatures list partially compensates but the direct "Did you mean?" guidance is gone. Consider an aliases or suggestions field on DefaultFunctionRegistryEntry.

🔵 P3 — Nice-to-Have

7. Type duplication between family and PSL layers (~65 lines)migrations/types.ts re-declares structurally identical types from the PSL layer. Architecturally justified by layering rules but could benefit from a compile-time compatibility assertion or shared types in sql/core.

8. CI workflow uses direct ${{ }} interpolation in shell run: block.github/workflows/pr-code-security.yml:33-34. base.sha is safe but the pattern is copy-paste-risky. Best practice: pass through env: variable.

9. No introspection API for composed registry state — Neither ExecutionContext nor any metadata object exposes what default functions/generators are registered. Agents must attempt interpretation and parse diagnostics to discover capabilities.

10. ksuid missing from test fixture generator descriptorstest/fixtures.ts includes 5 of 6 builtin generators. Not breaking but diverges from production.

11. new Map<string, never>() as empty registry defaultinterpreter.ts:1099. Using never is technically correct but non-obvious. new Map<string, DefaultFunctionRegistryEntry>() would be clearer.

12. Git history cleanup recommended — 33 commits is high. 3 review-artifact commits net to zero, fix chains should be squashed, ADR 170 and test timeout housekeeping could be separate PRs. Suggest squashing to ~10-15 focused commits before merge.


Performance

No regressions. All registry lookups are O(1) Map.get. The linear scan of execution.mutations.defaults in applyMutationDefaults is negligible at current schema sizes and trivially optimizable via pre-indexing if needed later.

Security

No critical vulnerabilities. GeneratedValueSpec.id widening is guarded by regex validation. All registries use Map (prototype-pollution safe). Duplicate detection prevents malicious override. dbgenerated() raw SQL pass-through is an accepted risk under the developer-trust model.

Architecture

Fully compliant with domain/layer/plane rules. Zero import violations. Clean separation of control-time and runtime seams. Correctly follows existing composition patterns. The GeneratedValueSpec.id widening to string is the right architectural call.

Agent-Native

6/7 capabilities agent-accessible. All composition is programmatic. Contract artifacts are machine-readable. Main gap: no registry introspection API.


Recommended Next Steps

  1. Address P1 (handler return type) — only blocking item
  2. Triage P2 findings — especially structured errors (Package layering #2), params validation (Decouple extensions #3), fixture duplication (Add PGVector extension #4)
  3. Consider squashing commits before merge

Review performed by 8 parallel agents: architecture-strategist, security-sentinel, performance-oracle, pattern-recognition-specialist, code-simplicity-reviewer, kieran-typescript-reviewer, agent-native-reviewer, git-history-analyzer

@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from ad6722f to c5dbc99 Compare March 11, 2026 16:08
Copy link
Copy Markdown

@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: 10

🧹 Nitpick comments (6)
packages/3-targets/6-adapters/postgres/src/exports/runtime.ts (1)

48-56: Consider extracting shared generator factory.

This function contains no Postgres-specific logic—it maps all builtinGeneratorIds identically. If other adapters (e.g., MySQL) need the same generators, consider extracting this to a shared utility (e.g., in @prisma-next/ids/runtime) to avoid duplication across adapter packages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-targets/6-adapters/postgres/src/exports/runtime.ts` around lines
48 - 56, The createPostgresMutationDefaultGenerators function duplicates a
generic mapping of builtinGeneratorIds to generator objects (using generateId)
with no Postgres-specific logic; extract this shared factory into a reusable
utility (e.g., a function named createBuiltinMutationDefaultGenerators) in a
common runtime module (such as an ids/runtime shared package) and replace
createPostgresMutationDefaultGenerators to call that shared function, keeping
references to builtinGeneratorIds and generateId so other adapters (MySQL, etc.)
can import and reuse the same generator factory.
packages/2-sql/5-runtime/src/sql-context.ts (1)

386-398: Consider adding runtime schema validation for generator params.

The spec.params are passed directly to generator.generate() without runtime validation. While authoring-time validation exists in PSL lowering, a malformed contract (or future changes) could pass invalid params to generators at runtime.

If generators define a paramsSchema, validating spec.params here would provide defense-in-depth and clearer error messages when params are invalid.

♻️ Sketch of optional validation
 case 'generator': {
   const generator = generatorRegistry.get(spec.id);
   if (!generator) {
     throw runtimeError(
       'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
       `Contract references mutation default generator '${spec.id}' but no runtime component provides it.`,
       { id: spec.id },
     );
   }
+  // If generator declares a paramsSchema, validate params
+  if (generator.paramsSchema && spec.params) {
+    const result = generator.paramsSchema(spec.params);
+    if (result instanceof arktype.errors) {
+      throw runtimeError(
+        'RUNTIME.MUTATION_DEFAULT_PARAMS_INVALID',
+        `Invalid params for mutation default generator '${spec.id}'.`,
+        { id: spec.id, params: spec.params },
+      );
+    }
+  }
   // nosemgrep: javascript.express.security.express-wkhtml-injection.express-wkhtmltoimage-injection
   return generator.generate(spec.params);
 }

This would require extending RuntimeMutationDefaultGenerator to optionally include paramsSchema. Consider deferring if authoring-time validation is deemed sufficient.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/5-runtime/src/sql-context.ts` around lines 386 - 398, The code
calls generator.generate(spec.params) from the generatorRegistry without
validating spec.params; add runtime validation by extending
RuntimeMutationDefaultGenerator to optionally expose a paramsSchema and, before
calling generator.generate in the 'generator' case, validate spec.params against
that schema and throw a clear runtimeError (e.g.,
RUNTIME.MUTATION_DEFAULT_GENERATOR_INVALID_PARAMS) including the generator id
and validation errors if validation fails; keep the existing path to call
generator.generate(spec.params) only when params pass validation.
packages/2-sql/1-core/contract/test/validate.test.ts (1)

65-107: Move these execution-default cases into a split test file.

validate.test.ts is already well past the 500-line cap, and adding another concern here makes it harder to navigate. Please move these new cases into a focused file such as validate.execution-defaults.test.ts.

As per coding guidelines "Keep test files under 500 lines to maintain readability and navigability" and "Use descriptive file names with the pattern {base}.{category}.test.ts."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/test/validate.test.ts` around lines 65 - 107,
Extract the two "it" cases that reference execution defaults from
validate.test.ts into a new focused test file named
validate.execution-defaults.test.ts: copy the tests that construct contract
using baseContract and call validateContract<SqlContract<SqlStorage>> (the cases
titled "accepts custom execution default generator ids" and "rejects non-flat
execution default generator ids") into the new file, import the same helpers
(baseContract, validateContract, SqlContract, SqlStorage) at the top, remove the
original tests from validate.test.ts, keep the tests' code and assertions
unchanged, and run the test suite to ensure imports and types are correct.
packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts (1)

35-49: Use ifDefined() for these conditional spreads.

The inline ...(cond ? { ... } : {}) pattern appears in both object builders here. This repo standardizes on ifDefined() for conditional spreads, so it would be better to align these constructors with the rest of the package.

As per coding guidelines, {packages,examples,test}/**/*.{ts,tsx}: Use ifDefined() from @prisma-next/utils/defined for conditional object spreads instead of inline conditional spread patterns.

Also applies to: 316-325

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts`
around lines 35 - 49, Replace the inline conditional spread in
executionGenerator with the repo-standard ifDefined() helper: change the spread
...(params ? { params } : {}) to ...ifDefined(params, p => ({ params: p }))
after importing ifDefined from '@prisma-next/utils/defined'; also apply the same
replacement to the similar conditional spread used elsewhere in this file (the
other object-builder around the 316-325 region) so both constructors use
ifDefined() for conditional spreads.
packages/2-sql/2-authoring/contract-psl/test/fixtures.ts (1)

24-33: Use ifDefined() for the optional params field.

Inline conditional spreads diverge from the helper this repo uses for optional object properties.

♻️ Proposed cleanup
+import { ifDefined } from '@prisma-next/utils/defined';
+
 function executionGenerator(id: string, params?: Record<string, unknown>) {
   return {
     ok: true as const,
     value: {
       kind: 'execution' as const,
       generated: {
         kind: 'generator' as const,
         id,
-        ...(params ? { params } : {}),
+        ...ifDefined('params', params),
       },
     },
   };
 }

As per coding guidelines, "Use ifDefined() from @prisma-next/utils/defined for conditional object spreads instead of inline conditional spread patterns."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts` around lines 24 -
33, Replace the inline conditional spread for optional params in
executionGenerator with the repository helper: instead of using ...(params ? {
params } : {}), call the ifDefined helper from '@prisma-next/utils/defined' to
conditionally add the params property; update the generation object in
executionGenerator to use ifDefined('params', params) so the optional property
follows the project's standard pattern.
packages/2-sql/2-authoring/contract-psl/src/interpreter.ts (1)

1115-1116: Consider clearer empty registry typing.

new Map<string, never>() is functionally correct but semantically awkward. A more explicit empty map type could improve readability.

Suggested alternative
   const defaultFunctionRegistry =
-    input.controlMutationDefaults?.defaultFunctionRegistry ?? new Map<string, never>();
+    input.controlMutationDefaults?.defaultFunctionRegistry ?? 
+    (new Map() as ControlMutationDefaultRegistry);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/src/interpreter.ts` around lines 1115
- 1116, The defaultFunctionRegistry fallback uses new Map<string, never>() which
is semantically confusing; replace it with a clearer function-registry type such
as new Map<string, (...args: unknown[]) => unknown>() (or new Map<string,
Function>() / Map<string, unknown> depending on expected usage) so the intent is
explicit. Update the assignment for defaultFunctionRegistry (the expression
using input.controlMutationDefaults?.defaultFunctionRegistry) to use the clearer
Map type and adjust any surrounding type annotations if necessary.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pr-code-security.yml:
- Line 36: The semgrep invocation places the positional target "." after flags
and leaves $BASELINE_ARG unquoted; update the semgrep command (the line invoking
"semgrep scan --severity ERROR --error --sarif --config auto --exclude-rule ...
--output=semgrep-results.sarif $BASELINE_ARG") so the positional argument "."
comes immediately after "semgrep scan" and before any flags, and quote
"$BASELINE_ARG" to prevent word-splitting/empty-value issues (e.g., place "."
first and change $BASELINE_ARG to "$BASELINE_ARG").
- Around line 31-36: Avoid interpolating ${{ github.event.pull_request.base.sha
}} directly in the run shell; instead expose it via an env var and reference
that safe variable in the script. Set an environment variable (e.g.,
BASELINE_COMMIT) from ${{ github.event.pull_request.base.sha }} and in the run
block test it with [ -n "$BASELINE_COMMIT" ] to populate BASELINE_ARG, then pass
$BASELINE_ARG to the semgrep invocation (the variables to edit are BASELINE_ARG
and the semgrep command lines shown in the diff).

In `@examples/prisma-next-demo/prisma-next.config.ts`:
- Around line 22-31: The prismaContract call includes a redundant
composedExtensionPacks option which duplicates the top-level extensionPacks and
causes providers to merge without deduping (e.g., appending pgvector twice);
remove the composedExtensionPacks: extensionPacks.map((pack) => pack.id) entry
from the prismaContract(...) options so the contract relies on the
loader-provided composedExtensionPacks in the sourceContext and avoid duplicate
extension pack entries.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`:
- Around line 59-65: The ControlMutationDefaultEntry.lower method currently
returns unknown which forces an unsafe cast to LoweredDefaultResult downstream;
change the signature of ControlMutationDefaultEntry.lower to return
LoweredDefaultResult (the discriminated union) instead of unknown, update all
implementations of lower to construct and return the correct discriminated
objects, and remove the unsafe cast at the callsite that treats the result as
LoweredDefaultResult (the code using the cast should accept the typed return
directly). Ensure usages of ParsedDefaultFunctionCall and
DefaultFunctionLoweringContext within lower still match the contract and that
any callers (e.g., the place performing the former "as LoweredDefaultResult"
cast) rely on the new typed return.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts`:
- Around line 91-321: The fixture duplicates the full builtin lowering registry
and generator descriptors in createBuiltinLikeControlMutationDefaults(); replace
the inlined defaultFunctionRegistry and generatorDescriptors with the real
production contribution (or, if tests only need limited behavior, replace them
with minimal stub maps that expose only the functions/descriptors used by these
tests). Locate createBuiltinLikeControlMutationDefaults and swap the hardcoded
Map and array for a reference to the assembled production contribution (or
construct tiny stub entries for functions like 'uuid','cuid','nanoid', and
generators 'uuidv4','nanoid', etc.) so tests no longer mirror the production
implementation.

In `@packages/2-sql/3-tooling/family/src/core/assembly.ts`:
- Around line 248-268: Replace the bare Error throws in the duplicate checks
with the repo’s structured error envelope (do not throw raw Error): when
detecting duplicates for generatorDescriptor.id and for functionName (in the
blocks using generatorOwners, generatorMap, defaultFunctionRegistry,
functionOwners and descriptor.id) construct and throw a structured/typed error
(e.g., DuplicateContributionError or createErrorEnvelope) that includes a stable
code (like "DUPLICATE_GENERATOR" / "DUPLICATE_FUNCTION"), the conflicting keys
(generatorDescriptor.id or functionName) and both descriptor ids (descriptor.id
and owner) in the error details; make the same change for the scalar-descriptor
duplicate branch noted at lines 290-298 so callers can programmatically inspect
code and details instead of parsing a message.

In `@packages/2-sql/3-tooling/family/src/core/migrations/types.ts`:
- Around line 58-61: The handler return type currently uses unknown; define a
local discriminated union (e.g. ControlMutationDefaultFunctionResult) that
models the valid lowering outcomes and use that instead of unknown for
ControlMutationDefaultFunctionHandler; update the type declaration to return
ControlMutationDefaultFunctionResult and ensure the union's discriminant and
payload fields match the lowering result shape expected by the interpreter and
consumers (use the existing symbols ControlMutationDefaultFunctionCall and
ControlMutationDefaultLoweringContext to locate the handler signature and
replace the unknown return type).

In
`@packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts`:
- Around line 87-132: The lowerNow and lowerAutoincrement functions currently
ignore input.context and therefore allow invalid combinations like String
`@default`(now()) or String `@default`(autoincrement()); update both lowerers
(lowerNow and lowerAutoincrement) to validate the target field's
codec/native-type via input.context (e.g., check context.field or
context.applicableCodecIds) and return a failure LoweredDefaultResult with an
applicability diagnostic when the codec/type is incompatible, or alternatively
remove these from direct lowering and instead register them via
createPostgresMutationDefaultGeneratorDescriptors with appropriate
applicableCodecIds so the registry enforces compatibility.
- Around line 2-14: This file in src/core imports control-plane types and
lowering handlers (ControlMutationDefaultFunctionEntry,
ControlMutationDefaultGeneratorDescriptor, PslScalarTypeDescriptor,
builtinGeneratorRegistryMetadata, resolveBuiltinGeneratedColumnDescriptor,
DefaultFunctionLoweringContext, DefaultFunctionLoweringHandler) which makes core
depend on control APIs—move all lowering/descriptor factory logic that
references those symbols out of src/core into a control-plane module (e.g.,
create src/exports/control.ts or a new src/control/* file), reimplement the
factories and DefaultFunctionLoweringHandler implementations there, update any
package exports to expose them from the new control module, and leave only
genuinely shared types/helpers in src/core that do not import
`@prisma-next/family-sql/control` or `@prisma-next/sql-contract-psl`; also update
any import sites to import the factories/handlers from the new control module
rather than src/core.
- Around line 79-85: parseStringLiteral currently trims outer quotes but doesn't
decode Postgres-style escapes, so dbgenerated() defaults that contain escaped
quotes/newlines are emitted with backslashes; replace the ad-hoc reparse with
the parser-provided decoded string or implement proper PSL unescaping: update
parseStringLiteral to accept and return the parser's parsed string value (use
the token/value produced by the SQL parser instead of raw source) or if only raw
text is available, unescape per PostgreSQL string-literal rules (handling E''
escapes, backslash escapes, doubled quotes, and standard_conforming_strings) and
return the fully decoded string; apply the same fix where parseStringLiteral is
used (including the other occurrence referenced around parseStringLiteral lines
252-273).

---

Nitpick comments:
In `@packages/2-sql/1-core/contract/test/validate.test.ts`:
- Around line 65-107: Extract the two "it" cases that reference execution
defaults from validate.test.ts into a new focused test file named
validate.execution-defaults.test.ts: copy the tests that construct contract
using baseContract and call validateContract<SqlContract<SqlStorage>> (the cases
titled "accepts custom execution default generator ids" and "rejects non-flat
execution default generator ids") into the new file, import the same helpers
(baseContract, validateContract, SqlContract, SqlStorage) at the top, remove the
original tests from validate.test.ts, keep the tests' code and assertions
unchanged, and run the test suite to ensure imports and types are correct.

In `@packages/2-sql/2-authoring/contract-psl/src/interpreter.ts`:
- Around line 1115-1116: The defaultFunctionRegistry fallback uses new
Map<string, never>() which is semantically confusing; replace it with a clearer
function-registry type such as new Map<string, (...args: unknown[]) =>
unknown>() (or new Map<string, Function>() / Map<string, unknown> depending on
expected usage) so the intent is explicit. Update the assignment for
defaultFunctionRegistry (the expression using
input.controlMutationDefaults?.defaultFunctionRegistry) to use the clearer Map
type and adjust any surrounding type annotations if necessary.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts`:
- Around line 24-33: Replace the inline conditional spread for optional params
in executionGenerator with the repository helper: instead of using ...(params ?
{ params } : {}), call the ifDefined helper from '@prisma-next/utils/defined' to
conditionally add the params property; update the generation object in
executionGenerator to use ifDefined('params', params) so the optional property
follows the project's standard pattern.

In `@packages/2-sql/5-runtime/src/sql-context.ts`:
- Around line 386-398: The code calls generator.generate(spec.params) from the
generatorRegistry without validating spec.params; add runtime validation by
extending RuntimeMutationDefaultGenerator to optionally expose a paramsSchema
and, before calling generator.generate in the 'generator' case, validate
spec.params against that schema and throw a clear runtimeError (e.g.,
RUNTIME.MUTATION_DEFAULT_GENERATOR_INVALID_PARAMS) including the generator id
and validation errors if validation fails; keep the existing path to call
generator.generate(spec.params) only when params pass validation.

In
`@packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts`:
- Around line 35-49: Replace the inline conditional spread in executionGenerator
with the repo-standard ifDefined() helper: change the spread ...(params ? {
params } : {}) to ...ifDefined(params, p => ({ params: p })) after importing
ifDefined from '@prisma-next/utils/defined'; also apply the same replacement to
the similar conditional spread used elsewhere in this file (the other
object-builder around the 316-325 region) so both constructors use ifDefined()
for conditional spreads.

In `@packages/3-targets/6-adapters/postgres/src/exports/runtime.ts`:
- Around line 48-56: The createPostgresMutationDefaultGenerators function
duplicates a generic mapping of builtinGeneratorIds to generator objects (using
generateId) with no Postgres-specific logic; extract this shared factory into a
reusable utility (e.g., a function named createBuiltinMutationDefaultGenerators)
in a common runtime module (such as an ids/runtime shared package) and replace
createPostgresMutationDefaultGenerators to call that shared function, keeping
references to builtinGeneratorIds and generateId so other adapters (MySQL, etc.)
can import and reuse the same generator factory.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 6adc8522-9c55-4891-a92c-00d089b52d73

📥 Commits

Reviewing files that changed from the base of the PR and between e172608 and c5dbc99.

📒 Files selected for processing (46)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • .github/workflows/pr-code-security.yml
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • docs/architecture docs/adrs/ADR 170 - Pack-provided type constructors and field presets.md
  • examples/prisma-next-demo/prisma-next.config.ts
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/1-framework/2-authoring/ids/src/generator-ids.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/1-framework/2-authoring/ids/test/ids.test.ts
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/1-core/contract/test/validate.test.ts
  • packages/2-sql/2-authoring/contract-psl/README.md
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
🚧 Files skipped from review as they are similar to previous changes (21)
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/1-framework/2-authoring/ids/test/ids.test.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/1-framework/2-authoring/ids/src/generator-ids.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts

Comment thread .github/workflows/pr-code-security.yml
Comment thread .github/workflows/pr-code-security.yml
Comment thread examples/prisma-next-demo/prisma-next.config.ts
Comment thread packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
Comment thread packages/2-sql/3-tooling/family/src/core/assembly.ts
Comment thread packages/2-sql/3-tooling/family/src/core/migrations/types.ts Outdated
Comment thread packages/2-sql/5-runtime/src/sql-context.ts
Comment thread packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
Comment thread packages/2-sql/5-runtime/test/mutation-default-generators.test.ts Outdated
@SevInf
Copy link
Copy Markdown
Contributor

SevInf commented Mar 12, 2026

More fundamental design question to this: suppose I am working on extension that adds citext codec. Theoretically, citext columns can have a default generated by any of the existing generators that output strings. What's my path to achieving this?

I see 2 possible answers:

  • Bug generator authors to add my codec id into their applicableCodecIds
  • Provide my own generators that would be identical to existing ones, but would include my codec

@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented Mar 16, 2026

@SevInf my idea was that either package can provide the linkage from generator to column type:

  • given that the generator function is already provided (by another package), and your package provides a new column type, it can register the linkage between the generator function and its new column type
  • given that the column type is already provided (by another package), and your package provides a new generator function, it can register the linkage between the column type and its new generator function

wmadden added a commit that referenced this pull request Mar 20, 2026
test(sql-runtime): add test for user-provided values overriding generated defaults

Verifies that applyMutationDefaults skips the generator when the user
explicitly provides a value for a column that has a generated default.

PR #214 review thread (SevInf)
EOF
)
wmadden added a commit that referenced this pull request Mar 20, 2026
test(sql-runtime): clarify test title for duplicate generator error case

Rename from "includes both owners when duplicate generator ids are
composed" to "throws error naming both owners when duplicate generator
ids are composed" so the title reflects this is an error-path test.

PR #214 review thread (SevInf)
EOF
)
Copy link
Copy Markdown

@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 (6)
docs/architecture docs/subsystems/7. Migration System.md (2)

343-343: Rephrase capability wording as requirements, not declarations.

“capability declarations” reads like contract-defined capability ownership. Prefer “capability requirements” to align with adapter-reported/negotiated semantics.

As per coding guidelines: “Frame contract capabilities as requirements, not definitions” and “Avoid wording that implies the contract owns or defines capabilities.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture` docs/subsystems/7. Migration System.md at line 343, Update
the wording to frame capabilities as requirements rather than declarations:
change the sentence to say that when a contract change only affects capability
requirements (no schema changes), the runner verifies the environment satisfies
the new requirements and updates the `profile_hash` in the marker without
applying any DDL, while the `core_hash` stays the same; ensure you replace
"capability declarations" with "capability requirements" wherever this sentence
appears so it aligns with adapter-reported/negotiated semantics and the
project's phrasing guidelines.

363-370: Unify error-code format with the documented convention.

Line 363 defines a stable category/code format, but Lines 369-370 use MIGRATION.*. Please either normalize those codes to the documented shape or adjust the convention text to match actual emitted formats.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture` docs/subsystems/7. Migration System.md around lines 363 -
370, The documented convention states errors must use a stable category/code
shape but the table mixes formats; update the two migration-style codes to
follow category/code (e.g., replace "MIGRATION.AMBIGUOUS_LEAF" and
"MIGRATION.NO_RESOLVABLE_LEAF" with "migration/ambiguous-leaf" and
"migration/no-resolvable-leaf") or alternatively change the convention line to
include the dot-separated form—make the change consistently in the table and any
references to the symbols "MIGRATION.AMBIGUOUS_LEAF" and
"MIGRATION.NO_RESOLVABLE_LEAF" so they match the chosen convention.
packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts (1)

37-42: Type duplication between DefaultFunctionRegistryEntry and ControlMutationDefaultEntry.

These two interfaces have identical shapes — both define lower: DefaultFunctionLoweringHandler (or equivalent signature) and usageSignatures?: readonly string[]. This was noted as a P3 finding in the PR review comments. Consider either:

  1. Using DefaultFunctionRegistryEntry directly for ControlMutationDefaultRegistry, or
  2. Having ControlMutationDefaultEntry extend DefaultFunctionRegistryEntry
♻️ Suggested consolidation
-export interface ControlMutationDefaultEntry {
-  readonly lower: (input: {
-    readonly call: ParsedDefaultFunctionCall;
-    readonly context: DefaultFunctionLoweringContext;
-  }) => LoweredDefaultResult;
-  readonly usageSignatures?: readonly string[];
-}
-
-export type ControlMutationDefaultRegistry = ReadonlyMap<string, ControlMutationDefaultEntry>;
+export type ControlMutationDefaultRegistry = DefaultFunctionRegistry;

Also applies to: 59-67

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`
around lines 37 - 42, The interfaces DefaultFunctionRegistryEntry and
ControlMutationDefaultEntry are identical; remove the duplication by making
ControlMutationDefaultEntry reuse DefaultFunctionRegistryEntry (either replace
ControlMutationDefaultEntry with DefaultFunctionRegistryEntry in
ControlMutationDefaultRegistry or declare ControlMutationDefaultEntry extends
DefaultFunctionRegistryEntry), then update the ControlMutationDefaultRegistry
type to ReadonlyMap<string, DefaultFunctionRegistryEntry> (or the extended name)
and adjust any references to
ControlMutationDefaultEntry/ControlMutationDefaultRegistry accordingly; ensure
DefaultFunctionLoweringHandler and usageSignatures remain unchanged.
.github/workflows/record-cli.yml (1)

74-84: Consider pinning the PR action to a commit hash for consistency.

Other actions in this workflow use commit hashes (e.g., actions/checkout@8e8c483...), but peter-evans/create-pull-request uses a version tag @v7. For supply-chain security consistency, consider pinning to a specific commit hash.

Example with commit hash
       - name: Create pull request
-        uses: peter-evans/create-pull-request@v7
+        uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88bde2c9da4d # v7.0.5

You can find the latest commit hash for v7 at https://github.com/peter-evans/create-pull-request/releases

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/record-cli.yml around lines 74 - 84, Replace the floating
tag for the create-pull-request action with a pinned commit hash to match other
actions' supply-chain pinning; locate the line using "uses:
peter-evans/create-pull-request@v7" and update it to "uses:
peter-evans/create-pull-request@<commit-hash>" (fetch the appropriate v7 commit
SHA from the action's GitHub releases page), commit the workflow change, and
ensure the rest of the block (commit-message, title, body, branch,
delete-branch) remains unchanged.
packages/1-framework/3-tooling/cli/scripts/record.ts (1)

54-54: Consider using pathe instead of node:path.

Per repository conventions, pathe is preferred over node:path for path operations in TypeScript files. This provides consistent behavior across platforms and works in non-Node runtimes.

Based on learnings: "In the Prisma-next repository, prefer importing and using 'pathe' over the built-in 'node:path' module for path operations across the codebase (including CLI commands and tooling files)."

Suggested change
-import { dirname, join, relative, resolve } from 'node:path';
+import { dirname, join, relative, resolve } from 'pathe';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/3-tooling/cli/scripts/record.ts` at line 54, Replace the
import of path utilities from 'node:path' with equivalent named imports from
'pathe' (remove "import { dirname, join, relative, resolve } from 'node:path'")
and update any uses of dirname, join, relative, and resolve in this file to rely
on those 'pathe' exports (ensure tree-shaken named imports are used). This keeps
behavior consistent with repository conventions and non-Node runtimes while
preserving the existing symbol names (dirname, join, relative, resolve) used
elsewhere in record.ts.
packages/1-framework/3-tooling/cli/src/commands/db-verify.ts (1)

303-305: Remove the Result<never, CliStructuredError> cast in this branch.

After CliStructuredError.is(result.failure), you already have the exact failure value. Rebuilding the error result with notOk(result.failure) keeps this branch type-safe and avoids an unchecked cast.

♻️ Suggested change
-      if (CliStructuredError.is(result.failure)) {
-        const exitCode = handleResult(result as Result<never, CliStructuredError>, flags, ui);
+      if (CliStructuredError.is(result.failure)) {
+        const exitCode = handleResult(notOk(result.failure), flags, ui);
         process.exit(exitCode);
       }
As per coding guidelines "Avoid blind casts like `as unknown as X` in production TypeScript code. Use type predicates (`value is X`) or type guards instead to let the compiler narrow types safely."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/1-framework/3-tooling/cli/src/commands/db-verify.ts` around lines
303 - 305, The branch uses an unsafe cast when calling handleResult; instead of
casting to Result<never, CliStructuredError>, construct a proper error Result
with notOk(result.failure) so the compiler can narrow types via the
CliStructuredError.is() predicate; update the call to handleResult to pass
notOk(result.failure) (keeping flags and ui) rather than using the Result<never,
CliStructuredError> cast.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/architecture` docs/subsystems/7. Migration System.md:
- Around line 241-250: Add a language tag to the fenced code block that shows
the migration directory tree so markdown linters won't raise MD040; locate the
triple-backtick fence immediately before the "migrations/" block in the
Migration System document and change it to include a language tag (for example,
```text) and ensure the closing triple-backticks remain unchanged.

In `@packages/1-framework/3-tooling/cli/CLI_RECORDING.md`:
- Around line 44-58: Update the unlabeled fenced code blocks in CLI_RECORDING.md
so markdownlint stops flagging them: change the triple-backtick fences around
the diagram (the block starting at the top shown in the diff and the second
block around lines 107-123) to include a language tag such as text or plaintext
(e.g., ```text) rather than being unlabeled; ensure both fenced blocks are
consistently updated to the chosen label so the document remains lint-clean.

In `@packages/1-framework/3-tooling/cli/src/commands/db-verify.ts`:
- Around line 212-216: The schema structural check is being run without the
resolved dbConnection, causing mismatches; update the call to
client.schemaVerify to forward the selected dbConnection (the same one resolved
into dbConnection and passed to client.verify) so that schemaVerify({
contractIR: contractJson, strict: false, onProgress }) becomes schemaVerify({
contractIR: contractJson, strict: false, onProgress, dbConnection }) (or the
appropriate parameter name expected by client.schemaVerify) so both
client.verify and client.schemaVerify use the same connection context.

---

Nitpick comments:
In @.github/workflows/record-cli.yml:
- Around line 74-84: Replace the floating tag for the create-pull-request action
with a pinned commit hash to match other actions' supply-chain pinning; locate
the line using "uses: peter-evans/create-pull-request@v7" and update it to
"uses: peter-evans/create-pull-request@<commit-hash>" (fetch the appropriate v7
commit SHA from the action's GitHub releases page), commit the workflow change,
and ensure the rest of the block (commit-message, title, body, branch,
delete-branch) remains unchanged.

In `@docs/architecture` docs/subsystems/7. Migration System.md:
- Line 343: Update the wording to frame capabilities as requirements rather than
declarations: change the sentence to say that when a contract change only
affects capability requirements (no schema changes), the runner verifies the
environment satisfies the new requirements and updates the `profile_hash` in the
marker without applying any DDL, while the `core_hash` stays the same; ensure
you replace "capability declarations" with "capability requirements" wherever
this sentence appears so it aligns with adapter-reported/negotiated semantics
and the project's phrasing guidelines.
- Around line 363-370: The documented convention states errors must use a stable
category/code shape but the table mixes formats; update the two migration-style
codes to follow category/code (e.g., replace "MIGRATION.AMBIGUOUS_LEAF" and
"MIGRATION.NO_RESOLVABLE_LEAF" with "migration/ambiguous-leaf" and
"migration/no-resolvable-leaf") or alternatively change the convention line to
include the dot-separated form—make the change consistently in the table and any
references to the symbols "MIGRATION.AMBIGUOUS_LEAF" and
"MIGRATION.NO_RESOLVABLE_LEAF" so they match the chosen convention.

In `@packages/1-framework/3-tooling/cli/scripts/record.ts`:
- Line 54: Replace the import of path utilities from 'node:path' with equivalent
named imports from 'pathe' (remove "import { dirname, join, relative, resolve }
from 'node:path'") and update any uses of dirname, join, relative, and resolve
in this file to rely on those 'pathe' exports (ensure tree-shaken named imports
are used). This keeps behavior consistent with repository conventions and
non-Node runtimes while preserving the existing symbol names (dirname, join,
relative, resolve) used elsewhere in record.ts.

In `@packages/1-framework/3-tooling/cli/src/commands/db-verify.ts`:
- Around line 303-305: The branch uses an unsafe cast when calling handleResult;
instead of casting to Result<never, CliStructuredError>, construct a proper
error Result with notOk(result.failure) so the compiler can narrow types via the
CliStructuredError.is() predicate; update the call to handleResult to pass
notOk(result.failure) (keeping flags and ui) rather than using the Result<never,
CliStructuredError> cast.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`:
- Around line 37-42: The interfaces DefaultFunctionRegistryEntry and
ControlMutationDefaultEntry are identical; remove the duplication by making
ControlMutationDefaultEntry reuse DefaultFunctionRegistryEntry (either replace
ControlMutationDefaultEntry with DefaultFunctionRegistryEntry in
ControlMutationDefaultRegistry or declare ControlMutationDefaultEntry extends
DefaultFunctionRegistryEntry), then update the ControlMutationDefaultRegistry
type to ReadonlyMap<string, DefaultFunctionRegistryEntry> (or the extended name)
and adjust any references to
ControlMutationDefaultEntry/ControlMutationDefaultRegistry accordingly; ensure
DefaultFunctionLoweringHandler and usageSignatures remain unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 3d7aa9c9-7f60-4da9-ad72-774cca936723

📥 Commits

Reviewing files that changed from the base of the PR and between c5dbc99 and 60e904e.

⛔ Files ignored due to path filters (39)
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-init/apply.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-init/dry-run.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-init/help.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-update/additive-dry-run.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-update/help.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/db-update/no-changes.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/direct-update/01-contract-emit-v2.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/direct-update/02-db-update-dry-run.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/direct-update/03-db-update-apply.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/direct-update/04-db-update-noop.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/direct-update/05-db-verify.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-missing-marker/01-db-verify-fail.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-missing-marker/02-db-schema-verify-fail.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-missing-marker/03-db-introspect-empty.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-missing-marker/04-db-init-recovery.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-missing-marker/05-db-verify-pass.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-phantom/01-db-verify-false-positive.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-phantom/02-db-schema-verify-fail.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-phantom/03-db-introspect-diverged.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-phantom/04-db-update-recovery.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-phantom/05-db-schema-verify-pass.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-stale-marker/01-db-verify-fail.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-stale-marker/02-db-schema-verify-fail.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-stale-marker/03-db-update-recovery.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/drift-stale-marker/04-db-verify-pass.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/01-contract-emit.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/02-db-init-dry-run.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/03-db-init.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/04-db-init-idempotent.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/05-db-verify.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/06-db-schema-verify.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/07-db-schema-verify-strict.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/08-db-introspect.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/09-db-verify-json.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/recordings/svgs/greenfield-setup/10-db-schema-verify-json.svg is excluded by !**/*.svg
  • packages/1-framework/3-tooling/cli/test/__snapshots__/help.snapshot.test.ts.snap is excluded by !**/*.snap
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/psl-contract-authoring/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/spec.md is excluded by !projects/**
📒 Files selected for processing (92)
  • .gitattributes
  • .github/workflows/record-cli.yml
  • docker-compose.yaml
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • docs/architecture docs/adrs/ADR 170 - Pack-provided type constructors and field presets.md
  • docs/architecture docs/adrs/ADR 171 - Parameterized native types in contracts.md
  • docs/architecture docs/subsystems/7. Migration System.md
  • package.json
  • packages/1-framework/1-core/migration/control-plane/src/errors.ts
  • packages/1-framework/1-core/migration/control-plane/src/exports/errors.ts
  • packages/1-framework/3-tooling/cli/CLI_RECORDING.md
  • packages/1-framework/3-tooling/cli/README.md
  • packages/1-framework/3-tooling/cli/package.json
  • packages/1-framework/3-tooling/cli/recordings/.gitignore
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/apply.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/help.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/additive-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/help.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/no-changes.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/01-contract-emit-v2.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/02-db-update-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/03-db-update-apply.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/04-db-update-noop.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/05-db-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/01-db-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/02-db-schema-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/03-db-introspect-empty.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/04-db-init-recovery.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/05-db-verify-pass.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/01-db-verify-false-positive.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/02-db-schema-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/03-db-introspect-diverged.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/04-db-update-recovery.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/05-db-schema-verify-pass.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/01-db-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/02-db-schema-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/03-db-update-recovery.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/04-db-verify-pass.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/01-contract-emit.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/02-db-init-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/03-db-init.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/04-db-init-idempotent.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/05-db-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/06-db-schema-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/07-db-schema-verify-strict.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/08-db-introspect.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/09-db-verify-json.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/10-db-schema-verify-json.ascii
  • packages/1-framework/3-tooling/cli/recordings/config.ts
  • packages/1-framework/3-tooling/cli/recordings/fixtures/contract-additive.ts
  • packages/1-framework/3-tooling/cli/recordings/fixtures/contract-base.ts
  • packages/1-framework/3-tooling/cli/recordings/fixtures/prisma-next.config.ts
  • packages/1-framework/3-tooling/cli/scripts/record.ts
  • packages/1-framework/3-tooling/cli/src/commands/db-verify.ts
  • packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/verify.ts
  • packages/1-framework/3-tooling/cli/src/utils/global-flags.ts
  • packages/1-framework/3-tooling/cli/test/setup.ts
  • packages/1-framework/3-tooling/cli/test/utils/test-helpers.ts
  • packages/1-framework/3-tooling/cli/vitest.config.ts
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • test/integration/.gitignore
  • test/integration/package.json
  • test/integration/test/cli-journeys/README.md
  • test/integration/test/cli-journeys/brownfield-adoption.e2e.test.ts
  • test/integration/test/cli-journeys/config-errors.e2e.test.ts
  • test/integration/test/cli-journeys/connection-and-contract-errors.e2e.test.ts
  • test/integration/test/cli-journeys/db-update-workflows.e2e.test.ts
  • test/integration/test/cli-journeys/drift-marker.e2e.test.ts
  • test/integration/test/cli-journeys/drift-migration-dag.e2e.test.ts
  • test/integration/test/cli-journeys/drift-schema.e2e.test.ts
  • test/integration/test/cli-journeys/greenfield-setup.e2e.test.ts
  • test/integration/test/cli-journeys/help-and-flags.e2e.test.ts
  • test/integration/test/cli-journeys/multi-step-migration.e2e.test.ts
  • test/integration/test/cli-journeys/schema-evolution-migrations.e2e.test.ts
  • test/integration/test/cli.db-verify.e2e.test.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract-add-table.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract-additive.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract-base.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract-destructive.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract-v3.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/contract.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma-next.config.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/cli-journeys/prisma-next.config.with-db.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/db-verify/contract.ts
  • test/integration/test/utils/journey-test-helpers.ts
  • test/integration/vitest.journeys.config.ts
  • turbo.json
✅ Files skipped from review due to trivial changes (48)
  • packages/1-framework/3-tooling/cli/package.json
  • docs/architecture docs/adrs/ADR 171 - Parameterized native types in contracts.md
  • .gitattributes
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/03-db-update-recovery.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/04-db-init-idempotent.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/01-db-verify-fail.ascii
  • packages/1-framework/1-core/migration/control-plane/src/exports/errors.ts
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/04-db-update-noop.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/01-contract-emit-v2.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/apply.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/02-db-schema-verify-fail.ascii
  • docker-compose.yaml
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/no-changes.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/05-db-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/06-db-schema-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/02-db-init-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/additive-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/05-db-verify.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/03-db-introspect-empty.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/03-db-init.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-update/help.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/04-db-verify-pass.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/db-init/help.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/03-db-update-apply.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/08-db-introspect.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/05-db-schema-verify-pass.ascii
  • package.json
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/01-db-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/direct-update/02-db-update-dry-run.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/02-db-schema-verify-fail.ascii
  • docs/architecture docs/ADR-INDEX.md
  • packages/1-framework/3-tooling/cli/recordings/fixtures/contract-base.ts
  • packages/1-framework/3-tooling/cli/recordings/fixtures/prisma-next.config.ts
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/03-db-introspect-diverged.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/09-db-verify-json.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/01-db-verify-false-positive.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/04-db-init-recovery.ascii
  • packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/07-db-schema-verify-strict.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-stale-marker/02-db-schema-verify-fail.ascii
  • packages/1-framework/3-tooling/cli/test/setup.ts
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/10-db-schema-verify-json.ascii
  • packages/1-framework/3-tooling/cli/recordings/config.ts
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-missing-marker/05-db-verify-pass.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/drift-phantom/04-db-update-recovery.ascii
  • packages/1-framework/3-tooling/cli/recordings/ascii/greenfield-setup/01-contract-emit.ascii
  • packages/1-framework/3-tooling/cli/recordings/.gitignore

Comment thread docs/architecture docs/subsystems/7. Migration System.md Outdated
Comment thread packages/1-framework/3-tooling/cli/CLI_RECORDING.md
Comment thread packages/1-framework/3-tooling/cli/src/commands/db-verify.ts
wmadden added a commit that referenced this pull request Mar 20, 2026
…ated defaults

Verifies that applyMutationDefaults skips the generator when the user
explicitly provides a value for a column that has a generated default.

PR #214 review thread (SevInf)
wmadden added a commit that referenced this pull request Mar 20, 2026
Rename from 'includes both owners when duplicate generator ids are
composed' to 'throws error naming both owners when duplicate generator
ids are composed' so the title reflects this is an error-path test.

PR #214 review thread (SevInf)
@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from 60e904e to f8f9355 Compare March 20, 2026 15:12
wmadden added 2 commits March 20, 2026 16:15
…gistry

Route @default(functionCall) lowering through an injected registry so function semantics stay out of the parser and interpreter core. This adds TS-parity mappings for uuid/ulid/nanoid/dbgenerated, preserves storage defaults/literals, and emits stable diagnostics for unknown functions versus invalid arguments.
…yping

Narrow generator ids to the contract union and update tests to use index-signature-safe assertions. This keeps Milestone 5 coverage intact while satisfying repo-wide strict typecheck settings.
wmadden added 23 commits March 20, 2026 16:15
Address review feedback by replacing blind ID generator casts with a type guard, removing the direct re-export pattern in ids index, narrowing the interpreter builder cast to a single cast, and documenting the intentional test-only escape.
Resolve review feedback by switching inline numeric timeout values to shared @prisma-next/test-utils timeout constants in the affected test suites.
Update SQL runtime architecture docs to include mutation default generators and remove an invalid postgres target dependency, with lockfile updates from pnpm install.
…tests

After rebase, the interpreter requires target and scalarTypeDescriptors
in all calls. Tests that only passed { document } now fail with
PSL_TARGET_CONTEXT_REQUIRED. Add baseInput with postgres fixtures and
pass baseOptions to provider helper calls missing the options argument.
Extract builtinGeneratorIds and BuiltinGeneratorId into generator-ids.ts
so that index.ts (the main entry point) no longer transitively imports
uniku. This prevents uniku side-effect imports from leaking into
downstream dist bundles (e.g. target-postgres/control.mjs) where uniku
is not a declared dependency.
Add error-path test for generateId with unknown generator id in ids
package. Add comprehensive unit tests for control-mutation-defaults.ts
in adapter-postgres covering all default function lowering handlers,
generator descriptors, and PSL scalar type descriptors.
- Remove unused builtinGeneratorIds import from generators.ts
- Import BuiltinGeneratorId from generator-ids.ts in runtime.ts (moved
  during previous refactor)
- Fix test stubs to match ControlMutationDefaultFunctionCall and
  ControlMutationDefaultLoweringContext type shapes (required raw, span,
  modelName, fieldName properties)
Record the thin-core/fat-interfaces boundary and add a follow-on spec to move ID generator implementations and privileged vocabularies out of low layers into composed components.
Semgrep flags generator.generate(...) with an Express/wkhtml SSRF rule.
Suppress the rule at the callsite.
Semgrep auto ruleset misclassifies generator.generate(...) as an Express wkhtml/phantom SSRF sink.
Exclude the specific rule from PR code scanning to avoid noisy false positives.
Inline the generator map logic into assembleControlMutationDefaultContributions
so each descriptor's controlMutationDefaults() is called exactly once, avoiding
snapshot drift between generator and function collection passes.

Add regression test asserting single evaluation per descriptor.
resolveNanoidColumnDescriptor now throws when size is present but
not an integer between 2 and 255, preventing generated.params from
diverging from the declared column descriptor.
Adds ADR 170 to define pack-provided type constructors and field presets.
Records dot namespacing, hard-error duplicates, and that presets may imply constraints.
Updates the ids follow-up spec to use composed column helpers aligned with this model.
Rephrases ADR 170 to be more accessible and intent-first while preserving the same decisions.
Updates ADR 170 to lead with concrete TS and PSL examples and clarifies
that common family or target helpers may be unnamespaced while extension
helpers stay namespaced.
…r rebase

Remove obsolete codecTypes/operationTypes from test contract mappings,
matching upstream changes to SqlMappings type.
… changes

After rebasing onto main, the provider source callback now receives a
ContractSourceContext parameter (providing composedExtensionPacks from
the CLI layer), target and scalarTypeDescriptors are required in
PrismaContractOptions, and pgvector nativeType no longer includes
params (just 'vector' with typeParams.length separate).

- Widen ControlMutationDefaults to accept control-layer handler types
  (unknown return) so assembly output is directly assignable
- Update demo config to use assemblePslInterpretationContributions
- Fix integration test to pass required prismaContract options
- Align pgvector test expectations with nativeType expansion hooks
…ies across ADRs

ADR 169: rewrite section 3 to separate surface-agnostic mutation default
descriptors from surface-specific argument resolution, with explicit naming
guidance against PSL-coupled terminology in shared types.

ADR 170: cross-reference ADR 169 (defaults) and new ADR 171 (typeParams).

Renumber parameterized native types ADR from 170 to 171 to resolve the
number collision with type constructors and field presets.
Add ADR 170 implementation as a follow-up milestone in the PSL contract
authoring project plan and spec. Type constructors (e.g. Uuid(7)) and
field presets (e.g. CreatedAt) bundle column type + mutation default +
constraints into a single pack-provided declaration.

Linear: TML-2093
…lt function handlers

ControlMutationDefaultFunctionHandler previously returned `unknown`,
losing type information at the assembly boundary and forcing an unsafe
`as LoweredDefaultResult` cast in the PSL interpreter.

Define ControlMutationDefaultFunctionResult as the precise discriminated
union in family-sql, update ControlMutationDefaultEntry.lower in
contract-psl to match, and remove the cast.
…ated defaults

Verifies that applyMutationDefaults skips the generator when the user
explicitly provides a value for a column that has a generated default.

PR #214 review thread (SevInf)
Rename from 'includes both owners when duplicate generator ids are
composed' to 'throws error naming both owners when duplicate generator
ids are composed' so the title reflects this is an error-path test.

PR #214 review thread (SevInf)
@wmadden wmadden force-pushed the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch from f8f9355 to cfb9fb4 Compare March 20, 2026 15:15
Copy link
Copy Markdown

@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: 6

🧹 Nitpick comments (4)
packages/2-sql/1-core/contract/test/validate.test.ts (1)

65-107: Split this spec before adding more scenarios.

This file is already well above the 500-line limit; please move these new execution-default cases into a focused split file (for example validate.execution-defaults.test.ts) to keep tests navigable.

As per coding guidelines, "Keep test files under 500 lines to maintain readability and navigability. If a test file exceeds this limit, it should be split into multiple files."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/test/validate.test.ts` around lines 65 - 107,
Move the two execution-default specs ("accepts custom execution default
generator ids" and "rejects non-flat execution default generator ids") out of
this large validate.test.ts into a new focused test file for execution-default
scenarios (e.g., validate.execution-defaults.test.ts); retain the same test
bodies and imports (keep references to validateContract, SqlContract,
SqlStorage, and baseContract) and update any test-suite describe blocks as
needed so the tests run standalone and the original file is kept under 500
lines.
packages/2-sql/1-core/contract/src/validators.ts (1)

24-26: Centralize generator-id validation to prevent cross-layer drift.

This regex/schema now exists in multiple places; consider exporting a shared GeneratorIdSchema (or at least a shared regex constant) so contract-ts and core validation can’t diverge over time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/1-core/contract/src/validators.ts` around lines 24 - 26, The
generator-id validation is duplicated across layers; extract and export a single
shared schema/constant (e.g., GeneratorIdSchema or GENERATOR_ID_REGEX) and
replace local occurrences of generatorIdSchema with an import of that shared
symbol so contract-ts and core validation remain consistent; update the current
generatorIdSchema definition to re-export the centralized validation (use the
same type('string').narrow(...) or a reusable regex constant) and adjust imports
in any modules that currently define their own regex.
packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts (1)

230-258: Add a closest-match hint to PSL_UNKNOWN_DEFAULT_FUNCTION.

The current fallback always dumps the full supported-signature list, which is noisy for simple typos. Since the registry already carries usageSignatures, this is a good place to prepend a nearest-match hint without changing the new composition model.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`
around lines 230 - 258, Update lowerDefaultFunctionWithRegistry to compute the
nearest registry key to input.call.name (using a simple string-distance /
fuzzy-match over registry.keys(), and prefer matching against usageSignatures
entries when available) and prepend a short "Did you mean 'X'?" hint to the
diagnostic message before the full Supported functions list; keep
formatSupportedFunctionList unchanged but you may reuse its output for the full
list while constructing the hint, and reference symbols:
lowerDefaultFunctionWithRegistry, formatSupportedFunctionList,
ControlMutationDefaultRegistry, entry.usageSignatures, and input.call.name.
packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts (1)

24-131: Move these new cases into the existing split interpreter suites.

The added context/default/diagnostic coverage pushes this file further into an all-in-one test suite even though the package already has more focused siblings for those concerns. Moving these blocks there will keep failures easier to localize and stop interpreter.test.ts from growing past the repo’s test-file-size boundary again.

As per coding guidelines, “Keep test files under 500 lines to maintain readability and navigability. If a test file exceeds this limit, it should be split into multiple files.”

Also applies to: 597-862

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts` around
lines 24 - 131, Move the three new "it" test cases into the more focused
interpreter suites that already handle context, defaults and diagnostics instead
of leaving them in the monolithic interpreter.test.ts: specifically relocate the
tests titled "returns diagnostics when target context is missing", "uses
composed scalar type descriptors without hardcoded fallback", and "does not
derive generated column type without descriptor resolver" into the existing
split suites that handle diagnostics, scalar descriptor composition, and
default/generator behavior; update those target files to import and use the same
helpers referenced here (parsePslDocument,
interpretPslDocumentToSqlContractIRInternal, postgresTarget,
postgresScalarTypeDescriptors, builtinControlMutationDefaults) and ensure any
local test-specific fixtures (the custom scalarTypeDescriptors Map and
controlMutationDefaults block) are moved with their tests; finally remove these
three blocks from this file so interpreter.test.ts stays under the
test-file-size guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/1-framework/2-authoring/ids/src/index.ts`:
- Around line 89-106: Return deep-cloned or frozen copies of registry data
instead of sharing references: when building builtinGeneratorRegistryMetadata,
copy or Object.freeze the applicableCodecIds array and any object wrappers so
callers can't mutate builtinGeneratorMetadataById state; in
resolveBuiltinGeneratedColumnDescriptor, if
metadata.resolveGeneratedColumnDescriptor exists return a cloned/frozen result
(and if falling back to metadata.generatedColumnDescriptor return a
cloned/frozen copy) so callers cannot mutate shared typeParams,
applicableCodecIds, or generatedColumnDescriptor objects from the
builtinGeneratorMetadataById registry.

In `@packages/2-sql/1-core/contract/test/validate.test.ts`:
- Around line 89-107: The test currently asserts any "Contract structural
validation failed" but should assert the specific flat-id generator failure;
update the assertion in the test that calls validateContract (the case building
a contract with execution.mutations.defaults containing
onCreate.kind='generator' id='pack/slugid') to expect the precise validation
message or pattern for non-flat generator ids (e.g. match the validator's error
text for "flat id" or the path under execution.mutations.defaults/onCreate)
instead of the generic structural failure.

In `@packages/2-sql/2-authoring/contract-psl/src/interpreter.ts`:
- Around line 35-40: The input interface declares target and
scalarTypeDescriptors as required but the implementation (function using
InterpretPslDocumentToSqlContractIRInput) defensively checks for their absence
and returns PSL_TARGET_CONTEXT_REQUIRED and PSL_SCALAR_TYPE_CONTEXT_REQUIRED;
update the contract to match runtime behavior by making both target and
scalarTypeDescriptors optional on InterpretPslDocumentToSqlContractIRInput
(e.g., mark as ?), keep the existing runtime checks in the interpreter (where
PSL_TARGET_CONTEXT_REQUIRED and PSL_SCALAR_TYPE_CONTEXT_REQUIRED are returned)
and update any callers/tests to either supply those fields or intentionally omit
them without needing as unknown casts; do not remove the runtime guards unless
you intentionally want the caller to be required to provide them.

In `@packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts`:
- Around line 127-129: The test expectations for
assembleControlMutationDefaultContributions currently only assert the duplicated
function name and so miss checking that the error message includes the
conflicting owner/descriptors; update the assertions (for the occurrences around
the current expect and also at the other two locations referenced) to assert
that the thrown error message includes the two descriptor/owner identifiers
(e.g. both descriptor ids or owner names) in addition to the duplicate function
id by changing the matcher to check for those owner strings (use a regex or
snapshot that includes both owner identifiers) so regressions that drop owner
context will fail.

In `@packages/2-sql/5-runtime/src/sql-context.ts`:
- Around line 58-60: The RuntimeMutationDefaultGenerator currently exposes
generate(params?) but doesn't validate spec.params before calling it; add a
params schema/validator field to the RuntimeMutationDefaultGenerator interface
(e.g., paramsSchema or validateParams using Arktype) and, in places where
generator.generate(...) is invoked (the current call site around
RuntimeMutationDefaultGenerator usage and the other similar path at the section
referenced ~381-399), run the schema validator (reuse the pattern from
validateTypeParams()) and throw a stable runtime error when validation fails;
only call generator.generate with validated/parsed params to ensure
malformed/stale contract data is rejected early and consistently.

In `@packages/2-sql/5-runtime/test/mutation-default-generators.test.ts`:
- Around line 218-255: Add a small params-forwarding test that exercises the
generateId({ id, params }) branch of createTestMutationDefaultGenerators: extend
the existing test suite to include a contract default using a built-in generator
(e.g., id: 'nanoid') with explicit params (for example size/length) and call
context.applyMutationDefaults({ op: 'create', table: 'user', values: {} });
assert the returned/generated id respects the passed params (e.g., length or
pattern) so the test fails if params are not forwarded to generateId; reference
generateId and createTestMutationDefaultGenerators and use
context.applyMutationDefaults to locate where to add the case.

---

Nitpick comments:
In `@packages/2-sql/1-core/contract/src/validators.ts`:
- Around line 24-26: The generator-id validation is duplicated across layers;
extract and export a single shared schema/constant (e.g., GeneratorIdSchema or
GENERATOR_ID_REGEX) and replace local occurrences of generatorIdSchema with an
import of that shared symbol so contract-ts and core validation remain
consistent; update the current generatorIdSchema definition to re-export the
centralized validation (use the same type('string').narrow(...) or a reusable
regex constant) and adjust imports in any modules that currently define their
own regex.

In `@packages/2-sql/1-core/contract/test/validate.test.ts`:
- Around line 65-107: Move the two execution-default specs ("accepts custom
execution default generator ids" and "rejects non-flat execution default
generator ids") out of this large validate.test.ts into a new focused test file
for execution-default scenarios (e.g., validate.execution-defaults.test.ts);
retain the same test bodies and imports (keep references to validateContract,
SqlContract, SqlStorage, and baseContract) and update any test-suite describe
blocks as needed so the tests run standalone and the original file is kept under
500 lines.

In `@packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts`:
- Around line 230-258: Update lowerDefaultFunctionWithRegistry to compute the
nearest registry key to input.call.name (using a simple string-distance /
fuzzy-match over registry.keys(), and prefer matching against usageSignatures
entries when available) and prepend a short "Did you mean 'X'?" hint to the
diagnostic message before the full Supported functions list; keep
formatSupportedFunctionList unchanged but you may reuse its output for the full
list while constructing the hint, and reference symbols:
lowerDefaultFunctionWithRegistry, formatSupportedFunctionList,
ControlMutationDefaultRegistry, entry.usageSignatures, and input.call.name.

In `@packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts`:
- Around line 24-131: Move the three new "it" test cases into the more focused
interpreter suites that already handle context, defaults and diagnostics instead
of leaving them in the monolithic interpreter.test.ts: specifically relocate the
tests titled "returns diagnostics when target context is missing", "uses
composed scalar type descriptors without hardcoded fallback", and "does not
derive generated column type without descriptor resolver" into the existing
split suites that handle diagnostics, scalar descriptor composition, and
default/generator behavior; update those target files to import and use the same
helpers referenced here (parsePslDocument,
interpretPslDocumentToSqlContractIRInternal, postgresTarget,
postgresScalarTypeDescriptors, builtinControlMutationDefaults) and ensure any
local test-specific fixtures (the custom scalarTypeDescriptors Map and
controlMutationDefaults block) are moved with their tests; finally remove these
three blocks from this file so interpreter.test.ts stays under the
test-file-size guideline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: e53156d3-a62f-4257-9a53-f544621de649

📥 Commits

Reviewing files that changed from the base of the PR and between 60e904e and cfb9fb4.

⛔ Files ignored due to path filters (16)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/psl-contract-authoring/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/Follow-up - Pack-provided mutation default functions registry-plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/plans/plan.md is excluded by !projects/**
  • projects/psl-contract-authoring/references/authoring-surface-gap-inventory.md is excluded by !projects/**
  • projects/psl-contract-authoring/references/category-error-built-in-id-generators.md is excluded by !projects/**
  • projects/psl-contract-authoring/spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Follow-up - Pack-provided mutation default functions registry.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 1 - Pluggable contract sources.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 2 - PSL parser.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 3 - Fixture-driven parity harness.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 4 - Parameterized attributes and pgvector parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 5 - ID variants and default function parity.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 6 - Close-out.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/Milestone 7 - PSL sql template literal syntax.spec.md is excluded by !projects/**
  • projects/psl-contract-authoring/specs/follow-up-move-id-generators-to-composition.spec.md is excluded by !projects/**
📒 Files selected for processing (55)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • .github/workflows/pr-code-security.yml
  • docs/architecture docs/ADR-INDEX.md
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • docs/architecture docs/adrs/ADR 170 - Pack-provided type constructors and field presets.md
  • docs/architecture docs/adrs/ADR 171 - Parameterized native types in contracts.md
  • examples/prisma-next-demo/prisma-next.config.ts
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • packages/1-framework/2-authoring/ids/src/generator-ids.ts
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/1-framework/2-authoring/ids/test/ids.test.ts
  • packages/2-sql/1-core/contract/src/validators.ts
  • packages/2-sql/1-core/contract/test/validate.test.ts
  • packages/2-sql/2-authoring/contract-psl/README.md
  • packages/2-sql/2-authoring/contract-psl/src/default-function-registry.ts
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • packages/2-sql/3-tooling/family/README.md
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/3-tooling/family/test/mutation-default-assembly.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/2-sql/5-runtime/README.md
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-mutation-defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
  • test/integration/test/authoring/parity/default-pack-slugid/packs.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • test/integration/test/authoring/psl.pgvector-dbinit.test.ts
  • test/integration/test/authoring/templates/prisma-next.config.parity-psl.ts
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts
✅ Files skipped from review due to trivial changes (18)
  • .cursor/rules/use-timeouts-helper-in-tests.mdc
  • packages/1-framework/1-core/shared/contract/src/types.ts
  • docs/architecture docs/adrs/ADR 171 - Parameterized native types in contracts.md
  • packages/1-framework/2-authoring/ids/src/generators.ts
  • packages/3-targets/6-adapters/postgres/package.json
  • packages/1-framework/2-authoring/ids/src/generator-ids.ts
  • packages/1-framework/2-authoring/ids/test/ids.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.relations.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/schema.prisma
  • docs/architecture docs/ADR-INDEX.md
  • packages/2-sql/2-authoring/contract-psl/src/exports/index.ts
  • packages/2-sql/3-tooling/family/src/core/assembly.ts
  • packages/2-sql/2-authoring/contract-psl/test/default-function-registry.test.ts
  • packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts
  • packages/2-sql/2-authoring/contract-psl/test/composed-mutation-defaults.test.ts
  • packages/2-sql/3-tooling/family/src/core/migrations/types.ts
  • packages/3-targets/6-adapters/postgres/test/control-mutation-defaults.test.ts
  • test/integration/test/authoring/parity/default-pack-slugid/expected.contract.json
🚧 Files skipped from review as they are similar to previous changes (20)
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • packages/2-sql/4-lanes/sql-lane/test/utils/guards.test.ts
  • packages/1-framework/2-authoring/ids/src/runtime.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • examples/prisma-next-demo/prisma-next.config.ts
  • packages/2-sql/5-runtime/src/exports/index.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.diagnostics.test.ts
  • packages/3-targets/6-adapters/postgres/src/exports/control.ts
  • test/integration/test/authoring/templates/prisma-next.config.parity-psl.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • docs/architecture docs/adrs/ADR 169 - Declared applicability for mutation default generators.md
  • test/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.parity-psl.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract.ts
  • test/integration/test/authoring/parity/default-pack-slugid/contract.ts
  • packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json
  • packages/2-sql/3-tooling/family/src/exports/control.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/interpreter.defaults.test.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts

Comment thread packages/1-framework/2-authoring/ids/src/index.ts
Comment thread packages/2-sql/1-core/contract/test/validate.test.ts
Comment thread packages/2-sql/2-authoring/contract-psl/src/interpreter.ts
Comment thread packages/2-sql/5-runtime/src/sql-context.ts
Comment thread packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
… and extensionPacks

The rebase onto main brought in changes that now emit capabilities and
extensionPacks into contracts. Update the golden file to match.
@wmadden wmadden merged commit f43560c into main Mar 23, 2026
12 checks passed
wmadden added a commit that referenced this pull request Mar 23, 2026
…ated defaults

Verifies that applyMutationDefaults skips the generator when the user
explicitly provides a value for a column that has a generated default.

PR #214 review thread (SevInf)
wmadden added a commit that referenced this pull request Mar 23, 2026
Rename from 'includes both owners when duplicate generator ids are
composed' to 'throws error naming both owners when duplicate generator
ids are composed' so the title reflects this is an error-path test.

PR #214 review thread (SevInf)
@wmadden wmadden deleted the tml-2025-follow-up-pack-provided-mutation-default-functions-registry-remove-psl branch March 23, 2026 08:07
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.

3 participants