Skip to content

TML-2835: make migration check single-target resolution multi-space#732

Merged
wmadden-electric merged 7 commits into
mainfrom
tml-2835-check-single-target-multi-space
Jun 5, 2026
Merged

TML-2835: make migration check single-target resolution multi-space#732
wmadden-electric merged 7 commits into
mainfrom
tml-2835-check-single-target-multi-space

Conversation

@wmadden-electric
Copy link
Copy Markdown
Contributor

@wmadden-electric wmadden-electric commented Jun 5, 2026

Completes the multi-space migration check work TML-2801 began. That slice made the holistic (no-arg) check span every contract space; its single-target mode (check <ref|path>) was deliberately left app-space-only as a follow-up. This makes single-target resolution multi-space too.

Changes

  • Single-target resolves across all contract spaces (migration-check.ts, checkSingleTarget): a migration reference is resolved per-space against each space's graph + refs (reusing TML-2801's enumerateCheckSpaces / CheckSpace), and the matched package is checked in its own space. A migration that lives in a non-app space (e.g. an extension space) is now resolved and checked, where before it was a PRECONDITION "not found on disk".
  • --space <id> narrows single-target resolution to one space, validated identically to the holistic path (isValidSpaceIderrorInvalidSpaceId; unknown id → errorSpaceNotFound; PRECONDITION).
  • Cross-space ambiguity is a precondition failure: a reference (dirName / hash-prefix) that resolves in more than one space exits PRECONDITION via a new errorAmbiguousMigrationRef factory (cli-errors.ts) that names the spaces and tells the user to qualify with --space.
  • Unresolvable references keep the shared error envelope: a reference that resolves in no space is surfaced through mapRefResolutionError (PN-RUN-3000), preserving the consistency contract TML-2801 established — not a bespoke string.
  • Filesystem-path targets resolve within whichever space's directory contains them (migration-path-target.ts, resolveTargetPathAcrossSpaces).
  • Human output shows the resolved space when it isn't app; the --help long description and examples are updated to describe multi-space single-target; the custom exit codes (0/2/4) remain documented in --help.

Why

migration check is the integrity verb; having single-target silently ignore non-app spaces meant a corrupted extension-space package could pass check <ref> while the no-arg check caught it. Resolving across spaces (with explicit ambiguity handling) closes that asymmetry and matches the policy list / graph / status already follow.

Behaviour note for reviewers: single-target now loads the full read aggregate (as the holistic path does) and therefore inherits the holistic path's integrity-refusal gate, where the old single-target path read only the app migrations directory. This is the spec's chosen design and is arguably more correct, but it does widen single-target's pre-resolution failure surface.

Out of scope: the holistic path (TML-2801, done); the other read verbs; runtime-validatable arktype --json schemas (TML-2836); --space semantics for show/log. Exit codes and the MigrationCheckResult shape are unchanged.

Closes TML-2835.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Migration check now resolves migration references across multiple contract spaces.
    • Added optional --space flag to limit resolution to a specific contract space.
    • Success output shows the resolved contract space when applicable.
  • Improvements

    • Clearer handling and messaging for ambiguous migration references; ambiguity treated as a precondition failure with guidance.
  • Tests

    • New test suite covering multi-space resolution, ambiguity, narrowing by --space, and related edge cases.

wmadden and others added 4 commits June 5, 2026 06:53
`checkSingleTarget` now resolves a migration ref across all contract
spaces (via the already-loaded aggregate + `enumerateCheckSpaces`),
with `--space <id>` to narrow and a clear PRECONDITION error when a
ref is ambiguous across spaces. Path-based targets resolve to the
owning space's dir via `resolveTargetPathAcrossSpaces`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Will Madden <madden@prisma.io>
…red envelope (fix D2 regression)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Will Madden <madden@prisma.io>
…resolution (review F-1/F-2)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Will Madden <madden@prisma.io>
…/review

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric requested a review from a team as a code owner June 5, 2026 05:07
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: cedb23ff-d7f5-48f0-96f5-12e658d6a4e3

📥 Commits

Reviewing files that changed from the base of the PR and between 9b35865 and 4794692.

📒 Files selected for processing (2)
  • packages/1-framework/3-tooling/cli/src/commands/migration-check.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-check.ts

📝 Walkthrough

Walkthrough

The PR extends the migration check command to resolve migration references and filesystem paths across all in-scope contract spaces (optionally narrowed by --space), adds a path-resolution helper, a structured ambiguous-ref error, annotates outcomes with the resolved space ID, and adds an end-to-end Vitest suite covering multi-space scenarios.

Changes

Multi-space migration check single-target resolution

Layer / File(s) Summary
Ambiguous migration ref error handling
packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
New structured error factory errorAmbiguousMigrationRef reports when a migration reference resolves to multiple contract spaces with error code, message, guidance, and metadata (ref, spaceIds).
Cross-space path resolution utility
packages/1-framework/3-tooling/cli/src/utils/migration-path-target.ts
New helper resolveTargetPathAcrossSpaces resolves input filesystem paths to the first migration space whose migrationsDir contains them; returns the resolved path or null when outside all space directories.
Multi-space single-target command logic
packages/1-framework/3-tooling/cli/src/commands/migration-check.ts
Refactors check <ref/path> to load the aggregate before branching on target, enumerate spaces, accept optional --space filter, resolve paths across spaces (fallback to app-relative validation), resolve refs by parsing in each scoped space with ambiguity detection, rank parse failures by specificity, and include resolvedSpaceId in outcomes with conditional logging suffix.
Comprehensive multi-space resolution test suite
packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts
End-to-end Vitest suite covering successful non-app-space resolution, --space narrowing and invalid/escaped/unknown variants, ambiguous refs requiring --space, app-relative fallback, rejection of named contract refs as migration refs, and preservation of the most specific parse failure across spaces.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • prisma/prisma-next#726: Both PRs refactor migration-check.ts around multi-space resolution and --space scoping with overlapping changes to ref-resolution and error handling.

Poem

🐰 Across the contract spaces I hop and peep,
Finding migrations hidden in folders deep,
If two paths match, I shout “choose a space!” —
With --space we narrow each hop and leap,
Happy checks and tidy logs before sleep.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: extending single-target migration check resolution to work across multiple contract spaces, which is the primary objective of this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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-2835-check-single-target-multi-space

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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 Jun 5, 2026

Open in StackBlitz

@prisma-next/extension-author-tools

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

@prisma-next/mongo-runtime

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

@prisma-next/family-mongo

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

@prisma-next/sql-runtime

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

@prisma-next/family-sql

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

@prisma-next/extension-arktype-json

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

@prisma-next/middleware-cache

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

@prisma-next/mongo

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

@prisma-next/extension-paradedb

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

@prisma-next/extension-pgvector

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

@prisma-next/extension-postgis

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

@prisma-next/postgres

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

@prisma-next/sql-orm-client

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

@prisma-next/sqlite

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

@prisma-next/target-mongo

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

@prisma-next/adapter-mongo

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

@prisma-next/driver-mongo

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

@prisma-next/contract

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

@prisma-next/utils

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

@prisma-next/config

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

@prisma-next/errors

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

@prisma-next/framework-components

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

@prisma-next/operations

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

@prisma-next/ts-render

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

@prisma-next/contract-authoring

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

@prisma-next/ids

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

@prisma-next/psl-parser

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

@prisma-next/psl-printer

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

@prisma-next/cli

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

@prisma-next/cli-telemetry

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

@prisma-next/emitter

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

@prisma-next/migration-tools

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

prisma-next

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

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

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

@prisma-next/mongo-codec

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

@prisma-next/mongo-contract

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

@prisma-next/mongo-value

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

@prisma-next/mongo-contract-psl

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

@prisma-next/mongo-contract-ts

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

@prisma-next/mongo-emitter

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

@prisma-next/mongo-schema-ir

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

@prisma-next/mongo-query-ast

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

@prisma-next/mongo-orm

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

@prisma-next/mongo-query-builder

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

@prisma-next/mongo-lowering

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

@prisma-next/mongo-wire

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

@prisma-next/sql-contract

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

@prisma-next/sql-errors

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

@prisma-next/sql-operations

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

@prisma-next/sql-schema-ir

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

@prisma-next/sql-contract-psl

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

@prisma-next/sql-contract-ts

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

@prisma-next/sql-contract-emitter

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

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

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

@prisma-next/sql-relational-core

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

@prisma-next/sql-builder

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

@prisma-next/target-postgres

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

@prisma-next/target-sqlite

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

@prisma-next/adapter-postgres

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

@prisma-next/adapter-sqlite

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

@prisma-next/driver-postgres

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

@prisma-next/driver-sqlite

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

commit: 45ac628

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

size-limit report 📦

Path Size
postgres / no-emit 144.91 KB (0%)
postgres / emit 116.86 KB (0%)
mongo / no-emit 76.02 KB (0%)
mongo / emit 70.89 KB (0%)
cf-worker / no-emit 174.67 KB (0%)
cf-worker / emit 143.48 KB (0%)

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts (1)

21-27: 🏗️ Heavy lift

Prefer fixture-driven config wiring over module-level vi.mock

These tests currently rely on mocking ../../src/config-loader. Please switch to a real temp config fixture and pass it through command options so the suite uses direct imports and avoids module mocking.

As per coding guidelines, **/*.{test,spec}.{ts,tsx,js,jsx}: "Prefer direct imports over module mocks in test files".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts`
around lines 21 - 27, Remove the module-level vi.mock/vi.hoisted stubbing of
loadConfig and the vi.doUnmock/vi.resetModules cleanup; instead create a real
temporary config fixture file and pass its path into the command under test via
the command options so the test uses the real ../../src/config-loader import.
Concretely: delete references to mocks, vi.mock('../../src/config-loader'),
vi.doUnmock and vi.resetModules; write a temp config fixture in the test (or use
a test helper like writeTempConfig) and invoke the tested command (the
migration-check invocation in this file) with an explicit config option/path so
loadConfig is called against the real fixture. Ensure the fixture matches
expected shape used by loadConfig and clean up the temp file after the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/1-framework/3-tooling/cli/src/commands/migration-check.ts`:
- Around line 461-471: The loop currently records only the first parse failure
in firstParseFailure when parseMigrationRef(target, { graph: space.graph, refs:
space.refs }) fails, which makes no-hit diagnostics order-dependent; update the
logic to keep the most specific failure instead of the earliest by comparing the
failure kinds (e.g., prefer "wrong-grammar" over "not-found" or other less
specific kinds) and assign firstParseFailure = migResult.failure only if it is
more specific than the existing firstParseFailure; apply the same
specificity-preserving change to the other identical block that currently sets
firstParseFailure between lines handling scopedSpaces (the second occurrence
noted around the 492-498 region) so both loops choose the most informative parse
failure for the shared envelope.

---

Nitpick comments:
In
`@packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts`:
- Around line 21-27: Remove the module-level vi.mock/vi.hoisted stubbing of
loadConfig and the vi.doUnmock/vi.resetModules cleanup; instead create a real
temporary config fixture file and pass its path into the command under test via
the command options so the test uses the real ../../src/config-loader import.
Concretely: delete references to mocks, vi.mock('../../src/config-loader'),
vi.doUnmock and vi.resetModules; write a temp config fixture in the test (or use
a test helper like writeTempConfig) and invoke the tested command (the
migration-check invocation in this file) with an explicit config option/path so
loadConfig is called against the real fixture. Ensure the fixture matches
expected shape used by loadConfig and clean up the temp file after the test.
🪄 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: ea28ae49-37da-49fc-8cf7-31756877be20

📥 Commits

Reviewing files that changed from the base of the PR and between e32d06b and 9b35865.

⛔ Files ignored due to path filters (3)
  • projects/migration-graph-rendering/slices/check-single-target-multi-space/code-review.md is excluded by !projects/**
  • projects/migration-graph-rendering/slices/check-single-target-multi-space/plan.md is excluded by !projects/**
  • projects/migration-graph-rendering/slices/check-single-target-multi-space/spec.md is excluded by !projects/**
📒 Files selected for processing (4)
  • packages/1-framework/3-tooling/cli/src/commands/migration-check.ts
  • packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
  • packages/1-framework/3-tooling/cli/src/utils/migration-path-target.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-check-single-target-multi-space.test.ts

Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-check.ts Outdated
…Rabbit review)

When a single-target ref resolves in no space, report the most informative
parse failure (e.g. wrong-grammar) instead of whichever space failed first,
so the diagnostic is not order-dependent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Will Madden <madden@prisma.io>
Previous run had a V8 JIT crash (SIGILL, exit 132) in the
prisma-next-demo runner and a cascading MongoDB memory-server
timeout in retail-store — both unrelated to this PR's changes.

Signed-off-by: Will Madden <madden@prisma.io>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@wmadden-electric wmadden-electric enabled auto-merge (squash) June 5, 2026 07:52
@wmadden-electric wmadden-electric merged commit f061a47 into main Jun 5, 2026
21 checks passed
@wmadden-electric wmadden-electric deleted the tml-2835-check-single-target-multi-space branch June 5, 2026 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants