{"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  const elementLabel = 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 { namespaceId, entityKind, entityName } of elementCoordinates(contract.storage)) {\n      const key = `${namespaceId}:${entityKind}:${entityName}`;\n      const claimers = elementClaimedBy.get(key);\n      if (claimers) claimers.push(member.spaceId);\n      else {\n        elementClaimedBy.set(key, [member.spaceId]);\n        elementLabel.set(key, `${namespaceId}.${entityName}`);\n      }\n    }\n  }\n\n  const disjointness: IntegrityViolation[] = [];\n  for (const [key, claimedBy] of elementClaimedBy) {\n    if (claimedBy.length > 1) {\n      const element = elementLabel.get(key) ?? key;\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  ControlAdapterInstance,\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 adapter: ControlAdapterInstance<TFamilyId, TTargetId>;\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.adapter);\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  const synthedOps = await Promise.all(synthedPlan.operations);\n  return {\n    kind: 'ok',\n    result: {\n      plan,\n      displayOps: synthedOps,\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: synthedOps.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        adapter: input.adapter,\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      adapter: input.adapter,\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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"}