@prisma-next/cli 0.14.0 → 0.15.0-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +33 -14
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-CJzuo5wX.mjs → client-DwOyZz0a.mjs} +141 -123
  5. package/dist/client-DwOyZz0a.mjs.map +1 -0
  6. package/dist/{command-helpers-DGMvGBeX.mjs → command-helpers-CNwURRf9.mjs} +30 -11
  7. package/dist/command-helpers-CNwURRf9.mjs.map +1 -0
  8. package/dist/commands/contract-emit.mjs +1 -1
  9. package/dist/commands/contract-infer.mjs +1 -1
  10. package/dist/commands/db-init.mjs +3 -3
  11. package/dist/commands/db-schema.mjs +3 -3
  12. package/dist/commands/db-sign.mjs +5 -5
  13. package/dist/commands/db-sign.mjs.map +1 -1
  14. package/dist/commands/db-update.mjs +4 -4
  15. package/dist/commands/db-verify.d.mts.map +1 -1
  16. package/dist/commands/db-verify.mjs +1 -1
  17. package/dist/commands/migrate.d.mts +1 -1
  18. package/dist/commands/migrate.d.mts.map +1 -1
  19. package/dist/commands/migrate.mjs +37 -38
  20. package/dist/commands/migrate.mjs.map +1 -1
  21. package/dist/commands/migration-check.d.mts +1 -1
  22. package/dist/commands/migration-check.mjs +1 -1
  23. package/dist/commands/migration-graph.d.mts +1 -1
  24. package/dist/commands/migration-graph.mjs +9 -9
  25. package/dist/commands/migration-graph.mjs.map +1 -1
  26. package/dist/commands/migration-list.d.mts +6 -6
  27. package/dist/commands/migration-list.d.mts.map +1 -1
  28. package/dist/commands/migration-list.mjs +1 -1
  29. package/dist/commands/migration-log.d.mts +1 -1
  30. package/dist/commands/migration-log.mjs +1 -1
  31. package/dist/commands/migration-new.mjs +4 -4
  32. package/dist/commands/migration-new.mjs.map +1 -1
  33. package/dist/commands/migration-plan.d.mts.map +1 -1
  34. package/dist/commands/migration-plan.mjs +1 -1
  35. package/dist/commands/migration-show.mjs +4 -4
  36. package/dist/commands/migration-show.mjs.map +1 -1
  37. package/dist/commands/migration-status.d.mts +1 -1
  38. package/dist/commands/migration-status.mjs +1 -1
  39. package/dist/commands/ref.d.mts +1 -1
  40. package/dist/commands/ref.mjs +3 -3
  41. package/dist/commands/ref.mjs.map +1 -1
  42. package/dist/commands/telemetry/index.mjs +1 -1
  43. package/dist/{contract-at-errors-CFXsstzm.mjs → contract-at-errors-BHbY04pl.mjs} +2 -2
  44. package/dist/{contract-at-errors-CFXsstzm.mjs.map → contract-at-errors-BHbY04pl.mjs.map} +1 -1
  45. package/dist/{contract-emit-C8HmtboH.mjs → contract-emit-BeidkyUC.mjs} +9 -11
  46. package/dist/contract-emit-BeidkyUC.mjs.map +1 -0
  47. package/dist/{contract-emit-B_qriF8B.mjs → contract-emit-IQBYv351.mjs} +6 -6
  48. package/dist/contract-emit-IQBYv351.mjs.map +1 -0
  49. package/dist/{contract-infer-BYT_ra_U.mjs → contract-infer-B3Wq2cu1.mjs} +3 -3
  50. package/dist/{contract-infer-BYT_ra_U.mjs.map → contract-infer-B3Wq2cu1.mjs.map} +1 -1
  51. package/dist/{contract-space-aggregate-loader-ClI1KN6d.mjs → contract-space-aggregate-loader-BirzMmW1.mjs} +63 -5
  52. package/dist/contract-space-aggregate-loader-BirzMmW1.mjs.map +1 -0
  53. package/dist/{db-verify-C24FKhb7.mjs → db-verify-DpRrecs7.mjs} +57 -61
  54. package/dist/db-verify-DpRrecs7.mjs.map +1 -0
  55. package/dist/exports/control-api.d.mts +3 -3
  56. package/dist/exports/control-api.d.mts.map +1 -1
  57. package/dist/exports/control-api.mjs +2 -2
  58. package/dist/exports/index.d.mts +5 -1
  59. package/dist/exports/index.d.mts.map +1 -1
  60. package/dist/exports/index.mjs +4 -3
  61. package/dist/exports/index.mjs.map +1 -1
  62. package/dist/format-CaCF63ld.mjs +102 -0
  63. package/dist/format-CaCF63ld.mjs.map +1 -0
  64. package/dist/{framework-components-YVQHhPH7.mjs → framework-components-CnBcJDmF.mjs} +2 -2
  65. package/dist/{framework-components-YVQHhPH7.mjs.map → framework-components-CnBcJDmF.mjs.map} +1 -1
  66. package/dist/{init-0HwB-Vh8.mjs → init-Boa0LzeJ.mjs} +27 -19
  67. package/dist/init-Boa0LzeJ.mjs.map +1 -0
  68. package/dist/{inspect-live-schema-DF6IwcDl.mjs → inspect-live-schema-CldSQjVI.mjs} +4 -4
  69. package/dist/inspect-live-schema-CldSQjVI.mjs.map +1 -0
  70. package/dist/{migration-check-VwM8xCZV.mjs → migration-check-CGtYnR9k.mjs} +10 -11
  71. package/dist/migration-check-CGtYnR9k.mjs.map +1 -0
  72. package/dist/migration-cli.mjs +1 -1
  73. package/dist/migration-cli.mjs.map +1 -1
  74. package/dist/{migration-command-scaffold-DA-Lhx6o.mjs → migration-command-scaffold-B3m-MMAx.mjs} +4 -4
  75. package/dist/migration-command-scaffold-B3m-MMAx.mjs.map +1 -0
  76. package/dist/{migration-graph-command-render-CEez7YUK.mjs → migration-graph-command-render-B83xrnNy.mjs} +24 -24
  77. package/dist/{migration-graph-command-render-CEez7YUK.mjs.map → migration-graph-command-render-B83xrnNy.mjs.map} +1 -1
  78. package/dist/{migration-list-DlJJ_38Z.mjs → migration-list-DBU6Pneg.mjs} +16 -16
  79. package/dist/migration-list-DBU6Pneg.mjs.map +1 -0
  80. package/dist/{migration-log-CG0qQAFm.mjs → migration-log-BYngyvXa.mjs} +5 -5
  81. package/dist/migration-log-BYngyvXa.mjs.map +1 -0
  82. package/dist/{migration-path-target-Ce6OZImp.mjs → migration-path-target-DQa4Caoc.mjs} +2 -2
  83. package/dist/{migration-path-target-Ce6OZImp.mjs.map → migration-path-target-DQa4Caoc.mjs.map} +1 -1
  84. package/dist/{migration-plan-W_E8FQOk.mjs → migration-plan-D6bHpCzE.mjs} +30 -30
  85. package/dist/migration-plan-D6bHpCzE.mjs.map +1 -0
  86. package/dist/{migration-status-CD-LC2Ip.mjs → migration-status-CpQ5UhcU.mjs} +14 -14
  87. package/dist/migration-status-CpQ5UhcU.mjs.map +1 -0
  88. package/dist/{telemetry-BIM4beEO.mjs → telemetry-BQJ_XHa9.mjs} +2 -2
  89. package/dist/{telemetry-BIM4beEO.mjs.map → telemetry-BQJ_XHa9.mjs.map} +1 -1
  90. package/dist/{types-C_tYiJYx.d.mts → types-DFoqNIcQ.d.mts} +27 -21
  91. package/dist/types-DFoqNIcQ.d.mts.map +1 -0
  92. package/dist/{verify-DcOYZ1tH.mjs → verify-CInGyt4U.mjs} +58 -159
  93. package/dist/verify-CInGyt4U.mjs.map +1 -0
  94. package/package.json +28 -30
  95. package/src/cli.ts +7 -0
  96. package/src/commands/contract-emit.ts +1 -1
  97. package/src/commands/db-sign.ts +1 -1
  98. package/src/commands/db-verify.ts +34 -20
  99. package/src/commands/format.ts +75 -0
  100. package/src/commands/init/detect-package-manager.ts +8 -4
  101. package/src/commands/init/hygiene-package-scripts.ts +16 -3
  102. package/src/commands/inspect-live-schema.ts +1 -1
  103. package/src/commands/lsp.ts +32 -0
  104. package/src/commands/migrate.ts +47 -44
  105. package/src/commands/migration-check.ts +6 -6
  106. package/src/commands/migration-graph.ts +5 -5
  107. package/src/commands/migration-list.ts +13 -13
  108. package/src/commands/migration-log.ts +1 -1
  109. package/src/commands/migration-new.ts +1 -1
  110. package/src/commands/migration-plan.ts +15 -4
  111. package/src/commands/migration-show.ts +1 -1
  112. package/src/commands/migration-status.ts +10 -10
  113. package/src/commands/ref.ts +1 -1
  114. package/src/control-api/client.ts +8 -23
  115. package/src/control-api/operations/contract-emit.ts +9 -27
  116. package/src/control-api/operations/db-init.ts +2 -2
  117. package/src/control-api/operations/db-run.ts +18 -17
  118. package/src/control-api/operations/db-verify.ts +52 -44
  119. package/src/control-api/operations/format.ts +98 -0
  120. package/src/control-api/operations/migrate.ts +139 -95
  121. package/src/control-api/operations/run-migration.ts +6 -5
  122. package/src/control-api/types.ts +8 -8
  123. package/src/exports/index.ts +1 -0
  124. package/src/migration-cli.ts +1 -1
  125. package/src/utils/cli-errors.ts +14 -1
  126. package/src/utils/combine-verify-results.ts +94 -0
  127. package/src/utils/extension-pack-inputs.ts +1 -1
  128. package/src/utils/formatters/errors.ts +34 -5
  129. package/src/utils/formatters/verify.ts +89 -227
  130. package/src/utils/migration-command-scaffold.ts +1 -1
  131. package/src/utils/plan-resolution.ts +18 -18
  132. package/dist/client-CJzuo5wX.mjs.map +0 -1
  133. package/dist/command-helpers-DGMvGBeX.mjs.map +0 -1
  134. package/dist/config-loader-p9JMrekQ.mjs +0 -88
  135. package/dist/config-loader-p9JMrekQ.mjs.map +0 -1
  136. package/dist/config-loader.d.mts +0 -16
  137. package/dist/config-loader.d.mts.map +0 -1
  138. package/dist/config-loader.mjs +0 -2
  139. package/dist/contract-emit-B_qriF8B.mjs.map +0 -1
  140. package/dist/contract-emit-C8HmtboH.mjs.map +0 -1
  141. package/dist/contract-space-aggregate-loader-ClI1KN6d.mjs.map +0 -1
  142. package/dist/db-verify-C24FKhb7.mjs.map +0 -1
  143. package/dist/extension-pack-inputs-1ySHqxKG.mjs +0 -62
  144. package/dist/extension-pack-inputs-1ySHqxKG.mjs.map +0 -1
  145. package/dist/init-0HwB-Vh8.mjs.map +0 -1
  146. package/dist/inspect-live-schema-DF6IwcDl.mjs.map +0 -1
  147. package/dist/migration-check-VwM8xCZV.mjs.map +0 -1
  148. package/dist/migration-command-scaffold-DA-Lhx6o.mjs.map +0 -1
  149. package/dist/migration-list-DlJJ_38Z.mjs.map +0 -1
  150. package/dist/migration-log-CG0qQAFm.mjs.map +0 -1
  151. package/dist/migration-plan-W_E8FQOk.mjs.map +0 -1
  152. package/dist/migration-status-CD-LC2Ip.mjs.map +0 -1
  153. package/dist/types-C_tYiJYx.d.mts.map +0 -1
  154. package/dist/verify-DcOYZ1tH.mjs.map +0 -1
  155. package/src/config-loader.ts +0 -92
  156. package/src/config-path-validation.ts +0 -74
  157. package/src/utils/combine-schema-results.ts +0 -84
@@ -1,14 +1,13 @@
1
- import { F as CliStructuredError } from "./command-helpers-DGMvGBeX.mjs";
2
- import { n as toExtensionInputs } from "./extension-pack-inputs-1ySHqxKG.mjs";
3
- import { t as assertFrameworkComponentsCompatible } from "./framework-components-YVQHhPH7.mjs";
1
+ import { F as CliStructuredError } from "./command-helpers-CNwURRf9.mjs";
2
+ import { t as assertFrameworkComponentsCompatible } from "./framework-components-CnBcJDmF.mjs";
4
3
  import { t as enrichContract } from "./contract-enrichment-gn9sWbPw.mjs";
5
- import { t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-ClI1KN6d.mjs";
4
+ import { t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-BirzMmW1.mjs";
6
5
  import { emit } from "@prisma-next/emitter";
7
6
  import { ifDefined } from "@prisma-next/utils/defined";
8
7
  import { notOk, ok } from "@prisma-next/utils/result";
9
- import { APP_SPACE_ID, createControlStack, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaView } from "@prisma-next/framework-components/control";
8
+ import { APP_SPACE_ID, createControlStack, hasMigrations, hasOperationPreview, hasPslContractInfer, hasSchemaSubjectClassifier, hasSchemaView } from "@prisma-next/framework-components/control";
10
9
  import { blindCast, castAs } from "@prisma-next/utils/casts";
11
- import { buildSynthMigrationEdge, collectAggregateNamespaces, graphWalkStrategy, planMigration, requireHeadRef, verifyMigration } from "@prisma-next/migration-tools/aggregate";
10
+ import { allStorageElementsExternal, buildFabricatedMigrationEdge, collectAggregateNamespaces, planMigration, requireHeadRef, resolveRecordedPath, verifyMigration } from "@prisma-next/migration-tools/aggregate";
12
11
  import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
13
12
  import { errorNoInvariantPath } from "@prisma-next/migration-tools/errors";
14
13
  import { findPathWithDecision } from "@prisma-next/migration-tools/migration-graph";
@@ -144,7 +143,7 @@ function buildPerSpaceBreakdown(orderedResolutions, appSpaceId, options) {
144
143
  }
145
144
  /**
146
145
  * Materialise the `applyOrder` ordering into resolved per-space
147
- * entries. Throws if the planner output is missing a member listed
146
+ * entries. Throws if the planner output is missing a contract space listed
148
147
  * in `applyOrder` — a wiring bug that should never reach runtime.
149
148
  *
150
149
  * Exported so callers building their own success envelopes after a
@@ -196,10 +195,11 @@ const SPAN_IDS$1 = {
196
195
  * integrity violation short-circuits with a structured error.
197
196
  * 2. **Read DB state**: marker rows (`familyInstance.readAllMarkers`)
198
197
  * + introspected schema (`familyInstance.introspect`).
199
- * 3. **Plan**: {@link planMigration} chooses graph-walk vs synth per
200
- * member according to `callerPolicy.ignoreGraphFor`. The app member
201
- * is forced through synth (today's daily-driver behaviour); every
202
- * extension member walks its on-disk graph.
198
+ * 3. **Plan**: {@link planMigration} chooses `resolveRecordedPath` vs
199
+ * `planFromDiff` per space according to `callerPolicy.ignoreGraphFor`.
200
+ * The app space is forced through `planFromDiff` (today's daily-driver
201
+ * behaviour); every extension space walks its on-disk graph via
202
+ * `resolveRecordedPath`.
203
203
  * 4. **Apply** (when `mode === 'apply'`): every per-space `MigrationPlan`
204
204
  * feeds into the runner's `execute` — one outer
205
205
  * transaction across every space; failure on any space rolls back
@@ -252,7 +252,7 @@ async function executeRun(options) {
252
252
  adapter,
253
253
  migrations,
254
254
  frameworkComponents,
255
- callerPolicy: { ignoreGraphFor: new Set([aggregate.app.spaceId]) },
255
+ callerPolicy: { ignoreGraphFor: /* @__PURE__ */ new Set([aggregate.app.spaceId]) },
256
256
  operationPolicy: policy
257
257
  });
258
258
  if (!planResult.ok) {
@@ -273,7 +273,7 @@ async function executeRun(options) {
273
273
  const orderedResolutions = collectOrdered(planResult.value.applyOrder, planResult.value.perSpace);
274
274
  const plannerWarnings = aggregatePlannerWarnings(orderedResolutions);
275
275
  const appResolution = orderedResolutions.find((r) => r.spaceId === aggregate.app.spaceId);
276
- if (!appResolution) throw new Error("Aggregate planner returned no plan for the app member — the planner is supposed to always emit one.");
276
+ if (!appResolution) throw new Error("Aggregate planner returned no plan for the app space — the planner is supposed to always emit one.");
277
277
  const appPlan = appResolution.entry.plan;
278
278
  if (mode === "plan") {
279
279
  const aggregateOps = orderedResolutions.flatMap((r) => r.entry.displayOps);
@@ -325,22 +325,22 @@ function aggregatePlannerWarnings(orderedResolutions) {
325
325
  }
326
326
  /**
327
327
  * Compare the live `_prisma_marker` rows against the aggregate's
328
- * declared members. Any marker row whose `space` is not a member of
328
+ * declared contract spaces. Any marker row whose `space` is not a space of
329
329
  * the aggregate is an "orphan" — typically a marker left behind by
330
330
  * an extension that was removed from `extensionPacks` without first
331
331
  * cleaning up its on-disk migrations / database tables.
332
332
  *
333
333
  * Returns a {@link CliStructuredError} envelope (code `5002`,
334
334
  * `kind: 'orphanMarker'`) for the first orphan it finds, or `null`
335
- * when every marker row maps to a declared member. Mirrors the M2
335
+ * when every marker row maps to a declared contract space. Mirrors the M2
336
336
  * `runContractSpaceVerifierMarkerCheck` envelope so downstream
337
337
  * tooling (integration tests, JSON consumers) keeps asserting on the
338
338
  * same shape.
339
339
  */
340
340
  function detectOrphanMarkers(aggregate, markerRows) {
341
- const memberSpaceIds = new Set([aggregate.app.spaceId, ...aggregate.extensions.map((m) => m.spaceId)]);
341
+ const aggregateSpaceIds = /* @__PURE__ */ new Set([aggregate.app.spaceId, ...aggregate.extensions.map((m) => m.spaceId)]);
342
342
  const orphans = [];
343
- for (const [spaceId, row] of markerRows) if (row !== null && row !== void 0 && !memberSpaceIds.has(spaceId)) orphans.push(spaceId);
343
+ for (const [spaceId, row] of markerRows) if (row !== null && row !== void 0 && !aggregateSpaceIds.has(spaceId)) orphans.push(spaceId);
344
344
  if (orphans.length === 0) return null;
345
345
  orphans.sort((a, b) => a.localeCompare(b));
346
346
  return new CliStructuredError("5002", orphans.length === 1 ? `Orphan contract-space marker detected for "${orphans[0]}"` : `Orphan contract-space markers detected for ${orphans.length} spaces`, {
@@ -355,7 +355,7 @@ function detectOrphanMarkers(aggregate, markerRows) {
355
355
  });
356
356
  }
357
357
  function mapPlannerError(error) {
358
- if (error.kind === "appSynthFailure") return blindCast(notOk({
358
+ if (error.kind === "planFromDiffFailed") return blindCast(notOk({
359
359
  code: "PLANNING_FAILED",
360
360
  summary: "Migration planning failed due to conflicts",
361
361
  conflicts: error.conflicts,
@@ -544,11 +544,11 @@ const SPAN_IDS = {
544
544
  * structured CLI error.
545
545
  * 2. **Read DB state**: marker rows + (when `skipSchema` is `false`)
546
546
  * schema introspection.
547
- * 3. **Verify**: {@link verifyMigration} returns per-space
548
- * `markerCheck` + per-space pre-projected `schemaCheck` (closes F23).
549
- * Marker mismatches map to `CliStructuredError` (code `5002`) so
550
- * callers (CLI command) can render and exit. Schema results are
551
- * returned to the caller verbatim.
547
+ * 3. **Verify**: {@link verifyMigration} returns per-space `markerCheck` +
548
+ * per-space `schemaCheck` (each contract space verified against the full schema,
549
+ * then scoped to its own contract space). Marker mismatches map to
550
+ * `CliStructuredError` (code `5002`) so callers (CLI command) can render
551
+ * and exit. Verify results are returned to the caller verbatim.
552
552
  */
553
553
  async function executeDbVerify(options) {
554
554
  const { driver, familyInstance, onProgress, skipSchema, skipMarker } = options;
@@ -562,6 +562,8 @@ async function executeDbVerify(options) {
562
562
  onProgress,
563
563
  contract: collectAggregateNamespaces(aggregate)
564
564
  });
565
+ const classifySubjectGranularity = hasSchemaSubjectClassifier(familyInstance) ? (issue) => familyInstance.classifySubjectGranularity(issue) : void 0;
566
+ const classifyEntityKind = hasSchemaSubjectClassifier(familyInstance) ? (issue) => familyInstance.classifyEntityKind(issue) : void 0;
565
567
  emitVerifySpan(onProgress, "spanStart");
566
568
  return finaliseVerifyResult({
567
569
  verifyResult: verifyMigration({
@@ -569,7 +571,9 @@ async function executeDbVerify(options) {
569
571
  markersBySpaceId,
570
572
  schemaIntrospection,
571
573
  mode: options.mode,
572
- verifySchemaForMember: createPerMemberVerifier(options)
574
+ verifySchemaForSpace: createPerSpaceVerifier(options),
575
+ ...ifDefined("classifySubjectGranularity", classifySubjectGranularity),
576
+ ...ifDefined("classifyEntityKind", classifyEntityKind)
573
577
  }),
574
578
  aggregate,
575
579
  skipMarker,
@@ -616,18 +620,18 @@ async function runIntrospection(args) {
616
620
  }
617
621
  }
618
622
  /**
619
- * Build the per-member schema callback handed to the aggregate verifier.
623
+ * Build the per-space schema callback handed to the aggregate verifier.
620
624
  * When `skipSchema` is true the callback short-circuits with a synthetic
621
625
  * `ok` result so the verifier still runs the (cheap) schemaCheck loop
622
626
  * without invoking the family's verification path.
623
627
  */
624
- function createPerMemberVerifier(options) {
628
+ function createPerSpaceVerifier(options) {
625
629
  const { skipSchema, familyInstance, frameworkComponents } = options;
626
- return (projectedSchema, member, verifyMode) => {
627
- if (skipSchema) return buildSkippedSchemaResult(member);
630
+ return (schema, space, verifyMode) => {
631
+ if (skipSchema) return buildSkippedSchemaResult(space);
628
632
  return familyInstance.verifySchema({
629
- contract: member.contract(),
630
- schema: blindCast(projectedSchema),
633
+ contract: space.contract(),
634
+ schema,
631
635
  strict: verifyMode === "strict",
632
636
  frameworkComponents
633
637
  });
@@ -674,13 +678,14 @@ function finaliseVerifyResult(args) {
674
678
  emitVerifySpan(onProgress, "spanEndOk");
675
679
  return ok({
676
680
  schemaResults: verifyResult.value.schemaCheck.perSpace,
677
- memberOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
681
+ unclaimed: verifyResult.value.schemaCheck.unclaimed,
682
+ spaceOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
678
683
  appSpaceId: aggregate.app.spaceId
679
684
  });
680
685
  }
681
- function buildSkippedSchemaResult(member) {
682
- const contract = member.contract();
683
- const headRef = requireHeadRef(member);
686
+ function buildSkippedSchemaResult(space) {
687
+ const contract = space.contract();
688
+ const headRef = requireHeadRef(space);
684
689
  const profileHash = castAs(contract).profileHash;
685
690
  return {
686
691
  ok: true,
@@ -690,26 +695,7 @@ function buildSkippedSchemaResult(member) {
690
695
  ...profileHash ? { profileHash } : {}
691
696
  },
692
697
  target: { expected: contract.target },
693
- schema: {
694
- issues: [],
695
- root: {
696
- status: "pass",
697
- kind: "skipped",
698
- name: member.spaceId,
699
- contractPath: "",
700
- code: "SKIPPED",
701
- message: "Schema verification skipped",
702
- expected: void 0,
703
- actual: void 0,
704
- children: []
705
- },
706
- counts: {
707
- pass: 0,
708
- warn: 0,
709
- fail: 0,
710
- totalNodes: 0
711
- }
712
- },
698
+ schema: { issues: [] },
713
699
  timings: { total: 0 }
714
700
  };
715
701
  }
@@ -756,22 +742,26 @@ function mapMarkerCheckFailures(appSpaceId, section) {
756
742
  /**
757
743
  * Apply pending migrations across every contract space (app +
758
744
  * extensions). Replay-only: graph-walk against the on-disk graph for
759
- * every member; no synth, no introspection.
745
+ * every contract space; no synth, no introspection.
760
746
  *
761
747
  * Pipeline:
762
748
  *
763
749
  * 1. Load aggregate from disk (loader hydrates extension graphs;
764
750
  * caller provides app-space packages).
765
751
  * 2. Read live marker rows per space (`familyInstance.readAllMarkers`).
766
- * 3. Per member: `graphWalkStrategy` plots the path from the live
767
- * marker to `member.headRef.hash` (or `refHash` for the app
768
- * member when provided). Empty-graph members fail loudly a
769
- * "never planned" space is a user-error condition for replay.
752
+ * 3. Per space: `resolveRecordedPath` plots the path from the live
753
+ * marker to `space.headRef.hash` (or `refHash` for the app
754
+ * space when provided). An empty-graph space whose elements are ALL
755
+ * externally managed resolves declaratively (marker to head, zero
756
+ * ops), mirroring the db-init aggregate planner: such a space ships
757
+ * no DDL and has nothing to author. Every other empty-graph space
758
+ * fails loudly — "never planned" is a user-error condition for
759
+ * replay.
770
760
  * 4. Hand off to {@link runMigration} (the runner-driving tail
771
761
  * shared with `db init` / `db update`). Marker advancement is
772
762
  * inside the per-space transaction.
773
763
  *
774
- * Encodes the replay-only contract: every contract space must have an
764
+ * Encodes the replay-only contract: the app contract space must have an
775
765
  * authored migration graph on disk before this operation can advance it.
776
766
  */
777
767
  async function executeMigrate(options) {
@@ -786,29 +776,29 @@ async function executeMigrate(options) {
786
776
  if (!loaded.ok) throw loaded.failure;
787
777
  const aggregate = loaded.value;
788
778
  const markerRows = await familyInstance.readAllMarkers({ driver });
789
- const allMembers = [aggregate.app, ...aggregate.extensions];
779
+ const allSpaces = [aggregate.app, ...aggregate.extensions];
790
780
  const perSpacePlans = /* @__PURE__ */ new Map();
791
781
  const atHeadResolutions = /* @__PURE__ */ new Map();
792
- for (const member of allMembers) {
793
- const isAppMember = member.spaceId === aggregate.app.spaceId;
794
- const headRef = requireHeadRef(member);
795
- const memberTargetHash = isAppMember && refHash !== void 0 ? refHash : headRef.hash;
796
- const outcome = planMemberPath({
797
- member,
782
+ for (const space of allSpaces) {
783
+ const isAppSpace = space.spaceId === aggregate.app.spaceId;
784
+ const headRef = requireHeadRef(space);
785
+ const spaceTargetHash = isAppSpace && refHash !== void 0 ? refHash : headRef.hash;
786
+ const outcome = planSpacePath({
787
+ space,
798
788
  aggregate,
799
- targetHash: memberTargetHash,
800
- refInvariants: isAppMember && refHash !== void 0 ? refInvariants : void 0,
801
- liveMarker: markerRows.get(member.spaceId) ?? null,
802
- ...isAppMember ? { refName } : {}
789
+ targetHash: spaceTargetHash,
790
+ refInvariants: isAppSpace && refHash !== void 0 ? refInvariants : void 0,
791
+ liveMarker: markerRows.get(space.spaceId) ?? null,
792
+ ...isAppSpace ? { refName } : {}
803
793
  });
804
794
  if (outcome.kind === "at-head") {
805
- atHeadResolutions.set(member.spaceId, outcome.plan);
795
+ atHeadResolutions.set(space.spaceId, outcome.plan);
806
796
  continue;
807
797
  }
808
798
  if (outcome.kind === "never-planned") return notOk(buildNeverPlannedFailure(outcome.spaceId, outcome.targetHash));
809
799
  if (outcome.kind === "unreachable") return notOk(buildPathNotFoundFailure(outcome.spaceId, outcome.liveMarker, outcome.targetHash));
810
800
  if (outcome.kind === "unsatisfiable") {
811
- const structural = findPathWithDecision(outcome.targetMember.graph(), outcome.liveHash, memberTargetHash, { required: /* @__PURE__ */ new Set() });
801
+ const structural = findPathWithDecision(outcome.targetSpace.graph(), outcome.liveHash, spaceTargetHash, { required: /* @__PURE__ */ new Set() });
812
802
  const structuralPath = structural.kind === "ok" ? structural.decision.selectedPath.map((edge) => ({
813
803
  dirName: edge.dirName,
814
804
  migrationHash: edge.migrationHash,
@@ -823,11 +813,14 @@ async function executeMigrate(options) {
823
813
  structuralPath
824
814
  });
825
815
  }
826
- perSpacePlans.set(member.spaceId, outcome.plan);
816
+ perSpacePlans.set(space.spaceId, outcome.plan);
827
817
  }
828
818
  const canonicalOrder = [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId];
829
819
  const applyOrder = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId));
830
- if (sumPlannedOps(applyOrder, perSpacePlans) === 0) {
820
+ if (!applyOrder.some((spaceId) => {
821
+ const entry = perSpacePlans.get(spaceId);
822
+ return entry !== void 0 && planRequiresExecution(entry);
823
+ })) {
831
824
  const ordered = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId)).map((spaceId) => {
832
825
  const entry = perSpacePlans.get(spaceId) ?? atHeadResolutions.get(spaceId);
833
826
  if (entry === void 0) throw new Error(`Unreachable: missing per-space plan for "${spaceId}"`);
@@ -892,7 +885,7 @@ async function executeMigrate(options) {
892
885
  }));
893
886
  }
894
887
  /**
895
- * Compute the graph-walk path for one contract-space member.
888
+ * Compute the graph-walk path for one contract space.
896
889
  *
897
890
  * Encapsulates the invariant-correct input assembly that both
898
891
  * `executeMigrate` and `executeMigrateShowCommand` must use:
@@ -901,48 +894,69 @@ async function executeMigrate(options) {
901
894
  * - `targetInvariants` uses the caller-supplied `refInvariants` when a
902
895
  * `--to` ref was resolved (not always the file head ref's invariants).
903
896
  *
904
- * Both callers map the returned `MemberPathOutcome` to their own error
897
+ * Both callers map the returned `SpacePathOutcome` to their own error
905
898
  * representation; the path-compute logic is shared and identical.
906
899
  *
907
900
  * @internal Exported for `executeMigrateShowCommand`.
908
901
  */
909
- function planMemberPath({ member, aggregate, targetHash, refInvariants, liveMarker, refName }) {
910
- const isAppMember = member.spaceId === aggregate.app.spaceId;
911
- const headRef = requireHeadRef(member);
912
- if (member.graph().nodes.size === 0) {
902
+ function planSpacePath({ space, aggregate, targetHash, refInvariants, liveMarker, refName }) {
903
+ const isAppSpace = space.spaceId === aggregate.app.spaceId;
904
+ const headRef = requireHeadRef(space);
905
+ if (space.graph().nodes.size === 0) {
913
906
  const liveHash = liveMarker?.storageHash;
914
907
  if (targetHash === liveHash || liveHash === void 0 && targetHash === EMPTY_CONTRACT_HASH) return {
915
908
  kind: "at-head",
916
909
  plan: buildAtHeadResolution({
917
910
  aggregateTargetId: aggregate.targetId,
918
- member,
911
+ space,
919
912
  targetHash,
920
913
  liveMarker
921
914
  })
922
915
  };
916
+ if (!isAppSpace && allStorageElementsExternal(space.contract())) {
917
+ if (headRef.invariants.length > 0) return {
918
+ kind: "unsatisfiable",
919
+ spaceId: space.spaceId,
920
+ isAppSpace,
921
+ missing: [...headRef.invariants].sort(),
922
+ targetInvariants: headRef.invariants,
923
+ targetSpace: space,
924
+ liveHash: liveHash ?? EMPTY_CONTRACT_HASH,
925
+ refName: void 0
926
+ };
927
+ return {
928
+ kind: "ok",
929
+ plan: buildAtHeadResolution({
930
+ aggregateTargetId: aggregate.targetId,
931
+ space,
932
+ targetHash,
933
+ liveMarker
934
+ })
935
+ };
936
+ }
923
937
  return {
924
938
  kind: "never-planned",
925
- spaceId: member.spaceId,
939
+ spaceId: space.spaceId,
926
940
  targetHash
927
941
  };
928
942
  }
929
- const targetInvariants = isAppMember && refInvariants !== void 0 ? refInvariants : headRef.invariants;
930
- const targetMember = targetHash === headRef.hash && targetInvariants === headRef.invariants ? member : {
931
- ...member,
943
+ const targetInvariants = isAppSpace && refInvariants !== void 0 ? refInvariants : headRef.invariants;
944
+ const targetSpace = targetHash === headRef.hash && targetInvariants === headRef.invariants ? space : {
945
+ ...space,
932
946
  headRef: {
933
947
  hash: targetHash,
934
948
  invariants: targetInvariants
935
949
  }
936
950
  };
937
- const walked = graphWalkStrategy({
951
+ const walked = resolveRecordedPath({
938
952
  aggregateTargetId: aggregate.targetId,
939
- member: targetMember,
953
+ space: targetSpace,
940
954
  currentMarker: liveMarker,
941
- ...isAppMember && refName !== void 0 ? { refName } : {}
955
+ ...isAppSpace && refName !== void 0 ? { refName } : {}
942
956
  });
943
957
  if (walked.kind === "unreachable") return {
944
958
  kind: "unreachable",
945
- spaceId: member.spaceId,
959
+ spaceId: space.spaceId,
946
960
  liveMarker,
947
961
  targetHash
948
962
  };
@@ -950,11 +964,11 @@ function planMemberPath({ member, aggregate, targetHash, refInvariants, liveMark
950
964
  const liveHash = liveMarker?.storageHash ?? EMPTY_CONTRACT_HASH;
951
965
  return {
952
966
  kind: "unsatisfiable",
953
- spaceId: member.spaceId,
954
- isAppMember,
967
+ spaceId: space.spaceId,
968
+ isAppSpace,
955
969
  missing: walked.missing,
956
970
  targetInvariants,
957
- targetMember,
971
+ targetSpace,
958
972
  liveHash,
959
973
  refName
960
974
  };
@@ -965,41 +979,43 @@ function planMemberPath({ member, aggregate, targetHash, refInvariants, liveMark
965
979
  };
966
980
  }
967
981
  /**
968
- * Build a zero-op {@link PerSpacePlan} for an empty-graph
969
- * member whose live marker already matches the target. Lets the apply
970
- * pipeline thread the member through `perSpacePlans` -> `applyOrder`
971
- * -> the success envelope's `perSpace[]` block so the result reflects
972
- * every loaded space, even when there is nothing to execute.
982
+ * Build a zero-op {@link PerSpacePlan} for an empty-graph space —
983
+ * either one whose live marker already matches the target (at-head), or
984
+ * an all-external extension space whose marker must advance to the head
985
+ * ref with no DDL (declared-state). Lets the apply pipeline thread the
986
+ * space through `perSpacePlans` -> `applyOrder` -> the success
987
+ * envelope's `perSpace[]` block so the result reflects every loaded
988
+ * space, even when there is nothing to execute.
973
989
  */
974
990
  function buildAtHeadResolution(args) {
975
- const { aggregateTargetId, member, targetHash, liveMarker } = args;
991
+ const { aggregateTargetId, space, targetHash, liveMarker } = args;
976
992
  return {
977
993
  plan: {
978
994
  targetId: aggregateTargetId,
979
- spaceId: member.spaceId,
995
+ spaceId: space.spaceId,
980
996
  origin: liveMarker === null ? null : { storageHash: liveMarker.storageHash },
981
997
  destination: { storageHash: targetHash },
982
998
  operations: [],
983
999
  providedInvariants: []
984
1000
  },
985
1001
  displayOps: [],
986
- destinationContract: member.contract(),
987
- strategy: "graph-walk",
988
- migrationEdges: [buildSynthMigrationEdge({
1002
+ destinationContract: space.contract(),
1003
+ strategy: "declared-state",
1004
+ migrationEdges: [buildFabricatedMigrationEdge({
989
1005
  currentMarkerStorageHash: liveMarker?.storageHash,
990
1006
  destinationStorageHash: targetHash,
991
1007
  operationCount: 0
992
1008
  })]
993
1009
  };
994
1010
  }
995
- function sumPlannedOps(applyOrder, perSpacePlans) {
996
- let total = 0;
997
- for (const spaceId of applyOrder) {
998
- const entry = perSpacePlans.get(spaceId);
999
- if (!entry) continue;
1000
- total += entry.plan.operations.length;
1001
- }
1002
- return total;
1011
+ /**
1012
+ * A plan needs the runner when it executes operations or advances the
1013
+ * space's marker (a declared-state resolution has zero operations but a
1014
+ * destination hash the live marker doesn't carry yet).
1015
+ */
1016
+ function planRequiresExecution(entry) {
1017
+ if (entry.plan.operations.length > 0) return true;
1018
+ return entry.plan.origin?.storageHash !== entry.plan.destination.storageHash;
1003
1019
  }
1004
1020
  function buildSuccess(args) {
1005
1021
  const appResolution = args.orderedResolutions.find((r) => r.spaceId === args.aggregate.app.spaceId);
@@ -1041,10 +1057,12 @@ function buildSuccess(args) {
1041
1057
  };
1042
1058
  }
1043
1059
  /**
1044
- * Build the `neverPlanned` failure raised when a contract space has no on-disk
1045
- * migration graph but migrate was asked to reach a target hash. The `why`
1046
- * states only the condition; the recovery sequence is composed by
1047
- * `errorPathUnreachable`'s `fix`.
1060
+ * Build the `neverPlanned` failure raised when a contract space that
1061
+ * declares managed storage elements has no on-disk migration graph but
1062
+ * migrate was asked to reach a target hash. All-external spaces never reach
1063
+ * this: they resolve declaratively (marker advances to the head ref with
1064
+ * zero operations). The `why` states only the condition; the recovery
1065
+ * sequence is composed by `errorPathUnreachable`'s `fix`.
1048
1066
  *
1049
1067
  * @internal Exported for testing only.
1050
1068
  */
@@ -1052,7 +1070,7 @@ function buildNeverPlannedFailure(spaceId, targetHash) {
1052
1070
  return {
1053
1071
  code: "MIGRATION_PATH_NOT_FOUND",
1054
1072
  summary: `No on-disk migrations for contract space "${spaceId}"`,
1055
- why: `migrate is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}".`,
1073
+ why: `migrate is replay-only: a contract space that declares managed storage elements must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}".`,
1056
1074
  meta: {
1057
1075
  spaceId,
1058
1076
  target: targetHash,
@@ -1494,16 +1512,15 @@ var ControlClientImpl = class {
1494
1512
  });
1495
1513
  try {
1496
1514
  const stack = this.stack;
1497
- const extensionInputs = toExtensionInputs(blindCast(stack.extensionPacks));
1498
- const composedExtensionContracts = new Map(extensionInputs.filter((p) => p.contractSpace !== void 0).map((p) => [p.id, blindCast(p.contractSpace.contractJson)]));
1499
1515
  const sourceContext = {
1500
1516
  composedExtensionPacks: stack.extensionPacks.map((p) => p.id),
1501
- composedExtensionContracts,
1517
+ composedExtensionContracts: stack.extensionContracts,
1502
1518
  scalarTypeDescriptors: stack.scalarTypeDescriptors,
1503
1519
  authoringContributions: stack.authoringContributions,
1504
1520
  codecLookup: stack.codecLookup,
1505
1521
  controlMutationDefaults: stack.controlMutationDefaults,
1506
- resolvedInputs: contractConfig.source.inputs ?? []
1522
+ resolvedInputs: contractConfig.source.inputs ?? [],
1523
+ capabilities: stack.capabilities
1507
1524
  };
1508
1525
  const providerResult = await contractConfig.source.load(sourceContext);
1509
1526
  if (!providerResult.ok) {
@@ -1558,9 +1575,10 @@ var ControlClientImpl = class {
1558
1575
  });
1559
1576
  try {
1560
1577
  const enrichedIR = enrichContract(contractRaw, this.frameworkComponents ?? []);
1578
+ const rawContractJson = this.options.target.contractSerializer.serializeContract(enrichedIR);
1561
1579
  let deserializedContract;
1562
1580
  try {
1563
- deserializedContract = this.familyInstance.deserializeContract(enrichedIR);
1581
+ deserializedContract = this.familyInstance.deserializeContract(rawContractJson);
1564
1582
  } catch (error) {
1565
1583
  onProgress?.({
1566
1584
  action: "emit",
@@ -1606,6 +1624,6 @@ var ControlClientImpl = class {
1606
1624
  }
1607
1625
  };
1608
1626
  //#endregion
1609
- export { executeDbInit as a, executeDbUpdate as i, planMemberPath as n, ContractValidationError as o, executeDbVerify as r, createControlClient as t };
1627
+ export { executeDbInit as a, executeDbUpdate as i, planSpacePath as n, ContractValidationError as o, executeDbVerify as r, createControlClient as t };
1610
1628
 
1611
- //# sourceMappingURL=client-CJzuo5wX.mjs.map
1629
+ //# sourceMappingURL=client-DwOyZz0a.mjs.map