@prisma-next/migration-tools 0.12.0-dev.51 → 0.12.0-dev.52

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.
@@ -6,7 +6,7 @@ import { t as PackageLoadProblem } from "../io-BH4G3F-i.mjs";
6
6
  import { t as PathDecision } from "../migration-graph-CWEM2SLR.mjs";
7
7
  import { Result } from "@prisma-next/utils/result";
8
8
  import { ControlFamilyInstance, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, TargetMigrationsCapability } from "@prisma-next/framework-components/control";
9
- import { Contract } from "@prisma-next/contract/types";
9
+ import { Contract, StorageNamespace } from "@prisma-next/contract/types";
10
10
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
11
11
 
12
12
  //#region src/integrity-violation.d.ts
@@ -254,6 +254,21 @@ declare function createContractSpaceMember(args: {
254
254
  readonly resolveContract: () => Contract;
255
255
  readonly deserializeContract: (raw: unknown) => Contract;
256
256
  }): ContractSpaceMember;
257
+ /**
258
+ * Collect the union of every namespace declared across all members of an
259
+ * aggregate (app + extensions) and return a minimal object with the shape
260
+ * `{ storage: { namespaces } }` suitable for passing to
261
+ * `familyInstance.introspect`.
262
+ *
263
+ * Callers invoke this after the integrity gate (`buildContractSpaceAggregate`
264
+ * with `checkContracts: true`), so every `member.contract()` call is safe —
265
+ * no try/catch is needed here.
266
+ */
267
+ declare function collectAggregateNamespaces(aggregate: ContractSpaceAggregate): {
268
+ readonly storage: {
269
+ readonly namespaces: Readonly<Record<string, StorageNamespace>>;
270
+ };
271
+ };
257
272
  /**
258
273
  * Assemble a {@link ContractSpaceAggregate} value from its members and a
259
274
  * `checkIntegrity` implementation. The query methods (`listSpaces` /
@@ -286,6 +301,9 @@ interface IntegritySpaceState {
286
301
  * `null` means the head ref was read cleanly or is genuinely absent —
287
302
  * the absent case is judged `headRefMissing`, the corrupt case here is
288
303
  * judged `refUnreadable` (and suppresses `headRefMissing`).
304
+ *
305
+ * Always `null` for the app space — the app head ref is synthesised from
306
+ * the live contract, so there is no on-disk `head.json` to read or fail on.
289
307
  */
290
308
  readonly headRefProblem: RefLoadProblem | null;
291
309
  readonly isApp: boolean;
@@ -752,5 +770,5 @@ type VerifierOutput<TSchemaResult> = Result<VerifierSuccess<TSchemaResult>, Veri
752
770
  */
753
771
  declare function verifyMigration<TSchemaResult>(input: VerifierInput<TSchemaResult>): VerifierOutput<TSchemaResult>;
754
772
  //#endregion
755
- export { type AggregateCurrentDBState, type AggregateMigrationEdgeRef, type CallerPolicy, type ContractAtOptions, type ContractAtResult, type ContractMarkerRecordLike, type ContractSpaceAggregate, type ContractSpaceMember, type DeclaredExtensionEntry, type GraphWalkOutcome, type GraphWalkStrategyInputs, type IntegrityComputationInput, type IntegrityQueryOptions, type IntegritySpaceState, type IntegrityViolation, type LoadAggregateInput, type MarkerCheckResult, type MarkerCheckSection, type OrphanElement, type PerSpacePlan, type PlannerError, type PlannerInput, type PlannerOutput, type PlannerSuccess, type SchemaCheckSection, type VerifierError, type VerifierInput, type VerifierOutput, type VerifierSuccess, buildSynthMigrationEdge, computeIntegrityViolations, createContractSpaceAggregate, createContractSpaceMember, graphWalkStrategy, loadContractSpaceAggregate, loadProblemToViolation, planMigration, projectSchemaToSpace, requireHeadRef, verifyMigration };
773
+ export { type AggregateCurrentDBState, type AggregateMigrationEdgeRef, type CallerPolicy, type ContractAtOptions, type ContractAtResult, type ContractMarkerRecordLike, type ContractSpaceAggregate, type ContractSpaceMember, type DeclaredExtensionEntry, type GraphWalkOutcome, type GraphWalkStrategyInputs, type IntegrityComputationInput, type IntegrityQueryOptions, type IntegritySpaceState, type IntegrityViolation, type LoadAggregateInput, type MarkerCheckResult, type MarkerCheckSection, type OrphanElement, type PerSpacePlan, type PlannerError, type PlannerInput, type PlannerOutput, type PlannerSuccess, type SchemaCheckSection, type VerifierError, type VerifierInput, type VerifierOutput, type VerifierSuccess, buildSynthMigrationEdge, collectAggregateNamespaces, computeIntegrityViolations, createContractSpaceAggregate, createContractSpaceMember, graphWalkStrategy, loadContractSpaceAggregate, loadProblemToViolation, planMigration, projectSchemaToSpace, requireHeadRef, verifyMigration };
756
774
  //# sourceMappingURL=aggregate.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.d.mts","names":[],"sources":["../../src/integrity-violation.ts","../../src/aggregate/types.ts","../../src/aggregate/aggregate.ts","../../src/aggregate/check-integrity.ts","../../src/aggregate/loader.ts","../../src/aggregate/marker-types.ts","../../src/aggregate/planner-types.ts","../../src/aggregate/planner.ts","../../src/aggregate/project-schema-to-space.ts","../../src/aggregate/strategies/graph-walk.ts","../../src/aggregate/synth-migration-edge.ts","../../src/aggregate/verifier.ts"],"mappings":"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"}
1
+ {"version":3,"file":"aggregate.d.mts","names":[],"sources":["../../src/integrity-violation.ts","../../src/aggregate/types.ts","../../src/aggregate/aggregate.ts","../../src/aggregate/check-integrity.ts","../../src/aggregate/loader.ts","../../src/aggregate/marker-types.ts","../../src/aggregate/planner-types.ts","../../src/aggregate/planner.ts","../../src/aggregate/project-schema-to-space.ts","../../src/aggregate/strategies/graph-walk.ts","../../src/aggregate/synth-migration-edge.ts","../../src/aggregate/verifier.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkBA;;;;;;KAAY,kBAAA;EAAA,SAGG,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SAAiC,OAAA;AAAA;EAAA,SACjC,IAAA;EAAA,SAAoC,OAAA;EAAA,SAA0B,IAAA;AAAA;EAAA,SAE9D,IAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,MAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SAAiC,OAAA;AAAA;EAAA,SACjC,IAAA;EAAA,SAAwC,OAAA;AAAA;EAAA,SAExC,IAAA;EAAA,SACA,OAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SAAqC,OAAA;EAAA,SAA0B,MAAA;AAAA;EAAA,SAG/D,IAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,MAAA;AAAA;;;;ACjEf;;;;AACkB;AAGlB;;;;UD4EiB,sBAAA;EAAA,SACN,EAAA;EAAA,SACA,QAAQ;AAAA;;;;;;;;;;UAYF,qBAAA;EC5EgB;AAuCjC;;;;EAvCiC,SDkFtB,kBAAA,YAA8B,sBAAsB;ECvC3C;;;;EAAA,SD4CT,cAAA;AAAA;;;UCzGM,iBAAA;EAAA,SACN,OAAO;AAAA;AAAA,KAGN,gBAAA;EAAA,SAEG,UAAA;EAAA,SACA,IAAA;EAAA,SACA,YAAA;EAAA,SACA,WAAA;EAAA,SACA,QAAA,EAAU,QAAA;AAAA;EAAA,SAGV,UAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;EAAA,SACA,YAAA;EAAA,SACA,WAAA;EAAA,SACA,QAAA,EAAU,QAAQ;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAuChB,mBAAA;EAAA,SACN,OAAA;EAAA,SACA,QAAA,WAAmB,sBAAA;EAAA,SACnB,IAAA,EAAM,IAAA;EAAA,SACN,OAAA,EAAS,uBAAA;EAClB,KAAA,IAAS,cAAA;EACT,QAAA,IAAY,QAAA;EACZ,UAAA,CAAW,IAAA,UAAc,IAAA,GAAO,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;AAAA;;;;;;;ADyCrC;;;;ACzGzB;;;;AACkB;AAGlB;;;;;;;;;UAuFiB,sBAAA;EAAA,SACN,QAAA;EAAA,SACA,GAAA,EAAK,mBAAA;EAAA,SACL,UAAA,WAAqB,mBAAA;EAC9B,UAAA;EACA,QAAA,CAAS,EAAA;EACT,KAAA,CAAM,EAAA,WAAa,mBAAA;EACnB,MAAA,aAAmB,mBAAA;EACnB,cAAA,CAAe,IAAA,GAAO,qBAAA,YAAiC,kBAAA;AAAA;;;;;;;;;ADxFzD;;iBEoJgB,cAAA,CAAe,MAAA,EAAQ,mBAAA,GAAsB,uBAAuB;;;;;;;;;;;;;;iBAsBpE,yBAAA,CAA0B,IAAA;EAAA,SAC/B,OAAA;EAAA,SACA,QAAA,WAAmB,sBAAA;EAAA,SACnB,IAAA,EAAM,IAAA;EAAA,SACN,OAAA,EAAS,uBAAA;EAAA,SACT,OAAA;EAAA,SACA,eAAA,QAAuB,QAAA;EAAA,SACvB,mBAAA,GAAsB,GAAA,cAAiB,QAAA;AAAA,IAC9C,mBAAA;;;;;;;;;;;iBAoDY,0BAAA,CAA2B,SAAA,EAAW,sBAAA;EAAA,SAC3C,OAAA;IAAA,SAAoB,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,gBAAA;EAAA;AAAA;;;;;;;;;iBAmBnD,4BAAA,CAA6B,IAAA;EAAA,SAClC,QAAA;EAAA,SACA,GAAA,EAAK,mBAAA;EAAA,SACL,UAAA,WAAqB,mBAAA;EAAA,SACrB,cAAA,GAAiB,IAAA,GAAO,qBAAA,cAAmC,kBAAA;AAAA,IAClE,sBAAA;;;;;;;;;UC9Pa,mBAAA;EAAA,SACN,MAAA,EAAQ,mBAAA;EAAA,SACR,QAAA,WAAmB,kBAAA;EHHA;EAAA,SGKnB,WAAA,WAAsB,cAAA;EHLH;;;;;;;;;EAAA,SGenB,cAAA,EAAgB,cAAA;EAAA,SAChB,KAAA;AAAA;AAAA,UAGM,yBAAA;EAAA,SACN,QAAA;EAAA,SACA,MAAA,WAAiB,mBAAmB;AAAA;;;;;;;;iBAU/B,0BAAA,CACd,KAAA,EAAO,yBAAA,EACP,IAAA,GAAO,qBAAA,YACG,kBAAA;AAAA,iBAqEI,sBAAA,CACd,OAAA,UACA,OAAA,EAAS,kBAAA,GACR,kBAAkB;;;;;;;;;;;;AH1GrB;UIYiB,kBAAA;EAAA,SACN,aAAA;EAAA,SACA,mBAAA,GAAsB,GAAA,cAAiB,QAAA;EAAA,SACvC,WAAA,EAAa,QAAQ;AAAA;;;;;;;;;;;;;;;;;;;iBAqBV,0BAAA,CACpB,KAAA,EAAO,kBAAA,GACN,OAAA,CAAQ,sBAAA;;;;;;;;;;;;;;UC7CM,wBAAA;EAAA,SACN,WAAA;EAAA,SACA,UAAA;EAAA,SACA,WAAA;AAAA;;;;;;;;ALIX;;;;;;;;;;;UMaiB,YAAA;EAAA,SACN,cAAA,EAAgB,WAAW;AAAA;;;;;;;;;;;;;;;;;UAmBrB,uBAAA;EAAA,SACN,gBAAA,EAAkB,WAAW,SAAS,wBAAA;EAAA,SACtC,mBAAA;AAAA;;;;;;;;;;;;;;;UAiBM,YAAA;EAAA,SACN,SAAA,EAAW,sBAAA;EAAA,SACX,cAAA,EAAgB,uBAAA;EAAA,SAChB,cAAA,EAAgB,qBAAA,CAAsB,SAAA;EAAA,SACtC,UAAA,EAAY,0BAAA,CACnB,SAAA,EACA,SAAA,EACA,qBAAA,CAAsB,SAAA;EAAA,SAEf,mBAAA,EAAqB,aAAA,CAAc,8BAAA,CAA+B,SAAA,EAAW,SAAA;EAAA,SAC7E,YAAA,EAAc,YAAA;EAAA,SACd,eAAA,EAAiB,wBAAA;AAAA;;;;;;AN+BH;;;;ACzGzB;;;;AACkB;AAGlB;;;;;;;;;AAAA,UKgGiB,yBAAA;EAAA,SACN,aAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,cAAA;AAAA;AAAA,UAGM,YAAA;EAAA,SACN,IAAA,EAAM,aAAA;EAAA,SACN,UAAA,WAAqB,sBAAA;EAAA,SACrB,mBAAA,EAAqB,QAAA;EAAA,SACrB,QAAA;EAAA,SACA,QAAA,YAAoB,wBAAA;ELtDD;;;;EAAA,SK2DnB,cAAA,WAAyB,yBAAA;ELtDF;;;;;;;;;;EAAA,SKiEvB,YAAA,GAAe,YAAA;AAAA;AAAA,UAGT,cAAA;EAAA,SACN,QAAA,EAAU,WAAW,SAAS,YAAA;ELtEvC;;;;;;;;EAAA,SK+ES,UAAA;AAAA;ALnDX;;;;;AAAA,KK2DY,YAAA;EAAA,SACG,IAAA;EAAA,SAA2C,OAAA;EAAA,SAA0B,MAAA;AAAA;EAAA,SAErE,IAAA;EAAA,SACA,OAAA;EAAA,SACA,iBAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA,WAAoB,wBAAwB;AAAA;EAAA,SAE5C,IAAA;EAAA,SAAiC,OAAA;EAAA,SAA0B,MAAA;AAAA;AAAA,KAE9D,aAAA,GAAgB,MAAA,CAAO,cAAA,EAAgB,YAAA;;;;;;;;;;;;;ANzJnD;;;;;;;;;;;;iBOsBsB,aAAA,oDAAA,CACpB,KAAA,EAAO,YAAA,CAAa,SAAA,EAAW,SAAA,IAC9B,OAAA,CAAQ,aAAA;;;;;;;;;;;;;;APxBX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBQuCgB,oBAAA,CACd,MAAA,WACA,MAAA,EAAQ,mBAAA,EACR,YAAA,EAAc,aAAA,CAAc,mBAAA;;;;;;;;;;;KC3ClB,gBAAA;EAAA,SACG,IAAA;EAAA,SAAqB,MAAA,EAAQ,YAAY;AAAA;EAAA,SACzC,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAAgC,OAAA;AAAA;AAAA,UAE9B,uBAAA;EAAA,SACN,iBAAA;EAAA,SACA,MAAA,EAAQ,mBAAA;EAAA,SACR,aAAA,EAAe,wBAAwB;ETMnC;;;;;;EAAA,SSCJ,OAAA;AAAA;;;;;;;;;;;;;;;;iBAkBK,iBAAA,CAAkB,KAAA,EAAO,uBAAA,GAA0B,gBAAgB;;;iBChDnE,uBAAA,CAAwB,IAAA;EAAA,SAC7B,wBAAA;EAAA,SACA,sBAAA;EAAA,SACA,cAAA;AAAA,IACP,yBAAyB;;;;;;;;;UCQZ,aAAA;EAAA,SACN,SAAA,EAAW,sBAAA;EAAA,SACX,gBAAA,EAAkB,WAAA,SAAoB,wBAAA;EAAA,SACtC,mBAAA;EAAA,SACA,IAAA;;;;;;;;;;;;;WAaA,qBAAA,GACP,eAAA,WACA,MAAA,EAAQ,mBAAA,EACR,IAAA,2BACG,aAAA;AAAA;;;;;;;KASK,iBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SAAoC,OAAA;AAAA;AAAA,UAElC,kBAAA;EAAA,SACN,QAAA,EAAU,WAAA,SAAoB,iBAAA;EAAA,SAC9B,aAAA;IAAA,SACE,OAAA;IAAA,SACA,GAAA,EAAK,wBAAA;EAAA;AAAA;;;;;;;;AXcG;AAerB;;KWfY,aAAA;EAAA,SAA2B,IAAA;EAAA,SAAwB,IAAI;AAAA;AAAA,UAElD,kBAAA;EAAA,SACN,QAAA,EAAU,WAAA,SAAoB,aAAA;EXgCsB;;;;EAAA,SW3BpD,cAAA,WAAyB,aAAA;AAAA;AAAA,UAGnB,eAAA;EAAA,SACN,WAAA,EAAa,kBAAA;EAAA,SACb,WAAA,EAAa,kBAAA,CAAmB,aAAA;AAAA;AAAA,KAG/B,aAAA;EAAA,SACD,IAAA;EAAA,SACA,MAAM;AAAA;AAAA,KAGL,cAAA,kBAAgC,MAAA,CAAO,eAAA,CAAgB,aAAA,GAAgB,aAAA;;;;;;;;;;;;;;;;;;AVpElD;AAuCjC;;;;iBUqDgB,eAAA,eAAA,CACd,KAAA,EAAO,aAAA,CAAc,aAAA,IACpB,cAAA,CAAe,aAAA"}
@@ -161,6 +161,21 @@ function createContractSpaceMember(args) {
161
161
  };
162
162
  }
163
163
  /**
164
+ * Collect the union of every namespace declared across all members of an
165
+ * aggregate (app + extensions) and return a minimal object with the shape
166
+ * `{ storage: { namespaces } }` suitable for passing to
167
+ * `familyInstance.introspect`.
168
+ *
169
+ * Callers invoke this after the integrity gate (`buildContractSpaceAggregate`
170
+ * with `checkContracts: true`), so every `member.contract()` call is safe —
171
+ * no try/catch is needed here.
172
+ */
173
+ function collectAggregateNamespaces(aggregate) {
174
+ const merged = {};
175
+ for (const member of aggregate.spaces()) for (const [key, ns] of Object.entries(member.contract().storage.namespaces)) merged[key] = ns;
176
+ return { storage: { namespaces: merged } };
177
+ }
178
+ /**
164
179
  * Assemble a {@link ContractSpaceAggregate} value from its members and a
165
180
  * `checkIntegrity` implementation. The query methods (`listSpaces` /
166
181
  * `hasSpace` / `space` / `spaces`) are derived here so every aggregate —
@@ -226,7 +241,7 @@ function computeIntegrityViolations(input, opts) {
226
241
  kind: "headRefMissing",
227
242
  spaceId
228
243
  });
229
- else if (!headRefPresentInGraph(member, member.headRef.hash)) violations.push({
244
+ else if (member.packages.length > 0 && !headRefPresentInGraph(member, member.headRef.hash)) violations.push({
230
245
  kind: "headRefNotInGraph",
231
246
  spaceId,
232
247
  hash: member.headRef.hash
@@ -952,6 +967,6 @@ function detectOrphanElements(schemaIntrospection, members) {
952
967
  return orphans;
953
968
  }
954
969
  //#endregion
955
- export { buildSynthMigrationEdge, computeIntegrityViolations, createContractSpaceAggregate, createContractSpaceMember, graphWalkStrategy, loadContractSpaceAggregate, loadProblemToViolation, planMigration, projectSchemaToSpace, requireHeadRef, verifyMigration };
970
+ export { buildSynthMigrationEdge, collectAggregateNamespaces, computeIntegrityViolations, createContractSpaceAggregate, createContractSpaceMember, graphWalkStrategy, loadContractSpaceAggregate, loadProblemToViolation, planMigration, projectSchemaToSpace, requireHeadRef, verifyMigration };
956
971
 
957
972
  //# sourceMappingURL=aggregate.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.mjs","names":["detailOf"],"sources":["../../src/aggregate/aggregate.ts","../../src/aggregate/check-integrity.ts","../../src/aggregate/loader.ts","../../src/aggregate/strategies/graph-walk.ts","../../src/aggregate/project-schema-to-space.ts","../../src/aggregate/synth-migration-edge.ts","../../src/aggregate/strategies/synth.ts","../../src/aggregate/planner.ts","../../src/aggregate/verifier.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { join } from 'pathe';\nimport {\n errorBundleNotFoundForGraphNode,\n errorContractDeserializationFailed,\n errorHashNotInGraph,\n errorInvalidJson,\n errorMissingFile,\n errorSnapshotMissing,\n MigrationToolsError,\n} from '../errors';\nimport type { MigrationGraph } from '../graph';\nimport { isGraphNode } from '../graph-membership';\nimport type { IntegrityQueryOptions, IntegrityViolation } from '../integrity-violation';\nimport { reconstructGraph } from '../migration-graph';\nimport type { OnDiskMigrationPackage } from '../package';\nimport type { Refs } from '../refs';\nimport { readRefSnapshot } from '../refs/snapshot';\nimport type { ContractSpaceHeadRecord } from '../verify-contract-spaces';\nimport type {\n ContractAtOptions,\n ContractAtResult,\n ContractSpaceAggregate,\n ContractSpaceMember,\n} from './types';\n\nfunction hasErrnoCode(error: unknown, code: string): boolean {\n return error instanceof Error && (error as { code?: string }).code === code;\n}\n\nfunction contractAtMemoKey(hash: string, refName: string | undefined): string {\n return `${hash}\\0${refName ?? ''}`;\n}\n\nfunction deserializeContractAtPath(\n filePath: string,\n contractJson: unknown,\n deserializeContract: (raw: unknown) => Contract,\n): Contract {\n try {\n return deserializeContract(contractJson);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n throw error;\n }\n const message = error instanceof Error ? error.message : String(error);\n throw errorContractDeserializationFailed(filePath, message);\n }\n}\n\nasync function readGraphNodeEndContract(\n packageDir: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<{ contractJson: unknown; contractDts: string; contract: Contract }> {\n const jsonPath = join(packageDir, 'end-contract.json');\n const dtsPath = join(packageDir, 'end-contract.d.ts');\n\n let rawJson: string;\n try {\n rawJson = await readFile(jsonPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile('end-contract.json', packageDir);\n }\n throw error;\n }\n\n let contractJson: unknown;\n try {\n contractJson = JSON.parse(rawJson);\n } catch (error) {\n throw errorInvalidJson(jsonPath, error instanceof Error ? error.message : String(error));\n }\n\n let contractDts: string;\n try {\n contractDts = await readFile(dtsPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile('end-contract.d.ts', packageDir);\n }\n throw error;\n }\n\n const contract = deserializeContractAtPath(jsonPath, contractJson, deserializeContract);\n return { contractJson, contractDts, contract };\n}\n\nasync function resolveContractAt(args: {\n readonly hash: string;\n readonly opts: ContractAtOptions | undefined;\n readonly refsDir: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly graph: MigrationGraph;\n readonly deserializeContract: (raw: unknown) => Contract;\n}): Promise<ContractAtResult> {\n const { hash, opts, refsDir, packages, graph, deserializeContract } = args;\n const refName = opts?.refName;\n\n if (refName !== undefined) {\n const snapshot = await readRefSnapshot(refsDir, refName);\n if (snapshot) {\n const jsonPath = join(refsDir, `${refName}.contract.json`);\n return {\n hash,\n contractJson: snapshot.contract,\n contractDts: snapshot.contractDts,\n contract: deserializeContractAtPath(jsonPath, snapshot.contract, deserializeContract),\n provenance: 'snapshot',\n };\n }\n\n if (isGraphNode(hash, graph)) {\n return resolveGraphNodeContractAt({\n hash,\n packages,\n deserializeContract,\n explicitLabel: refName,\n });\n }\n\n throw errorSnapshotMissing(refName);\n }\n\n if (isGraphNode(hash, graph)) {\n return resolveGraphNodeContractAt({ hash, packages, deserializeContract });\n }\n\n throw errorHashNotInGraph(hash, graph);\n}\n\nasync function resolveGraphNodeContractAt(args: {\n readonly hash: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly deserializeContract: (raw: unknown) => Contract;\n readonly explicitLabel?: string;\n}): Promise<ContractAtResult> {\n const { hash, packages, deserializeContract, explicitLabel } = args;\n const matchingBundle = packages.find((pkg) => pkg.metadata.to === hash);\n if (!matchingBundle) {\n throw errorBundleNotFoundForGraphNode(hash, explicitLabel);\n }\n\n const { contractJson, contractDts, contract } = await readGraphNodeEndContract(\n matchingBundle.dirPath,\n deserializeContract,\n );\n return {\n hash,\n contractJson,\n contractDts,\n contract,\n provenance: 'graph-node',\n sourceDir: matchingBundle.dirPath,\n };\n}\n\n/**\n * Resolve a member's head ref, asserting it is present. The apply/verify\n * engine only runs after `checkIntegrity` has refused on `headRefMissing`,\n * so a member reaching the planner / verifier without a head ref is a\n * programming error (the integrity gate was skipped), not a user-facing\n * state. The app member's head ref is always synthesised, so this only\n * ever guards an ungated extension space.\n */\nexport function requireHeadRef(member: ContractSpaceMember): ContractSpaceHeadRecord {\n if (member.headRef === null) {\n throw new Error(\n `Contract space \"${member.spaceId}\" has no head ref; the integrity gate must refuse a missing head ref before planning or verifying.`,\n );\n }\n return member.headRef;\n}\n\n/**\n * Build a {@link ContractSpaceMember} with lazily-memoised `graph()`,\n * `contract()`, and `contractAt()` facets.\n *\n * `graph()` reconstructs the migration graph from `packages` on first\n * call and caches it. `contract()` calls `resolveContract` on first call\n * and caches the result; a throwing `resolveContract` (e.g. a missing or\n * undeserializable on-disk contract) re-throws on each call rather than\n * caching a value — `checkIntegrity` surfaces that as `contractUnreadable`.\n * `contractAt()` materializes the contract at an arbitrary graph node with\n * the same resolution order as plan-time ref resolution: ref snapshot first\n * (when `opts.refName` is set), else the matching package's `end-contract.*`.\n */\nexport function createContractSpaceMember(args: {\n readonly spaceId: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly refs: Refs;\n readonly headRef: ContractSpaceHeadRecord | null;\n readonly refsDir: string;\n readonly resolveContract: () => Contract;\n readonly deserializeContract: (raw: unknown) => Contract;\n}): ContractSpaceMember {\n const { spaceId, packages, refs, headRef, refsDir, resolveContract, deserializeContract } = args;\n let graphMemo: MigrationGraph | undefined;\n let contractMemo: Contract | undefined;\n const contractAtMemo = new Map<string, ContractAtResult>();\n\n function memberGraph(): MigrationGraph {\n graphMemo ??= reconstructGraph(packages);\n return graphMemo;\n }\n\n return {\n spaceId,\n packages,\n refs,\n headRef,\n graph: memberGraph,\n contract() {\n contractMemo ??= resolveContract();\n return contractMemo;\n },\n async contractAt(hash, opts) {\n const key = contractAtMemoKey(hash, opts?.refName);\n const cached = contractAtMemo.get(key);\n if (cached) {\n return cached;\n }\n\n const result = await resolveContractAt({\n hash,\n opts,\n refsDir,\n packages,\n graph: memberGraph(),\n deserializeContract,\n });\n contractAtMemo.set(key, result);\n return result;\n },\n };\n}\n\n/**\n * Assemble a {@link ContractSpaceAggregate} value from its members and a\n * `checkIntegrity` implementation. The query methods (`listSpaces` /\n * `hasSpace` / `space` / `spaces`) are derived here so every aggregate —\n * loader-built or test-built — shares one query surface: `app` first,\n * then `extensions` in the order supplied (the loader sorts them\n * lex-ascending by `spaceId`).\n */\nexport function createContractSpaceAggregate(args: {\n readonly targetId: string;\n readonly app: ContractSpaceMember;\n readonly extensions: readonly ContractSpaceMember[];\n readonly checkIntegrity: (opts?: IntegrityQueryOptions) => readonly IntegrityViolation[];\n}): ContractSpaceAggregate {\n const { targetId, app, extensions, checkIntegrity } = args;\n const ordered: readonly ContractSpaceMember[] = [app, ...extensions];\n const byId = new Map(ordered.map((m) => [m.spaceId, m]));\n return {\n targetId,\n app,\n extensions,\n listSpaces: () => ordered.map((m) => m.spaceId),\n hasSpace: (id) => byId.has(id),\n space: (id) => byId.get(id),\n spaces: () => ordered,\n checkIntegrity,\n };\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport { EMPTY_CONTRACT_HASH } from '../constants';\nimport { MigrationToolsError } from '../errors';\nimport type {\n DeclaredExtensionEntry,\n IntegrityQueryOptions,\n IntegrityViolation,\n} from '../integrity-violation';\nimport type { PackageLoadProblem } from '../io';\nimport type { OnDiskMigrationPackage } from '../package';\nimport type { RefLoadProblem } from '../refs';\nimport type { ContractSpaceMember } from './types';\n\n/**\n * One space's load-time facts that `checkIntegrity` judges: the loaded\n * member, the load-time problems `readMigrationsDir` surfaced for it, and\n * whether it is the app space (the app head ref is synthesised, so the\n * head-ref checks are skipped for it).\n */\nexport interface IntegritySpaceState {\n readonly member: ContractSpaceMember;\n readonly problems: readonly PackageLoadProblem[];\n /** Per-ref problems: a user ref `*.json` that exists but is unparseable. */\n readonly refProblems: readonly RefLoadProblem[];\n /**\n * The space's `refs/head.json` problem when it exists but is unparseable.\n * `null` means the head ref was read cleanly or is genuinely absent —\n * the absent case is judged `headRefMissing`, the corrupt case here is\n * judged `refUnreadable` (and suppresses `headRefMissing`).\n */\n readonly headRefProblem: RefLoadProblem | null;\n readonly isApp: boolean;\n}\n\nexport interface IntegrityComputationInput {\n readonly targetId: string;\n readonly spaces: readonly IntegritySpaceState[];\n}\n\n/**\n * Walk the loaded model and return **every** integrity violation — never\n * bailing at the first. Structurally-derivable violations (load-time\n * problems, self-edges, missing / unreachable head refs) are always\n * produced; layout-drift checks require `declaredExtensions`, and\n * contract / target / disjointness checks require `checkContracts`.\n */\nexport function computeIntegrityViolations(\n input: IntegrityComputationInput,\n opts?: IntegrityQueryOptions,\n): readonly IntegrityViolation[] {\n const violations: IntegrityViolation[] = [];\n\n for (const { member, problems, refProblems, headRefProblem, isApp } of input.spaces) {\n const { spaceId } = member;\n\n for (const problem of problems) {\n violations.push(loadProblemToViolation(spaceId, problem));\n }\n\n for (const refProblem of refProblems) {\n violations.push({\n kind: 'refUnreadable',\n spaceId,\n refName: refProblem.refName,\n detail: refProblem.detail,\n });\n }\n if (headRefProblem !== null) {\n violations.push({\n kind: 'refUnreadable',\n spaceId,\n refName: headRefProblem.refName,\n detail: headRefProblem.detail,\n });\n }\n\n for (const pkg of member.packages) {\n const from = pkg.metadata.from ?? EMPTY_CONTRACT_HASH;\n const isSelfEdge = from === pkg.metadata.to;\n const hasDataOp = pkg.ops.some((op) => op.operationClass === 'data');\n if (isSelfEdge && !hasDataOp) {\n violations.push({ kind: 'sameSourceAndTarget', spaceId, dirName: pkg.dirName, hash: from });\n }\n }\n\n violations.push(...duplicateMigrationHashViolations(spaceId, member.packages));\n\n // The app head ref is synthesised from the live contract, so it is\n // always present and reachable; only extension spaces read their head\n // ref from disk and can be missing or point outside the graph. A head\n // ref that exists but is unparseable is already surfaced above as\n // `refUnreadable`, so it is not also reported as `headRefMissing`.\n if (!isApp && headRefProblem === null) {\n if (member.headRef === null) {\n violations.push({ kind: 'headRefMissing', spaceId });\n } else if (!headRefPresentInGraph(member, member.headRef.hash)) {\n violations.push({ kind: 'headRefNotInGraph', spaceId, hash: member.headRef.hash });\n }\n }\n }\n\n if (opts?.declaredExtensions !== undefined) {\n violations.push(...layoutViolations(input.spaces, opts.declaredExtensions));\n }\n\n if (opts?.checkContracts === true) {\n violations.push(...contractViolations(input));\n }\n\n return violations;\n}\n\nexport function loadProblemToViolation(\n spaceId: string,\n problem: PackageLoadProblem,\n): IntegrityViolation {\n switch (problem.kind) {\n case 'hashMismatch':\n return {\n kind: 'hashMismatch',\n spaceId,\n dirName: problem.dirName,\n stored: problem.stored,\n computed: problem.computed,\n };\n case 'providedInvariantsMismatch':\n return { kind: 'providedInvariantsMismatch', spaceId, dirName: problem.dirName };\n case 'packageUnloadable':\n return {\n kind: 'packageUnloadable',\n spaceId,\n dirName: problem.dirName,\n detail: problem.detail,\n };\n }\n}\n\nfunction duplicateMigrationHashViolations(\n spaceId: string,\n packages: readonly OnDiskMigrationPackage[],\n): readonly IntegrityViolation[] {\n const dirNamesByHash = new Map<string, string[]>();\n for (const pkg of packages) {\n const hash = pkg.metadata.migrationHash;\n const dirNames = dirNamesByHash.get(hash);\n if (dirNames) dirNames.push(pkg.dirName);\n else dirNamesByHash.set(hash, [pkg.dirName]);\n }\n\n const out: IntegrityViolation[] = [];\n for (const [migrationHash, dirNames] of dirNamesByHash) {\n if (dirNames.length > 1) {\n out.push({\n kind: 'duplicateMigrationHash',\n spaceId,\n migrationHash,\n dirNames: [...dirNames].sort(),\n });\n }\n }\n return out;\n}\n\n/**\n * Whether a space's head-ref hash is present in its reconstructed graph.\n * An empty graph is reachable only by the empty-contract sentinel.\n */\nfunction headRefPresentInGraph(member: ContractSpaceMember, headHash: string): boolean {\n const graph = member.graph();\n if (graph.nodes.size === 0) {\n return headHash === EMPTY_CONTRACT_HASH;\n }\n return graph.nodes.has(headHash);\n}\n\nfunction layoutViolations(\n spaces: readonly IntegritySpaceState[],\n declaredExtensions: readonly DeclaredExtensionEntry[],\n): readonly IntegrityViolation[] {\n const out: IntegrityViolation[] = [];\n const extensionSpaceIds = new Set(spaces.filter((s) => !s.isApp).map((s) => s.member.spaceId));\n const declaredIds = new Set(declaredExtensions.map((d) => d.id));\n\n for (const id of [...extensionSpaceIds].sort()) {\n if (!declaredIds.has(id)) {\n out.push({ kind: 'orphanSpaceDir', spaceId: id });\n }\n }\n for (const id of [...declaredIds].sort()) {\n if (!extensionSpaceIds.has(id)) {\n out.push({ kind: 'declaredButUnmigrated', spaceId: id });\n }\n }\n return out;\n}\n\nfunction contractViolations(input: IntegrityComputationInput): readonly IntegrityViolation[] {\n const out: IntegrityViolation[] = [];\n const elementClaimedBy = new Map<string, string[]>();\n\n for (const { member } of input.spaces) {\n let contract: ReturnType<ContractSpaceMember['contract']>;\n try {\n contract = member.contract();\n } catch (error) {\n out.push({ kind: 'contractUnreadable', spaceId: member.spaceId, detail: detailOf(error) });\n continue;\n }\n\n if (contract.target !== input.targetId) {\n out.push({\n kind: 'targetMismatch',\n spaceId: member.spaceId,\n expected: input.targetId,\n actual: contract.target,\n });\n }\n\n for (const { entityName: elementName } of elementCoordinates(contract.storage)) {\n const claimers = elementClaimedBy.get(elementName);\n if (claimers) claimers.push(member.spaceId);\n else elementClaimedBy.set(elementName, [member.spaceId]);\n }\n }\n\n const disjointness: IntegrityViolation[] = [];\n for (const [element, claimedBy] of elementClaimedBy) {\n if (claimedBy.length > 1) {\n disjointness.push({ kind: 'disjointness', element, claimedBy: [...claimedBy].sort() });\n }\n }\n disjointness.sort((a, b) =>\n a.kind === 'disjointness' && b.kind === 'disjointness' ? a.element.localeCompare(b.element) : 0,\n );\n out.push(...disjointness);\n return out;\n}\n\nfunction detailOf(error: unknown): string {\n if (MigrationToolsError.is(error)) return error.why;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { MigrationToolsError } from '../errors';\nimport { readMigrationsDir } from '../io';\nimport { readContractSpaceContract } from '../read-contract-space-contract';\nimport { readContractSpaceHeadRef } from '../read-contract-space-head-ref';\nimport { HEAD_REF_NAME, type RefLoadProblem, readRefsTolerant } from '../refs';\nimport {\n APP_SPACE_ID,\n isValidSpaceId,\n RESERVED_SPACE_SUBDIR_NAMES,\n spaceMigrationDirectory,\n spaceRefsDirectory,\n} from '../space-layout';\nimport { listContractSpaceDirectories } from '../verify-contract-spaces';\nimport { createContractSpaceAggregate, createContractSpaceMember } from './aggregate';\nimport { computeIntegrityViolations, type IntegritySpaceState } from './check-integrity';\nimport type { ContractSpaceAggregate } from './types';\n\nexport type { DeclaredExtensionEntry } from '../integrity-violation';\n\n/**\n * Inputs for {@link loadContractSpaceAggregate}.\n *\n * Construction reads migration **state** from disk (`migrations/<space>/`\n * packages + refs + head refs). The app's *live* contract is not a disk\n * artefact — in Prisma Next it is always compiled from the project's\n * central contract, so the caller always has it and threads it in as\n * `appContract`. `deserializeContract` is held and called lazily only for\n * the on-disk extension contracts (`migrations/<ext>/contract.json`).\n */\nexport interface LoadAggregateInput {\n readonly migrationsDir: string;\n readonly deserializeContract: (raw: unknown) => Contract;\n readonly appContract: Contract;\n}\n\n/**\n * Build a tolerant, queryable {@link ContractSpaceAggregate} from on-disk\n * migration state plus the caller's live app contract.\n *\n * Building **never throws on disk content**: a hash- or\n * invariants-mismatched package is retained, an unparseable package is\n * omitted, a missing extension head ref leaves `headRef: null`, and an\n * unreadable on-disk contract defers its failure to `member.contract()`.\n * Every such problem is judged by {@link ContractSpaceAggregate.checkIntegrity}\n * rather than aborting the load. The only rejections are catastrophic I/O\n * (a `migrations/` that exists but is unreadable for reasons other than\n * absence).\n *\n * The app space's head ref is synthesised from the live contract's\n * storage hash (the app contract is authored independently of the\n * migration graph), and `app.contract()` returns the supplied contract.\n * Extension spaces read their contract, refs, and head ref from disk.\n */\nexport async function loadContractSpaceAggregate(\n input: LoadAggregateInput,\n): Promise<ContractSpaceAggregate> {\n const { migrationsDir, deserializeContract, appContract } = input;\n const targetId = appContract.target;\n\n const appState = await loadAppSpace(migrationsDir, appContract, deserializeContract);\n const extensionStates = await loadExtensionSpaces(migrationsDir, deserializeContract);\n\n const spaces: readonly IntegritySpaceState[] = [appState, ...extensionStates];\n\n return createContractSpaceAggregate({\n targetId,\n app: appState.member,\n extensions: extensionStates.map((state) => state.member),\n checkIntegrity: (opts) => computeIntegrityViolations({ targetId, spaces }, opts),\n });\n}\n\nasync function loadAppSpace(\n migrationsDir: string,\n appContract: Contract,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<IntegritySpaceState> {\n const spaceDir = spaceMigrationDirectory(migrationsDir, APP_SPACE_ID);\n const { packages, problems } = await readMigrationsDir(spaceDir);\n const { refs, problems: refProblems } = await readRefsTolerant(spaceRefsDirectory(spaceDir));\n\n const member = createContractSpaceMember({\n spaceId: APP_SPACE_ID,\n packages,\n refs,\n headRef: { hash: appContract.storage.storageHash, invariants: [] },\n refsDir: spaceRefsDirectory(spaceDir),\n resolveContract: () => appContract,\n deserializeContract,\n });\n\n // The app head ref is synthesised from the live contract, so there is\n // no on-disk head.json to be missing or corrupt for it.\n return { member, problems, refProblems, headRefProblem: null, isApp: true };\n}\n\nasync function loadExtensionSpaces(\n migrationsDir: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<readonly IntegritySpaceState[]> {\n const candidateDirs = await listContractSpaceDirectories(migrationsDir);\n const extensionIds = candidateDirs\n .filter((name) => name !== APP_SPACE_ID)\n .filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name))\n .filter(isValidSpaceId)\n .sort();\n\n const states: IntegritySpaceState[] = [];\n for (const spaceId of extensionIds) {\n states.push(await loadExtensionSpace(migrationsDir, spaceId, deserializeContract));\n }\n return states;\n}\n\nasync function loadExtensionSpace(\n migrationsDir: string,\n spaceId: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<IntegritySpaceState> {\n const spaceDir = spaceMigrationDirectory(migrationsDir, spaceId);\n const { packages, problems } = await readMigrationsDir(spaceDir);\n const { refs, problems: refProblems } = await readRefsTolerant(spaceRefsDirectory(spaceDir));\n const { headRef, problem: headRefProblem } = await readHeadRefTolerant(migrationsDir, spaceId);\n const rawContract = await readRawContractDeferred(migrationsDir, spaceId);\n\n const member = createContractSpaceMember({\n spaceId,\n packages,\n refs,\n headRef,\n refsDir: spaceRefsDirectory(spaceDir),\n resolveContract: () => deserializeContract(rawContract()),\n deserializeContract,\n });\n\n return { member, problems, refProblems, headRefProblem, isApp: false };\n}\n\n/**\n * The result of resolving an extension's `refs/head.json`: the parsed\n * head ref (or `null` when the file is absent or corrupt) plus a problem\n * when the file exists but cannot be parsed.\n */\ninterface HeadRefReadResult {\n readonly headRef: Awaited<ReturnType<typeof readContractSpaceHeadRef>>;\n readonly problem: RefLoadProblem | null;\n}\n\n/**\n * Read an extension's head ref, distinguishing a *genuinely absent*\n * `head.json` (`headRef: null`, no problem — judged `headRefMissing`)\n * from one that *exists but cannot be parsed* (`headRef: null` plus a\n * problem — judged `refUnreadable`, not `headRefMissing`).\n * `readContractSpaceHeadRef` already returns `null` only for ENOENT and\n * throws for unparseable / schema-invalid content, so the throw is the\n * corruption signal. Construction never throws on disk content.\n */\nfunction isToleratedRefHeadReadError(error: unknown): boolean {\n if (MigrationToolsError.is(error)) return true;\n if (!(error instanceof Error)) return false;\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'ENOENT' || code === 'EISDIR';\n}\n\nasync function readHeadRefTolerant(\n migrationsDir: string,\n spaceId: string,\n): Promise<HeadRefReadResult> {\n try {\n const headRef = await readContractSpaceHeadRef(migrationsDir, spaceId);\n return { headRef, problem: null };\n } catch (error) {\n if (!isToleratedRefHeadReadError(error)) {\n throw error;\n }\n return { headRef: null, problem: { refName: HEAD_REF_NAME, detail: detailOf(error) } };\n }\n}\n\nfunction detailOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Read the raw on-disk contract eagerly (cheap I/O) but defer its\n * (throwing) failure to call time, so a missing or unparseable\n * `contract.json` becomes a `contract()` throw — surfaced as\n * `contractUnreadable` — rather than a construction failure.\n */\nasync function readRawContractDeferred(\n migrationsDir: string,\n spaceId: string,\n): Promise<() => unknown> {\n try {\n const raw = await readContractSpaceContract(migrationsDir, spaceId);\n return () => raw;\n } catch (error) {\n return () => {\n throw error;\n };\n }\n}\n","import type { MigrationPlan } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '../../constants';\nimport { findPathWithDecision } from '../../migration-graph';\nimport type { MigrationOps, OnDiskMigrationPackage } from '../../package';\nimport { requireHeadRef } from '../aggregate';\nimport type { ContractMarkerRecordLike } from '../marker-types';\nimport type { PerSpacePlan } from '../planner-types';\nimport type { ContractSpaceMember } from '../types';\n\n/**\n * Outcome variants for the graph-walk strategy. Mirrors\n * {@link import('../../compute-extension-space-apply-path').ExtensionSpaceApplyPathOutcome}\n * but operates against the member's lazily-reconstructed `graph()`\n * instead of re-reading from disk. The aggregate planner converts\n * these into {@link import('../planner-types').PlannerError}\n * variants.\n */\nexport type GraphWalkOutcome =\n | { readonly kind: 'ok'; readonly result: PerSpacePlan }\n | { readonly kind: 'unreachable' }\n | { readonly kind: 'unsatisfiable'; readonly missing: readonly string[] };\n\nexport interface GraphWalkStrategyInputs {\n readonly aggregateTargetId: string;\n readonly member: ContractSpaceMember;\n readonly currentMarker: ContractMarkerRecordLike | null;\n /**\n * Optional ref name to decorate the resulting `PathDecision`. Used by\n * `migrate` to surface the user-supplied `--to <name>` in\n * structured-progress events and invariant-path error envelopes. The\n * strategy itself does not interpret it.\n */\n readonly refName?: string;\n}\n\n/**\n * Walk a member's hydrated migration graph from the live marker to\n * `member.headRef.hash`, covering every required invariant.\n *\n * Pure synchronous function — no I/O. The aggregate's loader has\n * already integrity-checked every package and reconstructed the graph;\n * this strategy just looks up ops by `migrationHash` and assembles a\n * `MigrationPlan` with `targetId` set from the aggregate (no\n * placeholder cast).\n *\n * Required invariants are computed as `headRef.invariants \\ marker.invariants`\n * — the marker already declares some invariants satisfied; the path\n * only needs to provide the remainder. Mirrors today's\n * `computeExtensionSpaceApplyPath` semantics.\n */\nexport function graphWalkStrategy(input: GraphWalkStrategyInputs): GraphWalkOutcome {\n const { aggregateTargetId, member, currentMarker, refName } = input;\n const headRef = requireHeadRef(member);\n const graph = member.graph();\n const packagesByMigrationHash = new Map<string, OnDiskMigrationPackage>(\n member.packages.map((pkg) => [pkg.metadata.migrationHash, pkg]),\n );\n\n const fromHash = currentMarker?.storageHash ?? EMPTY_CONTRACT_HASH;\n const markerInvariants = new Set(currentMarker?.invariants ?? []);\n const required = new Set(headRef.invariants.filter((id) => !markerInvariants.has(id)));\n\n const outcome = findPathWithDecision(graph, fromHash, headRef.hash, {\n required,\n ...(refName !== undefined ? { refName } : {}),\n });\n\n if (outcome.kind === 'unreachable') {\n return { kind: 'unreachable' };\n }\n if (outcome.kind === 'unsatisfiable') {\n return { kind: 'unsatisfiable', missing: outcome.missing };\n }\n\n const pathOps: MigrationOps[number][] = [];\n const providedInvariantsSet = new Set<string>();\n const edgeRefs: Array<{\n migrationHash: string;\n dirName: string;\n from: string;\n to: string;\n operationCount: number;\n }> = [];\n for (const edge of outcome.decision.selectedPath) {\n const pkg = packagesByMigrationHash.get(edge.migrationHash);\n if (!pkg) {\n throw new Error(\n `Migration package missing for edge ${edge.migrationHash} in space \"${member.spaceId}\". The hydrated migration graph and packagesByMigrationHash map are out of sync — this should be unreachable; report.`,\n );\n }\n for (const op of pkg.ops) pathOps.push(op);\n for (const invariant of pkg.metadata.providedInvariants) providedInvariantsSet.add(invariant);\n edgeRefs.push({\n migrationHash: edge.migrationHash,\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n operationCount: pkg.ops.length,\n });\n }\n\n const plan: MigrationPlan = {\n targetId: aggregateTargetId,\n spaceId: member.spaceId,\n origin: currentMarker === null ? null : { storageHash: currentMarker.storageHash },\n destination: { storageHash: headRef.hash },\n operations: pathOps,\n providedInvariants: [...providedInvariantsSet].sort(),\n };\n\n return {\n kind: 'ok',\n result: {\n plan,\n displayOps: pathOps,\n destinationContract: member.contract(),\n strategy: 'graph-walk',\n migrationEdges: edgeRefs,\n pathDecision: outcome.decision,\n },\n };\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport type { ContractSpaceMember } from './types';\n\n/**\n * Project the **introspected live schema** to the slice claimed by a\n * single contract-space member.\n *\n * \"Schema\" here means the live introspected database state — the\n * planner / verifier sees this object as a `MongoSchemaIR` (Mongo) or\n * `SqlSchemaIR` (SQL). It is **not** a database schema in the SQL\n * `CREATE SCHEMA` sense, nor a contract-space namespace. The\n * function's job is to filter that introspected state down to the\n * elements claimed by one space, so a per-space verify pass doesn't\n * see another space's storage as \"extras\".\n *\n * Returns the same `schema` value with every top-level storage element\n * (table or collection) claimed by **other** members of the aggregate\n * removed. Elements not claimed by any member flow through unchanged —\n * the planner / verifier sees them as orphans (extras in strict mode).\n *\n * Used by:\n *\n * - The aggregate planner's **synth strategy**: when synthesising a\n * plan against a member's contract, the live schema must be projected\n * to that member's slice so the planner doesn't treat elements claimed\n * by other members as \"extras\" and emit destructive ops to drop them.\n * - The aggregate verifier's **schemaCheck**: projects per member so the\n * single-contract verify only sees the slice claimed by the member it\n * is checking. Closes the architectural concern that a multi-member\n * deployment makes each member's elements look like extras to every\n * other member's verify pass.\n *\n * **Duck-typing semantics**: the helper operates on `unknown` for the\n * schema and falls through structurally if the shape doesn't match.\n * Two storage shapes are recognised today:\n *\n * - SQL families expose `storage.tables: Record<string, ...>` on\n * contracts and the introspected schema mirrors the same record shape.\n * Pruning iterates the record entries.\n * - Mongo exposes `storage.collections: Record<string, ...>` on\n * contracts; the introspected `MongoSchemaIR` exposes\n * `collections: ReadonlyArray<{name: string, ...}>`. Pruning iterates\n * the array on the schema side and the record's keys on the\n * other-member side.\n *\n * Schemas of unrecognised shape are returned unchanged. The function\n * never imports family classes (`SqlSchemaIR`, `MongoSchemaIR`); the\n * projected schema is a plain object — `{...schema, tables: pruned}` or\n * `{...schema, collections: pruned}` — that downstream consumers\n * duck-type. A future family with a different storage shape gets the\n * schema returned unchanged rather than blowing up the aggregate\n * planner.\n *\n * Record-shape detection guards against arrays (`!Array.isArray`) so\n * an unrecognised array-shaped value falls through unchanged rather\n * than being pruned by numeric keys.\n */\nexport function projectSchemaToSpace(\n schema: unknown,\n member: ContractSpaceMember,\n otherMembers: ReadonlyArray<ContractSpaceMember>,\n): unknown {\n if (typeof schema !== 'object' || schema === null) return schema;\n\n const ownedByOthers = collectOwnedNames(member, otherMembers);\n if (ownedByOthers.size === 0) return schema;\n\n const schemaObj = schema as { readonly tables?: unknown; readonly collections?: unknown };\n\n if (\n typeof schemaObj.tables === 'object' &&\n schemaObj.tables !== null &&\n !Array.isArray(schemaObj.tables)\n ) {\n return pruneRecord(schemaObj, 'tables', ownedByOthers);\n }\n\n if (Array.isArray(schemaObj.collections)) {\n return pruneCollectionsArray(schemaObj, ownedByOthers);\n }\n\n if (\n typeof schemaObj.collections === 'object' &&\n schemaObj.collections !== null &&\n !Array.isArray(schemaObj.collections)\n ) {\n return pruneRecord(schemaObj, 'collections', ownedByOthers);\n }\n\n return schema;\n}\n\nfunction collectOwnedNames(\n member: ContractSpaceMember,\n otherMembers: ReadonlyArray<ContractSpaceMember>,\n): Set<string> {\n const owned = new Set<string>();\n for (const other of otherMembers) {\n if (other.spaceId === member.spaceId) continue;\n for (const { entityName } of elementCoordinates(other.contract().storage)) {\n owned.add(entityName);\n }\n }\n return owned;\n}\n\nfunction pruneRecord(\n schemaObj: { readonly tables?: unknown; readonly collections?: unknown },\n field: 'tables' | 'collections',\n ownedByOthers: ReadonlySet<string>,\n): unknown {\n const source = schemaObj[field] as Record<string, unknown>;\n let removed = false;\n const pruned: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(source)) {\n if (ownedByOthers.has(name)) {\n removed = true;\n } else {\n pruned[name] = value;\n }\n }\n if (!removed) return schemaObj;\n return { ...schemaObj, [field]: pruned };\n}\n\nfunction pruneCollectionsArray(\n schemaObj: { readonly collections?: unknown },\n ownedByOthers: ReadonlySet<string>,\n): unknown {\n const source = schemaObj.collections as ReadonlyArray<unknown>;\n let removed = false;\n const pruned: unknown[] = [];\n for (const entry of source) {\n if (typeof entry === 'object' && entry !== null) {\n const name = (entry as { readonly name?: unknown }).name;\n if (typeof name === 'string' && ownedByOthers.has(name)) {\n removed = true;\n continue;\n }\n }\n pruned.push(entry);\n }\n if (!removed) return schemaObj;\n return { ...schemaObj, collections: pruned };\n}\n","import type { AggregateMigrationEdgeRef } from './planner-types';\n\nexport function buildSynthMigrationEdge(args: {\n readonly currentMarkerStorageHash: string | null | undefined;\n readonly destinationStorageHash: string;\n readonly operationCount: number;\n}): AggregateMigrationEdgeRef {\n return {\n dirName: '',\n migrationHash: args.destinationStorageHash,\n from: args.currentMarkerStorageHash ?? '',\n to: args.destinationStorageHash,\n operationCount: args.operationCount,\n };\n}\n","import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlFamilyInstance,\n MigrationOperationPolicy,\n MigrationPlan,\n MigrationPlannerConflict,\n MigrationPlannerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport type { ContractMarkerRecordLike } from '../marker-types';\nimport type { PerSpacePlan } from '../planner-types';\nimport { projectSchemaToSpace } from '../project-schema-to-space';\nimport { buildSynthMigrationEdge } from '../synth-migration-edge';\nimport type { ContractSpaceMember } from '../types';\n\nexport interface SynthStrategyInputs<TFamilyId extends string, TTargetId extends string> {\n readonly aggregateTargetId: string;\n readonly currentMarker: ContractMarkerRecordLike | null;\n readonly member: ContractSpaceMember;\n readonly otherMembers: ReadonlyArray<ContractSpaceMember>;\n readonly schemaIntrospection: unknown;\n readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId, unknown>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n readonly operationPolicy: MigrationOperationPolicy;\n}\n\nexport type SynthStrategyOutcome =\n | { readonly kind: 'ok'; readonly result: PerSpacePlan }\n | { readonly kind: 'failure'; readonly conflicts: readonly MigrationPlannerConflict[] };\n\n/**\n * The {@link MigrationPlanner.plan} interface is declared as synchronous,\n * but historical and test fixture call sites have always invoked it\n * with `await` (see prior `db-apply-per-space.ts`). Tolerating a\n * Promise here keeps existing test mocks working without changing the\n * declared family SPI.\n */\ntype MaybeAsyncPlannerResult = MigrationPlannerResult | Promise<MigrationPlannerResult>;\n\n/**\n * Synthesise a migration plan for a single member by projecting the\n * live schema down to that member's claimed slice and delegating to\n * the family's `createPlanner(...).plan(...)`.\n *\n * Pre-projection (via {@link projectSchemaToSpace}) closes the F23\n * concern: without it, the family's planner sees other members'\n * tables as \"extras\" and emits destructive ops to drop them. With it,\n * the planner only sees the slice this member claims.\n *\n * The synthesised plan's `targetId` is set from `aggregateTargetId`\n * (the aggregate's ambient target). The family's planner does not\n * stamp `targetId` on the produced plan; the aggregate planner is\n * the single point that knows the target.\n *\n * Used by:\n *\n * - The app member by default (CLI policy\n * `ignoreGraphFor: { app.spaceId }`).\n * - Any extension member whose `headRef.invariants` is empty (the\n * strategy selector falls back to synth when graph-walk isn't\n * required).\n */\nexport async function synthStrategy<TFamilyId extends string, TTargetId extends string>(\n input: SynthStrategyInputs<TFamilyId, TTargetId>,\n): Promise<SynthStrategyOutcome> {\n const projectedSchema = projectSchemaToSpace(\n input.schemaIntrospection,\n input.member,\n input.otherMembers,\n );\n\n const planner = input.migrations.createPlanner(input.familyInstance);\n const plannerResult: MigrationPlannerResult = await (planner.plan({\n contract: input.member.contract(),\n schema: projectedSchema,\n policy: input.operationPolicy,\n fromContract: null,\n frameworkComponents: input.frameworkComponents,\n spaceId: input.member.spaceId,\n }) as MaybeAsyncPlannerResult);\n\n if (plannerResult.kind === 'failure') {\n return { kind: 'failure', conflicts: plannerResult.conflicts };\n }\n\n const synthedPlan = plannerResult.plan;\n // The family planner returns a class-instance-shaped plan whose\n // `destination` / `operations` are accessors on the prototype, often\n // backed by private fields. A naive spread (`{ ...synthedPlan }`)\n // would lose those accessors and produce a plan with\n // `destination: undefined`; rebinding the prototype on a plain\n // object would break private-field access. We instead wrap the plan\n // in a Proxy that forwards every read except `targetId`, which is\n // stamped from the aggregate's ambient target. This preserves the\n // planner's class semantics while keeping the aggregate the single\n // source of truth for `targetId`.\n const plan: MigrationPlan = new Proxy(synthedPlan, {\n get(target, prop) {\n if (prop === 'targetId') return input.aggregateTargetId;\n // Forward `this` as the original target so prototype-bound\n // private fields (#destination, #operations, …) resolve.\n return Reflect.get(target, prop, target);\n },\n has(target, prop) {\n if (prop === 'targetId') return true;\n return Reflect.has(target, prop);\n },\n });\n\n const destinationStorageHash = synthedPlan.destination.storageHash;\n return {\n kind: 'ok',\n result: {\n plan,\n displayOps: synthedPlan.operations,\n destinationContract: input.member.contract(),\n strategy: 'synth',\n ...(plannerResult.warnings && plannerResult.warnings.length > 0\n ? { warnings: plannerResult.warnings }\n : {}),\n migrationEdges: [\n buildSynthMigrationEdge({\n currentMarkerStorageHash: input.currentMarker?.storageHash,\n destinationStorageHash,\n operationCount: synthedPlan.operations.length,\n }),\n ],\n },\n };\n}\n","import { notOk, ok } from '@prisma-next/utils/result';\nimport { requireHeadRef } from './aggregate';\nimport type { PerSpacePlan, PlannerError, PlannerInput, PlannerOutput } from './planner-types';\nimport { graphWalkStrategy } from './strategies/graph-walk';\nimport { synthStrategy } from './strategies/synth';\nimport type { ContractSpaceMember } from './types';\n\nexport type {\n AggregateCurrentDBState,\n AggregateMigrationEdgeRef,\n CallerPolicy,\n PerSpacePlan,\n PlannerError,\n PlannerInput,\n PlannerOutput,\n PlannerSuccess,\n} from './planner-types';\n\n/**\n * Plan a migration across every member of a {@link ContractSpaceAggregate}.\n *\n * Strategy selection per member, in order; first match wins:\n *\n * 1. If `callerPolicy.ignoreGraphFor.has(member.spaceId)`:\n * - If `member.headRef.invariants` is empty → synth.\n * - Else → `policyConflict` (synth cannot satisfy authored invariants).\n * 2. Else if `member.graph()` is non-empty AND graph-walk\n * succeeds → graph-walk.\n * 3. Else if `member.headRef.invariants` is empty → synth.\n * 4. Else → graph-walk failure → `extensionPathUnreachable` /\n * `extensionPathUnsatisfiable`.\n *\n * Output `applyOrder` is `[...aggregate.extensions.map(spaceId), aggregate.app.spaceId]`\n * — extensions alphabetical, then app — matching today's\n * `concatenateSpaceApplyInputs` ordering. This preserves\n * `MigrationRunnerFailure.failingSpace` attribution byte-for-byte.\n *\n * Every emitted `MigrationPlan` has `targetId = aggregate.targetId`.\n * No placeholder cast; no patch step.\n */\nexport async function planMigration<TFamilyId extends string, TTargetId extends string>(\n input: PlannerInput<TFamilyId, TTargetId>,\n): Promise<PlannerOutput> {\n const { aggregate, currentDBState, callerPolicy } = input;\n const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];\n\n const perSpace = new Map<string, PerSpacePlan>();\n\n // Iterate in apply order so a per-member error short-circuits the\n // walk in the same order the runner would walk inputs.\n const orderedMembers: ReadonlyArray<ContractSpaceMember> = [\n ...aggregate.extensions,\n aggregate.app,\n ];\n\n for (const member of orderedMembers) {\n const otherMembers = allMembers.filter((m) => m.spaceId !== member.spaceId);\n const currentMarker = currentDBState.markersBySpaceId.get(member.spaceId) ?? null;\n const headRef = requireHeadRef(member);\n\n const ignoreGraph = callerPolicy.ignoreGraphFor.has(member.spaceId);\n const invariantsRequired = headRef.invariants.length > 0;\n\n if (ignoreGraph && invariantsRequired) {\n const conflict: PlannerError = {\n kind: 'policyConflict',\n spaceId: member.spaceId,\n detail: `\\`callerPolicy.ignoreGraphFor\\` requested for space \"${member.spaceId}\", but the member declares non-empty head-ref invariants (${headRef.invariants.join(', ')}). Synthesising a plan from the contract IR cannot satisfy authored invariants — the graph must be walked. Either remove \"${member.spaceId}\" from \\`ignoreGraphFor\\` or amend the on-disk head ref to declare zero invariants.`,\n };\n return notOk(conflict);\n }\n\n if (ignoreGraph) {\n const synthOutcome = await synthStrategy({\n aggregateTargetId: aggregate.targetId,\n currentMarker,\n member,\n otherMembers,\n schemaIntrospection: currentDBState.schemaIntrospection,\n familyInstance: input.familyInstance,\n migrations: input.migrations,\n frameworkComponents: input.frameworkComponents,\n operationPolicy: input.operationPolicy,\n });\n if (synthOutcome.kind === 'failure') {\n return notOk({\n kind: 'appSynthFailure',\n spaceId: member.spaceId,\n conflicts: synthOutcome.conflicts,\n });\n }\n perSpace.set(member.spaceId, synthOutcome.result);\n continue;\n }\n\n // Try graph-walk first when the graph has nodes; fall back to synth\n // when the graph is empty AND no invariants are required.\n if (member.graph().nodes.size > 0) {\n const walked = graphWalkStrategy({\n aggregateTargetId: aggregate.targetId,\n member,\n currentMarker,\n });\n if (walked.kind === 'ok') {\n perSpace.set(member.spaceId, walked.result);\n continue;\n }\n if (walked.kind === 'unreachable') {\n return notOk({\n kind: 'extensionPathUnreachable',\n spaceId: member.spaceId,\n target: headRef.hash,\n });\n }\n // unsatisfiable — surface\n return notOk({\n kind: 'extensionPathUnsatisfiable',\n spaceId: member.spaceId,\n missingInvariants: walked.missing,\n });\n }\n\n // Empty graph: synth is the only option, and it can only satisfy\n // empty-invariant members.\n if (invariantsRequired) {\n return notOk({\n kind: 'extensionPathUnsatisfiable',\n spaceId: member.spaceId,\n missingInvariants: [...headRef.invariants].sort(),\n });\n }\n\n const synthOutcome = await synthStrategy({\n aggregateTargetId: aggregate.targetId,\n currentMarker,\n member,\n otherMembers,\n schemaIntrospection: currentDBState.schemaIntrospection,\n familyInstance: input.familyInstance,\n migrations: input.migrations,\n frameworkComponents: input.frameworkComponents,\n operationPolicy: input.operationPolicy,\n });\n if (synthOutcome.kind === 'failure') {\n return notOk({\n kind: 'appSynthFailure',\n spaceId: member.spaceId,\n conflicts: synthOutcome.conflicts,\n });\n }\n perSpace.set(member.spaceId, synthOutcome.result);\n }\n\n return ok({\n perSpace,\n applyOrder: [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId],\n });\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { requireHeadRef } from './aggregate';\nimport type { ContractMarkerRecordLike } from './marker-types';\nimport { projectSchemaToSpace } from './project-schema-to-space';\nimport type { ContractSpaceAggregate, ContractSpaceMember } from './types';\n\n/**\n * Caller policy for the verifier. Today's only knob is\n * `mode`: `strict` treats orphan elements (live tables not claimed by\n * any aggregate member) as errors; `lenient` treats them as\n * informational. Maps directly to `db verify --strict`.\n */\nexport interface VerifierInput<TSchemaResult> {\n readonly aggregate: ContractSpaceAggregate;\n readonly markersBySpaceId: ReadonlyMap<string, ContractMarkerRecordLike | null>;\n readonly schemaIntrospection: unknown;\n readonly mode: 'strict' | 'lenient';\n /**\n * Caller-supplied per-space schema verifier. The CLI wires this to\n * the family's `verifySqlSchema` (SQL) / equivalent (other\n * families). The verifier projects the schema to the\n * member's slice via {@link projectSchemaToSpace} before invoking\n * the callback, so single-contract semantics are preserved.\n *\n * Typed structurally with a generic `TSchemaResult` so the\n * migration-tools layer doesn't depend on the SQL family's\n * `VerifySqlSchemaResult`. CLI callers pass the family's type\n * through unchanged.\n */\n readonly verifySchemaForMember: (\n projectedSchema: unknown,\n member: ContractSpaceMember,\n mode: 'strict' | 'lenient',\n ) => TSchemaResult;\n}\n\n/**\n * Marker-check result per member. Mirrors the four cases the\n * `verifyContractSpaces` primitive surfaces today, plus an `'absent'`\n * case for greenfield spaces (no marker row written yet — `db init`\n * not run).\n */\nexport type MarkerCheckResult =\n | { readonly kind: 'ok' }\n | { readonly kind: 'absent' }\n | {\n readonly kind: 'hashMismatch';\n readonly markerHash: string;\n readonly expected: string;\n }\n | { readonly kind: 'missingInvariants'; readonly missing: readonly string[] };\n\nexport interface MarkerCheckSection {\n readonly perSpace: ReadonlyMap<string, MarkerCheckResult>;\n readonly orphanMarkers: readonly {\n readonly spaceId: string;\n readonly row: ContractMarkerRecordLike;\n }[];\n}\n\n/**\n * A live storage element (today: a top-level table) not claimed by any\n * member of the aggregate. The verifier always reports these;\n * the caller decides what to do — `db verify --strict` treats them as\n * errors, the lenient default treats them as informational.\n *\n * Today only `kind: 'table'` exists. The discriminated shape leaves\n * room for orphan columns / indexes / sequences in the future without\n * breaking the type contract.\n */\nexport type OrphanElement = { readonly kind: 'table'; readonly name: string };\n\nexport interface SchemaCheckSection<TSchemaResult> {\n readonly perSpace: ReadonlyMap<string, TSchemaResult>;\n /**\n * Live elements present in the introspected schema that are not\n * claimed by **any** aggregate member. Sorted alphabetically by name.\n */\n readonly orphanElements: readonly OrphanElement[];\n}\n\nexport interface VerifierSuccess<TSchemaResult> {\n readonly markerCheck: MarkerCheckSection;\n readonly schemaCheck: SchemaCheckSection<TSchemaResult>;\n}\n\nexport type VerifierError = {\n readonly kind: 'introspectionFailure';\n readonly detail: string;\n};\n\nexport type VerifierOutput<TSchemaResult> = Result<VerifierSuccess<TSchemaResult>, VerifierError>;\n\n/**\n * Verify a {@link ContractSpaceAggregate} against the live database\n * state. Bundles two checks:\n *\n * - `markerCheck` per member: compare the live marker row against the\n * member's `headRef.hash` + `headRef.invariants`. Absence is a\n * distinct kind, not an error (callers — `db verify` strict vs\n * `db init` precondition — choose how to interpret it).\n * - `schemaCheck` per member: project the live schema to the slice\n * the member claims via {@link projectSchemaToSpace}, then delegate\n * to the caller-supplied `verifySchemaForMember`. The pre-projection\n * means the family's single-contract verifier no longer sees other\n * members' tables as `extras`, so a multi-member deployment never\n * surfaces cross-member tables as orphaned schema elements.\n *\n * `markerCheck.orphanMarkers` lists every marker row whose `space` is\n * not a member of the aggregate. `db verify` callers reject orphans;\n * future tooling may not.\n *\n * Pure synchronous function; no I/O. The caller (CLI) gathers\n * `markersBySpaceId` and `schemaIntrospection` ahead of the call.\n */\nexport function verifyMigration<TSchemaResult>(\n input: VerifierInput<TSchemaResult>,\n): VerifierOutput<TSchemaResult> {\n try {\n return runVerifyMigration(input);\n } catch (error) {\n return notOk({\n kind: 'introspectionFailure',\n detail: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nfunction runVerifyMigration<TSchemaResult>(\n input: VerifierInput<TSchemaResult>,\n): VerifierOutput<TSchemaResult> {\n const { aggregate, markersBySpaceId, schemaIntrospection, mode, verifySchemaForMember } = input;\n const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];\n const memberSpaceIds = new Set(allMembers.map((m) => m.spaceId));\n\n // Marker check per member.\n const markerPerSpace = new Map<string, MarkerCheckResult>();\n for (const member of allMembers) {\n const marker = markersBySpaceId.get(member.spaceId) ?? null;\n if (marker === null) {\n markerPerSpace.set(member.spaceId, { kind: 'absent' });\n continue;\n }\n const headRef = requireHeadRef(member);\n if (marker.storageHash !== headRef.hash) {\n markerPerSpace.set(member.spaceId, {\n kind: 'hashMismatch',\n markerHash: marker.storageHash,\n expected: headRef.hash,\n });\n continue;\n }\n const markerInvariants = new Set(marker.invariants);\n const missing = headRef.invariants.filter((id) => !markerInvariants.has(id));\n if (missing.length > 0) {\n markerPerSpace.set(member.spaceId, {\n kind: 'missingInvariants',\n missing: [...missing].sort(),\n });\n continue;\n }\n markerPerSpace.set(member.spaceId, { kind: 'ok' });\n }\n\n // Orphan markers: entries in markersBySpaceId whose spaceId is not a\n // member of the aggregate.\n const orphanMarkers: { spaceId: string; row: ContractMarkerRecordLike }[] = [];\n for (const [spaceId, row] of markersBySpaceId) {\n if (row !== null && !memberSpaceIds.has(spaceId)) {\n orphanMarkers.push({ spaceId, row });\n }\n }\n orphanMarkers.sort((a, b) => a.spaceId.localeCompare(b.spaceId));\n\n // Schema check per member (with per-space pre-projection).\n const schemaPerSpace = new Map<string, TSchemaResult>();\n for (const member of allMembers) {\n const others = allMembers.filter((m) => m.spaceId !== member.spaceId);\n const projected = projectSchemaToSpace(schemaIntrospection, member, others);\n schemaPerSpace.set(member.spaceId, verifySchemaForMember(projected, member, mode));\n }\n\n return ok({\n markerCheck: {\n perSpace: markerPerSpace,\n orphanMarkers,\n },\n schemaCheck: {\n perSpace: schemaPerSpace,\n orphanElements: detectOrphanElements(schemaIntrospection, allMembers),\n },\n });\n}\n\n/**\n * Live tables not claimed by any aggregate member. Duck-typed against\n * the introspected schema's `tables` map; schemas whose shape doesn't\n * match return an empty list (consistent with\n * {@link projectSchemaToSpace}'s fall-through).\n */\nfunction detectOrphanElements(\n schemaIntrospection: unknown,\n members: ReadonlyArray<ContractSpaceMember>,\n): readonly OrphanElement[] {\n if (typeof schemaIntrospection !== 'object' || schemaIntrospection === null) return [];\n const liveTables = (schemaIntrospection as { readonly tables?: unknown }).tables;\n if (typeof liveTables !== 'object' || liveTables === null) return [];\n\n const claimedTables = new Set<string>();\n for (const member of members) {\n const contract = member.contract();\n for (const { entityName } of elementCoordinates(contract.storage)) {\n claimedTables.add(entityName);\n }\n }\n\n const orphans: OrphanElement[] = [];\n for (const tableName of Object.keys(liveTables as Record<string, unknown>)) {\n if (!claimedTables.has(tableName)) {\n orphans.push({ kind: 'table', name: tableName });\n }\n }\n orphans.sort((a, b) => a.name.localeCompare(b.name));\n return orphans;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"aggregate.mjs","names":["detailOf"],"sources":["../../src/aggregate/aggregate.ts","../../src/aggregate/check-integrity.ts","../../src/aggregate/loader.ts","../../src/aggregate/strategies/graph-walk.ts","../../src/aggregate/project-schema-to-space.ts","../../src/aggregate/synth-migration-edge.ts","../../src/aggregate/strategies/synth.ts","../../src/aggregate/planner.ts","../../src/aggregate/verifier.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract, StorageNamespace } from '@prisma-next/contract/types';\nimport { join } from 'pathe';\nimport {\n errorBundleNotFoundForGraphNode,\n errorContractDeserializationFailed,\n errorHashNotInGraph,\n errorInvalidJson,\n errorMissingFile,\n errorSnapshotMissing,\n MigrationToolsError,\n} from '../errors';\nimport type { MigrationGraph } from '../graph';\nimport { isGraphNode } from '../graph-membership';\nimport type { IntegrityQueryOptions, IntegrityViolation } from '../integrity-violation';\nimport { reconstructGraph } from '../migration-graph';\nimport type { OnDiskMigrationPackage } from '../package';\nimport type { Refs } from '../refs';\nimport { readRefSnapshot } from '../refs/snapshot';\nimport type { ContractSpaceHeadRecord } from '../verify-contract-spaces';\nimport type {\n ContractAtOptions,\n ContractAtResult,\n ContractSpaceAggregate,\n ContractSpaceMember,\n} from './types';\n\nfunction hasErrnoCode(error: unknown, code: string): boolean {\n return error instanceof Error && (error as { code?: string }).code === code;\n}\n\nfunction contractAtMemoKey(hash: string, refName: string | undefined): string {\n return `${hash}\\0${refName ?? ''}`;\n}\n\nfunction deserializeContractAtPath(\n filePath: string,\n contractJson: unknown,\n deserializeContract: (raw: unknown) => Contract,\n): Contract {\n try {\n return deserializeContract(contractJson);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n throw error;\n }\n const message = error instanceof Error ? error.message : String(error);\n throw errorContractDeserializationFailed(filePath, message);\n }\n}\n\nasync function readGraphNodeEndContract(\n packageDir: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<{ contractJson: unknown; contractDts: string; contract: Contract }> {\n const jsonPath = join(packageDir, 'end-contract.json');\n const dtsPath = join(packageDir, 'end-contract.d.ts');\n\n let rawJson: string;\n try {\n rawJson = await readFile(jsonPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile('end-contract.json', packageDir);\n }\n throw error;\n }\n\n let contractJson: unknown;\n try {\n contractJson = JSON.parse(rawJson);\n } catch (error) {\n throw errorInvalidJson(jsonPath, error instanceof Error ? error.message : String(error));\n }\n\n let contractDts: string;\n try {\n contractDts = await readFile(dtsPath, 'utf-8');\n } catch (error) {\n if (hasErrnoCode(error, 'ENOENT')) {\n throw errorMissingFile('end-contract.d.ts', packageDir);\n }\n throw error;\n }\n\n const contract = deserializeContractAtPath(jsonPath, contractJson, deserializeContract);\n return { contractJson, contractDts, contract };\n}\n\nasync function resolveContractAt(args: {\n readonly hash: string;\n readonly opts: ContractAtOptions | undefined;\n readonly refsDir: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly graph: MigrationGraph;\n readonly deserializeContract: (raw: unknown) => Contract;\n}): Promise<ContractAtResult> {\n const { hash, opts, refsDir, packages, graph, deserializeContract } = args;\n const refName = opts?.refName;\n\n if (refName !== undefined) {\n const snapshot = await readRefSnapshot(refsDir, refName);\n if (snapshot) {\n const jsonPath = join(refsDir, `${refName}.contract.json`);\n return {\n hash,\n contractJson: snapshot.contract,\n contractDts: snapshot.contractDts,\n contract: deserializeContractAtPath(jsonPath, snapshot.contract, deserializeContract),\n provenance: 'snapshot',\n };\n }\n\n if (isGraphNode(hash, graph)) {\n return resolveGraphNodeContractAt({\n hash,\n packages,\n deserializeContract,\n explicitLabel: refName,\n });\n }\n\n throw errorSnapshotMissing(refName);\n }\n\n if (isGraphNode(hash, graph)) {\n return resolveGraphNodeContractAt({ hash, packages, deserializeContract });\n }\n\n throw errorHashNotInGraph(hash, graph);\n}\n\nasync function resolveGraphNodeContractAt(args: {\n readonly hash: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly deserializeContract: (raw: unknown) => Contract;\n readonly explicitLabel?: string;\n}): Promise<ContractAtResult> {\n const { hash, packages, deserializeContract, explicitLabel } = args;\n const matchingBundle = packages.find((pkg) => pkg.metadata.to === hash);\n if (!matchingBundle) {\n throw errorBundleNotFoundForGraphNode(hash, explicitLabel);\n }\n\n const { contractJson, contractDts, contract } = await readGraphNodeEndContract(\n matchingBundle.dirPath,\n deserializeContract,\n );\n return {\n hash,\n contractJson,\n contractDts,\n contract,\n provenance: 'graph-node',\n sourceDir: matchingBundle.dirPath,\n };\n}\n\n/**\n * Resolve a member's head ref, asserting it is present. The apply/verify\n * engine only runs after `checkIntegrity` has refused on `headRefMissing`,\n * so a member reaching the planner / verifier without a head ref is a\n * programming error (the integrity gate was skipped), not a user-facing\n * state. The app member's head ref is always synthesised, so this only\n * ever guards an ungated extension space.\n */\nexport function requireHeadRef(member: ContractSpaceMember): ContractSpaceHeadRecord {\n if (member.headRef === null) {\n throw new Error(\n `Contract space \"${member.spaceId}\" has no head ref; the integrity gate must refuse a missing head ref before planning or verifying.`,\n );\n }\n return member.headRef;\n}\n\n/**\n * Build a {@link ContractSpaceMember} with lazily-memoised `graph()`,\n * `contract()`, and `contractAt()` facets.\n *\n * `graph()` reconstructs the migration graph from `packages` on first\n * call and caches it. `contract()` calls `resolveContract` on first call\n * and caches the result; a throwing `resolveContract` (e.g. a missing or\n * undeserializable on-disk contract) re-throws on each call rather than\n * caching a value — `checkIntegrity` surfaces that as `contractUnreadable`.\n * `contractAt()` materializes the contract at an arbitrary graph node with\n * the same resolution order as plan-time ref resolution: ref snapshot first\n * (when `opts.refName` is set), else the matching package's `end-contract.*`.\n */\nexport function createContractSpaceMember(args: {\n readonly spaceId: string;\n readonly packages: readonly OnDiskMigrationPackage[];\n readonly refs: Refs;\n readonly headRef: ContractSpaceHeadRecord | null;\n readonly refsDir: string;\n readonly resolveContract: () => Contract;\n readonly deserializeContract: (raw: unknown) => Contract;\n}): ContractSpaceMember {\n const { spaceId, packages, refs, headRef, refsDir, resolveContract, deserializeContract } = args;\n let graphMemo: MigrationGraph | undefined;\n let contractMemo: Contract | undefined;\n const contractAtMemo = new Map<string, ContractAtResult>();\n\n function memberGraph(): MigrationGraph {\n graphMemo ??= reconstructGraph(packages);\n return graphMemo;\n }\n\n return {\n spaceId,\n packages,\n refs,\n headRef,\n graph: memberGraph,\n contract() {\n contractMemo ??= resolveContract();\n return contractMemo;\n },\n async contractAt(hash, opts) {\n const key = contractAtMemoKey(hash, opts?.refName);\n const cached = contractAtMemo.get(key);\n if (cached) {\n return cached;\n }\n\n const result = await resolveContractAt({\n hash,\n opts,\n refsDir,\n packages,\n graph: memberGraph(),\n deserializeContract,\n });\n contractAtMemo.set(key, result);\n return result;\n },\n };\n}\n\n/**\n * Collect the union of every namespace declared across all members of an\n * aggregate (app + extensions) and return a minimal object with the shape\n * `{ storage: { namespaces } }` suitable for passing to\n * `familyInstance.introspect`.\n *\n * Callers invoke this after the integrity gate (`buildContractSpaceAggregate`\n * with `checkContracts: true`), so every `member.contract()` call is safe —\n * no try/catch is needed here.\n */\nexport function collectAggregateNamespaces(aggregate: ContractSpaceAggregate): {\n readonly storage: { readonly namespaces: Readonly<Record<string, StorageNamespace>> };\n} {\n const merged: Record<string, StorageNamespace> = {};\n for (const member of aggregate.spaces()) {\n for (const [key, ns] of Object.entries(member.contract().storage.namespaces)) {\n merged[key] = ns;\n }\n }\n return { storage: { namespaces: merged } };\n}\n\n/**\n * Assemble a {@link ContractSpaceAggregate} value from its members and a\n * `checkIntegrity` implementation. The query methods (`listSpaces` /\n * `hasSpace` / `space` / `spaces`) are derived here so every aggregate —\n * loader-built or test-built — shares one query surface: `app` first,\n * then `extensions` in the order supplied (the loader sorts them\n * lex-ascending by `spaceId`).\n */\nexport function createContractSpaceAggregate(args: {\n readonly targetId: string;\n readonly app: ContractSpaceMember;\n readonly extensions: readonly ContractSpaceMember[];\n readonly checkIntegrity: (opts?: IntegrityQueryOptions) => readonly IntegrityViolation[];\n}): ContractSpaceAggregate {\n const { targetId, app, extensions, checkIntegrity } = args;\n const ordered: readonly ContractSpaceMember[] = [app, ...extensions];\n const byId = new Map(ordered.map((m) => [m.spaceId, m]));\n return {\n targetId,\n app,\n extensions,\n listSpaces: () => ordered.map((m) => m.spaceId),\n hasSpace: (id) => byId.has(id),\n space: (id) => byId.get(id),\n spaces: () => ordered,\n checkIntegrity,\n };\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport { EMPTY_CONTRACT_HASH } from '../constants';\nimport { MigrationToolsError } from '../errors';\nimport type {\n DeclaredExtensionEntry,\n IntegrityQueryOptions,\n IntegrityViolation,\n} from '../integrity-violation';\nimport type { PackageLoadProblem } from '../io';\nimport type { OnDiskMigrationPackage } from '../package';\nimport type { RefLoadProblem } from '../refs';\nimport type { ContractSpaceMember } from './types';\n\n/**\n * One space's load-time facts that `checkIntegrity` judges: the loaded\n * member, the load-time problems `readMigrationsDir` surfaced for it, and\n * whether it is the app space (the app head ref is synthesised, so the\n * head-ref checks are skipped for it).\n */\nexport interface IntegritySpaceState {\n readonly member: ContractSpaceMember;\n readonly problems: readonly PackageLoadProblem[];\n /** Per-ref problems: a user ref `*.json` that exists but is unparseable. */\n readonly refProblems: readonly RefLoadProblem[];\n /**\n * The space's `refs/head.json` problem when it exists but is unparseable.\n * `null` means the head ref was read cleanly or is genuinely absent —\n * the absent case is judged `headRefMissing`, the corrupt case here is\n * judged `refUnreadable` (and suppresses `headRefMissing`).\n *\n * Always `null` for the app space — the app head ref is synthesised from\n * the live contract, so there is no on-disk `head.json` to read or fail on.\n */\n readonly headRefProblem: RefLoadProblem | null;\n readonly isApp: boolean;\n}\n\nexport interface IntegrityComputationInput {\n readonly targetId: string;\n readonly spaces: readonly IntegritySpaceState[];\n}\n\n/**\n * Walk the loaded model and return **every** integrity violation — never\n * bailing at the first. Structurally-derivable violations (load-time\n * problems, self-edges, missing / unreachable head refs) are always\n * produced; layout-drift checks require `declaredExtensions`, and\n * contract / target / disjointness checks require `checkContracts`.\n */\nexport function computeIntegrityViolations(\n input: IntegrityComputationInput,\n opts?: IntegrityQueryOptions,\n): readonly IntegrityViolation[] {\n const violations: IntegrityViolation[] = [];\n\n for (const { member, problems, refProblems, headRefProblem, isApp } of input.spaces) {\n const { spaceId } = member;\n\n for (const problem of problems) {\n violations.push(loadProblemToViolation(spaceId, problem));\n }\n\n for (const refProblem of refProblems) {\n violations.push({\n kind: 'refUnreadable',\n spaceId,\n refName: refProblem.refName,\n detail: refProblem.detail,\n });\n }\n if (headRefProblem !== null) {\n violations.push({\n kind: 'refUnreadable',\n spaceId,\n refName: headRefProblem.refName,\n detail: headRefProblem.detail,\n });\n }\n\n for (const pkg of member.packages) {\n const from = pkg.metadata.from ?? EMPTY_CONTRACT_HASH;\n const isSelfEdge = from === pkg.metadata.to;\n const hasDataOp = pkg.ops.some((op) => op.operationClass === 'data');\n if (isSelfEdge && !hasDataOp) {\n violations.push({ kind: 'sameSourceAndTarget', spaceId, dirName: pkg.dirName, hash: from });\n }\n }\n\n violations.push(...duplicateMigrationHashViolations(spaceId, member.packages));\n\n // For non-app spaces: a missing head.json is always an authoring error\n // (headRefMissing). The graph-reachability check (headRefNotInGraph) only\n // applies when the space actually has a migration graph — an extension that\n // ships no packages (e.g. all-external auth/storage spaces) has nothing to\n // reach the head ref through, and requiring the head hash to appear in an\n // empty graph would always fail. When a space ships no migrations, the\n // planner emits no DDL for it — the database is treated as already at the\n // declared state.\n if (!isApp && headRefProblem === null) {\n if (member.headRef === null) {\n violations.push({ kind: 'headRefMissing', spaceId });\n } else if (\n member.packages.length > 0 &&\n !headRefPresentInGraph(member, member.headRef.hash)\n ) {\n violations.push({ kind: 'headRefNotInGraph', spaceId, hash: member.headRef.hash });\n }\n }\n }\n\n if (opts?.declaredExtensions !== undefined) {\n violations.push(...layoutViolations(input.spaces, opts.declaredExtensions));\n }\n\n if (opts?.checkContracts === true) {\n violations.push(...contractViolations(input));\n }\n\n return violations;\n}\n\nexport function loadProblemToViolation(\n spaceId: string,\n problem: PackageLoadProblem,\n): IntegrityViolation {\n switch (problem.kind) {\n case 'hashMismatch':\n return {\n kind: 'hashMismatch',\n spaceId,\n dirName: problem.dirName,\n stored: problem.stored,\n computed: problem.computed,\n };\n case 'providedInvariantsMismatch':\n return { kind: 'providedInvariantsMismatch', spaceId, dirName: problem.dirName };\n case 'packageUnloadable':\n return {\n kind: 'packageUnloadable',\n spaceId,\n dirName: problem.dirName,\n detail: problem.detail,\n };\n }\n}\n\nfunction duplicateMigrationHashViolations(\n spaceId: string,\n packages: readonly OnDiskMigrationPackage[],\n): readonly IntegrityViolation[] {\n const dirNamesByHash = new Map<string, string[]>();\n for (const pkg of packages) {\n const hash = pkg.metadata.migrationHash;\n const dirNames = dirNamesByHash.get(hash);\n if (dirNames) dirNames.push(pkg.dirName);\n else dirNamesByHash.set(hash, [pkg.dirName]);\n }\n\n const out: IntegrityViolation[] = [];\n for (const [migrationHash, dirNames] of dirNamesByHash) {\n if (dirNames.length > 1) {\n out.push({\n kind: 'duplicateMigrationHash',\n spaceId,\n migrationHash,\n dirNames: [...dirNames].sort(),\n });\n }\n }\n return out;\n}\n\n/**\n * Whether a space's head-ref hash is present in its reconstructed graph.\n * An empty graph is reachable only by the empty-contract sentinel.\n */\nfunction headRefPresentInGraph(member: ContractSpaceMember, headHash: string): boolean {\n const graph = member.graph();\n if (graph.nodes.size === 0) {\n return headHash === EMPTY_CONTRACT_HASH;\n }\n return graph.nodes.has(headHash);\n}\n\nfunction layoutViolations(\n spaces: readonly IntegritySpaceState[],\n declaredExtensions: readonly DeclaredExtensionEntry[],\n): readonly IntegrityViolation[] {\n const out: IntegrityViolation[] = [];\n const extensionSpaceIds = new Set(spaces.filter((s) => !s.isApp).map((s) => s.member.spaceId));\n const declaredIds = new Set(declaredExtensions.map((d) => d.id));\n\n for (const id of [...extensionSpaceIds].sort()) {\n if (!declaredIds.has(id)) {\n out.push({ kind: 'orphanSpaceDir', spaceId: id });\n }\n }\n for (const id of [...declaredIds].sort()) {\n if (!extensionSpaceIds.has(id)) {\n out.push({ kind: 'declaredButUnmigrated', spaceId: id });\n }\n }\n return out;\n}\n\nfunction contractViolations(input: IntegrityComputationInput): readonly IntegrityViolation[] {\n const out: IntegrityViolation[] = [];\n const elementClaimedBy = new Map<string, string[]>();\n\n for (const { member } of input.spaces) {\n let contract: ReturnType<ContractSpaceMember['contract']>;\n try {\n contract = member.contract();\n } catch (error) {\n out.push({ kind: 'contractUnreadable', spaceId: member.spaceId, detail: detailOf(error) });\n continue;\n }\n\n if (contract.target !== input.targetId) {\n out.push({\n kind: 'targetMismatch',\n spaceId: member.spaceId,\n expected: input.targetId,\n actual: contract.target,\n });\n }\n\n for (const { entityName: elementName } of elementCoordinates(contract.storage)) {\n const claimers = elementClaimedBy.get(elementName);\n if (claimers) claimers.push(member.spaceId);\n else elementClaimedBy.set(elementName, [member.spaceId]);\n }\n }\n\n const disjointness: IntegrityViolation[] = [];\n for (const [element, claimedBy] of elementClaimedBy) {\n if (claimedBy.length > 1) {\n disjointness.push({ kind: 'disjointness', element, claimedBy: [...claimedBy].sort() });\n }\n }\n disjointness.sort((a, b) =>\n a.kind === 'disjointness' && b.kind === 'disjointness' ? a.element.localeCompare(b.element) : 0,\n );\n out.push(...disjointness);\n return out;\n}\n\nfunction detailOf(error: unknown): string {\n if (MigrationToolsError.is(error)) return error.why;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { MigrationToolsError } from '../errors';\nimport { readMigrationsDir } from '../io';\nimport { readContractSpaceContract } from '../read-contract-space-contract';\nimport { readContractSpaceHeadRef } from '../read-contract-space-head-ref';\nimport { HEAD_REF_NAME, type RefLoadProblem, readRefsTolerant } from '../refs';\nimport {\n APP_SPACE_ID,\n isValidSpaceId,\n RESERVED_SPACE_SUBDIR_NAMES,\n spaceMigrationDirectory,\n spaceRefsDirectory,\n} from '../space-layout';\nimport { listContractSpaceDirectories } from '../verify-contract-spaces';\nimport { createContractSpaceAggregate, createContractSpaceMember } from './aggregate';\nimport { computeIntegrityViolations, type IntegritySpaceState } from './check-integrity';\nimport type { ContractSpaceAggregate } from './types';\n\nexport type { DeclaredExtensionEntry } from '../integrity-violation';\n\n/**\n * Inputs for {@link loadContractSpaceAggregate}.\n *\n * Construction reads migration **state** from disk (`migrations/<space>/`\n * packages + refs + head refs). The app's *live* contract is not a disk\n * artefact — in Prisma Next it is always compiled from the project's\n * central contract, so the caller always has it and threads it in as\n * `appContract`. `deserializeContract` is held and called lazily only for\n * the on-disk extension contracts (`migrations/<ext>/contract.json`).\n */\nexport interface LoadAggregateInput {\n readonly migrationsDir: string;\n readonly deserializeContract: (raw: unknown) => Contract;\n readonly appContract: Contract;\n}\n\n/**\n * Build a tolerant, queryable {@link ContractSpaceAggregate} from on-disk\n * migration state plus the caller's live app contract.\n *\n * Building **never throws on disk content**: a hash- or\n * invariants-mismatched package is retained, an unparseable package is\n * omitted, a missing extension head ref leaves `headRef: null`, and an\n * unreadable on-disk contract defers its failure to `member.contract()`.\n * Every such problem is judged by {@link ContractSpaceAggregate.checkIntegrity}\n * rather than aborting the load. The only rejections are catastrophic I/O\n * (a `migrations/` that exists but is unreadable for reasons other than\n * absence).\n *\n * The app space's head ref is synthesised from the live contract's\n * storage hash (the app contract is authored independently of the\n * migration graph), and `app.contract()` returns the supplied contract.\n * Extension spaces read their contract, refs, and head ref from disk.\n */\nexport async function loadContractSpaceAggregate(\n input: LoadAggregateInput,\n): Promise<ContractSpaceAggregate> {\n const { migrationsDir, deserializeContract, appContract } = input;\n const targetId = appContract.target;\n\n const appState = await loadAppSpace(migrationsDir, appContract, deserializeContract);\n const extensionStates = await loadExtensionSpaces(migrationsDir, deserializeContract);\n\n const spaces: readonly IntegritySpaceState[] = [appState, ...extensionStates];\n\n return createContractSpaceAggregate({\n targetId,\n app: appState.member,\n extensions: extensionStates.map((state) => state.member),\n checkIntegrity: (opts) => computeIntegrityViolations({ targetId, spaces }, opts),\n });\n}\n\nasync function loadAppSpace(\n migrationsDir: string,\n appContract: Contract,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<IntegritySpaceState> {\n const spaceDir = spaceMigrationDirectory(migrationsDir, APP_SPACE_ID);\n const { packages, problems } = await readMigrationsDir(spaceDir);\n const { refs, problems: refProblems } = await readRefsTolerant(spaceRefsDirectory(spaceDir));\n\n const member = createContractSpaceMember({\n spaceId: APP_SPACE_ID,\n packages,\n refs,\n headRef: { hash: appContract.storage.storageHash, invariants: [] },\n refsDir: spaceRefsDirectory(spaceDir),\n resolveContract: () => appContract,\n deserializeContract,\n });\n\n // The app head ref is synthesised from the live contract, so there is\n // no on-disk head.json to be missing or corrupt for it.\n return {\n member,\n problems,\n refProblems,\n headRefProblem: null,\n isApp: true,\n };\n}\n\nasync function loadExtensionSpaces(\n migrationsDir: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<readonly IntegritySpaceState[]> {\n const candidateDirs = await listContractSpaceDirectories(migrationsDir);\n const extensionIds = candidateDirs\n .filter((name) => name !== APP_SPACE_ID)\n .filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name))\n .filter(isValidSpaceId)\n .sort();\n\n const states: IntegritySpaceState[] = [];\n for (const spaceId of extensionIds) {\n states.push(await loadExtensionSpace(migrationsDir, spaceId, deserializeContract));\n }\n return states;\n}\n\nasync function loadExtensionSpace(\n migrationsDir: string,\n spaceId: string,\n deserializeContract: (raw: unknown) => Contract,\n): Promise<IntegritySpaceState> {\n const spaceDir = spaceMigrationDirectory(migrationsDir, spaceId);\n const { packages, problems } = await readMigrationsDir(spaceDir);\n const { refs, problems: refProblems } = await readRefsTolerant(spaceRefsDirectory(spaceDir));\n const { headRef, problem: headRefProblem } = await readHeadRefTolerant(migrationsDir, spaceId);\n\n const rawContract = await readRawContractDeferred(migrationsDir, spaceId);\n\n const member = createContractSpaceMember({\n spaceId,\n packages,\n refs,\n headRef,\n refsDir: spaceRefsDirectory(spaceDir),\n resolveContract: () => deserializeContract(rawContract()),\n deserializeContract,\n });\n\n return { member, problems, refProblems, headRefProblem, isApp: false };\n}\n\n/**\n * The result of resolving an extension's `refs/head.json`: the parsed\n * head ref (or `null` when the file is absent or corrupt) plus a problem\n * when the file exists but cannot be parsed.\n */\ninterface HeadRefReadResult {\n readonly headRef: Awaited<ReturnType<typeof readContractSpaceHeadRef>>;\n readonly problem: RefLoadProblem | null;\n}\n\n/**\n * Read an extension's head ref, distinguishing a *genuinely absent*\n * `head.json` (`headRef: null`, no problem — judged `headRefMissing`)\n * from one that *exists but cannot be parsed* (`headRef: null` plus a\n * problem — judged `refUnreadable`, not `headRefMissing`).\n * `readContractSpaceHeadRef` already returns `null` only for ENOENT and\n * throws for unparseable / schema-invalid content, so the throw is the\n * corruption signal. Construction never throws on disk content.\n */\nfunction isToleratedRefHeadReadError(error: unknown): boolean {\n if (MigrationToolsError.is(error)) return true;\n if (!(error instanceof Error)) return false;\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'ENOENT' || code === 'EISDIR';\n}\n\nasync function readHeadRefTolerant(\n migrationsDir: string,\n spaceId: string,\n): Promise<HeadRefReadResult> {\n try {\n const headRef = await readContractSpaceHeadRef(migrationsDir, spaceId);\n return { headRef, problem: null };\n } catch (error) {\n if (!isToleratedRefHeadReadError(error)) {\n throw error;\n }\n return { headRef: null, problem: { refName: HEAD_REF_NAME, detail: detailOf(error) } };\n }\n}\n\nfunction detailOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Read the raw on-disk contract eagerly (cheap I/O) but defer its\n * (throwing) failure to call time, so a missing or unparseable\n * `contract.json` becomes a `contract()` throw — surfaced as\n * `contractUnreadable` — rather than a construction failure.\n */\nasync function readRawContractDeferred(\n migrationsDir: string,\n spaceId: string,\n): Promise<() => unknown> {\n try {\n const raw = await readContractSpaceContract(migrationsDir, spaceId);\n return () => raw;\n } catch (error) {\n return () => {\n throw error;\n };\n }\n}\n","import type { MigrationPlan } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '../../constants';\nimport { findPathWithDecision } from '../../migration-graph';\nimport type { MigrationOps, OnDiskMigrationPackage } from '../../package';\nimport { requireHeadRef } from '../aggregate';\nimport type { ContractMarkerRecordLike } from '../marker-types';\nimport type { PerSpacePlan } from '../planner-types';\nimport type { ContractSpaceMember } from '../types';\n\n/**\n * Outcome variants for the graph-walk strategy. Mirrors\n * {@link import('../../compute-extension-space-apply-path').ExtensionSpaceApplyPathOutcome}\n * but operates against the member's lazily-reconstructed `graph()`\n * instead of re-reading from disk. The aggregate planner converts\n * these into {@link import('../planner-types').PlannerError}\n * variants.\n */\nexport type GraphWalkOutcome =\n | { readonly kind: 'ok'; readonly result: PerSpacePlan }\n | { readonly kind: 'unreachable' }\n | { readonly kind: 'unsatisfiable'; readonly missing: readonly string[] };\n\nexport interface GraphWalkStrategyInputs {\n readonly aggregateTargetId: string;\n readonly member: ContractSpaceMember;\n readonly currentMarker: ContractMarkerRecordLike | null;\n /**\n * Optional ref name to decorate the resulting `PathDecision`. Used by\n * `migrate` to surface the user-supplied `--to <name>` in\n * structured-progress events and invariant-path error envelopes. The\n * strategy itself does not interpret it.\n */\n readonly refName?: string;\n}\n\n/**\n * Walk a member's hydrated migration graph from the live marker to\n * `member.headRef.hash`, covering every required invariant.\n *\n * Pure synchronous function — no I/O. The aggregate's loader has\n * already integrity-checked every package and reconstructed the graph;\n * this strategy just looks up ops by `migrationHash` and assembles a\n * `MigrationPlan` with `targetId` set from the aggregate (no\n * placeholder cast).\n *\n * Required invariants are computed as `headRef.invariants \\ marker.invariants`\n * — the marker already declares some invariants satisfied; the path\n * only needs to provide the remainder. Mirrors today's\n * `computeExtensionSpaceApplyPath` semantics.\n */\nexport function graphWalkStrategy(input: GraphWalkStrategyInputs): GraphWalkOutcome {\n const { aggregateTargetId, member, currentMarker, refName } = input;\n const headRef = requireHeadRef(member);\n const graph = member.graph();\n const packagesByMigrationHash = new Map<string, OnDiskMigrationPackage>(\n member.packages.map((pkg) => [pkg.metadata.migrationHash, pkg]),\n );\n\n const fromHash = currentMarker?.storageHash ?? EMPTY_CONTRACT_HASH;\n const markerInvariants = new Set(currentMarker?.invariants ?? []);\n const required = new Set(headRef.invariants.filter((id) => !markerInvariants.has(id)));\n\n const outcome = findPathWithDecision(graph, fromHash, headRef.hash, {\n required,\n ...(refName !== undefined ? { refName } : {}),\n });\n\n if (outcome.kind === 'unreachable') {\n return { kind: 'unreachable' };\n }\n if (outcome.kind === 'unsatisfiable') {\n return { kind: 'unsatisfiable', missing: outcome.missing };\n }\n\n const pathOps: MigrationOps[number][] = [];\n const providedInvariantsSet = new Set<string>();\n const edgeRefs: Array<{\n migrationHash: string;\n dirName: string;\n from: string;\n to: string;\n operationCount: number;\n }> = [];\n for (const edge of outcome.decision.selectedPath) {\n const pkg = packagesByMigrationHash.get(edge.migrationHash);\n if (!pkg) {\n throw new Error(\n `Migration package missing for edge ${edge.migrationHash} in space \"${member.spaceId}\". The hydrated migration graph and packagesByMigrationHash map are out of sync — this should be unreachable; report.`,\n );\n }\n for (const op of pkg.ops) pathOps.push(op);\n for (const invariant of pkg.metadata.providedInvariants) providedInvariantsSet.add(invariant);\n edgeRefs.push({\n migrationHash: edge.migrationHash,\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n operationCount: pkg.ops.length,\n });\n }\n\n const plan: MigrationPlan = {\n targetId: aggregateTargetId,\n spaceId: member.spaceId,\n origin: currentMarker === null ? null : { storageHash: currentMarker.storageHash },\n destination: { storageHash: headRef.hash },\n operations: pathOps,\n providedInvariants: [...providedInvariantsSet].sort(),\n };\n\n return {\n kind: 'ok',\n result: {\n plan,\n displayOps: pathOps,\n destinationContract: member.contract(),\n strategy: 'graph-walk',\n migrationEdges: edgeRefs,\n pathDecision: outcome.decision,\n },\n };\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport type { ContractSpaceMember } from './types';\n\n/**\n * Project the **introspected live schema** to the slice claimed by a\n * single contract-space member.\n *\n * \"Schema\" here means the live introspected database state — the\n * planner / verifier sees this object as a `MongoSchemaIR` (Mongo) or\n * `SqlSchemaIR` (SQL). It is **not** a database schema in the SQL\n * `CREATE SCHEMA` sense, nor a contract-space namespace. The\n * function's job is to filter that introspected state down to the\n * elements claimed by one space, so a per-space verify pass doesn't\n * see another space's storage as \"extras\".\n *\n * Returns the same `schema` value with every top-level storage element\n * (table or collection) claimed by **other** members of the aggregate\n * removed. Elements not claimed by any member flow through unchanged —\n * the planner / verifier sees them as orphans (extras in strict mode).\n *\n * Used by:\n *\n * - The aggregate planner's **synth strategy**: when synthesising a\n * plan against a member's contract, the live schema must be projected\n * to that member's slice so the planner doesn't treat elements claimed\n * by other members as \"extras\" and emit destructive ops to drop them.\n * - The aggregate verifier's **schemaCheck**: projects per member so the\n * single-contract verify only sees the slice claimed by the member it\n * is checking. Closes the architectural concern that a multi-member\n * deployment makes each member's elements look like extras to every\n * other member's verify pass.\n *\n * **Duck-typing semantics**: the helper operates on `unknown` for the\n * schema and falls through structurally if the shape doesn't match.\n * Two storage shapes are recognised today:\n *\n * - SQL families expose `storage.tables: Record<string, ...>` on\n * contracts and the introspected schema mirrors the same record shape.\n * Pruning iterates the record entries.\n * - Mongo exposes `storage.collections: Record<string, ...>` on\n * contracts; the introspected `MongoSchemaIR` exposes\n * `collections: ReadonlyArray<{name: string, ...}>`. Pruning iterates\n * the array on the schema side and the record's keys on the\n * other-member side.\n *\n * Schemas of unrecognised shape are returned unchanged. The function\n * never imports family classes (`SqlSchemaIR`, `MongoSchemaIR`); the\n * projected schema is a plain object — `{...schema, tables: pruned}` or\n * `{...schema, collections: pruned}` — that downstream consumers\n * duck-type. A future family with a different storage shape gets the\n * schema returned unchanged rather than blowing up the aggregate\n * planner.\n *\n * Record-shape detection guards against arrays (`!Array.isArray`) so\n * an unrecognised array-shaped value falls through unchanged rather\n * than being pruned by numeric keys.\n */\nexport function projectSchemaToSpace(\n schema: unknown,\n member: ContractSpaceMember,\n otherMembers: ReadonlyArray<ContractSpaceMember>,\n): unknown {\n if (typeof schema !== 'object' || schema === null) return schema;\n\n const ownedByOthers = collectOwnedNames(member, otherMembers);\n if (ownedByOthers.size === 0) return schema;\n\n const schemaObj = schema as { readonly tables?: unknown; readonly collections?: unknown };\n\n if (\n typeof schemaObj.tables === 'object' &&\n schemaObj.tables !== null &&\n !Array.isArray(schemaObj.tables)\n ) {\n return pruneRecord(schemaObj, 'tables', ownedByOthers);\n }\n\n if (Array.isArray(schemaObj.collections)) {\n return pruneCollectionsArray(schemaObj, ownedByOthers);\n }\n\n if (\n typeof schemaObj.collections === 'object' &&\n schemaObj.collections !== null &&\n !Array.isArray(schemaObj.collections)\n ) {\n return pruneRecord(schemaObj, 'collections', ownedByOthers);\n }\n\n return schema;\n}\n\nfunction collectOwnedNames(\n member: ContractSpaceMember,\n otherMembers: ReadonlyArray<ContractSpaceMember>,\n): Set<string> {\n const owned = new Set<string>();\n for (const other of otherMembers) {\n if (other.spaceId === member.spaceId) continue;\n for (const { entityName } of elementCoordinates(other.contract().storage)) {\n owned.add(entityName);\n }\n }\n return owned;\n}\n\nfunction pruneRecord(\n schemaObj: { readonly tables?: unknown; readonly collections?: unknown },\n field: 'tables' | 'collections',\n ownedByOthers: ReadonlySet<string>,\n): unknown {\n const source = schemaObj[field] as Record<string, unknown>;\n let removed = false;\n const pruned: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(source)) {\n if (ownedByOthers.has(name)) {\n removed = true;\n } else {\n pruned[name] = value;\n }\n }\n if (!removed) return schemaObj;\n return { ...schemaObj, [field]: pruned };\n}\n\nfunction pruneCollectionsArray(\n schemaObj: { readonly collections?: unknown },\n ownedByOthers: ReadonlySet<string>,\n): unknown {\n const source = schemaObj.collections as ReadonlyArray<unknown>;\n let removed = false;\n const pruned: unknown[] = [];\n for (const entry of source) {\n if (typeof entry === 'object' && entry !== null) {\n const name = (entry as { readonly name?: unknown }).name;\n if (typeof name === 'string' && ownedByOthers.has(name)) {\n removed = true;\n continue;\n }\n }\n pruned.push(entry);\n }\n if (!removed) return schemaObj;\n return { ...schemaObj, collections: pruned };\n}\n","import type { AggregateMigrationEdgeRef } from './planner-types';\n\nexport function buildSynthMigrationEdge(args: {\n readonly currentMarkerStorageHash: string | null | undefined;\n readonly destinationStorageHash: string;\n readonly operationCount: number;\n}): AggregateMigrationEdgeRef {\n return {\n dirName: '',\n migrationHash: args.destinationStorageHash,\n from: args.currentMarkerStorageHash ?? '',\n to: args.destinationStorageHash,\n operationCount: args.operationCount,\n };\n}\n","import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlFamilyInstance,\n MigrationOperationPolicy,\n MigrationPlan,\n MigrationPlannerConflict,\n MigrationPlannerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport type { ContractMarkerRecordLike } from '../marker-types';\nimport type { PerSpacePlan } from '../planner-types';\nimport { projectSchemaToSpace } from '../project-schema-to-space';\nimport { buildSynthMigrationEdge } from '../synth-migration-edge';\nimport type { ContractSpaceMember } from '../types';\n\nexport interface SynthStrategyInputs<TFamilyId extends string, TTargetId extends string> {\n readonly aggregateTargetId: string;\n readonly currentMarker: ContractMarkerRecordLike | null;\n readonly member: ContractSpaceMember;\n readonly otherMembers: ReadonlyArray<ContractSpaceMember>;\n readonly schemaIntrospection: unknown;\n readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId, unknown>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n readonly operationPolicy: MigrationOperationPolicy;\n}\n\nexport type SynthStrategyOutcome =\n | { readonly kind: 'ok'; readonly result: PerSpacePlan }\n | { readonly kind: 'failure'; readonly conflicts: readonly MigrationPlannerConflict[] };\n\n/**\n * The {@link MigrationPlanner.plan} interface is declared as synchronous,\n * but historical and test fixture call sites have always invoked it\n * with `await` (see prior `db-apply-per-space.ts`). Tolerating a\n * Promise here keeps existing test mocks working without changing the\n * declared family SPI.\n */\ntype MaybeAsyncPlannerResult = MigrationPlannerResult | Promise<MigrationPlannerResult>;\n\n/**\n * Synthesise a migration plan for a single member by projecting the\n * live schema down to that member's claimed slice and delegating to\n * the family's `createPlanner(...).plan(...)`.\n *\n * Pre-projection (via {@link projectSchemaToSpace}) closes the F23\n * concern: without it, the family's planner sees other members'\n * tables as \"extras\" and emits destructive ops to drop them. With it,\n * the planner only sees the slice this member claims.\n *\n * The synthesised plan's `targetId` is set from `aggregateTargetId`\n * (the aggregate's ambient target). The family's planner does not\n * stamp `targetId` on the produced plan; the aggregate planner is\n * the single point that knows the target.\n *\n * Used by:\n *\n * - The app member by default (CLI policy\n * `ignoreGraphFor: { app.spaceId }`).\n * - Any extension member whose `headRef.invariants` is empty (the\n * strategy selector falls back to synth when graph-walk isn't\n * required).\n */\nexport async function synthStrategy<TFamilyId extends string, TTargetId extends string>(\n input: SynthStrategyInputs<TFamilyId, TTargetId>,\n): Promise<SynthStrategyOutcome> {\n const projectedSchema = projectSchemaToSpace(\n input.schemaIntrospection,\n input.member,\n input.otherMembers,\n );\n\n const planner = input.migrations.createPlanner(input.familyInstance);\n const plannerResult: MigrationPlannerResult = await (planner.plan({\n contract: input.member.contract(),\n schema: projectedSchema,\n policy: input.operationPolicy,\n fromContract: null,\n frameworkComponents: input.frameworkComponents,\n spaceId: input.member.spaceId,\n }) as MaybeAsyncPlannerResult);\n\n if (plannerResult.kind === 'failure') {\n return { kind: 'failure', conflicts: plannerResult.conflicts };\n }\n\n const synthedPlan = plannerResult.plan;\n // The family planner returns a class-instance-shaped plan whose\n // `destination` / `operations` are accessors on the prototype, often\n // backed by private fields. A naive spread (`{ ...synthedPlan }`)\n // would lose those accessors and produce a plan with\n // `destination: undefined`; rebinding the prototype on a plain\n // object would break private-field access. We instead wrap the plan\n // in a Proxy that forwards every read except `targetId`, which is\n // stamped from the aggregate's ambient target. This preserves the\n // planner's class semantics while keeping the aggregate the single\n // source of truth for `targetId`.\n const plan: MigrationPlan = new Proxy(synthedPlan, {\n get(target, prop) {\n if (prop === 'targetId') return input.aggregateTargetId;\n // Forward `this` as the original target so prototype-bound\n // private fields (#destination, #operations, …) resolve.\n return Reflect.get(target, prop, target);\n },\n has(target, prop) {\n if (prop === 'targetId') return true;\n return Reflect.has(target, prop);\n },\n });\n\n const destinationStorageHash = synthedPlan.destination.storageHash;\n return {\n kind: 'ok',\n result: {\n plan,\n displayOps: synthedPlan.operations,\n destinationContract: input.member.contract(),\n strategy: 'synth',\n ...(plannerResult.warnings && plannerResult.warnings.length > 0\n ? { warnings: plannerResult.warnings }\n : {}),\n migrationEdges: [\n buildSynthMigrationEdge({\n currentMarkerStorageHash: input.currentMarker?.storageHash,\n destinationStorageHash,\n operationCount: synthedPlan.operations.length,\n }),\n ],\n },\n };\n}\n","import { notOk, ok } from '@prisma-next/utils/result';\nimport { requireHeadRef } from './aggregate';\nimport type { PerSpacePlan, PlannerError, PlannerInput, PlannerOutput } from './planner-types';\nimport { graphWalkStrategy } from './strategies/graph-walk';\nimport { synthStrategy } from './strategies/synth';\nimport type { ContractSpaceMember } from './types';\n\nexport type {\n AggregateCurrentDBState,\n AggregateMigrationEdgeRef,\n CallerPolicy,\n PerSpacePlan,\n PlannerError,\n PlannerInput,\n PlannerOutput,\n PlannerSuccess,\n} from './planner-types';\n\n/**\n * Plan a migration across every member of a {@link ContractSpaceAggregate}.\n *\n * Strategy selection per member, in order; first match wins:\n *\n * 1. If `callerPolicy.ignoreGraphFor.has(member.spaceId)`:\n * - If `member.headRef.invariants` is empty → synth.\n * - Else → `policyConflict` (synth cannot satisfy authored invariants).\n * 2. Else if `member.graph()` is non-empty AND graph-walk\n * succeeds → graph-walk.\n * 3. Else if `member.headRef.invariants` is empty → synth.\n * 4. Else → graph-walk failure → `extensionPathUnreachable` /\n * `extensionPathUnsatisfiable`.\n *\n * Output `applyOrder` is `[...aggregate.extensions.map(spaceId), aggregate.app.spaceId]`\n * — extensions alphabetical, then app — matching today's\n * `concatenateSpaceApplyInputs` ordering. This preserves\n * `MigrationRunnerFailure.failingSpace` attribution byte-for-byte.\n *\n * Every emitted `MigrationPlan` has `targetId = aggregate.targetId`.\n * No placeholder cast; no patch step.\n */\nexport async function planMigration<TFamilyId extends string, TTargetId extends string>(\n input: PlannerInput<TFamilyId, TTargetId>,\n): Promise<PlannerOutput> {\n const { aggregate, currentDBState, callerPolicy } = input;\n const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];\n\n const perSpace = new Map<string, PerSpacePlan>();\n\n // Iterate in apply order so a per-member error short-circuits the\n // walk in the same order the runner would walk inputs.\n const orderedMembers: ReadonlyArray<ContractSpaceMember> = [\n ...aggregate.extensions,\n aggregate.app,\n ];\n\n for (const member of orderedMembers) {\n const otherMembers = allMembers.filter((m) => m.spaceId !== member.spaceId);\n const currentMarker = currentDBState.markersBySpaceId.get(member.spaceId) ?? null;\n const headRef = requireHeadRef(member);\n\n const ignoreGraph = callerPolicy.ignoreGraphFor.has(member.spaceId);\n const invariantsRequired = headRef.invariants.length > 0;\n\n if (ignoreGraph && invariantsRequired) {\n const conflict: PlannerError = {\n kind: 'policyConflict',\n spaceId: member.spaceId,\n detail: `\\`callerPolicy.ignoreGraphFor\\` requested for space \"${member.spaceId}\", but the member declares non-empty head-ref invariants (${headRef.invariants.join(', ')}). Synthesising a plan from the contract IR cannot satisfy authored invariants — the graph must be walked. Either remove \"${member.spaceId}\" from \\`ignoreGraphFor\\` or amend the on-disk head ref to declare zero invariants.`,\n };\n return notOk(conflict);\n }\n\n if (ignoreGraph) {\n const synthOutcome = await synthStrategy({\n aggregateTargetId: aggregate.targetId,\n currentMarker,\n member,\n otherMembers,\n schemaIntrospection: currentDBState.schemaIntrospection,\n familyInstance: input.familyInstance,\n migrations: input.migrations,\n frameworkComponents: input.frameworkComponents,\n operationPolicy: input.operationPolicy,\n });\n if (synthOutcome.kind === 'failure') {\n return notOk({\n kind: 'appSynthFailure',\n spaceId: member.spaceId,\n conflicts: synthOutcome.conflicts,\n });\n }\n perSpace.set(member.spaceId, synthOutcome.result);\n continue;\n }\n\n // Try graph-walk first when the graph has nodes; fall back to synth\n // when the graph is empty AND no invariants are required.\n if (member.graph().nodes.size > 0) {\n const walked = graphWalkStrategy({\n aggregateTargetId: aggregate.targetId,\n member,\n currentMarker,\n });\n if (walked.kind === 'ok') {\n perSpace.set(member.spaceId, walked.result);\n continue;\n }\n if (walked.kind === 'unreachable') {\n return notOk({\n kind: 'extensionPathUnreachable',\n spaceId: member.spaceId,\n target: headRef.hash,\n });\n }\n // unsatisfiable — surface\n return notOk({\n kind: 'extensionPathUnsatisfiable',\n spaceId: member.spaceId,\n missingInvariants: walked.missing,\n });\n }\n\n // Empty graph: synth is the only option, and it can only satisfy\n // empty-invariant members.\n if (invariantsRequired) {\n return notOk({\n kind: 'extensionPathUnsatisfiable',\n spaceId: member.spaceId,\n missingInvariants: [...headRef.invariants].sort(),\n });\n }\n\n const synthOutcome = await synthStrategy({\n aggregateTargetId: aggregate.targetId,\n currentMarker,\n member,\n otherMembers,\n schemaIntrospection: currentDBState.schemaIntrospection,\n familyInstance: input.familyInstance,\n migrations: input.migrations,\n frameworkComponents: input.frameworkComponents,\n operationPolicy: input.operationPolicy,\n });\n if (synthOutcome.kind === 'failure') {\n return notOk({\n kind: 'appSynthFailure',\n spaceId: member.spaceId,\n conflicts: synthOutcome.conflicts,\n });\n }\n perSpace.set(member.spaceId, synthOutcome.result);\n }\n\n return ok({\n perSpace,\n applyOrder: [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId],\n });\n}\n","import { elementCoordinates } from '@prisma-next/framework-components/ir';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { requireHeadRef } from './aggregate';\nimport type { ContractMarkerRecordLike } from './marker-types';\nimport { projectSchemaToSpace } from './project-schema-to-space';\nimport type { ContractSpaceAggregate, ContractSpaceMember } from './types';\n\n/**\n * Caller policy for the verifier. Today's only knob is\n * `mode`: `strict` treats orphan elements (live tables not claimed by\n * any aggregate member) as errors; `lenient` treats them as\n * informational. Maps directly to `db verify --strict`.\n */\nexport interface VerifierInput<TSchemaResult> {\n readonly aggregate: ContractSpaceAggregate;\n readonly markersBySpaceId: ReadonlyMap<string, ContractMarkerRecordLike | null>;\n readonly schemaIntrospection: unknown;\n readonly mode: 'strict' | 'lenient';\n /**\n * Caller-supplied per-space schema verifier. The CLI wires this to\n * the family's `verifySqlSchema` (SQL) / equivalent (other\n * families). The verifier projects the schema to the\n * member's slice via {@link projectSchemaToSpace} before invoking\n * the callback, so single-contract semantics are preserved.\n *\n * Typed structurally with a generic `TSchemaResult` so the\n * migration-tools layer doesn't depend on the SQL family's\n * `VerifySqlSchemaResult`. CLI callers pass the family's type\n * through unchanged.\n */\n readonly verifySchemaForMember: (\n projectedSchema: unknown,\n member: ContractSpaceMember,\n mode: 'strict' | 'lenient',\n ) => TSchemaResult;\n}\n\n/**\n * Marker-check result per member. Mirrors the four cases the\n * `verifyContractSpaces` primitive surfaces today, plus an `'absent'`\n * case for greenfield spaces (no marker row written yet — `db init`\n * not run).\n */\nexport type MarkerCheckResult =\n | { readonly kind: 'ok' }\n | { readonly kind: 'absent' }\n | {\n readonly kind: 'hashMismatch';\n readonly markerHash: string;\n readonly expected: string;\n }\n | { readonly kind: 'missingInvariants'; readonly missing: readonly string[] };\n\nexport interface MarkerCheckSection {\n readonly perSpace: ReadonlyMap<string, MarkerCheckResult>;\n readonly orphanMarkers: readonly {\n readonly spaceId: string;\n readonly row: ContractMarkerRecordLike;\n }[];\n}\n\n/**\n * A live storage element (today: a top-level table) not claimed by any\n * member of the aggregate. The verifier always reports these;\n * the caller decides what to do — `db verify --strict` treats them as\n * errors, the lenient default treats them as informational.\n *\n * Today only `kind: 'table'` exists. The discriminated shape leaves\n * room for orphan columns / indexes / sequences in the future without\n * breaking the type contract.\n */\nexport type OrphanElement = { readonly kind: 'table'; readonly name: string };\n\nexport interface SchemaCheckSection<TSchemaResult> {\n readonly perSpace: ReadonlyMap<string, TSchemaResult>;\n /**\n * Live elements present in the introspected schema that are not\n * claimed by **any** aggregate member. Sorted alphabetically by name.\n */\n readonly orphanElements: readonly OrphanElement[];\n}\n\nexport interface VerifierSuccess<TSchemaResult> {\n readonly markerCheck: MarkerCheckSection;\n readonly schemaCheck: SchemaCheckSection<TSchemaResult>;\n}\n\nexport type VerifierError = {\n readonly kind: 'introspectionFailure';\n readonly detail: string;\n};\n\nexport type VerifierOutput<TSchemaResult> = Result<VerifierSuccess<TSchemaResult>, VerifierError>;\n\n/**\n * Verify a {@link ContractSpaceAggregate} against the live database\n * state. Bundles two checks:\n *\n * - `markerCheck` per member: compare the live marker row against the\n * member's `headRef.hash` + `headRef.invariants`. Absence is a\n * distinct kind, not an error (callers — `db verify` strict vs\n * `db init` precondition — choose how to interpret it).\n * - `schemaCheck` per member: project the live schema to the slice\n * the member claims via {@link projectSchemaToSpace}, then delegate\n * to the caller-supplied `verifySchemaForMember`. The pre-projection\n * means the family's single-contract verifier no longer sees other\n * members' tables as `extras`, so a multi-member deployment never\n * surfaces cross-member tables as orphaned schema elements.\n *\n * `markerCheck.orphanMarkers` lists every marker row whose `space` is\n * not a member of the aggregate. `db verify` callers reject orphans;\n * future tooling may not.\n *\n * Pure synchronous function; no I/O. The caller (CLI) gathers\n * `markersBySpaceId` and `schemaIntrospection` ahead of the call.\n */\nexport function verifyMigration<TSchemaResult>(\n input: VerifierInput<TSchemaResult>,\n): VerifierOutput<TSchemaResult> {\n try {\n return runVerifyMigration(input);\n } catch (error) {\n return notOk({\n kind: 'introspectionFailure',\n detail: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nfunction runVerifyMigration<TSchemaResult>(\n input: VerifierInput<TSchemaResult>,\n): VerifierOutput<TSchemaResult> {\n const { aggregate, markersBySpaceId, schemaIntrospection, mode, verifySchemaForMember } = input;\n const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];\n const memberSpaceIds = new Set(allMembers.map((m) => m.spaceId));\n\n // Marker check per member.\n const markerPerSpace = new Map<string, MarkerCheckResult>();\n for (const member of allMembers) {\n const marker = markersBySpaceId.get(member.spaceId) ?? null;\n if (marker === null) {\n markerPerSpace.set(member.spaceId, { kind: 'absent' });\n continue;\n }\n const headRef = requireHeadRef(member);\n if (marker.storageHash !== headRef.hash) {\n markerPerSpace.set(member.spaceId, {\n kind: 'hashMismatch',\n markerHash: marker.storageHash,\n expected: headRef.hash,\n });\n continue;\n }\n const markerInvariants = new Set(marker.invariants);\n const missing = headRef.invariants.filter((id) => !markerInvariants.has(id));\n if (missing.length > 0) {\n markerPerSpace.set(member.spaceId, {\n kind: 'missingInvariants',\n missing: [...missing].sort(),\n });\n continue;\n }\n markerPerSpace.set(member.spaceId, { kind: 'ok' });\n }\n\n // Orphan markers: entries in markersBySpaceId whose spaceId is not a\n // member of the aggregate.\n const orphanMarkers: { spaceId: string; row: ContractMarkerRecordLike }[] = [];\n for (const [spaceId, row] of markersBySpaceId) {\n if (row !== null && !memberSpaceIds.has(spaceId)) {\n orphanMarkers.push({ spaceId, row });\n }\n }\n orphanMarkers.sort((a, b) => a.spaceId.localeCompare(b.spaceId));\n\n // Schema check per member (with per-space pre-projection).\n const schemaPerSpace = new Map<string, TSchemaResult>();\n for (const member of allMembers) {\n const others = allMembers.filter((m) => m.spaceId !== member.spaceId);\n const projected = projectSchemaToSpace(schemaIntrospection, member, others);\n schemaPerSpace.set(member.spaceId, verifySchemaForMember(projected, member, mode));\n }\n\n return ok({\n markerCheck: {\n perSpace: markerPerSpace,\n orphanMarkers,\n },\n schemaCheck: {\n perSpace: schemaPerSpace,\n orphanElements: detectOrphanElements(schemaIntrospection, allMembers),\n },\n });\n}\n\n/**\n * Live tables not claimed by any aggregate member. Duck-typed against\n * the introspected schema's `tables` map; schemas whose shape doesn't\n * match return an empty list (consistent with\n * {@link projectSchemaToSpace}'s fall-through).\n */\nfunction detectOrphanElements(\n schemaIntrospection: unknown,\n members: ReadonlyArray<ContractSpaceMember>,\n): readonly OrphanElement[] {\n if (typeof schemaIntrospection !== 'object' || schemaIntrospection === null) return [];\n const liveTables = (schemaIntrospection as { readonly tables?: unknown }).tables;\n if (typeof liveTables !== 'object' || liveTables === null) return [];\n\n const claimedTables = new Set<string>();\n for (const member of members) {\n const contract = member.contract();\n for (const { entityName } of elementCoordinates(contract.storage)) {\n claimedTables.add(entityName);\n }\n }\n\n const orphans: OrphanElement[] = [];\n for (const tableName of Object.keys(liveTables as Record<string, unknown>)) {\n if (!claimedTables.has(tableName)) {\n orphans.push({ kind: 'table', name: tableName });\n }\n }\n orphans.sort((a, b) => a.name.localeCompare(b.name));\n return orphans;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@prisma-next/migration-tools",
3
- "version": "0.12.0-dev.51",
3
+ "version": "0.12.0-dev.52",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "On-disk migration persistence, hash verification, and chain reconstruction for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/contract": "0.12.0-dev.51",
10
- "@prisma-next/framework-components": "0.12.0-dev.51",
11
- "@prisma-next/utils": "0.12.0-dev.51",
9
+ "@prisma-next/contract": "0.12.0-dev.52",
10
+ "@prisma-next/framework-components": "0.12.0-dev.52",
11
+ "@prisma-next/utils": "0.12.0-dev.52",
12
12
  "arktype": "^2.2.0",
13
13
  "pathe": "^2.0.3",
14
14
  "prettier": "^3.8.3"
15
15
  },
16
16
  "devDependencies": {
17
- "@prisma-next/test-utils": "0.12.0-dev.51",
18
- "@prisma-next/tsconfig": "0.12.0-dev.51",
19
- "@prisma-next/tsdown": "0.12.0-dev.51",
17
+ "@prisma-next/test-utils": "0.12.0-dev.52",
18
+ "@prisma-next/tsconfig": "0.12.0-dev.52",
19
+ "@prisma-next/tsdown": "0.12.0-dev.52",
20
20
  "tsdown": "0.22.0",
21
21
  "typescript": "5.9.3",
22
22
  "vitest": "4.1.6"
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import type { Contract } from '@prisma-next/contract/types';
2
+ import type { Contract, StorageNamespace } from '@prisma-next/contract/types';
3
3
  import { join } from 'pathe';
4
4
  import {
5
5
  errorBundleNotFoundForGraphNode,
@@ -236,6 +236,28 @@ export function createContractSpaceMember(args: {
236
236
  };
237
237
  }
238
238
 
239
+ /**
240
+ * Collect the union of every namespace declared across all members of an
241
+ * aggregate (app + extensions) and return a minimal object with the shape
242
+ * `{ storage: { namespaces } }` suitable for passing to
243
+ * `familyInstance.introspect`.
244
+ *
245
+ * Callers invoke this after the integrity gate (`buildContractSpaceAggregate`
246
+ * with `checkContracts: true`), so every `member.contract()` call is safe —
247
+ * no try/catch is needed here.
248
+ */
249
+ export function collectAggregateNamespaces(aggregate: ContractSpaceAggregate): {
250
+ readonly storage: { readonly namespaces: Readonly<Record<string, StorageNamespace>> };
251
+ } {
252
+ const merged: Record<string, StorageNamespace> = {};
253
+ for (const member of aggregate.spaces()) {
254
+ for (const [key, ns] of Object.entries(member.contract().storage.namespaces)) {
255
+ merged[key] = ns;
256
+ }
257
+ }
258
+ return { storage: { namespaces: merged } };
259
+ }
260
+
239
261
  /**
240
262
  * Assemble a {@link ContractSpaceAggregate} value from its members and a
241
263
  * `checkIntegrity` implementation. The query methods (`listSpaces` /
@@ -27,6 +27,9 @@ export interface IntegritySpaceState {
27
27
  * `null` means the head ref was read cleanly or is genuinely absent —
28
28
  * the absent case is judged `headRefMissing`, the corrupt case here is
29
29
  * judged `refUnreadable` (and suppresses `headRefMissing`).
30
+ *
31
+ * Always `null` for the app space — the app head ref is synthesised from
32
+ * the live contract, so there is no on-disk `head.json` to read or fail on.
30
33
  */
31
34
  readonly headRefProblem: RefLoadProblem | null;
32
35
  readonly isApp: boolean;
@@ -85,15 +88,21 @@ export function computeIntegrityViolations(
85
88
 
86
89
  violations.push(...duplicateMigrationHashViolations(spaceId, member.packages));
87
90
 
88
- // The app head ref is synthesised from the live contract, so it is
89
- // always present and reachable; only extension spaces read their head
90
- // ref from disk and can be missing or point outside the graph. A head
91
- // ref that exists but is unparseable is already surfaced above as
92
- // `refUnreadable`, so it is not also reported as `headRefMissing`.
91
+ // For non-app spaces: a missing head.json is always an authoring error
92
+ // (headRefMissing). The graph-reachability check (headRefNotInGraph) only
93
+ // applies when the space actually has a migration graph an extension that
94
+ // ships no packages (e.g. all-external auth/storage spaces) has nothing to
95
+ // reach the head ref through, and requiring the head hash to appear in an
96
+ // empty graph would always fail. When a space ships no migrations, the
97
+ // planner emits no DDL for it — the database is treated as already at the
98
+ // declared state.
93
99
  if (!isApp && headRefProblem === null) {
94
100
  if (member.headRef === null) {
95
101
  violations.push({ kind: 'headRefMissing', spaceId });
96
- } else if (!headRefPresentInGraph(member, member.headRef.hash)) {
102
+ } else if (
103
+ member.packages.length > 0 &&
104
+ !headRefPresentInGraph(member, member.headRef.hash)
105
+ ) {
97
106
  violations.push({ kind: 'headRefNotInGraph', spaceId, hash: member.headRef.hash });
98
107
  }
99
108
  }
@@ -92,7 +92,13 @@ async function loadAppSpace(
92
92
 
93
93
  // The app head ref is synthesised from the live contract, so there is
94
94
  // no on-disk head.json to be missing or corrupt for it.
95
- return { member, problems, refProblems, headRefProblem: null, isApp: true };
95
+ return {
96
+ member,
97
+ problems,
98
+ refProblems,
99
+ headRefProblem: null,
100
+ isApp: true,
101
+ };
96
102
  }
97
103
 
98
104
  async function loadExtensionSpaces(
@@ -122,6 +128,7 @@ async function loadExtensionSpace(
122
128
  const { packages, problems } = await readMigrationsDir(spaceDir);
123
129
  const { refs, problems: refProblems } = await readRefsTolerant(spaceRefsDirectory(spaceDir));
124
130
  const { headRef, problem: headRefProblem } = await readHeadRefTolerant(migrationsDir, spaceId);
131
+
125
132
  const rawContract = await readRawContractDeferred(migrationsDir, spaceId);
126
133
 
127
134
  const member = createContractSpaceMember({
@@ -1,4 +1,5 @@
1
1
  export {
2
+ collectAggregateNamespaces,
2
3
  createContractSpaceAggregate,
3
4
  createContractSpaceMember,
4
5
  requireHeadRef,