Skip to content

refactor(cli): promote migration plan/show to aggregate, retire drift surface (TML-2457)#482

Merged
wmadden merged 18 commits into
mainfrom
tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot
May 12, 2026
Merged

refactor(cli): promote migration plan/show to aggregate, retire drift surface (TML-2457)#482
wmadden merged 18 commits into
mainfrom
tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot

Conversation

@wmadden
Copy link
Copy Markdown
Contributor

@wmadden wmadden commented May 11, 2026

closes TML-2457

Key snippet (intention in code)

// BEFORE — migration plan: two independent flat passes
const migratePass = await runContractSpaceMigratePass({ migrationsDir, extensionPacks: toMigratePassInputs(canonicalExtensionInputs) });
const extensionMigrationsResult = await runContractSpaceExtensionMigrationsPass({ ... });
// then plan only the app space: spaceId: APP_SPACE_ID
// AFTER — migration plan: seed → aggregate → plan all spaces
const seedResult = await runContractSpaceSeedPhase({ migrationsDir, extensionPacks: canonicalExtensionInputs });
const aggregateResult = await buildContractSpaceAggregate({ targetId, migrationsDir, appContract, extensionPacks, validateContract });
// then plan against aggregateResult.aggregate.app (spaceId comes from aggregate)

Intent

migration plan and migration show were the last commands in the migration family that didn't know about the ContractSpaceAggregate introduced in M2.5. They operated through flat, extension-unaware passes and could only plan the app space in isolation. This change promotes both commands to the aggregate and retires the "drift" concept — a discrepancy detector between descriptor-embedded contractJson and on-disk pinned artifacts — whose existence was causing db verify and the aggregate loader to silently read contractSpace.contractJson from extension descriptors at runtime, in violation of NFR3 (the framework's runner and verifier must never import extension descriptors).

The story

  1. Introduce a phase-1 seed component that unconditionally re-emits per-space pinned artifacts and materializes any descriptor-shipped migration packages not yet on disk. Previously this was split across two passes with different data shapes; now it's a single entry point.

  2. Rewrite migration plan as a two-phase pipeline. Phase 1 seeds. Phase 2 loads the ContractSpaceAggregate and runs the planner against aggregate.app. Because phase 1 guarantees every declared extension has its head ref pinned, the loader's declaredButUnmigrated precheck always passes — resolving the chicken-and-egg problem that previously made aggregate-loading at plan time impractical.

  3. Rewrite migration show to enumerate all spaces in the aggregate (app first, then extensions). The result shape changes from a single flat object to { spaces: MigrationShowSpaceResult[] }, with each entry carrying its spaceId. The formatter adds per-space headings when there are multiple spaces, matching the sectioning style of migration status.

  4. Retire the drift surface. The "drift" concept is deleted: detectSpaceContractDrift, formatContractSpaceDriftWarning, SpaceContractDriftResult, the LoadAggregateError.driftViolation variant, and the contractSpace field on DeclaredExtensionEntry. The phase-1 seed unconditionally refreshes pinned artifacts, so drift is never observable.

  5. Fix a latent NFR3 violation. The aggregate loader was calling toDeclaredExtensions(toExtensionInputs(packs)), where toExtensionInputs reads pack.contractSpace.contractJson and immediately discards it — including inside db verify. The fix introduces toDeclaredExtensionsFromRaw, which uses 'contractSpace' in pack (a property existence check that does not invoke the accessor) and extracts only id and targetId.

Behavior changes & evidence

Compatibility / migration / risk

MigrationShowResult loses its flat top-level fields and gains spaces: readonly MigrationShowSpaceResult[]. Any code destructuring MigrationShowResult directly needs to switch to result.spaces[0] for the app space. Within this repo, only the CLI formatter is affected and is updated.

DeclaredExtensionEntry loses its contractSpace field. LoadAggregateError loses its driftViolation variant. Both are breaking to code that matches on those shapes; no remaining callers within this repo after this PR.

APP_SPACE_ID source count: 74 before → 70 after. Survivors are in structurally placed, out-of-scope surfaces (legacy single-app SQL/target statement builders, framework constant declarations, migration-tools aggregate identifiers). Reducing further requires Move 2, deferred indefinitely.

Follow-ups / open questions

  • R2 path-pruning (migration plan materializes every extension migration the descriptor ships, regardless of apply-path traversal): deferred indefinitely.
  • Legacy single-app SQL surface (2-sql/9-family, cli/src/control-api/client.ts, adapter params: [APP_SPACE_ID]): parallel ticket (TML-2457 OQ2).

Non-goals / intentionally out of scope

  • Move 2 (promoting appSpaceId: string into contract IR): closed negatively by demonstration — residual APP_SPACE_ID references are structurally placed and cannot be removed without a contract IR change.
  • migration new — app-space-only by design.
  • Pre-existing test flakiness in client.test.ts / migration-status-aggregate-spaces.test.ts (PGlite connection ordering, plan.md Open Items Add PGVector extension #4).

Summary by CodeRabbit

  • New Features

    • Migration plan/show are per-space (app + extensions), list missing-extension placeholders, show per-space previews, and report newly emitted migration directories.
  • Refactor

    • Extension artefacts and descriptor-provided migration packages are materialized to disk in a seed phase before planning so plans validate against a consistent on-disk state.
  • Bug Fixes

    • Pending counts now count migration edges; plan mode tolerates orphan markers while apply still enforces them; structural-path lookups use a consistent empty-hash sentinel.
  • Tests

    • Added seed-phase and per-space tests; updated helpers and removed obsolete drift tests.

@wmadden wmadden requested a review from a team as a code owner May 11, 2026 12:54
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: a7b2a44f-131c-4248-aa32-e0117bad7a89

📥 Commits

Reviewing files that changed from the base of the PR and between efb161f and 7a8abe4.

📒 Files selected for processing (3)
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts

📝 Walkthrough

Walkthrough

Phase-based migration planning: Phase 1 seeds per-extension contract artefacts and materialises descriptor-shipped migration packages to disk (recording newly created migrations/<spaceId>/<dirName> entries). Phase 2 loads a contract-space aggregate from the seeded disk state and then plans using the aggregate; drift-detection/migrate passes removed. Migration-show and formatters now produce per-space results.

Changes

Migration planning: seed + aggregate load

Layer / File(s) Summary
Seed-phase implementation and contract-space artefact materialisation
packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts, packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
Adds runContractSpaceSeedPhase that filters extension packs with contractSpace, deterministically plans per-space work, re-emits contract.json / placeholder contract.d.ts / refs/head.json, materialises missing descriptor migration-package directories, and returns per-space records marking `action: 'updated'
Aggregate loader simplification & descriptor independence
packages/1-framework/3-tooling/migration/src/aggregate/loader.ts, packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts, packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
Removes descriptor-driven drift detection and hashing. DeclaredExtensionEntry reduced to { id, targetId }; LoadAggregateInput no longer accepts a hashContract callback. Loader determines spaces from on-disk migrations/<id>/, drops the driftViolation error variant, and tests adjusted to assert descriptor-independence.
Extension pack input adapter refactor
packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts, packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
toDeclaredExtensions now returns readonly DeclaredExtensionEntry[] of { id, targetId } for packs with contractSpace. Adds toDeclaredExtensionsFromRaw to derive entries from raw descriptors without reading contractSpace.contractJson. Removed per-consumer migrate/migrations adapter exports; tests updated.
Migration-plan command: phase-based refactor & CLI output
packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts, packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
Implements Phase 1 seed (calls seed-phase runner) and collects emittedExtensionDirs; Phase 2 builds the contract-space aggregate from seeded disk state. Planner now uses aggregate.app.contract and aggregate.app.spaceId (replacing APP_SPACE_ID). MigrationPlanResult adds emittedExtensionDirs; summary computed with buildPlanSummary(plannedOps.length, emittedExtensionDirs.length). Tests updated to include target in contract JSON fixtures.
Migration-show command: per-space results & resolution
packages/1-framework/3-tooling/cli/src/commands/migration-show.ts, packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
migration show now returns ordered spaces[] of MigrationShowSpacePresent/MigrationShowSpaceMissing. Command reads app contract JSON from disk (structured ENOENT/invalid-JSON handling), builds the aggregate, creates an offline control client for previews, resolves app-space targets (path or hash prefix) or latest leaf, and resolves latest on-disk package per extension space (emitting missing when none). Tests and help text updated to the per-space model.
Formatter updates for per-space rendering
packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts, packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
Refactors formatMigrationShowOutput to render result.spaces per-space via formatSpaceShowBlock(), print separators for multi-space results, render missing-space summaries, include per-space previews, and mark destructive operations with (destructive). Tests updated to assert the new markers and per-space layout.
Removed migrate/extension-migrations passes
packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts (removed), packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts (removed) and corresponding tests
Deleted prior per-extension migrate and extension-migrations pass modules and their tests; their responsibilities are consolidated into the new seed-phase implementation and its tests.
Removed drift-detection module & re-exports
packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts (removed), packages/1-framework/3-tooling/migration/src/exports/aggregate.ts, packages/1-framework/3-tooling/migration/src/exports/spaces.ts
Deleted detectSpaceContractDrift and its test coverage. Removed AggregateContractHasher and drift-related re-exports; loader/CLI no longer produce a dedicated driftViolation branch that surfaced drift meta in 5002 errors.
Aggregate-loader / CLI wiring & input threading
packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
buildContractSpaceAggregate now derives declaredExtensions via toDeclaredExtensionsFromRaw(...) and accepts optional appMigrationPackages?: ReadonlyArray<OnDiskMigrationPackage> (default []). mapLoadAggregateError no longer special-cases drift failures and preserves CLI error codes/meta shape.
Status/marker/apply behavior tweaks
packages/1-framework/3-tooling/cli/src/commands/migration-status.ts, packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts, packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
loadAggregateStatusSpaces now computes pendingCount as the count of migration edges (migrationEdges.length) instead of plan operations. executeAggregateApply skips orphan-marker detection in plan mode and enforces it in apply mode. executeMigrationApply uses EMPTY_CONTRACT_HASH sentinel for structural-path diagnostics when no live marker exists.
Integration & tests adjusted for descriptor independence and per-space outputs
various tests & examples
Tests updated across the suite: removed integration test asserting loader drift as fatal, added AC15 test ensuring loader does not access contractSpace.contractJson, adjusted many tests to provide declared extensions as { id, targetId }, enforced canonical per-space ordering in outputs, and updated example contract.d.ts JSDoc to reference re-emission on migration plan.
sequenceDiagram
    participant CLI as Migration CLI
    participant Seed as Phase 1: Seed
    participant Loader as Phase 2: Aggregate Loader
    participant Planner as Migration Planner
    participant User as User

    CLI->>Seed: runContractSpaceSeedPhase(extensionPacks, migrationsDir)
    Seed->>Seed: emit contract.json, placeholder .d.ts, refs/head.json
    Seed->>Seed: materialize missing descriptor migration packages
    Seed-->>CLI: emittedExtensionDirs[], seeded records

    CLI->>Loader: buildContractSpaceAggregate(declaredExtensions, appMigrationPackages)
    Loader->>Loader: validate aggregate from seeded disk state
    Loader-->>CLI: aggregate

    CLI->>Planner: planAggregate(aggregate.app.contract, aggregate.app.spaceId)
    Planner-->>CLI: planned operations

    CLI->>CLI: buildPlanSummary(plannedOpsCount, emittedExtensionDirsCount)
    CLI-->>User: MigrationPlanResult (includes emittedExtensionDirs + summary)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

🐰 I seeded each space with gentle paws,
Wrote heads and stubs and tidy clause,
Then read the disk and built a plan so neat,
Per-space stories lined in ordered beat,
A hop, a thunk — migrations in their rows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.83% 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 title 'refactor(cli): promote migration plan/show to aggregate, retire drift surface (TML-2457)' directly summarizes the main changes: refactoring migration commands to use aggregate-based workflows and removing drift-related surface.
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-2457-reduce-app_space_id-coupling-route-through-aggregate-slot

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

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: 13

Caution

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

⚠️ Outside diff range comments (1)
packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts (1)

130-140: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate the orphan-marker preflight to apply mode only.

This runs before the mode === 'plan' branch, so db init/update --dry-run now fails on orphan markers even though plan mode never advances markers. That blocks users from inspecting the aggregate plan before they clean up a retired space.

Suggested fix
-  const orphanMarkerError = detectOrphanMarkers(aggregate, markerRows);
-  if (orphanMarkerError !== null) {
-    throw orphanMarkerError;
-  }
+  if (mode === 'apply') {
+    const orphanMarkerError = detectOrphanMarkers(aggregate, markerRows);
+    if (orphanMarkerError !== null) {
+      throw orphanMarkerError;
+    }
+  }
🤖 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/src/control-api/operations/db-apply-aggregate.ts`
around lines 130 - 140, The orphan-marker preflight (call to detectOrphanMarkers
using aggregate and markerRows that sets orphanMarkerError and throws it) should
only run when performing an apply, not during plan/dry-run; move or
conditionally execute the detectOrphanMarkers check so it is skipped when mode
=== 'plan' (or when a dry-run flag is set) to avoid failing db init/update
--dry-run while still preserving the check for actual apply operations.
🧹 Nitpick comments (7)
test/integration/test/cli.db-update.e2e.test.ts (1)

311-313: 💤 Low value

Remove transient milestone/task IDs from comment.

The comment references "M6 T6.5/T6.6" which are transient project artifacts that should not appear in source code. Describe the behavior change itself instead.

Proposed fix
-          // M6 T6.5/T6.6: `Signature:` was renamed to per-space `marker:`
-          // (or `App-space marker:` in single-space fallback).
+          // `Signature:` was renamed to per-space `marker:`
+          // (or `App-space marker:` in single-space fallback).
           expect(applyOutput).toMatch(/marker:/);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/integration/test/cli.db-update.e2e.test.ts` around lines 311 - 313,
Remove the transient milestone/task IDs ("M6 T6.5/T6.6") from the test comment
and replace them with a short description of the behavior change: that the old
"Signature:" label was renamed to a per-space "marker:" (and to "App-space
marker:" when using the single-space fallback). Update the comment surrounding
expect(applyOutput).toMatch(/marker:/) to reflect that behavior change (mention
"Signature: renamed to per-space marker / App-space marker fallback") and delete
any numeric milestone/task references.
packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts (1)

142-152: ⚡ Quick win

Prefer an own-property check for contractSpace.

'contractSpace' in raw also matches prototype properties, so a class-based descriptor with an inherited getter can be treated as contract-space-bearing even when it never declared one itself. Object.hasOwn(raw as object, 'contractSpace') keeps the no-accessor behavior and matches the loader's intended semantics.

Suggested change
-    if ('contractSpace' in (raw as object)) {
+    if (Object.hasOwn(raw as object, 'contractSpace')) {

As per coding guidelines, "Always use Object.hasOwn() instead of hasOwnProperty() to check for own properties."

🤖 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/src/utils/extension-pack-inputs.ts` around
lines 142 - 152, The function toDeclaredExtensionsFromRaw currently checks
`'contractSpace' in (raw as object)` which matches inherited properties; change
that check to use Object.hasOwn(raw as object, 'contractSpace') so only own
properties are detected, leaving the rest of the logic (casting to `{ readonly
id: string; readonly targetId: string }` and pushing to DeclaredExtensionEntry)
unchanged; update the conditional in the loop over extensionPacks inside
toDeclaredExtensionsFromRaw accordingly.
packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts (1)

186-200: ⚡ Quick win

Drop the generated @ts-nocheck directive.

This placeholder .d.ts already type-checks as-is, so emitting // @ts-nocheck`` only weakens the repo's TS guarantees and can hide accidental regressions in future template edits.

Suggested change
 function buildPlaceholderContractDts(spaceId: string): string {
   return [
-    '// `@ts-nocheck`',
     '/**',
     ` * Placeholder \`.d.ts\` for extension space "${spaceId}".`,

As per coding guidelines, "Never use @ts-nocheck."

🤖 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/src/utils/contract-space-seed-phase.ts`
around lines 186 - 200, The placeholder generator buildPlaceholderContractDts
currently emits a leading "// `@ts-nocheck`" which weakens TypeScript guarantees;
remove that entry from the returned array so the function no longer includes the
`@ts-nocheck` directive (leave the rest of the JSDoc, export {}, and formatting
intact so the string join still produces the same output minus the ts-nocheck
line).
packages/1-framework/3-tooling/cli/src/control-api/operations/apply-aggregate.ts (1)

91-95: 💤 Low value

Remove transient artifact references from comment.

The comment references "M6 AC4 / AC5" which are milestone acceptance criteria IDs. These should not appear in source code comments.

🤖 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/src/control-api/operations/apply-aggregate.ts`
around lines 91 - 95, Update the comment on the readonly property perSpace
(typed as AggregatePerSpaceExecutionEntry[]) to remove the transient artifact
references "M6 AC4 / AC5"; replace them with a short, stable descriptive phrase
(for example "markers populated per acceptance criteria" or simply remove the
parenthetical entirely) so the comment contains no milestone/AC IDs while still
conveying that markers are populated for each space.
packages/1-framework/3-tooling/cli/src/control-api/types.ts (2)

529-541: ⚡ Quick win

Remove sub-spec section reference from JSDoc.

The comment references "Sub-spec § migration apply semantics + § Required changes 1" — this is a transient project artifact. Describe the behavior directly instead.

♻️ Suggested fix
 /**
  * Options for the aggregate-walking `migrationApply` operation.
  *
  * The control-api operation is responsible for: loading the
  * contract-space aggregate, reading per-space marker rows from the
  * live database, plotting per-space paths via `graphWalkStrategy`
  * (replay-only — no synth, no introspection), and dispatching
  * through the shared `applyAggregate` primitive. The CLI command
  * just resolves the descriptor surface (config, refs, contract
  * envelope, app-space migration packages) and hands the inputs in.
- *
- * Sub-spec § `migration apply` semantics + § Required changes 1.
  */
🤖 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/src/control-api/types.ts` around lines 529
- 541, The JSDoc for the migrationApply operation currently includes a transient
project reference "Sub-spec § `migration apply` semantics + § Required changes
1"; update the comment for the migrationApply options by removing that sub-spec
reference and replacing it with a concise plain-language description of the
behavior and responsibilities (load contract-space aggregate, read per-space
marker rows, plot per-space paths via graphWalkStrategy in replay-only mode, and
dispatch via applyAggregate) so the docs are self-contained and do not reference
internal artifacts; locate the block around the migrationApply/options JSDoc in
types.ts and edit the comment text accordingly.

312-323: ⚡ Quick win

Remove sub-spec section references from JSDoc.

The comment references "M6 sub-spec § Output shape contract" and "F4 / F7 from e2e-verification.md" — these are transient project artifacts that should not appear in source comments. Describe the constraint or behavior itself instead.

♻️ Suggested fix
 /**
  * Per-space breakdown of an aggregate plan / apply.
  *
  * Surfaces the canonical schedule shape — extensions alphabetically,
  * then app — together with the operations attributed to each space and,
  * when the run was applied, the resulting per-space marker hash.
- *
- * M6 sub-spec § Output shape contract — every space involved in a run
- * is observable in the success summary, including its post-apply
- * marker, so the per-space invariant is visible to the user (closing
- * F4 / F7 from `e2e-verification.md`).
+ *
+ * Every space involved in a run is observable in the success summary,
+ * including its post-apply marker, so the per-space invariant is
+ * visible to the user.
  */
🤖 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/src/control-api/types.ts` around lines 312
- 323, Remove the transient project references in the JSDoc block that begins
"Per-space breakdown of an aggregate plan / apply" and replace the "M6 sub-spec
§ Output shape contract — ... F4 / F7" sentence with a plain description of the
behavior: state that the success summary includes every space involved in a run,
lists extensions (alphabetically) then app, and includes each space's post-apply
marker hash so the per-space invariant is observable to the user.
packages/1-framework/3-tooling/migration/src/exports/aggregate.ts (1)

21-25: ⚡ Quick win

Verify the new edge-ref type is exported from the public aggregate surface.

AggregatePerSpacePlan now carries migrationEdges, but this export list still doesn't surface AggregateMigrationEdgeRef. If consumers are meant to import the new edge metadata from @prisma-next/migration-tools/aggregate, add it here alongside the other planner types.

Based on learnings: in packages with a src/exports directory, treat files there as explicit public API export surfaces.

🤖 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/migration/src/exports/aggregate.ts` around
lines 21 - 25, The public aggregate export surface is missing the new edge-ref
type; add an export for type AggregateMigrationEdgeRef (so consumers can import
the migrationEdges metadata referenced on AggregatePerSpacePlan) to the
aggregate exports list — e.g. export { type AggregateMigrationEdgeRef } from the
module that defines it (referencing AggregatePerSpacePlan and
AggregateMigrationEdgeRef to locate the declarations) alongside the existing
graph-walk exports.
🤖 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-plan.ts`:
- Around line 67-79: The plan result currently only exposes emittedExtensionDirs
and thus misses seed-phase updates that rewrite files without creating dirs;
update the plan result type/return in migration-plan.ts (where
emittedExtensionDirs is declared) to also include either the full seeded update
records or at minimum an array like seededExtensionUpdates: readonly { spaceId:
string; action: 'created' | 'updated' | 'skipped' }[]; ensure the code that
computes newMigrationDirs / seed-phase work populates this new
seededExtensionUpdates (and keep emittedExtensionDirs derived/flattened from it)
so JSON/no-op callers can detect non-directory mutations.
- Around line 290-299: Replace the ad-hoc familyInstanceForValidate created from
{} and any with the real family instance from the actual control stack: call
createControlStack(config) before invoking buildContractSpaceAggregate, grab the
family instance produced by that control stack (instead of calling
config.family.create({} as any)), and pass a validateContract wrapper that calls
that realInstance.validateContract; this ensures the driver parameter is
provided to ControlFamilyDescriptor.create() and removes the use of any.

In `@packages/1-framework/3-tooling/cli/src/commands/migration-show.ts`:
- Around line 315-323: The loop over aggregate.extensions currently skips
extensions whose on-disk directory is empty (when resolveLatestFromDir returns
value === null), which silently hides missing seeds/materializations; instead,
when extPkgResult.ok is true but extPkgResult.value === null, push an explicit
placeholder or error entry into spaces so the result reflects the loaded
extension even if nothing is on disk. Modify the branch inside the loop that
checks extPkgResult.value: if null, call or construct a placeholder space result
(include ext.spaceId, a marker like "missing-on-disk" or an error message, and
the client) and push it onto spaces; keep the existing behavior for
extPkgResult.ok === false (return extPkgResult) and continue to use
pkgToSpaceResult for non-null values.
- Around line 229-255: The code instantiates the family with a bogus empty
object (familyInstanceForValidate = config.family.create({} as any)), bypassing
the control-plane stack; replace that with a proper ControlStack built from the
existing config: call createControlStack(config) and use the resulting stack to
create the family instance (e.g., const stack = createControlStack(config);
const familyInstanceForValidate = stack.family.create(...)) so you no longer
pass {} as any or need the biome-ignore any suppressions, and keep
validateContract using familyInstanceForValidate.validateContract as before.

In `@packages/1-framework/3-tooling/cli/src/commands/migration-status.ts`:
- Around line 740-750: The current validateContract helper creates a family with
config.family.create({} as any), which bypasses create-time requirements (like
driver) and can hide errors; change validateContract to accept or receive an
existing family/validator instance instead of constructing one here, remove the
ad-hoc config.family.create({} as any) call, and thread the provided
family/validator through to call familyInstance.validateContract(json). Ensure
callers of validateContract pass a family created with the required driver
parameter (i.e., use ControlFamilyDescriptor.create(driver, ...) or the existing
family/validator already available in the command pipeline) so family
construction never uses an empty object and validation errors surface correctly.
- Around line 707-717: Currently any exception from client.readAllMarkers() is
swallowed and treated as "markers unknown"; change this to only fallback when
the method truly doesn't exist. Before calling, check that client.readAllMarkers
is a function (e.g., typeof client.readAllMarkers === 'function'); if it's
absent set allMarkers = null and skip the call, otherwise call await
client.readAllMarkers() and allow real runtime/query errors to propagate (do not
catch them and convert to null). Reference client.readAllMarkers and the
allMarkers variable when making this change.
- Around line 489-499: pendingCount is incorrectly counting operations via
walked.result.plan.operations.length (inflating counts when a migration has many
ops and missing zero-op migrations); update the logic in the migration-status
computation (where pendingCount is set, referencing pendingCount,
walked.result.plan.operations, graphWalkStrategy, liveMarker, and
MigrationStatusSpaceEntry['status']) to count pending migrations instead of
operations — e.g., derive pendingCount from the plan's migration entries (or
count distinct migration identifiers referenced by operations) so each authored
migration counts once and zero-op migrations are still reported as pending when
appropriate.

In
`@packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts`:
- Around line 185-188: The fallback for "no marker" uses '' which differs from
the empty-hash sentinel used by graphWalkStrategy and can drop the structural
path; change the line that computes fromHash (currently using
liveMarker?.storageHash ?? '') to use the same empty-hash sentinel constant used
by graphWalkStrategy (e.g., EMPTY_CONTRACT_HASH or the project’s EMPTY_HASH
constant) so findPathWithDecision is called with the correct sentinel; update
imports or references as needed and keep the rest (structural,
findPathWithDecision, MIGRATION.NO_INVARIANT_PATH) unchanged.

In `@packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts`:
- Around line 76-81: Replace the transient M6/F1/F4/F7 references with a direct
description of the formatter contract: state that this formatter produces a
per-space execution breakdown as an array of AggregatePerSpaceExecutionEntry
items, emitted in canonical schedule order (extensions listed alphabetically,
followed by the app), and that each entry contains per-space markers plus
operations grouped by space; ensure the comment names
AggregatePerSpaceExecutionEntry so readers can find the type definition.

In `@packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts`:
- Around line 460-499: The test "renders per-space section headings when
multiple spaces are present" currently only asserts presence of headings and dir
names; update it to assert ordering by checking the positions in the stripped
output produced by formatMigrationShowOutput: compute stripped.indexOf('── app
──') and stripped.indexOf('── cipherstash ──') (and/or the dir names
'20260101_100000_app_init' and '0000000001-init') and add assertions that the
app indices are less than the cipherstash indices so the test fails if the
sections render in the wrong order.

In `@packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts`:
- Around line 65-74: Test only asserts one perSpace entry shape, so a change
that reorders result.perSpace could slip through; update the test to explicitly
assert the canonical ordering of the full perSpace array by checking the
sequence of spaceId values on the actual MigrationApplyResult (e.g., read the
test's result.perSpace and assert result.perSpace.map(p => p.spaceId) equals the
expected array like ['pgvector', ...]) while keeping the existing per-entry
shape checks (the symbols to update are the test case that builds `entry:
MigrationApplyResult['perSpace'][number]`, the `expect(Object.keys(entry)...`
assertions, and whatever variable holds the full `result.perSpace` in this test
file).

In `@packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts`:
- Around line 22-24: The comment above the test expectation still references
transient planning artifacts like "M6 sub-spec § Output shape § footer" and must
be replaced with a stable, behavior-centric description; update the comment that
precedes the assertion on expect(stripped).toContain('Next: prisma-next
migration status') (and the other comments around lines covering the similar
block at 57-65) to simply state the observable behavior being asserted — e.g.,
"No-op apply still includes the canonical next-step hint so users know where to
verify state" — and remove any "M6", "AC*" or sub-spec references.

In `@packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts`:
- Line 153: The test description contains transient artifact references ("AC7"
and "pre-M6"); update the describe block titled "operation labels (AC7 —
first-time-user-readable)" and any related inline comments to remove
milestone/acceptance IDs and instead state the behavior being validated (e.g.,
"operation labels — first-time-user readable" or "operation labels are
human-readable for first-time users"); locate and edit the describe(...) string
and nearby comments in the cipherstash-codec.test.ts test (the describe block
starting with "operation labels (AC7 — first-time-user-readable)") and change
the text and comments to describe the constraint/behavior without referencing
transient artifacts.

---

Outside diff comments:
In
`@packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts`:
- Around line 130-140: The orphan-marker preflight (call to detectOrphanMarkers
using aggregate and markerRows that sets orphanMarkerError and throws it) should
only run when performing an apply, not during plan/dry-run; move or
conditionally execute the detectOrphanMarkers check so it is skipped when mode
=== 'plan' (or when a dry-run flag is set) to avoid failing db init/update
--dry-run while still preserving the check for actual apply operations.

---

Nitpick comments:
In
`@packages/1-framework/3-tooling/cli/src/control-api/operations/apply-aggregate.ts`:
- Around line 91-95: Update the comment on the readonly property perSpace (typed
as AggregatePerSpaceExecutionEntry[]) to remove the transient artifact
references "M6 AC4 / AC5"; replace them with a short, stable descriptive phrase
(for example "markers populated per acceptance criteria" or simply remove the
parenthetical entirely) so the comment contains no milestone/AC IDs while still
conveying that markers are populated for each space.

In `@packages/1-framework/3-tooling/cli/src/control-api/types.ts`:
- Around line 529-541: The JSDoc for the migrationApply operation currently
includes a transient project reference "Sub-spec § `migration apply` semantics +
§ Required changes 1"; update the comment for the migrationApply options by
removing that sub-spec reference and replacing it with a concise plain-language
description of the behavior and responsibilities (load contract-space aggregate,
read per-space marker rows, plot per-space paths via graphWalkStrategy in
replay-only mode, and dispatch via applyAggregate) so the docs are
self-contained and do not reference internal artifacts; locate the block around
the migrationApply/options JSDoc in types.ts and edit the comment text
accordingly.
- Around line 312-323: Remove the transient project references in the JSDoc
block that begins "Per-space breakdown of an aggregate plan / apply" and replace
the "M6 sub-spec § Output shape contract — ... F4 / F7" sentence with a plain
description of the behavior: state that the success summary includes every space
involved in a run, lists extensions (alphabetically) then app, and includes each
space's post-apply marker hash so the per-space invariant is observable to the
user.

In `@packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts`:
- Around line 186-200: The placeholder generator buildPlaceholderContractDts
currently emits a leading "// `@ts-nocheck`" which weakens TypeScript guarantees;
remove that entry from the returned array so the function no longer includes the
`@ts-nocheck` directive (leave the rest of the JSDoc, export {}, and formatting
intact so the string join still produces the same output minus the ts-nocheck
line).

In `@packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts`:
- Around line 142-152: The function toDeclaredExtensionsFromRaw currently checks
`'contractSpace' in (raw as object)` which matches inherited properties; change
that check to use Object.hasOwn(raw as object, 'contractSpace') so only own
properties are detected, leaving the rest of the logic (casting to `{ readonly
id: string; readonly targetId: string }` and pushing to DeclaredExtensionEntry)
unchanged; update the conditional in the loop over extensionPacks inside
toDeclaredExtensionsFromRaw accordingly.

In `@packages/1-framework/3-tooling/migration/src/exports/aggregate.ts`:
- Around line 21-25: The public aggregate export surface is missing the new
edge-ref type; add an export for type AggregateMigrationEdgeRef (so consumers
can import the migrationEdges metadata referenced on AggregatePerSpacePlan) to
the aggregate exports list — e.g. export { type AggregateMigrationEdgeRef } from
the module that defines it (referencing AggregatePerSpacePlan and
AggregateMigrationEdgeRef to locate the declarations) alongside the existing
graph-walk exports.

In `@test/integration/test/cli.db-update.e2e.test.ts`:
- Around line 311-313: Remove the transient milestone/task IDs ("M6 T6.5/T6.6")
from the test comment and replace them with a short description of the behavior
change: that the old "Signature:" label was renamed to a per-space "marker:"
(and to "App-space marker:" when using the single-space fallback). Update the
comment surrounding expect(applyOutput).toMatch(/marker:/) to reflect that
behavior change (mention "Signature: renamed to per-space marker / App-space
marker fallback") and delete any numeric milestone/task references.
🪄 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: 1bfc8532-0e63-4dd4-b656-ef3d165fdfcb

📥 Commits

Reviewing files that changed from the base of the PR and between f39a42c and b30f49a.

⛔ Files ignored due to path filters (3)
  • projects/extension-contract-spaces/plan.md is excluded by !projects/**
  • projects/extension-contract-spaces/specs/migration-cli-aggregate.spec.md is excluded by !projects/**
  • projects/extension-contract-spaces/specs/migration-plan-show-aggregate.spec.md is excluded by !projects/**
📒 Files selected for processing (50)
  • packages/1-framework/1-core/framework-components/src/control/control-capabilities.ts
  • packages/1-framework/1-core/framework-components/src/control/control-migration-types.ts
  • packages/1-framework/3-tooling/cli/src/commands/db-init.ts
  • packages/1-framework/3-tooling/cli/src/commands/db-update.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-apply.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/control-api/client.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-invariants.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/client.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/db-update.test.ts
  • packages/1-framework/3-tooling/cli/test/output.db-update.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner-types.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/strategies/graph-walk.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/2-mongo-family/9-family/src/core/mongo-target-descriptor.ts
  • packages/3-extensions/cipherstash/src/core/cipherstash-codec.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
  • test/integration/test/cli.db-init.contract-space-verifier.test.ts
  • test/integration/test/cli.db-update.e2e.test.ts
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • test/integration/test/cli.loader.drift.test.ts
💤 Files with no reviewable changes (9)
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • test/integration/test/cli.loader.drift.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/client.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts

Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts Outdated
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-show.ts Outdated
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
Comment thread packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
Comment thread packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts Outdated
@wmadden wmadden force-pushed the tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot branch from b30f49a to 2789c80 Compare May 12, 2026 03:42
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 12, 2026

Open in StackBlitz

@prisma-next/mongo-runtime

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

@prisma-next/family-mongo

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

@prisma-next/sql-runtime

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

@prisma-next/family-sql

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

@prisma-next/extension-arktype-json

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

@prisma-next/extension-cipherstash

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

@prisma-next/middleware-telemetry

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

@prisma-next/mongo

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

@prisma-next/extension-paradedb

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

@prisma-next/extension-pgvector

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

@prisma-next/postgres

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

@prisma-next/sql-orm-client

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

@prisma-next/sqlite

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

@prisma-next/target-mongo

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

@prisma-next/adapter-mongo

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

@prisma-next/driver-mongo

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

@prisma-next/contract

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

@prisma-next/utils

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

@prisma-next/config

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

@prisma-next/errors

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

@prisma-next/framework-components

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

@prisma-next/operations

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

@prisma-next/ts-render

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

@prisma-next/contract-authoring

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

@prisma-next/ids

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

@prisma-next/psl-parser

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

@prisma-next/psl-printer

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

@prisma-next/cli

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

@prisma-next/emitter

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

@prisma-next/migration-tools

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

prisma-next

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

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

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

@prisma-next/mongo-codec

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

@prisma-next/mongo-contract

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

@prisma-next/mongo-value

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

@prisma-next/mongo-contract-psl

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

@prisma-next/mongo-contract-ts

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

@prisma-next/mongo-emitter

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

@prisma-next/mongo-schema-ir

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

@prisma-next/mongo-query-ast

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

@prisma-next/mongo-orm

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

@prisma-next/mongo-query-builder

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

@prisma-next/mongo-lowering

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

@prisma-next/mongo-wire

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

@prisma-next/sql-contract

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

@prisma-next/sql-errors

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

@prisma-next/sql-operations

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

@prisma-next/sql-schema-ir

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

@prisma-next/sql-contract-psl

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

@prisma-next/sql-contract-ts

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

@prisma-next/sql-contract-emitter

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

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

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

@prisma-next/sql-relational-core

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

@prisma-next/sql-builder

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

@prisma-next/target-postgres

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

@prisma-next/target-sqlite

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

@prisma-next/adapter-postgres

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

@prisma-next/adapter-sqlite

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

@prisma-next/driver-postgres

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

@prisma-next/driver-sqlite

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

commit: 7a8abe4

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/1-framework/3-tooling/cli/src/commands/migration-show.ts (1)

246-255: 💤 Low value

Use ifDefined() for conditional object spread.

Line 253 uses an inline conditional spread pattern. Per coding guidelines, prefer ifDefined() from @prisma-next/utils/defined for these cases.

♻️ Suggested refactor
+import { ifDefined } from '@prisma-next/utils/defined';
+
 // ...
 
   const client = createControlClient({
     family: config.family,
     target: config.target,
     adapter: config.adapter,
-    ...(config.driver ? { driver: config.driver } : {}),
+    ...ifDefined('driver', config.driver),
     extensionPacks: config.extensionPacks ?? [],
   });

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 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/src/commands/migration-show.ts` around
lines 246 - 255, Replace the inline conditional spread for driver with
ifDefined: import ifDefined from '@prisma-next/utils/defined' and change the
object spread inside createControlClient to use ...ifDefined({ driver:
config.driver }) instead of ...(config.driver ? { driver: config.driver } : {}),
leaving other properties (family, target, adapter, extensionPacks) unchanged;
ensure the new import is added at the top of the file.
🤖 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/utils/extension-pack-inputs.ts`:
- Around line 141-149: The check using "'contractSpace' in (raw as object)" in
toDeclaredExtensionsFromRaw can throw for null or primitive values; update the
loop to first guard that raw is a non-null object (e.g. typeof raw === 'object'
&& raw !== null) before using the in operator, then narrow/cast to the expected
shape (pack with id and targetId) and only push when those properties exist;
this fixes the TypeError when extensionPacks contains nulls/primitives while
keeping the existing push semantics in toDeclaredExtensionsFromRaw.

---

Nitpick comments:
In `@packages/1-framework/3-tooling/cli/src/commands/migration-show.ts`:
- Around line 246-255: Replace the inline conditional spread for driver with
ifDefined: import ifDefined from '@prisma-next/utils/defined' and change the
object spread inside createControlClient to use ...ifDefined({ driver:
config.driver }) instead of ...(config.driver ? { driver: config.driver } : {}),
leaving other properties (family, target, adapter, extensionPacks) unchanged;
ensure the new import is added at the top of the file.
🪄 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: 02b00545-1707-456e-b7d6-7d6a2a9291bd

📥 Commits

Reviewing files that changed from the base of the PR and between b30f49a and 2789c80.

📒 Files selected for processing (22)
  • 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/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
💤 Files with no reviewable changes (8)
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts

Comment thread packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts Outdated
@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented May 12, 2026

Addressed the nitpicks from the CodeRabbit review (#482 (review)):

  • A14a Gated orphan-marker preflight to apply mode in db-apply-aggregate.ts so db init/update --dry-run can still inspect the aggregate plan when a retired space has an orphan marker. → 0063b73
  • A14b No M6 T6.5/T6.6 references found in cli.db-update.e2e.test.ts (already clean) — no-op.
  • A14c Switched 'contractSpace' in raw to Object.hasOwn(raw, 'contractSpace') in extension-pack-inputs.ts. → 0063b73
  • A14d Dropped @ts-nocheck from placeholder .d.ts emitted by contract-space-seed-phase.ts; refreshed the cipherstash example mirror and updated the seed-phase test. → 0063b73
  • A14e apply-aggregate.ts perSpace JSDoc already free of M6/AC* references (already clean) — no-op.
  • A14f / A14g Stripped sub-spec / M6 / F4 / F7 references from the migrationApply options + per-space breakdown JSDoc in control-api/types.ts. → ffed10c
  • A14h Re-exported AggregateMigrationEdgeRef from @prisma-next/migration-tools/aggregate. → 0063b73

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

🤖 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-show.ts`:
- Around line 140-145: The code treats a non-null result from readMigrationsDir
followed by findLatestMigration(graph) === null as "no package" and returns
ok(null); instead treat this as data corruption and return a failure: replace
the check in migration-show.ts (around readMigrationsDir, reconstructGraph,
findLatestMigration) so that when allPackages.length > 0 and
findLatestMigration(graph) returns null you return an error result (or throw)
with a clear message about a corrupted/invalid migration graph rather than
ok(null), so callers don’t collapse the broken history into kind: 'missing'.
- Around line 279-280: The branch that accepts path-like targets (the if block
using looksLikePath(target) and readMigrationPackage(resolve(target))) should
validate that the resolved path is inside the application migrations directory
before proceeding; modify the logic in migration-show.ts so after computing
resolved = resolve(target) you check it is a descendant of the app migrations
root (use the same migration dir computation used elsewhere in this file/module)
and reject (throw an error or return a clear message) if it is not, rather than
loading it and emitting aggregate.app.spaceId; ensure the check is applied to
the path branch that calls readMigrationPackage to prevent accidentally treating
extension-space package paths as app-space results.
🪄 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: 4629ed7d-62d4-425a-9f14-e8294aeb93b1

📥 Commits

Reviewing files that changed from the base of the PR and between ffed10c and 9cba4a1.

📒 Files selected for processing (1)
  • packages/1-framework/3-tooling/cli/src/commands/migration-show.ts

Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-show.ts Outdated
@wmadden wmadden force-pushed the tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot branch from 9cba4a1 to 2ee0412 Compare May 12, 2026 04:23
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.

♻️ Duplicate comments (1)
packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts (1)

9-12: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the OQ-4 planning artifact from these comments.

Lines 9-12 and 25-26 still embed spec OQ-4, which is the same transient-comment issue already cleaned up elsewhere in this file. Please describe the byte-identity behavior directly and drop the artifact ID.

✏️ Suggested wording
- * preview block. SQL statements get a trailing `;` if missing — matches the
- * legacy `string[]`-based renderer byte-for-byte (per spec OQ-4). Other
+ * preview block. SQL statements get a trailing `;` if missing — matching the
+ * legacy `string[]`-based renderer byte-for-byte. Other

- * legacy `DDL preview` label (preserves CLI byte-identity for SQL targets per
- * spec OQ-4); previews from any other family — or a mix that includes any
+ * legacy `DDL preview` label to preserve CLI byte-identity for SQL targets;
+ * previews from any other family — or a mix that includes any
As per coding guidelines, "Source-code comments must not reference transient project artifacts including: projects//... paths, milestone-task IDs, milestone-named acceptance criteria, and sub-spec section references."

Also applies to: 25-26

🤖 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/src/utils/formatters/migrations.ts` around
lines 9 - 12, Remove the transient artifact reference "OQ-4" from the comment
blocks that describe rendering a single statement of an OperationPreview and the
later related comment (mentions lines referencing the legacy renderer); instead
state the behavior directly — e.g. say SQL statements get a trailing ';' if
missing to match the legacy `string[]`-based renderer exactly (byte-for-byte),
and that other languages like 'mongodb-shell' render verbatim. Update the
comment text around the OperationPreview description and the subsequent note
(the one that also references the legacy renderer) to drop any OQ-4 ID and use
the explicit byte-identity phrasing.
🤖 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.

Duplicate comments:
In `@packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts`:
- Around line 9-12: Remove the transient artifact reference "OQ-4" from the
comment blocks that describe rendering a single statement of an OperationPreview
and the later related comment (mentions lines referencing the legacy renderer);
instead state the behavior directly — e.g. say SQL statements get a trailing ';'
if missing to match the legacy `string[]`-based renderer exactly
(byte-for-byte), and that other languages like 'mongodb-shell' render verbatim.
Update the comment text around the OperationPreview description and the
subsequent note (the one that also references the legacy renderer) to drop any
OQ-4 ID and use the explicit byte-identity phrasing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 20335559-540c-469f-858a-0b5129e9bd0a

📥 Commits

Reviewing files that changed from the base of the PR and between 9cba4a1 and 2ee0412.

⛔ Files ignored due to path filters (2)
  • projects/extension-contract-spaces/plan.md is excluded by !projects/**
  • projects/extension-contract-spaces/specs/migration-plan-show-aggregate.spec.md is excluded by !projects/**
📒 Files selected for processing (35)
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.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/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • test/integration/test/cli.loader.drift.test.ts
💤 Files with no reviewable changes (8)
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • test/integration/test/cli.loader.drift.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
✅ Files skipped from review due to trivial changes (10)
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts

@wmadden wmadden force-pushed the tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot branch 2 times, most recently from 8bd449a to 9a36495 Compare May 12, 2026 06:31
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)
packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts (1)

30-36: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clean up the temp directories these tests create.

createTempDir() now backs several new tests, but nothing removes the directories afterward. That leaves real state behind between runs.

Suggested fix
-import { mkdir } from 'node:fs/promises';
+import { mkdir, rm } from 'node:fs/promises';
...
-import { describe, expect, it } from 'vitest';
+import { afterEach, describe, expect, it } from 'vitest';
...
+const tempDirs = new Set<string>();
+
 async function createTempDir(prefix: string): Promise<string> {
   const dir = join(
     tmpdir(),
     `test-migration-show-${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`,
   );
   await mkdir(dir, { recursive: true });
+  tempDirs.add(dir);
   return dir;
 }
+
+afterEach(async () => {
+  await Promise.all(
+    [...tempDirs].map((dir) => rm(dir, { recursive: true, force: true })),
+  );
+  tempDirs.clear();
+});

As per coding guidelines, packages/1-framework/3-tooling/cli/**: “Tests must clean up their own ephemeral directories.”

🤖 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-show.test.ts`
around lines 30 - 36, The tests create temporary directories via createTempDir
(which uses mkdir) but never remove them; update the test suite to track each
created path and remove them in an afterEach or afterAll hook (use fs.rm or
rimraf with recursive: true / force: true) or change createTempDir to return a
cleanup function; ensure cleanup runs even on failures by registering it in the
test framework hooks and reference createTempDir when locating where to capture
and delete the directories.
🤖 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-show.ts`:
- Around line 115-119: The containment guard misidentifies cross-drive targets
because relative(appMigrationsDir, targetPath) can return an absolute path on
Windows; update the check that computes isOutsideAppDir (which currently uses
targetPath, relativeToApp, appMigrationsDir) to also reject absolute
relativeToApp values by calling path.isAbsolute(relativeToApp) (or isAbsolute on
the imported path module) so that any absolute path returned by relative is
treated as outside the app dir; keep the existing checks ('' | '.' |
startsWith('..')) and add the isAbsolute check to the OR chain.

---

Outside diff comments:
In `@packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts`:
- Around line 30-36: The tests create temporary directories via createTempDir
(which uses mkdir) but never remove them; update the test suite to track each
created path and remove them in an afterEach or afterAll hook (use fs.rm or
rimraf with recursive: true / force: true) or change createTempDir to return a
cleanup function; ensure cleanup runs even on failures by registering it in the
test framework hooks and reference createTempDir when locating where to capture
and delete the directories.
🪄 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: 69231072-3590-4b34-835e-97bbc74af202

📥 Commits

Reviewing files that changed from the base of the PR and between 9cba4a1 and 229c06e.

📒 Files selected for processing (35)
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.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/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • test/integration/test/cli.loader.drift.test.ts
💤 Files with no reviewable changes (8)
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • test/integration/test/cli.loader.drift.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
✅ Files skipped from review due to trivial changes (7)
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
🚧 Files skipped from review as they are similar to previous changes (17)
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts

Comment thread packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented May 12, 2026

Done — A21a addressed in a3c3bfe (migration-show.test.ts temp dirs tracked in a module-level list and removed in a suite-wide afterEach via rm({ recursive: true, force: true }), so cleanup runs even on failures). A20 (Windows containment guard) is addressed in 8710416. Both findings from this review are now resolved on the branch.

wmadden added 16 commits May 12, 2026 10:18
Adds `runContractSpaceSeedPhase` — the new phase-1 helper for the
two-phase `migration plan` pipeline (sub-spec § 4 of M6.5,
extension-contract-spaces). For every extension that exposes a
`contractSpace` it:

  1. reads the on-disk head ref
  2. unconditionally re-emits `contract.json`, `contract.d.ts`, and
     `refs/head.json` via `emitContractSpaceArtefacts`
  3. materialises every descriptor-shipped migration package not yet
     present on disk via `materialiseExtensionMigrationPackageIfMissing`

The return value enumerates per-space records (`updated` vs
`unchanged`, prior/new hash, newly-materialised migration directory
names) so the caller can render a single status line per touched
extension and so phase-2 can run on a now-consistent disk state.

Output ordering is alphabetical via `planAllSpaces`, matching the
canonical sort used by every other aggregate surface and surfacing
duplicate-spaceId failures before any write.

Composes existing primitives only — no new I/O surface.

Refs: TML-2457 (M6.5 / T6.5.1)
Signed-off-by: Will Madden <madden@prisma.io>
… (T6.5.2)

Drift previously fired only at apply/verify time on a descriptor field
the loader is forbidden to consult (NFR3 / AC15). The remaining call
sites pass the descriptor in just so the loader can hash it and
compare to the on-disk pin — purely informational, never load-bearing,
and structurally dead code once `migration plan` writes the pin.

This commit deletes the surface end-to-end:

- `detectSpaceContractDrift` + `SpaceContractDriftResult` (and unit
  tests) gone from `@prisma-next/migration-tools`.
- `LoadAggregateError.driftViolation` gone from the aggregate loader,
  along with the per-entry hash callback (`hashContract`) and the
  `contractSpace` field on `DeclaredExtensionEntry`.
- Loader layout precheck now treats every declared entry as
  contract-space-bearing; the CLI wrapper filters codec-only
  extensions out of `toDeclaredExtensions` to match.
- `formatContractSpaceDriftWarning` + the `drifts` channel gone from
  `runContractSpaceMigratePass` (left in place as an unconditional
  re-emit; T6.5.3 will retire the helper itself).
- `migration plan` no longer renders drift warnings.
- Integration test `cli.loader.drift.test.ts` deleted.
- Updated remaining loader / deletable-node_modules / extension-pack
  tests to match the simplified shape.

Locks AC4 (zero source matches for the four drift symbols under
`packages/`) and AC5 (`DeclaredExtensionEntry.contractSpace` field is
gone). The loader is now strictly free of descriptor `contractJson`
access at apply / verify time, tightening AC15 / NFR3 from "verify
does not require the descriptor" to "verify never reads the
descriptor hash."

Signed-off-by: Will Madden <madden@prisma.io>
… in migration plan (T6.5.3)

- Replace runContractSpaceMigratePass + runContractSpaceExtensionMigrationsPass with
  a single runContractSpaceSeedPhase call (phase 1).
- After the no-op check, load the ContractSpaceAggregate via buildContractSpaceAggregate
  (phase 2) and invoke the planner against aggregate.app instead of APP_SPACE_ID literal.
- Delete contract-space-migrate-pass.ts and contract-space-extension-migrations-pass.ts
  (and their tests) — no remaining callers.
- Remove toMigratePassInputs and toExtensionMigrationsInputs from extension-pack-inputs.ts.
- Update migration-plan-command.test.ts to include target field in contract JSON so the
  real aggregate loader passes the target-consistency check without a module-level mock.

Signed-off-by: Will Madden <madden@prisma.io>
Load ContractSpaceAggregate and iterate app + extension spaces so every
space's latest migration is shown. Adds per-space section headings when
multiple spaces are present, matching migration status's style.

Deleted the APP_SPACE_ID hard-code in migration-show.ts; the command now
relies on aggregate.app.spaceId and aggregate.extensions[*].spaceId for
all directory resolution.

Refs: TML-2457
Signed-off-by: Will Madden <madden@prisma.io>
… path (AC15)

buildContractSpaceAggregate previously called toExtensionInputs() which
reads pack.contractSpace.contractJson for every declared extension. The
aggregate loader only needs id + targetId to locate the on-disk directory;
the contract itself is always read from disk.

Introduce toDeclaredExtensionsFromRaw() in extension-pack-inputs.ts that
uses `'contractSpace' in pack` to detect contract-space membership
without invoking the property accessor, and wire it into
buildContractSpaceAggregate.

Add an AC15 regression test: an extension with a throwing contractSpace
getter passes through buildContractSpaceAggregate, returning a layout-
violation Result instead of a thrown exception.

Refs: TML-2457
Signed-off-by: Will Madden <madden@prisma.io>
…ce missing extension spaces

Lift `createControlStack(config)` / `family.create(stack)` to the
top of `migration plan` and `migration show`, then thread the same
typed `familyInstance` into `buildContractSpaceAggregate`. This drops
the `config.family.create({} as any)` workaround and all biome-ignore
suppressions around extensionPacks / validateContract — the validator
runs against a fully composed family instance (codec lookups etc. see
a consistent stack view), matching `migration status`.

In `migration show`, model per-space results as a discriminated union
(`kind: present` vs `kind: missing`). Extension spaces declared by an
aggregate but with no on-disk migration package now surface as
explicit `missing` placeholders instead of being silently skipped, so
JSON consumers enumerate every loaded extension. The formatter renders
a one-line placeholder for missing spaces.

Strengthen the multi-space heading test to assert app-before-extension
ordering (heading-index comparison), and add a missing-space test.

Signed-off-by: Will Madden <madden@prisma.io>
…; narrow readAllMarkers fallback

`pendingCount` for each space now uses `walked.result.migrationEdges.length`
instead of `plan.operations.length`. A single authored migration that
lowers to N ops (or zero ops) counts as exactly one unit of pending
work — the previous semantics conflated user-visible migrations with
their op decomposition and over-counted multi-op migrations.

The `readAllMarkers()` call site now probes
`typeof client.readAllMarkers === "function"` before invoking, so we
only swallow the unsupported-method case. Runtime / query errors from
a family that *does* expose the method propagate up instead of being
silently degraded to "markers unknown" status.

Tests pin both pending-count semantics (multi-op + zero-op) by mocking
`graphWalkStrategy` to return controlled edge/op counts.

Signed-off-by: Will Madden <madden@prisma.io>
`migration apply` recovers the structural path on `NO_INVARIANT_PATH`
by replaying the graph with no required invariants. When the live
marker is undefined (greenfield), the fallback used `""` as the from
hash, which is never a graph node — the structural lookup silently
returned no path and the error envelope lost its `structuralPath`
context.

Use `EMPTY_CONTRACT_HASH` instead, matching the sentinel `graphWalkStrategy`
uses for the same condition. Greenfield runs hitting an unsatisfiable
invariant set now surface the structural-path edges in the error
envelope, the same way non-greenfield runs do.

Signed-off-by: Will Madden <madden@prisma.io>
…rop @ts-nocheck, export edge-ref type

- `db init/update --dry-run` (mode === "plan") no longer fails on a
  lingering orphan marker: the preflight is now gated to `mode ===
  "apply"`. Users can introspect what an apply *would* do without
  having to clean up the orphan first; apply mode still refuses to
  silently advance the app marker around it.

- `toDeclaredExtensionsFromRaw` uses `Object.hasOwn(raw, "contractSpace")`
  instead of `"contractSpace" in raw`. The `in` operator walks the
  prototype chain and matches prototype getters; `Object.hasOwn`
  matches only own properties, so a descriptor that synthesises
  `contractSpace` via a prototype getter is correctly skipped here.

- Drop the `@ts-nocheck` directive from the placeholder
  `contract.d.ts` emitted by the seed phase. The placeholder is a
  self-contained `export {};` module that typechecks on its own; the
  repo bans `@ts-nocheck` outside negative type tests. Refresh the
  cipherstash-integration example mirror to match.

- Re-export `AggregateMigrationEdgeRef` from
  `@prisma-next/migration-tools/aggregate` so consumers (e.g. CLI
  status renderers) can name the `migrationEdges` payload that the
  graph-walk strategy attaches to each `AggregatePerSpacePlan`.

Signed-off-by: Will Madden <madden@prisma.io>
…n shape test

Strip references to transient project artefacts (milestone labels
like M6, acceptance-criteria ids like AC4/AC5/AC7, "sub-spec § …"
prose attribution, finding ids F4/F7) from source/test comments. The
behaviour each comment is describing — per-space markers visible in
the success summary, aggregate-driven perSpace breakdown, action-
first/column-first cipherstash operation labels — is unchanged; only
the descriptions are now self-contained.

Additionally pin the canonical `perSpace` ordering in the
`MigrationApplyResult` JSON-shape test: asserts
`perSpace.map(p => p.spaceId)` against `["pgvector", "app"]` so
accidentally sorting or reordering the array is caught alongside the
existing key-shape pin.

Signed-off-by: Will Madden <madden@prisma.io>
…on show

Matches the existing convention used in migration-apply, migration-status,
and contract-emit (per CodeRabbit nitpick).

Signed-off-by: Will Madden <madden@prisma.io>
… formatter

Strip the transient `spec OQ-4` references from the JSDoc on
`renderPreviewStatement` and `previewBlockHeader`. The comments now
describe the constraint directly: SQL statements get a trailing `;` so
the preview is byte-identical to the legacy renderer, and SQL-only
previews keep the legacy `DDL preview` label so the output stays
byte-identical to the pre-aggregate SQL CLI.

Signed-off-by: Will Madden <madden@prisma.io>
Two `migration show` paths used to swallow conditions that should be
runtime errors:

- `resolveLatestFromDir` collapsed a non-empty migrations directory
  whose `findLatestMigration(graph)` returned `null` into `ok(null)`,
  which the caller rendered as `kind: "missing"`. After
  `readMigrationsDir` returned packages, a null leaf is a corruption
  signal, not "no on-disk package". Return `notOk(errorRuntime(...))`
  naming the corrupted directory so the operator sees the broken
  history instead of a silent placeholder.

- The path-like-target branch resolved any path and emitted the result
  under `aggregate.app.spaceId`. Passing an extension-space package
  path (e.g. `migrations/cipherstash/0000000001-init`) produced a
  mislabeled app-space result. Extract `resolveAppTargetPath` and
  reject any target that does not resolve under `appMigrationsDir`,
  returning a clear "Target must point to an app-space migration"
  runtime error.

Both helpers are exported and covered by focused unit tests in
`migration-show.test.ts`, including a corrupted self-loop fixture and
an extension-space sibling path.

Signed-off-by: Will Madden <madden@prisma.io>
pathe.relative() can return an absolute path when the target cannot be expressed relative to the base (e.g. on Windows when the target is on a different drive). The previous guard only checked for "..", so a cross-drive target would slip through and be mislabeled as an app-space migration. Add isAbsolute(relativeToApp) to the rejection condition and a unit test covering the cross-drive case.

Signed-off-by: Will Madden <madden@prisma.io>
Tests in migration-show.test.ts used createTempDir() to mkdir under tmpdir() but never removed the directories, leaving real state behind between runs (violating the CLI guideline that tests must clean up their own ephemeral directories). Track every returned dir in a module-level list and remove them in a suite-wide afterEach with rm({ recursive: true, force: true }) so cleanup runs even on failures.

Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden force-pushed the tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot branch from a3c3bfe to efb161f Compare May 12, 2026 08:18
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)
packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts (1)

467-470: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove milestone/AC references from inline test comments.

Line 467 references transient artifacts (M6, T6.6, AC8), which violates the comment policy. Keep the behavior note, but drop planning IDs.

Suggested edit
-    // M6 (T6.6 / AC8): operationClass tags no longer inlined in the
-    // human-readable line. Destructive ops still render a "(destructive)"
-    // marker (replaces the old "[destructive]" tag); additive/widening/
-    // mutative/data render bare.
+    // Operation-class tags are no longer inlined in the human-readable line.
+    // Destructive ops still render a "(destructive)" marker (replacing the
+    // old "[destructive]" tag); additive/widening/mutative/data render bare.
As per coding guidelines: "Source-code comments must not reference transient project artifacts including ... milestone-task IDs ... [and] milestone-named acceptance criteria ..."
🤖 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-show.test.ts`
around lines 467 - 470, The inline test comment that begins "// M6 (T6.6 / AC8):
operationClass tags no longer inlined..." contains transient planning IDs; edit
that comment (in migration-show.test.ts near the test describing operationClass
rendering) to remove "M6 (T6.6 / AC8):" and any AC/task references while
preserving the behavior note about destructive ops rendering "(destructive)" and
additive/widening/mutative/data rendering bare; ensure the revised comment is
purely descriptive and contains no milestone/task/AC identifiers.
🤖 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/utils/extension-pack-inputs.ts`:
- Around line 149-151: The current check Object.hasOwn(raw, 'contractSpace')
will pass when contractSpace is an own key with value undefined, diverging from
toDeclaredExtensions behavior; update the guard in the block handling raw (the
same `raw` variable and the entries.push path) to require the key exists AND the
value is not undefined (e.g., Object.hasOwn(raw, 'contractSpace') && (raw as
any).contractSpace !== undefined) so only objects with a defined contractSpace
are accepted, matching toDeclaredExtensions semantics.

---

Outside diff comments:
In `@packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts`:
- Around line 467-470: The inline test comment that begins "// M6 (T6.6 / AC8):
operationClass tags no longer inlined..." contains transient planning IDs; edit
that comment (in migration-show.test.ts near the test describing operationClass
rendering) to remove "M6 (T6.6 / AC8):" and any AC/task references while
preserving the behavior note about destructive ops rendering "(destructive)" and
additive/widening/mutative/data rendering bare; ensure the revised comment is
purely descriptive and contains no milestone/task/AC identifiers.
🪄 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: 296d0dff-07f9-4990-b54e-da780db3e05d

📥 Commits

Reviewing files that changed from the base of the PR and between a3c3bfe and efb161f.

📒 Files selected for processing (35)
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.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/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts
  • packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-show.test.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/test/deletable-node-modules.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • test/integration/test/cli.loader.drift.test.ts
💤 Files with no reviewable changes (8)
  • packages/1-framework/3-tooling/migration/src/exports/spaces.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-extension-migrations-pass.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-migrate-pass.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-migrate-pass.test.ts
  • packages/1-framework/3-tooling/migration/test/detect-space-contract-drift.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-extension-migrations-pass.ts
  • packages/1-framework/3-tooling/migration/src/detect-space-contract-drift.ts
  • test/integration/test/cli.loader.drift.test.ts
✅ Files skipped from review due to trivial changes (9)
  • test/integration/test/cli.db-verify.aggregate-schema.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/cli/test/output.json-shapes.test.ts
  • packages/1-framework/3-tooling/cli/src/control-api/types.ts
  • packages/1-framework/3-tooling/cli/test/output.migration-commands.test.ts
  • packages/3-extensions/cipherstash/test/cipherstash-codec.test.ts
  • examples/cipherstash-integration/migrations/cipherstash/contract.d.ts
  • packages/1-framework/3-tooling/cli/test/utils/extension-pack-inputs.test.ts
  • packages/3-targets/6-adapters/sqlite/test/migrations/db-init-update.cli.test.ts
🚧 Files skipped from review as they are similar to previous changes (15)
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migration-apply.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-plan-command.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-status.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-seed-phase.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-plan.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/cli/test/commands/migration-status-aggregate-spaces.test.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-aggregate-loader.ts
  • packages/1-framework/3-tooling/cli/test/utils/contract-space-aggregate-loader.ac15.test.ts
  • packages/1-framework/3-tooling/cli/src/commands/migration-show.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/db-apply-aggregate.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/loader.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/loader.ts
  • packages/1-framework/3-tooling/cli/src/utils/formatters/migrations.ts
  • packages/1-framework/3-tooling/cli/src/utils/contract-space-seed-phase.ts

Comment thread packages/1-framework/3-tooling/cli/src/utils/extension-pack-inputs.ts Outdated
wmadden added 2 commits May 12, 2026 10:42
…pace semantics

Object.hasOwn(raw, "contractSpace") returned true even when the
property value was explicitly undefined, but the canonical
toDeclaredExtensions skips those (it checks pack.contractSpace ===
undefined). The descriptor-based check now mirrors that: an
explicit-undefined data property is treated as "no contract-space
declaration". Getter-backed contractSpace declarations stay included
without invoking the accessor, preserving the AC15 contract.

Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden wmadden merged commit 555aaf7 into main May 12, 2026
17 checks passed
@wmadden wmadden deleted the tml-2457-reduce-app_space_id-coupling-route-through-aggregate-slot branch May 12, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant