Skip to content

Add MongoDB data transform operations#349

Open
wmadden wants to merge 17 commits intomainfrom
tml-2219-data-migrations-for-mongodb
Open

Add MongoDB data transform operations#349
wmadden wants to merge 17 commits intomainfrom
tml-2219-data-migrations-for-mongodb

Conversation

@wmadden
Copy link
Copy Markdown
Contributor

@wmadden wmadden commented Apr 16, 2026

Summary

This is PR C in the stacked split of the original #349 (base: PR B —
tml-2219-b-class-flow-scaffolding).

Builds on the class-flow scaffolding spine (PR B) to introduce data
transform operations as a first-class MongoDB migration operation kind.

Highlights

  • dataTransform(name, { check?, run }) factory in
    @prisma-next/target-mongo/migration produces a serialized
    MongoDataTransformOperation with optional pre/postcheck and one or
    more raw run pipelines.
  • MongoMigrationRunner learns to dispatch data transform ops via a
    new DML executor in the Mongo adapter, distinguishing them from the
    DDL operations the existing planner emits.
  • Query-AST extends the operation union with
    MongoDataTransformOperation and MongoDataTransformCheck;
    AnyMongoMigrationOperation is now a real union.
  • Worked example: examples/retail-store/migrations/20260416_backfill-product-status
    demonstrates authoring a data migration with the contract snapshot.
  • Coverage: CLI journey, ops-serializer, runner, DML executor, and a
    Mongo migration journey test against mongo-memory-server replica set.
  • CI: wires scripts/lint-framework-target-imports.mjs into root
    lint:deps.

Stacked PR context

This PR depends on the following stack:

  1. PR D — Docs & ADRs (#TBD)
  2. PR A — CLI emit unification (#TBD)
  3. PR B — Class-flow scaffolding spine (Wire up class-based migration.ts new/apply/plan CLI commands #354)
  4. PR C (this PR) — Mongo data transforms ← base: PR B

Test plan

  • CI green (pnpm typecheck, pnpm lint, pnpm test)
  • examples/retail-store end-to-end: scaffold, fill placeholders, emit, apply backfill
  • CLI journey mongo-migration.e2e.test.ts passes against mongo-memory-server
  • dataTransform() round-trips through ops.json/runner

Summary by CodeRabbit

  • New Features

    • Added Mongo data-transform migrations with pre/post checks, idempotent execution, and ops.json round-trip support; CLI now authoring/emits/applies data transforms.
  • Examples

    • New example migrations demonstrating backfill/data-transform workflows and generated contract artifacts for Mongo.
  • Tooling

    • Runner/driver improvements to support executing data transforms against a live Mongo DB.
  • Tests

    • Extensive unit, integration, and e2e tests covering serialization, execution, CLI journeys, and runner behavior for data transforms.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

Adds a Mongo "data transform" migration operation and end-to-end support: new types, a dataTransform factory, serialization/deserialization, runner execution with pre/post checks and idempotency, driver/adapter wiring changes, tests, and example migrations demonstrating backfills.

Changes

Cohort / File(s) Summary
Type defs & control re-exports
packages/2-mongo-family/4-query/query-ast/src/migration-operation-types.ts, packages/2-mongo-family/4-query/query-ast/src/exports/control.ts
Introduced MongoDataTransformCheck and MongoDataTransformOperation; expanded AnyMongoMigrationOperation union and re-exported new types.
Migration factory & export
packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts, packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
Added exported dataTransform(...) factory that normalizes buildables, creates precheck/run/postcheck shapes, and provides defaults (filter/description).
Serialization / op schemas
packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts
Extended serializer/deserializer to support data-transform JSON shapes, added pipeline/DML deserializers, and dispatch by operationClass.
Runner execution & checks
packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
Added data-transform execution path with pre/post check evaluation, idempotency short-circuit, lowering via adapter, driver execution of run plans, and new helper functions for checks.
Runner deps & control exports
packages/3-mongo-target/2-mongo-adapter/src/core/runner-deps.ts, packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts
createMongoRunnerDeps now accepts (controlDriver, driver), returns includes adapter and driver; extractDb exported and re-exported.
Mongo driver refactor & exports
packages/3-mongo-target/3-mongo-driver/src/mongo-driver.ts, packages/3-mongo-target/3-mongo-driver/src/exports/index.ts
Exported MongoDriverImpl; made constructor private; added fromConnection and fromDb factories; createMongoDriver delegates to fromConnection.
Adapter/runner tests & runner wiring
packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts, packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts, packages/3-mongo-target/1-mongo-target/test/*
Extensive tests added for data-transform factory, serializer, runner behavior (idempotency, pre/post checks), and mixed DDL+DML execution; test harnesses updated to provide driver via createMongoRunnerDeps.
Integration & CLI fixtures/tests
test/integration/test/..., test/integration/test/cli-journeys/..., test/integration/test/fixtures/cli/...
Updated integration tests and CLI journey fixtures to include driver wiring (MongoDriverImpl.fromDb(extractDb(...))), added new end-to-end CLI migration journeys that exercise data transforms.
Examples / contracts / ops
examples/retail-store/migrations/..., examples/mongo-demo/migrations/...
Added example migrations demonstrating dataTransform backfills, generated contract JSON/TS artifacts, and produced corresponding ops.json.
Package metadata & deps
packages/3-mongo-target/1-mongo-target/package.json, packages/3-mongo-target/2-mongo-adapter/package.json, packages/2-mongo-family/9-family/package.json, package.json
Added workspace dependencies (@prisma-next/mongo-lowering, @prisma-next/driver-mongo) and tweaked lint:deps script.
Tests: serializers & unit suites
packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.*.test.ts, other test files
New serializer unit tests for DML/pipeline deserialization and round-trip of data-transform ops added.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Migration Client
    participant Runner as MongoMigrationRunner
    participant Adapter as MongoAdapter
    participant Driver as MongoDriver
    participant DB as MongoDB

    Client->>Runner: execute(dataTransformOp)
    Runner->>Runner: evaluate postchecks (idempotency)
    alt all postchecks satisfied
        Runner-->>Client: skipped (idempotent)
    else postchecks not satisfied
        Runner->>Runner: evaluate prechecks
        alt any precheck failed
            Runner-->>Client: PRECHECK_FAILED
        else prechecks pass
            loop each run plan
                Runner->>Adapter: lower(plan)
                Adapter-->>Runner: wireCommand
                Runner->>Driver: execute(wireCommand)
                Driver->>DB: run command
                DB-->>Driver: rows/result
                Driver-->>Runner: consumed/ok
            end
            Runner->>Runner: evaluate postchecks
            alt postchecks satisfied
                Runner-->>Client: success
            else
                Runner-->>Client: POSTCHECK_FAILED
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • saevarb

Poem

🐰 I hop through plans and filters neat,

prechecks sniff and postchecks meet.
DDL and data now dance in line,
backfills run, then all is fine.
A carrot-shaped commit—idempotent treat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.51% 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 'Add MongoDB data transform operations' is clear, concise, and directly summarizes the main change: introducing a new dataTransform factory and associated infrastructure for MongoDB data migration operations.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2219-data-migrations-for-mongodb

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 16, 2026

Open in StackBlitz

@prisma-next/mongo-runtime

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

@prisma-next/family-mongo

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

@prisma-next/sql-runtime

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

@prisma-next/family-sql

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

@prisma-next/middleware-telemetry

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/middleware-telemetry@349

@prisma-next/mongo

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

@prisma-next/extension-paradedb

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

@prisma-next/extension-pgvector

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

@prisma-next/postgres

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

@prisma-next/sql-orm-client

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

@prisma-next/sqlite

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

@prisma-next/target-mongo

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

@prisma-next/adapter-mongo

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

@prisma-next/driver-mongo

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

@prisma-next/contract

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

@prisma-next/utils

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

@prisma-next/config

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

@prisma-next/errors

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

@prisma-next/framework-components

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

@prisma-next/operations

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

@prisma-next/contract-authoring

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

@prisma-next/ids

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

@prisma-next/psl-parser

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

@prisma-next/psl-printer

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

@prisma-next/cli

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

@prisma-next/emitter

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

@prisma-next/migration-tools

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

prisma-next

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

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

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

@prisma-next/runtime-executor

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

@prisma-next/mongo-codec

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

@prisma-next/mongo-contract

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

@prisma-next/mongo-value

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

@prisma-next/mongo-contract-psl

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

@prisma-next/mongo-contract-ts

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

@prisma-next/mongo-emitter

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

@prisma-next/mongo-schema-ir

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

@prisma-next/mongo-query-ast

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

@prisma-next/mongo-orm

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

@prisma-next/mongo-pipeline-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-pipeline-builder@349

@prisma-next/mongo-lowering

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

@prisma-next/mongo-wire

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

@prisma-next/sql-contract

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

@prisma-next/sql-errors

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

@prisma-next/sql-operations

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

@prisma-next/sql-schema-ir

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

@prisma-next/sql-contract-psl

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

@prisma-next/sql-contract-ts

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

@prisma-next/sql-contract-emitter

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

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

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

@prisma-next/sql-relational-core

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

@prisma-next/sql-builder

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

@prisma-next/target-postgres

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

@prisma-next/target-sqlite

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

@prisma-next/adapter-postgres

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

@prisma-next/adapter-sqlite

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

@prisma-next/driver-postgres

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

@prisma-next/driver-sqlite

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

commit: 85d4709

Base automatically changed from migration-subsystem-refactor to main April 16, 2026 07:31
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from 7ca0000 to f5a79ad Compare April 16, 2026 07:32
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: 2

🧹 Nitpick comments (4)
packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts (1)

51-53: Consider documenting the lifecycle contract.

The empty close() implementation with comment "Connection lifecycle managed externally" is correct, but consider whether the MongoDriver interface should document this expectation to prevent misuse.

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

In `@packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts` around
lines 51 - 53, The empty close() in dml-executor.ts relies on an external
lifecycle contract that isn't documented; update the MongoDriver interface (the
close() method) to include a clear doc comment/JSDoc stating that connection
lifecycle is managed externally and implementations may be a no-op, and add a
short JSDoc comment above the async close() in DmlExecutor (or the class
containing close()) mirroring that contract so callers and implementors
understand it's intentionally a no-op.
packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts (1)

45-56: Cast to MongoQueryPlan assumes caller provides valid input.

After excluding symbol and Buildable, the remaining case is cast directly to MongoQueryPlan without validation. This relies on callers (the dataTransform function) only passing valid types, which is enforced by TypeScript at compile time but not at runtime.

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

In `@packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts`
around lines 45 - 56, resolveQueryResult currently casts any
non-symbol/non-Buildable value to MongoQueryPlan without runtime validation; add
a runtime type-guard for MongoQueryPlan (e.g., check required properties/methods
that a plan must have) and throw a clear error if the check fails. Update
resolveQueryResult to: after the isBuildable branch, verify the incoming result
has the expected MongoQueryPlan shape (or implement an isMongoQueryPlan helper),
then return it; if the check fails, throw an Error describing the invalid
runtime type and include the offending value for debugging.
packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts (1)

262-299: Consider adding tests for additional pipeline stage kinds.

Based on the MongoPipelineStage type definition (context snippet 4), additional stages like skip, unwind, group, replaceRoot, count, sortByCount, sample, redact, and out are supported but not tested here. While the current coverage is good for the most common stages, you may want to add tests for these in a follow-up to ensure complete deserialization coverage.

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

In `@packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts`
around lines 262 - 299, Add unit tests covering the additional
MongoPipelineStage variants so deserializePipelineStage is validated for all
supported kinds: create test cases that instantiate stages like MongoSkipStage,
MongoUnwindStage, MongoGroupStage, MongoReplaceRootStage, MongoCountStage,
MongoSortByCountStage, MongoSampleStage, MongoRedactStage, and MongoOutStage
(using their unique constructors/properties), JSON.stringify/JSON.parse each,
call deserializePipelineStage(json) and assert result.kind and the returned
stage's key properties (e.g., skip count, unwind field, group spec, replaceRoot
spec, count field, sortByCount spec, sample size, redact expression, out target)
to ensure correct round-trip deserialization.
packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts (1)

271-288: Consider adding early termination for check evaluation.

The current implementation collects all documents from the driver before evaluating filters (line 279-282). For checks that only need to confirm existence (expect: 'exists'), this could be optimized to terminate early when the first matching document is found, avoiding unnecessary memory allocation for large result sets.

💡 Optional optimization for early termination
 private async evaluateDataTransformChecks(
   checks: readonly MongoDataTransformCheck[],
   adapter: MongoAdapter,
   driver: MongoDriver,
   filterEvaluator: FilterEvaluator,
 ): Promise<boolean> {
   for (const check of checks) {
     const wireCommand = adapter.lower(check.source);
-    const documents: Record<string, unknown>[] = [];
-    for await (const row of driver.execute<Record<string, unknown>>(wireCommand)) {
-      documents.push(row);
+    let matchFound = false;
+    for await (const row of driver.execute<Record<string, unknown>>(wireCommand)) {
+      if (filterEvaluator.evaluate(check.filter, row)) {
+        matchFound = true;
+        break; // Early termination when match found
+      }
     }
-    const matchFound = documents.some((doc) => filterEvaluator.evaluate(check.filter, doc));
     const passed = check.expect === 'exists' ? matchFound : !matchFound;
     if (!passed) return false;
   }
   return true;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts` around lines
271 - 288, The loop in evaluateDataTransformChecks currently materializes all
rows into documents before filtering; change it to stream-evaluate rows from
driver.execute(wireCommand) directly using
filterEvaluator.evaluate(check.filter, row) and avoid pushing into documents.
For expect === 'exists' stop and mark the check passed as soon as a matching row
is found; for expect === 'not exists' stop and return false as soon as a match
is found, otherwise exhaust the iterator to confirm no matches. Update
evaluateDataTransformChecks (and usage of MongoAdapter.lower, driver.execute,
filterEvaluator.evaluate, and check.expect) to implement this early-termination
behavior and remove the intermediate documents array.
🤖 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/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts`:
- Around line 303-361: deserializePipelineStage currently handles only 7 kinds
and will throw for the other MongoPipelineStage variants; extend its switch to
cover the missing kinds: add cases for 'skip', 'unwind', 'group', 'replaceRoot',
'count', 'sortByCount', 'sample', 'redact', and 'out', constructing the
corresponding stage objects (e.g., MongoSkipStage, MongoUnwindStage,
MongoGroupStage, MongoReplaceRootStage, MongoCountStage, MongoSortByCountStage,
MongoSampleStage, MongoRedactStage, MongoOutStage) and mapping record fields to
constructor args; for nested/complex fields reuse existing helpers like
deserializeFilterExpr, deserializePipelineStage, deserializeExpression (or the
appropriate deserializer in this file) to convert sub-documents/arrays (e.g.,
group specs, unwind path/arrayHandling, replaceRoot/newRoot, sample/size,
sortByCount/expression, redact/expression, out/collection spec) so the full
MongoPipelineStage union is supported and no unknown-kind error occurs.

In `@packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts`:
- Around line 476-484: The tests call an undefined helper makeDriver() when
invoking runner.execute (e.g., driver: makeDriver()), causing a ReferenceError;
fix by either adding a simple makeDriver() factory that returns the expected
driver shape used by makeRunner()/runner.execute, or remove the driver:
makeDriver() argument from the failing test cases and let runner.execute rely on
its default/implicit driver like earlier tests do; update all occurrences where
driver: makeDriver() is used (search for makeDriver in this test file) so the
tests either supply a valid driver object or omit the parameter consistently.

---

Nitpick comments:
In `@packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts`:
- Around line 45-56: resolveQueryResult currently casts any
non-symbol/non-Buildable value to MongoQueryPlan without runtime validation; add
a runtime type-guard for MongoQueryPlan (e.g., check required properties/methods
that a plan must have) and throw a clear error if the check fails. Update
resolveQueryResult to: after the isBuildable branch, verify the incoming result
has the expected MongoQueryPlan shape (or implement an isMongoQueryPlan helper),
then return it; if the check fails, throw an Error describing the invalid
runtime type and include the offending value for debugging.

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts`:
- Around line 271-288: The loop in evaluateDataTransformChecks currently
materializes all rows into documents before filtering; change it to
stream-evaluate rows from driver.execute(wireCommand) directly using
filterEvaluator.evaluate(check.filter, row) and avoid pushing into documents.
For expect === 'exists' stop and mark the check passed as soon as a matching row
is found; for expect === 'not exists' stop and return false as soon as a match
is found, otherwise exhaust the iterator to confirm no matches. Update
evaluateDataTransformChecks (and usage of MongoAdapter.lower, driver.execute,
filterEvaluator.evaluate, and check.expect) to implement this early-termination
behavior and remove the intermediate documents array.

In
`@packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts`:
- Around line 262-299: Add unit tests covering the additional MongoPipelineStage
variants so deserializePipelineStage is validated for all supported kinds:
create test cases that instantiate stages like MongoSkipStage, MongoUnwindStage,
MongoGroupStage, MongoReplaceRootStage, MongoCountStage, MongoSortByCountStage,
MongoSampleStage, MongoRedactStage, and MongoOutStage (using their unique
constructors/properties), JSON.stringify/JSON.parse each, call
deserializePipelineStage(json) and assert result.kind and the returned stage's
key properties (e.g., skip count, unwind field, group spec, replaceRoot spec,
count field, sortByCount spec, sample size, redact expression, out target) to
ensure correct round-trip deserialization.

In `@packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts`:
- Around line 51-53: The empty close() in dml-executor.ts relies on an external
lifecycle contract that isn't documented; update the MongoDriver interface (the
close() method) to include a clear doc comment/JSDoc stating that connection
lifecycle is managed externally and implementations may be a no-op, and add a
short JSDoc comment above the async close() in DmlExecutor (or the class
containing close()) mirroring that contract so callers and implementors
understand it's intentionally a no-op.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 4567446e-2d41-4f68-a850-99c1c1215b77

📥 Commits

Reviewing files that changed from the base of the PR and between 931df5c and f5a79ad.

⛔ Files ignored due to path filters (3)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/mongo-migration-authoring/plans/data-migrations-plan.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/data-transform-check-unification.md is excluded by !projects/**
📒 Files selected for processing (17)
  • packages/1-framework/3-tooling/migration/src/migration-ts.ts
  • packages/2-mongo-family/4-query/query-ast/src/exports/control.ts
  • packages/2-mongo-family/4-query/query-ast/src/migration-operation-types.ts
  • packages/2-mongo-family/9-family/src/core/mongo-migration.ts
  • packages/3-mongo-target/1-mongo-target/package.json
  • packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
  • packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
  • packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts
  • packages/3-mongo-target/1-mongo-target/test/migration-e2e.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.test.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/runner-deps.ts
  • packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts

Comment thread packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.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.

🧹 Nitpick comments (1)
examples/retail-store/migrations/20260416_backfill-product-status/migration.ts (1)

11-21: Consider removing the long explanatory block comment.

This block can be trimmed since the implementation is already clear from the code.

♻️ Optional cleanup
-/**
- * Backfills a `status` field on all products that don't already have one.
- *
- * - **check.source**: an aggregate query that finds products missing `status`,
- *   limited to 1 result (we only need to know if any exist).
- * - **check.expect** (default `'exists'`): the transform runs when the source
- *   query finds at least one match. On retry, the postcheck (auto-inverted to
- *   `'notExists'`) skips re-execution if all products already have `status`.
- * - **run**: an updateMany that sets `status: 'active'` on every product
- *   where the field is missing.
- */
As per coding guidelines, "Do not add comments if avoidable; prefer code which expresses its intent."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@examples/retail-store/migrations/20260416_backfill-product-status/migration.ts`
around lines 11 - 21, Remove or trim the long explanatory block comment at the
top of the migration to avoid redundant documentation: delete the multi-line
description that explains check.source, check.expect and run (or replace it with
a single-line summary like "Backfills missing product.status to 'active'"),
leaving the actual migration code (the check and run/updateMany logic that sets
status) intact; reference symbols to find the code: look for the block
immediately above the migration's check.source, check.expect and run/updateMany
that mentions the status field and remove or shorten it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@examples/retail-store/migrations/20260416_backfill-product-status/migration.ts`:
- Around line 11-21: Remove or trim the long explanatory block comment at the
top of the migration to avoid redundant documentation: delete the multi-line
description that explains check.source, check.expect and run (or replace it with
a single-line summary like "Backfills missing product.status to 'active'"),
leaving the actual migration code (the check and run/updateMany logic that sets
status) intact; reference symbols to find the code: look for the block
immediately above the migration's check.source, check.expect and run/updateMany
that mentions the status field and remove or shorten it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 3f7d06a3-0a00-406a-b7fa-017ad4e6ccde

📥 Commits

Reviewing files that changed from the base of the PR and between 47d17bd and 8505d49.

📒 Files selected for processing (3)
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.json
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/ops.json
✅ Files skipped from review due to trivial changes (1)
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.json

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

Caution

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

⚠️ Outside diff range comments (1)
test/integration/test/mongo/migration-authoring-e2e.test.ts (1)

58-76: 🛠️ Refactor suggestion | 🟠 Major

runOps accepts data ops, but policy currently blocks operationClass: 'data'.

Line 58 widens input to AnyMongoMigrationOperation[], but ALL_POLICY excludes 'data'. This makes the helper accept inputs it may reject at runtime.

Proposed fix
 const ALL_POLICY = {
-  allowedOperationClasses: ['additive', 'widening', 'destructive'] as const,
+  allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] as const,
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/integration/test/mongo/migration-authoring-e2e.test.ts` around lines 58
- 76, runOps currently types its ops as AnyMongoMigrationOperation[] but calls
MongoMigrationRunner.execute with ALL_POLICY which forbids
operationClass:'data', so either narrow the runOps parameter to exclude data
operations or change the policy passed to the runner to one that permits data
ops. Concretely, update the runOps signature (the function named runOps) to a
type excluding { operationClass: 'data' } if the helper should only accept
schema/index ops, or replace ALL_POLICY in the call to runner.execute with a
policy constant that allows data operations (or compose a new policy that
includes data) so the declared input type matches runtime validation.
🧹 Nitpick comments (2)
packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts (2)

48-145: Group operation tests into nested contexts for clearer BDD flow.

Consider nesting by command family (e.g., describe('insert commands'), describe('update commands'), describe('delete commands')) so preconditions and behavior are easier to scan and maintain.

As per coding guidelines: "Group test assertions by the conditions under which they're true using nested describe() blocks" and "Write tests in BDD-style with readable, grouped context."

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

In `@packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts` around
lines 48 - 145, Tests are flat and should be reorganized into BDD-style nested
describe blocks by command family (e.g., describe('insert commands'),
describe('update commands'), describe('delete commands'),
describe('findOneAnd*'), describe('aggregate')), moving the related it(...)
cases (those that instantiate MigrationMongoDriver and use InsertOneWireCommand,
InsertManyWireCommand, UpdateOneWireCommand, UpdateManyWireCommand,
DeleteOneWireCommand, DeleteManyWireCommand, FindOneAndUpdateWireCommand,
FindOneAndDeleteWireCommand, AggregateWireCommand) into their respective nested
describes; consolidate shared setup (creating the 'items' collection, inserting
seed docs, and creating new MigrationMongoDriver(db)) into beforeEach hooks
inside each nested describe so preconditions are clear and duplicated code is
reduced, and keep the existing assertions inside the it blocks unchanged.

54-55: Prefer object matchers over repeated toHaveProperty assertions.

For result payload checks, toMatchObject (or toEqual where exact) aligns better with repo test conventions and keeps assertions more uniform.

Example refactor pattern
- expect(results[0]).toHaveProperty('insertedCount', 2);
+ expect(results[0]).toMatchObject({ insertedCount: 2 });

- expect(results[0]).toHaveProperty('modifiedCount', 1);
+ expect(results[0]).toMatchObject({ modifiedCount: 1 });

- expect(results[0]).toHaveProperty('name', 'charlie');
+ expect(results[0]).toMatchObject({ name: 'charlie' });

As per coding guidelines: "Prefer object comparison using toEqual or toMatchObject for assertions on objects, rather than property-by-property checks with toHaveProperty or individual property assertions."

Also applies to: 66-67, 75-76, 84-85, 93-94, 102-103, 116-118, 126-128

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

In `@packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts` around
lines 54 - 55, Replace repeated property assertions on the test result arrays
with object matchers: instead of asserting expect(results).toHaveLength(1);
expect(results[0]).toHaveProperty('insertedId'); (and the other similar pairs),
assert the array length and use toMatchObject/toEqual on results[0] to check the
expected shape (e.g., expect(results).toHaveLength(1);
expect(results[0]).toMatchObject({ insertedId: expect.anything() }) or a more
exact object when appropriate). Update the pairs at the other occurrences
referenced (the blocks around the current checks) so each test uses a single
object matcher for result objects rather than multiple toHaveProperty calls,
keeping the variable name results and the same expectations for insertedId or
other properties.
🤖 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/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts`:
- Around line 99-110: The data-transform path incorrectly increments
operationsExecuted even when executeDataTransform short-circuits for
idempotent/skipped ops; update executeDataTransform (in mongo-runner.ts) to
return a shape like { executed: boolean; failure?: MigrationRunnerResult }
(instead of possibly undefined), ensure it returns executed: false for early
postcheck-satisfied exits and for precheck failures (including failure payload),
and then change the caller block (where operation.operationClass === 'data') to
inspect the returned .executed flag: only increment operationsExecuted when
executed === true, and propagate/return any returned .failure immediately as
before.

---

Outside diff comments:
In `@test/integration/test/mongo/migration-authoring-e2e.test.ts`:
- Around line 58-76: runOps currently types its ops as
AnyMongoMigrationOperation[] but calls MongoMigrationRunner.execute with
ALL_POLICY which forbids operationClass:'data', so either narrow the runOps
parameter to exclude data operations or change the policy passed to the runner
to one that permits data ops. Concretely, update the runOps signature (the
function named runOps) to a type excluding { operationClass: 'data' } if the
helper should only accept schema/index ops, or replace ALL_POLICY in the call to
runner.execute with a policy constant that allows data operations (or compose a
new policy that includes data) so the declared input type matches runtime
validation.

---

Nitpick comments:
In `@packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts`:
- Around line 48-145: Tests are flat and should be reorganized into BDD-style
nested describe blocks by command family (e.g., describe('insert commands'),
describe('update commands'), describe('delete commands'),
describe('findOneAnd*'), describe('aggregate')), moving the related it(...)
cases (those that instantiate MigrationMongoDriver and use InsertOneWireCommand,
InsertManyWireCommand, UpdateOneWireCommand, UpdateManyWireCommand,
DeleteOneWireCommand, DeleteManyWireCommand, FindOneAndUpdateWireCommand,
FindOneAndDeleteWireCommand, AggregateWireCommand) into their respective nested
describes; consolidate shared setup (creating the 'items' collection, inserting
seed docs, and creating new MigrationMongoDriver(db)) into beforeEach hooks
inside each nested describe so preconditions are clear and duplicated code is
reduced, and keep the existing assertions inside the it blocks unchanged.
- Around line 54-55: Replace repeated property assertions on the test result
arrays with object matchers: instead of asserting
expect(results).toHaveLength(1);
expect(results[0]).toHaveProperty('insertedId'); (and the other similar pairs),
assert the array length and use toMatchObject/toEqual on results[0] to check the
expected shape (e.g., expect(results).toHaveLength(1);
expect(results[0]).toMatchObject({ insertedId: expect.anything() }) or a more
exact object when appropriate). Update the pairs at the other occurrences
referenced (the blocks around the current checks) so each test uses a single
object matcher for result objects rather than multiple toHaveProperty calls,
keeping the variable name results and the same expectations for insertedId or
other properties.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 9398642b-813b-4a25-ab39-4589ca426c3b

📥 Commits

Reviewing files that changed from the base of the PR and between 8505d49 and fd051ad.

📒 Files selected for processing (6)
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
  • packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts
  • test/integration/test/mongo/migration-authoring-e2e.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts

Comment thread packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.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: 5

Caution

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

⚠️ Outside diff range comments (4)
packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts (1)

165-167: ⚠️ Potential issue | 🟠 Major

Narrow destinationContract before reading profileHash.

Line 166 uses a blind cast and Line 167 immediately dereferences it. Since operations execute before this point (lines 99–163), if a caller passes an invalid value for destinationContract, the code throws after operations have already executed, leaving partial changes unrecoverable.

Suggested fix
+function hasProfileHash(value: unknown): value is { readonly profileHash: string } {
+  return (
+    typeof value === 'object' &&
+    value !== null &&
+    Object.hasOwn(value, 'profileHash') &&
+    typeof Reflect.get(value, 'profileHash') === 'string'
+  );
+}
+
   const destination = options.plan.destination;
-  const contract = options.destinationContract as { profileHash?: string };
-  const profileHash = contract.profileHash ?? destination.storageHash;
+  const profileHash = hasProfileHash(options.destinationContract)
+    ? options.destinationContract.profileHash
+    : destination.storageHash;

Per coding guidelines: "No blind casts in production code: as unknown as X is forbidden outside tests. Prefer type predicates or fix the type surface."

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

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts` around lines
165 - 167, The code blindly casts options.destinationContract and immediately
reads profileHash; add a runtime type-narrowing/validation step for
options.destinationContract before any operations run (before using
options.plan.destination or performing side effects) — implement a type guard
like isDestinationContract(obj) that checks for the expected shape (e.g., object
with optional profileHash string), call it early and either narrow the variable
or throw a clear error, then compute const profileHash = contract.profileHash ??
destination.storageHash only after validation; update references to
options.destinationContract/contract and ensure no operations execute prior to
this check so partial changes cannot occur.
packages/1-framework/3-tooling/migration/src/attestation.ts (1)

17-31: ⚠️ Potential issue | 🟠 Major

verifyMigration() no longer attests the full manifest.

Stripping fromContract, toContract, and hints means those fields can be edited after attestation and verifyMigration() will still return ok: true. All three are consumed in non-test code:

  • fromContract and toContract are used in migration planning and operation resolution (descriptor-planner.ts, planner-strategies.ts, operation-resolver.ts)
  • hints is displayed in CLI diagnostics (migration-status.ts)

Since the migration ID no longer covers data the toolchain trusts, either keep them in the hash or add a separate integrity check for this authorship metadata.

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

In `@packages/1-framework/3-tooling/migration/src/attestation.ts` around lines 17
- 31, computeMigrationId currently strips fromContract, toContract, and hints
from the canonicalized manifest which allows those fields to be modified after
attestation; update computeMigrationId (and any caller like verifyMigration that
relies on it) so the integrity covers authorship metadata: stop destructuring
out _fromContract, _toContract, and _hints (only strip migrationId and
signature) so canonicalManifest includes fromContract/toContract/hints, then
re-run the canonicalizeJson/sha256Hex steps to produce the migration ID;
alternatively, if you intentionally want separate attestations, add a companion
integrity check in verifyMigration that computes and verifies a hash over the
authorship metadata (fromContract/toContract/hints) against a stored signature,
but do not leave those fields unverified.
packages/1-framework/3-tooling/cli/test/control-api/db-update.test.ts (1)

1-598: 🛠️ Refactor suggestion | 🟠 Major

Split this test file; it exceeds the 500-line limit.

This file is currently over the readability threshold and mixes multiple concerns. Please split by concern (e.g., basic flow, destructive gate, progress events) into independently runnable test files.

As per coding guidelines, **/*.test.ts: "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/1-framework/3-tooling/cli/test/control-api/db-update.test.ts` around
lines 1 - 598, The test file is too large—split it into multiple smaller test
files grouped by concern (e.g., db-update.basic.test.ts for core flows that
exercise executeDbUpdate, db-update.destructive.test.ts for the "destructive
changes gate" describe block and its helpers, and db-update.progress.test.ts for
the "progress events" tests); move or duplicate the shared helpers
(createMockDriver, createMockFamilyInstance, createMockMigrations,
dummyContract) into a small test helper module or copy them at the top of each
new file so each file is independently runnable; ensure each new file imports
executeDbUpdate and ControlProgressEvent and retains the same test cases and
assertions (names and function references like executeDbUpdate,
createMockMigrations, createDestructiveMigrations, and the describe blocks) and
that test-level mocks (vi.fn) remain scoped to their file; finally run tests to
confirm each new file is under 500 lines and update any import paths
accordingly.
packages/1-framework/3-tooling/cli/src/commands/migration-new.ts (1)

231-244: ⚠️ Potential issue | 🟠 Major

Use instanceof CliStructuredError for consistent error detection.

The code uses a property-based check ('code' in error && typeof ...) to detect CliStructuredError, but other CLI commands (migration-ref.ts, db-verify.ts, db-sign.ts, contract-emit.ts) consistently use instanceof CliStructuredError. Since CliStructuredError is already imported, replace the property check with instanceof to align with the established pattern and improve type safety.

🤖 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/migration-new.ts` around
lines 231 - 244, The catch block is using a property-based check to detect
CliStructuredError; replace the "'code' in error && typeof ... === 'string'"
check with "error instanceof CliStructuredError" so the branch returns
notOk(error as CliStructuredError) consistently; update the catch to use
instanceof CliStructuredError (keeping the existing notOk(...) and fallback to
notOk(errorUnexpected(...)) behavior) referencing the CliStructuredError class
and the notOk and errorUnexpected calls in this catch.
🧹 Nitpick comments (12)
scripts/lint-framework-target-imports.mjs (1)

30-45: Externalize lint policy into repository config

The forbidden prefix and exception lists are embedded in executable logic. Move these policy knobs to a declarative config file and have this script consume them, so rule updates don’t require script edits.

As per coding guidelines, "Prefer declarative data structures (JSON/config files) over hardcoded conditionals for validation rules, constraints, and configuration logic in dependency-cruiser and build configurations" and "Define validation rules and exceptions in declarative format within configuration files (e.g., planeRules, layerOrder) rather than as hardcoded conditionals in generator logic".

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

In `@scripts/lint-framework-target-imports.mjs` around lines 30 - 45, The
hardcoded policy values (FORBIDDEN_SUBSTRING, FRAMEWORK_ROOT,
INCLUDED_EXTENSIONS, EXCLUDED_DIRECTORIES) should be moved to a declarative
config file (e.g., lint-framework-targets.config.json) and the script should
read/validate those values at startup; update
scripts/lint-framework-target-imports.mjs to load the JSON config, validate
required keys (forbiddenSubstring, frameworkRoot, includedExtensions,
excludedDirectories), use those values in place of the constants, and keep
sensible defaults/fallbacks when the config is missing or malformed to preserve
current behavior during rollout.
packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts (1)

60-74: Consolidate related field assertions with toMatchObject

This block checks one object shape via many scalar assertions; prefer a single object matcher for readability and failure grouping.

♻️ Suggested refactor
   it('produces correct operation structure with check', () => {
     const op = dataTransform('backfill-status', {
       check: {
         source: () => makeCheckPlan(),
       },
       run: () => makeRunPlan(),
     });

-    expect(op.id).toBe('data_transform.backfill-status');
-    expect(op.label).toBe('Data transform: backfill-status');
-    expect(op.operationClass).toBe('data');
-    expect(op.name).toBe('backfill-status');
-    expect(op.precheck).toHaveLength(1);
-    expect(op.postcheck).toHaveLength(1);
+    expect(op).toMatchObject({
+      id: 'data_transform.backfill-status',
+      label: 'Data transform: backfill-status',
+      operationClass: 'data',
+      name: 'backfill-status',
+      precheck: [expect.any(Object)],
+      postcheck: [expect.any(Object)],
+    });
   });

As per coding guidelines: **/*.test.ts: Prefer object matchers (toMatchObject) over multiple individual expect().toBe() calls when checking 2 or more related values in tests.

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

In `@packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts` around
lines 60 - 74, The test uses multiple scalar expect() assertions for related
fields on the operation object; replace those with a single
expect(op).toMatchObject({ id: 'data_transform.backfill-status', label: 'Data
transform: backfill-status', operationClass: 'data', name: 'backfill-status' })
to consolidate related assertions for the result of dataTransform, and retain
the separate length checks for op.precheck and op.postcheck
(expect(op.precheck).toHaveLength(1) and expect(op.postcheck).toHaveLength(1));
update the test that constructs op (via dataTransform('backfill-status', ...))
accordingly.
packages/1-framework/1-core/errors/test/migration.test.ts (1)

24-39: Prefer toThrow assertions over manual try/catch in this test.

This block can be expressed with expect(() => placeholder('foo')).toThrow(...) to match the repo’s test error-assertion pattern.

♻️ Proposed refactor
   it('placeholder throws a CliStructuredError that names the slot', () => {
-    let thrown: unknown;
-    try {
-      placeholder('foo');
-    } catch (error) {
-      thrown = error;
-    }
-
-    expect(CliStructuredError.is(thrown)).toBe(true);
-    expect(thrown).toMatchObject({
-      code: '2001',
-      domain: 'MIG',
-      meta: { slot: 'foo' },
-    });
-    expect((thrown as CliStructuredError).toEnvelope().code).toBe('PN-MIG-2001');
+    const invoke = () => placeholder('foo');
+    expect(invoke).toThrow(CliStructuredError);
+    expect(invoke).toThrow('foo');
   });

As per coding guidelines: "Use expect(() => ...).toThrow(...) to assert errors instead of manual try/catch blocks in tests."

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

In `@packages/1-framework/1-core/errors/test/migration.test.ts` around lines 24 -
39, Replace the manual try/catch in the test with Jest's expect(...).toThrow
pattern: assert the call with expect(() => placeholder('foo')).toThrow(); then
separately assert the error shape by using expect(() =>
placeholder('foo')).toThrowErrorMatchingInlineSnapshot or another
toThrow/toThrowError matcher that verifies the CliStructuredError properties
(CliStructuredError.is, code/domain/meta and toEnvelope()) so you remove the
manual try/catch while still validating placeholder, CliStructuredError, and the
envelope code.
examples/retail-store/test/manual-migration.test.ts (1)

52-58: Prefer a single object matcher for related operation assertions.

This test checks related operation fields with separate assertions; consolidating to toMatchObject makes failures easier to scan and aligns with repo test style.

♻️ Suggested assertion shape
-      expect(ops).toHaveLength(2);
-      expect(ops[0]!.id).toBe('collection.products.setValidation');
-      expect(ops[1]!.id).toContain('index.products.create');
+      expect(ops).toHaveLength(2);
+      expect(ops).toMatchObject([
+        { id: 'collection.products.setValidation' },
+        expect.objectContaining({ id: expect.stringContaining('index.products.create') }),
+      ]);

As per coding guidelines, **/*.test.ts: "Prefer object matchers (toMatchObject) over multiple individual expect().toBe() calls when checking 2 or more related values in tests".

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

In `@examples/retail-store/test/manual-migration.test.ts` around lines 52 - 58,
The test currently asserts related fields of the operations array with multiple
expect() calls; replace those with a single object matcher using toMatchObject
on the ops array from the AddProductValidation instance. Locate the
instantiation of AddProductValidation and the ops variable, then assert ops via
toMatchObject with an array shape covering both entries (first entry id equals
'collection.products.setValidation' and second entry id matches a
stringContaining 'index.products.create') so failures are reported as a single
consolidated diff and follow the repo test style.
packages/3-mongo-target/1-mongo-target/src/core/planner-produced-migration.ts (1)

45-52: Consider using ifDefined() for conditional object spreads.

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

Use ifDefined() utility
+import { ifDefined } from '@prisma-next/utils/defined';
+
 // ...

   renderTypeScript(): string {
     return renderCallsToTypeScript(this.calls, {
       from: this.meta.from,
       to: this.meta.to,
-      ...(this.meta.kind !== undefined ? { kind: this.meta.kind } : {}),
-      ...(this.meta.labels !== undefined ? { labels: this.meta.labels } : {}),
+      ...ifDefined('kind', this.meta.kind),
+      ...ifDefined('labels', this.meta.labels),
     });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/3-mongo-target/1-mongo-target/src/core/planner-produced-migration.ts`
around lines 45 - 52, The renderTypeScript method uses inline conditional object
spreads to pass meta fields to renderCallsToTypeScript; replace those inline
spreads with the ifDefined() helper from `@prisma-next/utils/defined` so optional
properties are only included when defined. In renderTypeScript(), import
ifDefined and call renderCallsToTypeScript(this.calls, { from: this.meta.from,
to: this.meta.to, ...ifDefined('kind', this.meta.kind), ...ifDefined('labels',
this.meta.labels) }) (keeping the same property names) so that kind and labels
are conditionally added via ifDefined rather than inline ternary spreads.
packages/2-mongo-family/9-family/src/core/mongo-emit.ts (1)

94-98: Unreachable branch in describeValue.

Line 96 returns 'an array' for arrays, but this function is only called from line 86 when !Array.isArray(operations) is true, making this branch unreachable. Consider removing it for clarity.

Simplify describeValue by removing unreachable branch
 function describeValue(value: unknown): string {
   if (value === null) return 'null';
-  if (Array.isArray(value)) return 'an array';
   return `a value of type ${typeof value}`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/2-mongo-family/9-family/src/core/mongo-emit.ts` around lines 94 -
98, The describeValue function contains an unreachable branch returning 'an
array' (Array.isArray(value)) because callers (e.g., the place that checks
!Array.isArray(operations) before calling describeValue) already guard against
arrays; remove the array branch and simplify describeValue to only handle null
and otherwise return `a value of type ${typeof value}` (update function
describeValue accordingly so it no longer checks Array.isArray).
packages/3-targets/3-targets/postgres/test/migrations/planner.authoring-surface.test.ts (1)

72-82: Prefer expect().toThrow() over manual try/catch for error assertions.

Per coding guidelines, use expect(() => ...).toThrow(...) instead of manual try/catch blocks in tests.

Refactor to use expect().toThrow()
-      let caught: unknown;
-      try {
-        success.plan.renderTypeScript();
-      } catch (err) {
-        caught = err;
-      }
-
-      expect(caught).toBeInstanceOf(CliStructuredError);
-      expect((caught as CliStructuredError).code).toBe('2010');
-      expect((caught as CliStructuredError).meta).toMatchObject({ targetId: 'postgres' });
+      expect(() => success.plan.renderTypeScript()).toThrow(CliStructuredError);
+      
+      try {
+        success.plan.renderTypeScript();
+      } catch (err) {
+        expect(err).toBeInstanceOf(CliStructuredError);
+        const cliErr = err as CliStructuredError;
+        expect(cliErr.code).toBe('2010');
+        expect(cliErr.meta).toMatchObject({ targetId: 'postgres' });
+      }

Alternatively, if you need to inspect the error properties, consider using a custom matcher or extracting the error in a controlled way:

expect(() => success.plan.renderTypeScript()).toThrowError(
  expect.objectContaining({
    code: '2010',
    meta: expect.objectContaining({ targetId: 'postgres' }),
  }),
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/3-targets/3-targets/postgres/test/migrations/planner.authoring-surface.test.ts`
around lines 72 - 82, Replace the manual try/catch around
success.plan.renderTypeScript() with Jest's expect-toThrow style: call expect(()
=> success.plan.renderTypeScript()).toThrowError(...) and assert the thrown
error is a CliStructuredError by using expect.objectContaining to check { code:
'2010', meta: expect.objectContaining({ targetId: 'postgres' }) }; this removes
the caught variable and aligns the test with Jest error-assertion patterns while
still validating the CliStructuredError properties.
packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts (1)

291-294: Avoid blind-casting planner conflicts into CLI conflicts.

Both as readonly CliErrorConflict[] casts erase the contract between the planner and the CLI layer. If either planner starts returning a new conflict variant, this path will still compile and can emit malformed conflict payloads. Please share the conflict type across the boundary or map the planner result explicitly here.

As per coding guidelines, "No blind casts in production code: as unknown as X is forbidden outside tests. Prefer type predicates or fix the type surface."

Also applies to: 328-330

🤖 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/migration-plan.ts` around
lines 291 - 294, The code presently blind-casts descriptorResult.conflicts to
readonly CliErrorConflict[] when calling errorMigrationPlanningFailed (and
similarly at the other occurrence), which can hide incompatible planner
variants; instead either export/share the planner conflict type so the CLI can
accept it safely or explicitly map/validate each planner conflict to a
CliErrorConflict before passing it into errorMigrationPlanningFailed (use a
small mapping function that converts planner conflict discriminants into
CliErrorConflict instances and throws/returns a safe default for unknown kinds).
Locate the usages around descriptorResult.conflicts in migration-plan.ts and
replace the "as readonly CliErrorConflict[]" casts with an explicit
mapping/validation step (or use a shared type alias) so the payload shape is
guaranteed at compile time and runtime.
packages/1-framework/3-tooling/cli/test/commands/migration-emit.test.ts (1)

133-245: Use rejection assertions instead of manual try/catch in these error-path tests.

These blocks are only checking that executeCommand(...) rejects, so await expect(...).rejects will read cleaner and remove the repeated bookkeeping. You can still keep the JSON-envelope assertions immediately after that.

♻️ Representative cleanup
-      let thrown = false;
-      try {
-        await executeCommand(command, ['--dir', 'migrations/20260101_test', '--json']);
-      } catch {
-        thrown = true;
-      }
-
-      expect(thrown).toBe(true);
+      await expect(
+        executeCommand(command, ['--dir', 'migrations/20260101_test', '--json']),
+      ).rejects.toBeDefined();

As per coding guidelines, "Use expect(() => ...).toThrow(...) to assert errors instead of manual try/catch blocks in tests."

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

In `@packages/1-framework/3-tooling/cli/test/commands/migration-emit.test.ts`
around lines 133 - 245, Several tests (using createMigrationEmitCommand and
executeCommand) use manual try/catch to assert rejection; replace each try/catch
block with an explicit async rejection assertion such as await
expect(executeCommand(command, ['--dir', 'migrations/20260101_test',
'--json'])).rejects.toBeDefined() (or .rejects.toThrow() if the rejection is an
Error) and leave the subsequent consoleOutput/JSON envelope assertions
unchanged; update the tests that reference mocks.emitMigrationMock and
mockMigrationCapableConfig accordingly to remove the thrown bookkeeping and rely
on the expect(...).rejects pattern for clarity and consistency.
examples/retail-store/migrations/20260416_backfill-product-status/migration.ts (1)

1-5: Use the target-owned Mongo migration entrypoint in this example.

This new example is demonstrating the current Mongo migration authoring surface, but it still pulls Migration from @prisma-next/family-mongo/migration. Switching both symbols to @prisma-next/target-mongo/migration keeps the example aligned with generated migrations and avoids preserving the old path in user-facing code.

♻️ Proposed fix
-import { Migration } from '@prisma-next/family-mongo/migration';
+import { Migration, dataTransform } from '@prisma-next/target-mongo/migration';
 import { validateMongoContract } from '@prisma-next/mongo-contract';
 import { mongoPipeline } from '@prisma-next/mongo-pipeline-builder';
 import { MongoExistsExpr, RawUpdateManyCommand } from '@prisma-next/mongo-query-ast/execution';
-import { dataTransform } from '@prisma-next/target-mongo/migration';

As per coding guidelines, "Do not add backward-compatibility shims; update all references immediately to use new approaches instead of maintaining parallel implementations."

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

In
`@examples/retail-store/migrations/20260416_backfill-product-status/migration.ts`
around lines 1 - 5, The example imports the Migration symbol from the deprecated
'@prisma-next/family-mongo/migration'; update the import so the example uses the
target-owned migration entrypoint by importing Migration from
'@prisma-next/target-mongo/migration' (and likewise replace any other
migration-related symbols that currently come from
'@prisma-next/family-mongo/migration' to the same
'@prisma-next/target-mongo/migration' module, e.g., the Migration
type/constructor used in this file) while leaving unrelated imports
(validateMongoContract, mongoPipeline, MongoExistsExpr, RawUpdateManyCommand,
dataTransform) as-is.
packages/1-framework/3-tooling/cli/src/lib/migration-emit.ts (1)

105-111: Consider adding runtime validation for evaluated descriptors.

The cast at line 107 assumes evaluateMigrationTs(dir) returns a valid OperationDescriptor[]. If the evaluated module exports unexpected data, this could lead to silent failures downstream.

💡 Proposed defensive check
   const pkg = await readMigrationPackage(dir);
   const descriptors = await evaluateMigrationTs(dir);
+  if (!Array.isArray(descriptors)) {
+    throw errorMigrationFileMissing(dir); // or a more specific error
+  }
   const operations = migrations.resolveDescriptors(descriptors as OperationDescriptor[], {

Alternatively, if evaluateMigrationTs has its own validation, this cast may be acceptable. The cast is used to bridge the framework-level generic return to the target-specific type.

🤖 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/lib/migration-emit.ts` around lines
105 - 111, The code currently casts the result of evaluateMigrationTs(dir) to
OperationDescriptor[] before passing to migrations.resolveDescriptors, which can
hide malformed exports; add a runtime validation step after calling
evaluateMigrationTs (the value assigned to descriptors) that verifies it's an
array and that each item has the required OperationDescriptor shape (e.g.,
required fields used by migrations.resolveDescriptors and
pkg.manifest.fromContract / toContract), and if validation fails throw or log a
descriptive error referencing evaluateMigrationTs and OperationDescriptor so the
failure is explicit; keep using readMigrationPackage and
migrations.resolveDescriptors but guard the input to resolveDescriptors with
this check to avoid silent downstream failures.
packages/2-mongo-family/9-family/test/mongo-emit.test.ts (1)

150-166: Use expect().rejects.toThrow() for async error assertions.

The coding guidelines prefer expect().toThrow() over manual try/catch blocks. For async functions, use the rejects modifier.

♻️ Proposed refactor
-    it('propagates a structured CliStructuredError with code PN-MIG-2001 and the slot in meta', async () => {
-      await writeFile(join(pkgDir, 'migration.ts'), placeholderMigration);
-
-      let thrown: unknown;
-      try {
-        await mongoEmit({ dir: pkgDir, frameworkComponents: [] });
-      } catch (error) {
-        thrown = error;
-      }
-
-      expect(CliStructuredError.is(thrown)).toBe(true);
-      expect(thrown).toMatchObject({
-        code: '2001',
-        domain: 'MIG',
-        meta: { slot: 'backfill-product-status:run' },
-      });
-    });
+    it('propagates a structured CliStructuredError with code PN-MIG-2001 and the slot in meta', async () => {
+      await writeFile(join(pkgDir, 'migration.ts'), placeholderMigration);
+
+      await expect(mongoEmit({ dir: pkgDir, frameworkComponents: [] })).rejects.toSatisfy(
+        (error) =>
+          CliStructuredError.is(error) &&
+          error.code === '2001' &&
+          error.domain === 'MIG' &&
+          error.meta?.slot === 'backfill-product-status:run',
+      );
+    });

Alternatively, if toSatisfy is not available, you can use a helper that extracts the error and asserts on it, but the key is to avoid the try/catch pattern when possible. The same pattern applies to the other error tests at lines 170-184, 188-225, and 228-260.

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

In `@packages/2-mongo-family/9-family/test/mongo-emit.test.ts` around lines 150 -
166, Replace the manual try/catch in the test with Jest's async rejection
assertions: call await expect(mongoEmit({ dir: pkgDir, frameworkComponents: []
})).rejects.toMatchObject({ code: '2001', domain: 'MIG', meta: { slot:
'backfill-product-status:run' } }) and also assert CliStructuredError.is via
awaiting the rejected value if needed (e.g., await
expect(...).rejects.toSatisfy(err => CliStructuredError.is(err))). Apply the
same pattern for the other error tests that currently use try/catch (the tests
that reference mongoEmit and validate structured error shapes).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@examples/retail-store/migrations/20260416_backfill-product-status/migration.ts`:
- Around line 13-18: The describe() override currently hardcodes to
'sha256:a1b2...' which doesn't match the actual bundled contract hash; update
the to field so it uses the real bundled contract storage hash (e.g. replace the
literal in describe().to with the contract's storage hash reference such as
contract.storage.storageHash or the variable that holds the bundled contract
hash) so migration.describe().to matches the bundled contract and emitted
migration.json uses the correct destination hash.

In `@packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts`:
- Around line 188-225: Replace the manual try/catch blocks in both tests with
Vitest's expect(() => ...).toThrow(CliStructuredError) to assert the error type,
then perform a separate capture to inspect properties; specifically, for the
test cases invoking dataTransform('backfill-product-status', { check: () =>
placeholder(...), ... }) and dataTransform('backfill-product-status', { run: ()
=> placeholder(...) }), call expect(() =>
dataTransform(...)).toThrow(CliStructuredError) and then capture the thrown
error (e.g., via a short try/catch around the same invocation) and assert
CliStructuredError.is(thrown) and the thrown object matches the expected
code/domain/meta values for placeholder slot, keeping references to
dataTransform, placeholder, and CliStructuredError to locate the changes.

In `@packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts`:
- Around line 16-21: The file currently exports the concrete class
MigrationMongoDriver which should be hidden; change the exported API to a
factory that returns the MongoDriver interface: make the class non-exported
(rename to migrationMongoDriver or keep MigrationMongoDriver but remove the
export), add and export a factory function like createMigrationMongoDriver(db:
Db): MongoDriver that instantiates the private class and returns it, and keep
the MongoDriver interface exported for typing; ensure all callers use the new
createMigrationMongoDriver factory instead of constructing the class directly.

In `@packages/3-targets/3-targets/postgres/src/exports/control.ts`:
- Around line 137-140: Remove the blind `as never` cast on the call to
inner.plan and fix the type mismatch by making the planner options structurally
correct: either extend the framework-facing MigrationPlanner options to include
readonly schemaName?: string, or build a properly typed
SqlMigrationPlannerPlanOptions object before calling inner.plan (map the
existing options plus schemaName: options.schemaName ?? 'public') and pass that
to inner.plan; update the call site where inner.plan(options as never) is used
so it passes the correctly typed options object instead of casting.

In `@scripts/lint-framework-target-imports.mjs`:
- Around line 67-74: The current check around FORBIDDEN_SUBSTRING on the lines
array only ignores lines starting with '*' or '//' and therefore still flags
text that appears inside /* ... */ block comments or after trailing inline
comments; update the logic in the loop that examines const line = lines[i] (and
uses const trimmed = line.trimStart()) to first strip or skip block-comment
content (introduce and use an inBlockComment boolean to ignore lines between /*
and */ or remove /*...*/ fragments on the same line) and also remove trailing
inline comments (e.g., drop the portion after '//' when it's not inside a string
or comment you already removed) before checking for FORBIDDEN_SUBSTRING so
violations.push(...) is only executed for real code, not documentation or inline
comments.

---

Outside diff comments:
In `@packages/1-framework/3-tooling/cli/src/commands/migration-new.ts`:
- Around line 231-244: The catch block is using a property-based check to detect
CliStructuredError; replace the "'code' in error && typeof ... === 'string'"
check with "error instanceof CliStructuredError" so the branch returns
notOk(error as CliStructuredError) consistently; update the catch to use
instanceof CliStructuredError (keeping the existing notOk(...) and fallback to
notOk(errorUnexpected(...)) behavior) referencing the CliStructuredError class
and the notOk and errorUnexpected calls in this catch.

In `@packages/1-framework/3-tooling/cli/test/control-api/db-update.test.ts`:
- Around line 1-598: The test file is too large—split it into multiple smaller
test files grouped by concern (e.g., db-update.basic.test.ts for core flows that
exercise executeDbUpdate, db-update.destructive.test.ts for the "destructive
changes gate" describe block and its helpers, and db-update.progress.test.ts for
the "progress events" tests); move or duplicate the shared helpers
(createMockDriver, createMockFamilyInstance, createMockMigrations,
dummyContract) into a small test helper module or copy them at the top of each
new file so each file is independently runnable; ensure each new file imports
executeDbUpdate and ControlProgressEvent and retains the same test cases and
assertions (names and function references like executeDbUpdate,
createMockMigrations, createDestructiveMigrations, and the describe blocks) and
that test-level mocks (vi.fn) remain scoped to their file; finally run tests to
confirm each new file is under 500 lines and update any import paths
accordingly.

In `@packages/1-framework/3-tooling/migration/src/attestation.ts`:
- Around line 17-31: computeMigrationId currently strips fromContract,
toContract, and hints from the canonicalized manifest which allows those fields
to be modified after attestation; update computeMigrationId (and any caller like
verifyMigration that relies on it) so the integrity covers authorship metadata:
stop destructuring out _fromContract, _toContract, and _hints (only strip
migrationId and signature) so canonicalManifest includes
fromContract/toContract/hints, then re-run the canonicalizeJson/sha256Hex steps
to produce the migration ID; alternatively, if you intentionally want separate
attestations, add a companion integrity check in verifyMigration that computes
and verifies a hash over the authorship metadata (fromContract/toContract/hints)
against a stored signature, but do not leave those fields unverified.

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts`:
- Around line 165-167: The code blindly casts options.destinationContract and
immediately reads profileHash; add a runtime type-narrowing/validation step for
options.destinationContract before any operations run (before using
options.plan.destination or performing side effects) — implement a type guard
like isDestinationContract(obj) that checks for the expected shape (e.g., object
with optional profileHash string), call it early and either narrow the variable
or throw a clear error, then compute const profileHash = contract.profileHash ??
destination.storageHash only after validation; update references to
options.destinationContract/contract and ensure no operations execute prior to
this check so partial changes cannot occur.

---

Nitpick comments:
In
`@examples/retail-store/migrations/20260416_backfill-product-status/migration.ts`:
- Around line 1-5: The example imports the Migration symbol from the deprecated
'@prisma-next/family-mongo/migration'; update the import so the example uses the
target-owned migration entrypoint by importing Migration from
'@prisma-next/target-mongo/migration' (and likewise replace any other
migration-related symbols that currently come from
'@prisma-next/family-mongo/migration' to the same
'@prisma-next/target-mongo/migration' module, e.g., the Migration
type/constructor used in this file) while leaving unrelated imports
(validateMongoContract, mongoPipeline, MongoExistsExpr, RawUpdateManyCommand,
dataTransform) as-is.

In `@examples/retail-store/test/manual-migration.test.ts`:
- Around line 52-58: The test currently asserts related fields of the operations
array with multiple expect() calls; replace those with a single object matcher
using toMatchObject on the ops array from the AddProductValidation instance.
Locate the instantiation of AddProductValidation and the ops variable, then
assert ops via toMatchObject with an array shape covering both entries (first
entry id equals 'collection.products.setValidation' and second entry id matches
a stringContaining 'index.products.create') so failures are reported as a single
consolidated diff and follow the repo test style.

In `@packages/1-framework/1-core/errors/test/migration.test.ts`:
- Around line 24-39: Replace the manual try/catch in the test with Jest's
expect(...).toThrow pattern: assert the call with expect(() =>
placeholder('foo')).toThrow(); then separately assert the error shape by using
expect(() => placeholder('foo')).toThrowErrorMatchingInlineSnapshot or another
toThrow/toThrowError matcher that verifies the CliStructuredError properties
(CliStructuredError.is, code/domain/meta and toEnvelope()) so you remove the
manual try/catch while still validating placeholder, CliStructuredError, and the
envelope code.

In `@packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts`:
- Around line 291-294: The code presently blind-casts descriptorResult.conflicts
to readonly CliErrorConflict[] when calling errorMigrationPlanningFailed (and
similarly at the other occurrence), which can hide incompatible planner
variants; instead either export/share the planner conflict type so the CLI can
accept it safely or explicitly map/validate each planner conflict to a
CliErrorConflict before passing it into errorMigrationPlanningFailed (use a
small mapping function that converts planner conflict discriminants into
CliErrorConflict instances and throws/returns a safe default for unknown kinds).
Locate the usages around descriptorResult.conflicts in migration-plan.ts and
replace the "as readonly CliErrorConflict[]" casts with an explicit
mapping/validation step (or use a shared type alias) so the payload shape is
guaranteed at compile time and runtime.

In `@packages/1-framework/3-tooling/cli/src/lib/migration-emit.ts`:
- Around line 105-111: The code currently casts the result of
evaluateMigrationTs(dir) to OperationDescriptor[] before passing to
migrations.resolveDescriptors, which can hide malformed exports; add a runtime
validation step after calling evaluateMigrationTs (the value assigned to
descriptors) that verifies it's an array and that each item has the required
OperationDescriptor shape (e.g., required fields used by
migrations.resolveDescriptors and pkg.manifest.fromContract / toContract), and
if validation fails throw or log a descriptive error referencing
evaluateMigrationTs and OperationDescriptor so the failure is explicit; keep
using readMigrationPackage and migrations.resolveDescriptors but guard the input
to resolveDescriptors with this check to avoid silent downstream failures.

In `@packages/1-framework/3-tooling/cli/test/commands/migration-emit.test.ts`:
- Around line 133-245: Several tests (using createMigrationEmitCommand and
executeCommand) use manual try/catch to assert rejection; replace each try/catch
block with an explicit async rejection assertion such as await
expect(executeCommand(command, ['--dir', 'migrations/20260101_test',
'--json'])).rejects.toBeDefined() (or .rejects.toThrow() if the rejection is an
Error) and leave the subsequent consoleOutput/JSON envelope assertions
unchanged; update the tests that reference mocks.emitMigrationMock and
mockMigrationCapableConfig accordingly to remove the thrown bookkeeping and rely
on the expect(...).rejects pattern for clarity and consistency.

In `@packages/2-mongo-family/9-family/src/core/mongo-emit.ts`:
- Around line 94-98: The describeValue function contains an unreachable branch
returning 'an array' (Array.isArray(value)) because callers (e.g., the place
that checks !Array.isArray(operations) before calling describeValue) already
guard against arrays; remove the array branch and simplify describeValue to only
handle null and otherwise return `a value of type ${typeof value}` (update
function describeValue accordingly so it no longer checks Array.isArray).

In `@packages/2-mongo-family/9-family/test/mongo-emit.test.ts`:
- Around line 150-166: Replace the manual try/catch in the test with Jest's
async rejection assertions: call await expect(mongoEmit({ dir: pkgDir,
frameworkComponents: [] })).rejects.toMatchObject({ code: '2001', domain: 'MIG',
meta: { slot: 'backfill-product-status:run' } }) and also assert
CliStructuredError.is via awaiting the rejected value if needed (e.g., await
expect(...).rejects.toSatisfy(err => CliStructuredError.is(err))). Apply the
same pattern for the other error tests that currently use try/catch (the tests
that reference mongoEmit and validate structured error shapes).

In
`@packages/3-mongo-target/1-mongo-target/src/core/planner-produced-migration.ts`:
- Around line 45-52: The renderTypeScript method uses inline conditional object
spreads to pass meta fields to renderCallsToTypeScript; replace those inline
spreads with the ifDefined() helper from `@prisma-next/utils/defined` so optional
properties are only included when defined. In renderTypeScript(), import
ifDefined and call renderCallsToTypeScript(this.calls, { from: this.meta.from,
to: this.meta.to, ...ifDefined('kind', this.meta.kind), ...ifDefined('labels',
this.meta.labels) }) (keeping the same property names) so that kind and labels
are conditionally added via ifDefined rather than inline ternary spreads.

In `@packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts`:
- Around line 60-74: The test uses multiple scalar expect() assertions for
related fields on the operation object; replace those with a single
expect(op).toMatchObject({ id: 'data_transform.backfill-status', label: 'Data
transform: backfill-status', operationClass: 'data', name: 'backfill-status' })
to consolidate related assertions for the result of dataTransform, and retain
the separate length checks for op.precheck and op.postcheck
(expect(op.precheck).toHaveLength(1) and expect(op.postcheck).toHaveLength(1));
update the test that constructs op (via dataTransform('backfill-status', ...))
accordingly.

In
`@packages/3-targets/3-targets/postgres/test/migrations/planner.authoring-surface.test.ts`:
- Around line 72-82: Replace the manual try/catch around
success.plan.renderTypeScript() with Jest's expect-toThrow style: call expect(()
=> success.plan.renderTypeScript()).toThrowError(...) and assert the thrown
error is a CliStructuredError by using expect.objectContaining to check { code:
'2010', meta: expect.objectContaining({ targetId: 'postgres' }) }; this removes
the caught variable and aligns the test with Jest error-assertion patterns while
still validating the CliStructuredError properties.

In `@scripts/lint-framework-target-imports.mjs`:
- Around line 30-45: The hardcoded policy values (FORBIDDEN_SUBSTRING,
FRAMEWORK_ROOT, INCLUDED_EXTENSIONS, EXCLUDED_DIRECTORIES) should be moved to a
declarative config file (e.g., lint-framework-targets.config.json) and the
script should read/validate those values at startup; update
scripts/lint-framework-target-imports.mjs to load the JSON config, validate
required keys (forbiddenSubstring, frameworkRoot, includedExtensions,
excludedDirectories), use those values in place of the constants, and keep
sensible defaults/fallbacks when the config is missing or malformed to preserve
current behavior during rollout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: a3f62431-5331-4d44-8800-ddf3b17cdca0

📥 Commits

Reviewing files that changed from the base of the PR and between fd051ad and 425ac5c.

⛔ Files ignored due to path filters (8)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/mongo-migration-authoring/specs/class-flow-scaffolding.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/data-migrations.spec.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/data-transform-placeholder.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/migration-emit-unification.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/migration-package-polish.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/planner-dual-output.spec.md is excluded by !projects/**
  • projects/mongo-migration-authoring/specs/target-owned-migration-scaffolding.md is excluded by !projects/**
📒 Files selected for processing (92)
  • examples/mongo-demo/migrations/20260409T1030_migration/migration.json
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/migration.json
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/migration.ts
  • examples/mongo-demo/test/manual-migration.test.ts
  • examples/retail-store/migrations/20260415_add-product-validation/migration.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.d.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.json
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/ops.json
  • examples/retail-store/test/manual-migration.test.ts
  • package.json
  • packages/1-framework/1-core/errors/package.json
  • packages/1-framework/1-core/errors/src/control.ts
  • packages/1-framework/1-core/errors/src/exports/migration.ts
  • packages/1-framework/1-core/errors/src/migration.ts
  • packages/1-framework/1-core/errors/test/migration.test.ts
  • packages/1-framework/1-core/errors/tsdown.config.ts
  • packages/1-framework/1-core/framework-components/src/control-migration-types.ts
  • packages/1-framework/1-core/framework-components/src/exports/control.ts
  • packages/1-framework/3-tooling/cli/README.md
  • packages/1-framework/3-tooling/cli/package.json
  • packages/1-framework/3-tooling/cli/src/cli.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-emit.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-new.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-verify.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-init.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-update.ts
  • packages/1-framework/3-tooling/cli/src/lib/migration-emit.ts
  • packages/1-framework/3-tooling/cli/src/lib/migration-strategy.ts
  • packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/help.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-e2e.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-emit.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-verify.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/db-update.test.ts
  • packages/1-framework/3-tooling/cli/test/lib/migration-strategy.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/tsdown.config.ts
  • packages/1-framework/3-tooling/cli/vitest.config.ts
  • packages/1-framework/3-tooling/migration/src/attestation.ts
  • packages/1-framework/3-tooling/migration/src/exports/migration-ts.ts
  • packages/1-framework/3-tooling/migration/src/migration-base.ts
  • packages/1-framework/3-tooling/migration/src/migration-ts.ts
  • packages/1-framework/3-tooling/migration/src/runtime-detection.ts
  • packages/1-framework/3-tooling/migration/test/attestation.test.ts
  • packages/1-framework/3-tooling/migration/test/migration-base.test.ts
  • packages/1-framework/3-tooling/migration/test/migration-ts.test.ts
  • packages/1-framework/3-tooling/migration/test/runtime-detection.test.ts
  • packages/2-mongo-family/9-family/package.json
  • packages/2-mongo-family/9-family/src/core/mongo-emit.ts
  • packages/2-mongo-family/9-family/src/core/mongo-migration.ts
  • packages/2-mongo-family/9-family/src/core/mongo-target-descriptor.ts
  • packages/2-mongo-family/9-family/test/mongo-emit.test.ts
  • packages/3-mongo-target/1-mongo-target/package.json
  • packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-planner.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
  • packages/3-mongo-target/1-mongo-target/src/core/planner-produced-migration.ts
  • packages/3-mongo-target/1-mongo-target/src/core/render-typescript.ts
  • packages/3-mongo-target/1-mongo-target/src/exports/control.ts
  • packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
  • packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts
  • packages/3-mongo-target/1-mongo-target/test/migration-e2e.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-planner.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • packages/3-mongo-target/1-mongo-target/test/planner-produced-migration.test.ts
  • packages/3-mongo-target/1-mongo-target/test/render-ops.test.ts
  • packages/3-mongo-target/1-mongo-target/test/render-typescript.test.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts
  • packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts
  • packages/3-targets/3-targets/postgres/package.json
  • packages/3-targets/3-targets/postgres/src/core/migrations/descriptor-planner.ts
  • packages/3-targets/3-targets/postgres/src/core/migrations/scaffolding.ts
  • packages/3-targets/3-targets/postgres/src/exports/control.ts
  • packages/3-targets/3-targets/postgres/test/migrations/descriptor-planner.scenarios.md
  • packages/3-targets/3-targets/postgres/test/migrations/descriptor-planner.scenarios.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/planner.authoring-surface.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/planner.contract-to-schema-ir.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/scaffolding.test.ts
  • scripts/lint-framework-target-imports.mjs
  • test/integration/test/cli-journeys/data-transform.e2e.test.ts
  • test/integration/test/cli-journeys/schema-evolution-migrations.e2e.test.ts
  • test/integration/test/mongo/migration-e2e.test.ts
  • test/integration/test/mongo/migration-m2-vocabulary.test.ts
  • test/integration/test/mongo/migration-psl-authoring.test.ts
  • test/integration/test/utils/journey-test-helpers.ts
💤 Files with no reviewable changes (4)
  • packages/3-targets/3-targets/postgres/src/core/migrations/descriptor-planner.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-verify.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/descriptor-planner.scenarios.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-verify.ts
✅ Files skipped from review due to trivial changes (18)
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/migration.json
  • packages/1-framework/3-tooling/cli/src/commands/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
  • packages/2-mongo-family/9-family/package.json
  • packages/1-framework/3-tooling/cli/test/commands/migration-e2e.test.ts
  • packages/1-framework/1-core/errors/src/exports/migration.ts
  • examples/mongo-demo/migrations/20260409T1030_migration/migration.json
  • examples/retail-store/migrations/20260416_backfill-product-status/ops.json
  • packages/1-framework/1-core/errors/tsdown.config.ts
  • packages/3-targets/3-targets/postgres/test/migrations/descriptor-planner.scenarios.md
  • package.json
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.json
  • packages/1-framework/3-tooling/migration/src/runtime-detection.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.d.ts
  • packages/1-framework/3-tooling/migration/src/migration-ts.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/3-mongo-target/1-mongo-target/package.json
  • packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
  • packages/2-mongo-family/9-family/src/core/mongo-migration.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts
  • packages/3-mongo-target/1-mongo-target/test/migration-e2e.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/dml-executor.test.ts

Comment thread packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts
Comment thread packages/3-mongo-target/2-mongo-adapter/src/core/dml-executor.ts Outdated
Comment thread packages/3-targets/3-targets/postgres/src/exports/control.ts Outdated
Comment thread scripts/lint-framework-target-imports.mjs
wmadden added a commit that referenced this pull request Apr 18, 2026
…ability

Surfaces a misconfigured target (registers a migrations capability but
implements neither `resolveDescriptors` nor `emit`) at the selector
itself, with a structured `errorTargetHasIncompleteMigrationCapabilities`
(PN-MIG-2011) that names the offending target. Previously the selector
silently fell through to `class-based`, deferring the failure to the emit
dispatch site, which then complained about the missing `emit` hook even
when the actual intent had been descriptor flow.

Threads `targetId` through `migrationStrategy(...)` callsites in
`migration plan` and `migration emit` so the error message is honest.
Test now asserts the throw rather than the fallthrough.

Closes review finding N03 from PR #349 code review.
wmadden added a commit that referenced this pull request Apr 18, 2026
Records two intentional deviations from the original design:

- `MigrationScaffoldContext` carries `fromHash`/`toHash` so class-flow
  targets can populate `describe()` on the rendered stub. Without these
  the user would have to fix the manifest identity by hand before
  `migration emit`. The spec now documents this in §In-scope and
  §Risks §5 (the latter previously characterised the identity fields as
  inert dummies).
- `TargetMigrationsCapability` retains a narrow optional
  `renderDescriptorTypeScript?(descriptors, context): string` hook for
  the descriptor-flow branch of `migration plan`. This is the minimal
  change that avoids unifying `migration plan` across strategies, which
  is in §Out of scope. Decision §5 and §Deletion now record the
  deviation explicitly.

Also updates the strategy-selector code snippet, AC §1 framework types,
and AC §5 strategy selector to match the shipped signature
(`migrationStrategy(migrations, targetId)` throwing PN-MIG-2011).

Closes review findings N04 and N05 from PR #349 code review.
wmadden added a commit that referenced this pull request Apr 18, 2026
The MongoDB Family subsystem doc still listed "migration runner" as a
non-goal and claimed schema evolution happens via data invariants only;
that has been wrong since the Mongo planner / runner / class-flow
authoring surface landed. Reframes migrations as a supported feature on
Mongo and points at `migration new`/`migration plan`/`migration emit`.

The Migration System subsystem doc described offline planning in
SQL-only terms (`SqlSchemaIR` + `PostgresMigrationPlanner`) and made no
mention of the class-flow authoring surface. Generalises the
contract-to-schema section across families, and adds an §Authoring
strategies section that explains the descriptor-flow vs class-flow
distinction and the `migrationStrategy(...)` selector.

Closes class-flow-scaffolding AC §8 from PR #349 code review.
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from 425ac5c to ba2734e Compare April 18, 2026 16:28
@wmadden wmadden changed the title feat(mongo-migration): add data transform support for MongoDB migrations feat(mongo,cli): data transforms + cli scaffolding for mongo migrations Apr 19, 2026
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from d84b34a to 8265d44 Compare April 19, 2026 10:15
@wmadden wmadden changed the title feat(mongo,cli): data transforms + cli scaffolding for mongo migrations feat(target-mongo): add MongoDB data transform operations Apr 19, 2026
@wmadden wmadden changed the base branch from main to tml-2219-b-class-flow-scaffolding April 19, 2026 10:15
@wmadden wmadden force-pushed the tml-2219-b-class-flow-scaffolding branch from d1c595a to 1e0bc67 Compare April 19, 2026 11:42
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from 8265d44 to 824404e Compare April 19, 2026 11:42
@wmadden wmadden force-pushed the tml-2219-b-class-flow-scaffolding branch from 1e0bc67 to f001281 Compare April 19, 2026 12:08
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from 824404e to f3c391e Compare April 19, 2026 12:08
@wmadden wmadden changed the title feat(target-mongo): add MongoDB data transform operations Add MongoDB data transform operations Apr 19, 2026
@wmadden wmadden force-pushed the tml-2219-b-class-flow-scaffolding branch 3 times, most recently from eca86d0 to 3ca7de9 Compare April 19, 2026 18:30
Base automatically changed from tml-2219-b-class-flow-scaffolding to main April 20, 2026 07:24
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from f3c391e to 54927c2 Compare April 20, 2026 07:28
Builds on the class-flow scaffolding spine (PR B) to introduce data
transform operations as a first-class MongoDB migration operation kind:

- `dataTransform(name, { check?, run })` factory in
  `@prisma-next/target-mongo/migration` produces a serialized
  `MongoDataTransformOperation` with optional pre/postcheck and one or
  more raw run pipelines.
- `MongoMigrationRunner` learns to dispatch data transform ops through
  a new DML executor in the Mongo adapter, distinguishing them from the
  DDL operations that the existing planner emits.
- The query-ast layer extends the operation union with
  `MongoDataTransformOperation` and `MongoDataTransformCheck`, so
  `AnyMongoMigrationOperation` is now a real union instead of a
  one-member alias.
- Adds the `backfill-product-status` migration to the retail-store
  example as a worked end-to-end demonstration of authoring a data
  migration with the contract snapshot.
- Adds CLI journey, ops-serializer, runner, and DML executor coverage,
  plus an end-to-end Mongo migration journey test against a
  mongo-memory-server replica set.
- Wires `scripts/lint-framework-target-imports.mjs` into the root
  `lint:deps` script so CI enforces the import boundary the spine
  relies on.
@wmadden wmadden force-pushed the tml-2219-data-migrations-for-mongodb branch from 54927c2 to cc4bbfd Compare April 20, 2026 09:23
wmadden added 9 commits April 20, 2026 15:41
The data-transform postcheck message used a different sentence shape,
hyphenated "post-check", and had a trailing period that the three other
runner diagnostics lacked. Align it to the same `Operation ${id} failed
during postcheck` pattern used by DDL precheck, DDL postcheck, and
data-transform precheck.
…t MATCH_ALL_FILTER

run now accepts only () => MongoQueryPlan | Buildable, matching
check.source and the spec decision that closures defer .build() to the
resolver. This makes placeholder("slot") throw at factory invocation
rather than at module load, and removes a silent extra surface nobody
was using.

Added a rationale comment on MATCH_ALL_FILTER explaining why
exists("_id") is used as a match-all filter (the AST has no identity
expression).
Added a check clause to the hand-authored dataTransform that detects
mixed-case user names. After the first apply all names are lower-case,
so on re-apply the postcheck is satisfied and the runner skips the
transform. Second apply exits 0 and data is byte-identical.

This pins the AC-E3 retry-skip path against a real mongodb-memory-server
instance, closing the only acceptance criterion that was previously
verified only via stubbed adapter/driver.
MongoDriverImpl and MigrationMongoDriver had identical dispatch logic for
all 9 wire-command kinds. The only differences were lifecycle ownership
(client vs no-client) and constructor shape. Every future wire kind
or driver bug fix had to be mirrored in both.

MongoDriverImpl now supports two construction modes via static factories:
- fromConnection(uri, dbName): owns the MongoClient, close() disconnects
- fromDb(db): borrows a Db, close() is a no-op

createMongoRunnerDeps takes an explicit MongoDriver parameter instead of
constructing one internally, keeping the adapter package (layer 2) free
of a runtime dependency on the driver package (layer 3). The family
descriptor composes the deps with MongoDriverImpl.fromDb().

dml-executor.ts and its test are deleted; the driver test gains two
fromDb-specific tests (execute works, close is no-op).
…he real pipeline

The backfill-product-status migration had a fabricated to hash
(sha256:a1b2c3d4...) that was never produced by the real pipeline.
Data transforms do not change storage state, so to == from.

Fixed the describe().to value and re-ran both example migrations via
Migration.run(), which now produces fully-attested artifacts including
a content-addressed migrationId. Both manifests were previously
migrationId: null.
…nd attest all five example migrations

Add migration.ts class-flow sources for the two planner-scaffolded
initial migrations (mongo-demo and retail-store) so users see the
canonical authoring surface, not just generated JSON.

Co-locate contract.json + contract.d.ts in every migration directory
that was missing them (four of five).

Re-emit all five migrations via Migration.run() so every migration.json
carries a real migrationId hash and complete fromContract/toContract.
…-trip, remove empty contract.prisma

F09: deserializeMongoQueryPlan now preserves annotations, refs,
projection, and projectionTypes on round-trip instead of silently
dropping them. Rename schema field columnTypeIds → projectionTypes
to match the PlanMeta interface. Add a round-trip test covering
all four fields.

F10: delete the zero-byte contract.prisma from the backfill example
migration — vanilla data transforms do not need a .prisma file.
… migrationId assertion

After F01 changed createMongoRunnerDeps to require a MongoDriver
parameter, 12 call sites in integration and example tests still passed
only one argument. Pass MongoDriverImpl.fromDb(extractDb(controlDriver))
at each site.

Also update retail-store manual-migration.test.ts to expect an attested
migrationId (sha256:…) now that Migration.run() produces fully-attested
manifests.
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 (3)
packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts (1)

424-436: Use ifDefined() for optional PlanMeta fields.

This block reintroduces inline conditional spreads in a package file. Please switch these optional assignments to ifDefined() so PlanMeta construction stays aligned with the repo convention.

♻️ Example shape
   const meta: PlanMeta = {
     target: data.meta.target,
     storageHash: data.meta.storageHash,
     lane: data.meta.lane,
     paramDescriptors: data.meta.paramDescriptors as PlanMeta['paramDescriptors'],
-    ...(data.meta.targetFamily !== undefined && { targetFamily: data.meta.targetFamily }),
-    ...(data.meta.profileHash !== undefined && { profileHash: data.meta.profileHash }),
-    ...(data.meta.annotations !== undefined && {
-      annotations: data.meta.annotations as PlanMeta['annotations'],
-    }),
-    ...(data.meta.refs !== undefined && { refs: data.meta.refs as PlanMeta['refs'] }),
-    ...(data.meta.projection !== undefined && { projection: data.meta.projection }),
-    ...(data.meta.projectionTypes !== undefined && { projectionTypes: data.meta.projectionTypes }),
+    ...ifDefined(data.meta.targetFamily, (targetFamily) => ({ targetFamily })),
+    ...ifDefined(data.meta.profileHash, (profileHash) => ({ profileHash })),
+    ...ifDefined(data.meta.annotations as PlanMeta['annotations'] | undefined, (annotations) => ({
+      annotations,
+    })),
+    ...ifDefined(data.meta.refs as PlanMeta['refs'] | undefined, (refs) => ({ refs })),
+    ...ifDefined(data.meta.projection, (projection) => ({ projection })),
+    ...ifDefined(data.meta.projectionTypes, (projectionTypes) => ({ projectionTypes })),
   };

Also add import { ifDefined } from '@prisma-next/utils/defined';.

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/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts`
around lines 424 - 436, Replace the inline conditional spreads when constructing
the PlanMeta object with the repo utility ifDefined: import ifDefined from
'@prisma-next/utils/defined' (add the import at top) and wrap each optional
field (targetFamily, profileHash, annotations, refs, projection,
projectionTypes) using ifDefined(data.meta.<field>, { <fieldName>:
data.meta.<field> }) or the library's documented pattern so the PlanMeta
construction uses ifDefined(...) instead of ...(condition && { ... }) while
keeping required fields (target, storageHash, lane, paramDescriptors) unchanged;
ensure types remain cast as before (e.g., as PlanMeta['annotations']).
packages/3-mongo-target/3-mongo-driver/src/exports/index.ts (1)

1-1: Keep MongoDriverImpl off the public API.

Re-exporting the concrete class here makes the implementation part of the supported package surface. Please expose fromDb() through a factory and keep callers pinned to MongoDriver, not MongoDriverImpl.

As per coding guidelines, "Export interfaces and factory functions for public APIs; keep concrete classes as private implementation details".

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

In `@packages/3-mongo-target/3-mongo-driver/src/exports/index.ts` at line 1,
Remove MongoDriverImpl from the public exports: stop re-exporting
MongoDriverImpl from the barrel (keep only createMongoDriver exported). Replace
any usage that relied on MongoDriverImpl with the public factory API by exposing
a fromDb factory that returns the MongoDriver interface (either add a fromDb
function export or attach fromDb to createMongoDriver as the public factory).
Ensure the exported symbol is createMongoDriver (and optionally
createMongoDriver.fromDb) and that callers depend on the MongoDriver interface
rather than the concrete MongoDriverImpl class.
packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts (1)

414-834: Split the new runner coverage into dedicated test files.

These data-transform and round-trip suites push this file far past the 500-line cap and add separate top-level concerns to an already large runner spec. Moving them into files like mongo-runner.data-transform.test.ts and mongo-runner.round-trip.test.ts will keep failures easier to navigate.

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/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts` around
lines 414 - 834, The file exceeds the 500-line guideline because two large
top-level suites ("MongoMigrationRunner - data transforms" and
"MongoMigrationRunner - E2E round-trip") are bundled in mongo-runner.test.ts;
split each suite into its own test file (e.g.,
mongo-runner.data-transform.test.ts and mongo-runner.round-trip.test.ts) by
moving the describe(...) blocks that contain makeDataTransformPlan,
makeCheckSource, makePrecheckObj/makePostcheckObj and the E2E round-trip tests
(which reference dataTransform, RawUpdateManyCommand, RawAggregateCommand,
MongoMigrationPlanner, serializeMongoOps, makeContract, makeRunner, db, etc.)
into their respective new files, preserve and export any shared helpers
(makeRunner, db setup/teardown) or import them from the original test utilities,
and update imports/exports so tests run unchanged aside from their new
locations; ensure package test config picks up the new filenames.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/retail-store/migrations/20260413T0314_migration/migration.ts`:
- Around line 29-65: The current collection validators created in
createCollection('carts') (and the similar blocks for orders, products,
invoices) are missing required fields from the contract (e.g., Price.amount in
carts/orders/products and subtotal, tax, total, unitPrice, lineTotal in
invoices); update each validator's $jsonSchema properties and required arrays to
include these missing scalar fields with correct bsonType (e.g., Price.amount as
an int/number, subtotal/tax/total/unitPrice/lineTotal as appropriate numeric
bsonType) and ensure nested objects (like price and invoice line items) list
these properties in their required arrays so the emitted schemas exactly match
the contract.d.ts/contract.json.
- Line 286: The migration creates a non-unique secondary index on carts.userId
which breaks the contract that carts.userId must be unique; update the migration
invocation that calls createIndex for the 'carts' collection (the
createIndex('carts', [{ field: 'userId', direction: 1 }]) call) to create a
unique index instead (use the migration API's unique flag/option or the
createUniqueIndex variant so the carts.userId index enforces uniqueness).

In
`@examples/retail-store/migrations/20260415_add-product-validation/contract.d.ts`:
- Around line 24-31: The emitted types PriceOutput and PriceInput declare amount
as required but the JSON Schema validators for the nested price objects (the
price properties used in the validators around the blocks you noted) only define
currency; update the source contract's price schema so each price.properties
includes an amount with bsonType: 'double' and add "amount" to the corresponding
required arrays for every nested price validator (the three price schema blocks
referenced), then re-run the generator to re-emit the contract.d.ts so the
runtime validators match the PriceInput/PriceOutput types.
- Around line 86-97: The generated contract types mark Invoice.subtotal,
Invoice.tax, Invoice.total and InvoiceLineItem.unitPrice,
InvoiceLineItem.lineTotal as required, but the emitted invoice validator does
not define these properties or mark them required; update the validator schema
to include those properties with the correct codec/type mappings (use the same
CodecTypes entries as in Invoice and InvoiceLineItem) and add them to the
required list, or if they are meant to be optional, change the Invoice and
InvoiceLineItem type declarations to optional for those fields and then
regenerate; ensure the symbol names Invoice, InvoiceLineItem and the invoice
validator (the function/constant producing the Invoice schema) stay in sync
before regenerating the artifacts.

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts`:
- Around line 274-290: In evaluateDataTransformChecks ensure we never execute
write commands: after obtaining wireCommand = adapter.lower(check.source)
validate it is read-only (e.g., command name is find, count, distinct, aggregate
without $out/$merge, listIndexes, findOne, etc.) and reject/throw an error for
any write-like commands (insert, update, delete, findAndModify, create/drop
indexes, aggregate with $out/$merge or any top-level insert/update/delete
fields) before calling driver.execute; use the wireCommand object returned by
adapter.lower and perform explicit checks for those write indicators and fail
fast rather than executing them.

In `@packages/3-mongo-target/3-mongo-driver/test/mongo-driver.test.ts`:
- Around line 317-321: The test name claims the external client remains usable
after driver.close(), but it doesn't assert that; update the test in
mongo-driver.test.ts (the spec that creates driver via
MongoDriverImpl.fromDb(seedClient.db(dbName)) and calls driver.close()) to
perform an immediate operation on the external seedClient after await
driver.close() (for example call seedClient.db(dbName).admin().ping() or run a
simple find/count) and assert it resolves/returns expected result to prove the
client is still usable.

---

Nitpick comments:
In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts`:
- Around line 424-436: Replace the inline conditional spreads when constructing
the PlanMeta object with the repo utility ifDefined: import ifDefined from
'@prisma-next/utils/defined' (add the import at top) and wrap each optional
field (targetFamily, profileHash, annotations, refs, projection,
projectionTypes) using ifDefined(data.meta.<field>, { <fieldName>:
data.meta.<field> }) or the library's documented pattern so the PlanMeta
construction uses ifDefined(...) instead of ...(condition && { ... }) while
keeping required fields (target, storageHash, lane, paramDescriptors) unchanged;
ensure types remain cast as before (e.g., as PlanMeta['annotations']).

In `@packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts`:
- Around line 414-834: The file exceeds the 500-line guideline because two large
top-level suites ("MongoMigrationRunner - data transforms" and
"MongoMigrationRunner - E2E round-trip") are bundled in mongo-runner.test.ts;
split each suite into its own test file (e.g.,
mongo-runner.data-transform.test.ts and mongo-runner.round-trip.test.ts) by
moving the describe(...) blocks that contain makeDataTransformPlan,
makeCheckSource, makePrecheckObj/makePostcheckObj and the E2E round-trip tests
(which reference dataTransform, RawUpdateManyCommand, RawAggregateCommand,
MongoMigrationPlanner, serializeMongoOps, makeContract, makeRunner, db, etc.)
into their respective new files, preserve and export any shared helpers
(makeRunner, db setup/teardown) or import them from the original test utilities,
and update imports/exports so tests run unchanged aside from their new
locations; ensure package test config picks up the new filenames.

In `@packages/3-mongo-target/3-mongo-driver/src/exports/index.ts`:
- Line 1: Remove MongoDriverImpl from the public exports: stop re-exporting
MongoDriverImpl from the barrel (keep only createMongoDriver exported). Replace
any usage that relied on MongoDriverImpl with the public factory API by exposing
a fromDb factory that returns the MongoDriver interface (either add a fromDb
function export or attach fromDb to createMongoDriver as the public factory).
Ensure the exported symbol is createMongoDriver (and optionally
createMongoDriver.fromDb) and that callers depend on the MongoDriver interface
rather than the concrete MongoDriverImpl class.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 38c44707-9fb5-4699-b78d-f9fc763eddb9

📥 Commits

Reviewing files that changed from the base of the PR and between fd051ad and f991ca7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (53)
  • examples/mongo-demo/migrations/20260409T1030_migration/contract.d.ts
  • examples/mongo-demo/migrations/20260409T1030_migration/contract.json
  • examples/mongo-demo/migrations/20260409T1030_migration/migration.json
  • examples/mongo-demo/migrations/20260409T1030_migration/migration.ts
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/contract.d.ts
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/contract.json
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/migration.json
  • examples/mongo-demo/test/manual-migration.test.ts
  • examples/retail-store/migrations/20260413T0314_migration/contract.d.ts
  • examples/retail-store/migrations/20260413T0314_migration/contract.json
  • examples/retail-store/migrations/20260413T0314_migration/migration.json
  • examples/retail-store/migrations/20260413T0314_migration/migration.ts
  • examples/retail-store/migrations/20260413T0314_migration/ops.json
  • examples/retail-store/migrations/20260415_add-product-validation/contract.d.ts
  • examples/retail-store/migrations/20260415_add-product-validation/contract.json
  • examples/retail-store/migrations/20260415_add-product-validation/migration.json
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.d.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.json
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.json
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/ops.json
  • examples/retail-store/test/manual-migration.test.ts
  • package.json
  • packages/2-mongo-family/4-query/query-ast/src/exports/control.ts
  • packages/2-mongo-family/4-query/query-ast/src/migration-operation-types.ts
  • packages/2-mongo-family/9-family/package.json
  • packages/2-mongo-family/9-family/src/core/mongo-target-descriptor.ts
  • packages/3-mongo-target/1-mongo-target/package.json
  • packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
  • packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
  • packages/3-mongo-target/1-mongo-target/test/data-transform.test.ts
  • packages/3-mongo-target/1-mongo-target/test/migration-e2e.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.dml.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.test.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • packages/3-mongo-target/2-mongo-adapter/package.json
  • packages/3-mongo-target/2-mongo-adapter/src/core/runner-deps.ts
  • packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-runner.test.ts
  • packages/3-mongo-target/3-mongo-driver/src/exports/index.ts
  • packages/3-mongo-target/3-mongo-driver/src/mongo-driver.ts
  • packages/3-mongo-target/3-mongo-driver/test/mongo-driver.test.ts
  • test/integration/test/cli-journeys/mongo-migration.e2e.test.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/mongo-cli-journeys/contract-additive.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/mongo-cli-journeys/contract-base.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/mongo-cli-journeys/prisma-next.config.with-db.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/package.json
  • test/integration/test/mongo/migration-authoring-e2e.test.ts
  • test/integration/test/mongo/migration-e2e.test.ts
  • test/integration/test/mongo/migration-m2-vocabulary.test.ts
  • test/integration/test/mongo/migration-psl-authoring.test.ts
✅ Files skipped from review due to trivial changes (21)
  • packages/3-mongo-target/2-mongo-adapter/package.json
  • packages/2-mongo-family/9-family/package.json
  • packages/3-mongo-target/1-mongo-target/package.json
  • test/integration/test/fixtures/cli/cli-e2e-test-app/package.json
  • packages/3-mongo-target/1-mongo-target/src/exports/migration.ts
  • packages/2-mongo-family/4-query/query-ast/src/exports/control.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.json
  • package.json
  • examples/retail-store/migrations/20260413T0314_migration/ops.json
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/mongo-cli-journeys/prisma-next.config.with-db.ts
  • packages/3-mongo-target/1-mongo-target/test/migration-e2e.test.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/mongo-cli-journeys/contract-base.ts
  • examples/retail-store/migrations/20260415_add-product-validation/migration.json
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/contract.json
  • examples/mongo-demo/migrations/20260409T1030_migration/contract.json
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • examples/retail-store/migrations/20260413T0314_migration/contract.json
  • examples/mongo-demo/migrations/20260409T1030_migration/contract.d.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/ops.json
  • examples/retail-store/migrations/20260416_backfill-product-status/contract.json
  • examples/retail-store/migrations/20260415_add-product-validation/contract.json
🚧 Files skipped from review as they are similar to previous changes (11)
  • examples/mongo-demo/migrations/20260415_add-posts-author-index/migration.json
  • packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts
  • test/integration/test/mongo/migration-authoring-e2e.test.ts
  • examples/mongo-demo/migrations/20260409T1030_migration/migration.json
  • packages/3-mongo-target/1-mongo-target/test/mongo-ops-serializer.test.ts
  • packages/2-mongo-family/4-query/query-ast/src/migration-operation-types.ts
  • examples/retail-store/migrations/20260416_backfill-product-status/migration.ts
  • packages/2-mongo-family/9-family/src/core/mongo-target-descriptor.ts
  • test/integration/test/mongo/migration-m2-vocabulary.test.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/runner-deps.ts
  • packages/3-mongo-target/1-mongo-target/src/core/migration-factories.ts

Comment thread examples/retail-store/migrations/20260413T0314_migration/migration.ts Outdated
Comment thread packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
Comment thread packages/3-mongo-target/3-mongo-driver/test/mongo-driver.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.

🧹 Nitpick comments (1)
packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts (1)

24-36: Move constant and helper above all imports for consistent organization.

The READ_ONLY_CHECK_COMMAND_KINDS constant and hasProfileHash function are placed between import blocks (after line 22 imports, before lines 35-36 imports), creating inconsistent module organization.

♻️ Suggested reordering
 import { notOk, ok } from '@prisma-next/utils/result';
+import { FilterEvaluator } from './filter-evaluator';
+import { deserializeMongoOps } from './mongo-ops-serializer';
 
 const READ_ONLY_CHECK_COMMAND_KINDS: ReadonlySet<string> = new Set(['aggregate', 'rawAggregate']);
 
 function hasProfileHash(value: unknown): value is { readonly profileHash: string } {
   return (
     typeof value === 'object' &&
     value !== null &&
     Object.hasOwn(value, 'profileHash') &&
     typeof (value as { profileHash: unknown }).profileHash === 'string'
   );
 }
-
-import { FilterEvaluator } from './filter-evaluator';
-import { deserializeMongoOps } from './mongo-ops-serializer';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts` around lines
24 - 36, Move the READ_ONLY_CHECK_COMMAND_KINDS constant and hasProfileHash type
guard so they are declared before any import statements to maintain consistent
module organization; specifically relocate the declarations that currently sit
between the import groups so they appear above the imports that reference
symbols like FilterEvaluator and deserializeMongoOps, ensuring no circular
dependency is introduced and running a quick type-check after the move.
🤖 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/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts`:
- Around line 24-36: Move the READ_ONLY_CHECK_COMMAND_KINDS constant and
hasProfileHash type guard so they are declared before any import statements to
maintain consistent module organization; specifically relocate the declarations
that currently sit between the import groups so they appear above the imports
that reference symbols like FilterEvaluator and deserializeMongoOps, ensuring no
circular dependency is introduced and running a quick type-check after the move.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 83aceb65-2b8f-40a1-9113-eccdf9f77ea0

📥 Commits

Reviewing files that changed from the base of the PR and between 4a7e183 and 85d4709.

📒 Files selected for processing (8)
  • examples/retail-store/migrations/20260413T0314_migration/migration.json
  • examples/retail-store/migrations/20260413T0314_migration/migration.ts
  • examples/retail-store/migrations/20260413T0314_migration/ops.json
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-runner.ts
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • packages/3-mongo-target/3-mongo-driver/test/mongo-driver.test.ts
  • test/integration/test/mongo/migration-authoring-e2e.test.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/3-mongo-target/1-mongo-target/test/mongo-runner.test.ts
  • packages/3-mongo-target/1-mongo-target/src/core/mongo-ops-serializer.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/3-mongo-target/3-mongo-driver/test/mongo-driver.test.ts
  • examples/retail-store/migrations/20260413T0314_migration/migration.json
  • examples/retail-store/migrations/20260413T0314_migration/migration.ts

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.

2 participants