import { n as OnDiskMigrationPackage } from "../package-CWicKzNs.mjs"; import { i as Refs, r as RefLoadProblem } from "../refs-BNCUu58Y.mjs"; import { t as ContractSpaceHeadRecord } from "../verify-contract-spaces-CnXNGpBV.mjs"; import { n as MigrationGraph } from "../graph-bDjJ4GL9.mjs"; import { t as PackageLoadProblem } from "../io-q04IrTcd.mjs"; import { t as PathDecision } from "../migration-graph-BJpeTOuY.mjs"; import { Result } from "@prisma-next/utils/result"; import { ControlAdapterInstance, ControlFamilyInstance, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, TargetMigrationsCapability } from "@prisma-next/framework-components/control"; import { Contract, StorageNamespace } from "@prisma-next/contract/types"; import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components"; //#region src/integrity-violation.d.ts /** * Every structural problem the migration model can carry. * * Violations come in three groups: * * - **Recoverable**: the package or space is retained in the model; * the violation is surfaced for policy (report, refuse, or ignore * depending on the command). * - **Config/contract-dependent**: produced only when the matching * `IntegrityQueryOptions` opt is set (declaredExtensions / * checkContracts). The model is built without them; they surface * when the caller explicitly asks for the broader integrity view. * - **Unloadable**: the package is omitted from the model entirely * (its on-disk content cannot be parsed into an `OnDiskMigrationPackage`). * * `checkIntegrity()` on `ContractSpaceAggregate` returns the full set — * all violations across all spaces — never bailing at the first hit. */ type IntegrityViolation = { readonly kind: 'sameSourceAndTarget'; readonly spaceId: string; readonly dirName: string; readonly hash: string; } | { readonly kind: 'hashMismatch'; readonly spaceId: string; readonly dirName: string; readonly stored: string; readonly computed: string; } | { readonly kind: 'providedInvariantsMismatch'; readonly spaceId: string; readonly dirName: string; } | { readonly kind: 'headRefMissing'; readonly spaceId: string; } | { readonly kind: 'headRefNotInGraph'; readonly spaceId: string; readonly hash: string; } | { readonly kind: 'duplicateMigrationHash'; readonly spaceId: string; readonly migrationHash: string; readonly dirNames: readonly string[]; } | { readonly kind: 'refUnreadable'; readonly spaceId: string; readonly refName: string; readonly detail: string; } | { readonly kind: 'orphanSpaceDir'; readonly spaceId: string; } | { readonly kind: 'declaredButUnmigrated'; readonly spaceId: string; } | { readonly kind: 'targetMismatch'; readonly spaceId: string; readonly expected: string; readonly actual: string; } | { readonly kind: 'disjointness'; readonly element: string; readonly claimedBy: readonly string[]; } | { readonly kind: 'contractUnreadable'; readonly spaceId: string; readonly detail: string; } | { readonly kind: 'packageUnloadable'; readonly spaceId: string; readonly dirName: string; readonly detail: string; }; /** * One declared extension entry, drawn from `Config.extensionPacks`. * * The integrity layer needs only: * * - `id` — the space id (also the directory name under `migrations/`), * used for the layout-drift checks (`orphanSpaceDir` / * `declaredButUnmigrated`). * - `targetId` — the target the declaring extension was configured for. * * Typed structurally so the migration-tools layer stays framework-neutral. */ interface DeclaredExtensionEntry { readonly id: string; readonly targetId: string; } /** * Options controlling which config/contract-dependent violation checks * `checkIntegrity()` runs. * * Both opts default to disabled: a caller without the app contract or * declared extensions still gets the structurally-derivable violations * (hashMismatch, providedInvariantsMismatch, headRefMissing, * headRefNotInGraph, refUnreadable, sameSourceAndTarget, packageUnloadable). */ interface IntegrityQueryOptions { /** * When provided, enables layout-drift checks: `orphanSpaceDir` * (a directory exists on disk for an extension not in the list) and * `declaredButUnmigrated` (an extension in the list has no on-disk dir). */ readonly declaredExtensions?: readonly DeclaredExtensionEntry[]; /** * When true, enables contract/disjointness/target checks: * `contractUnreadable`, `targetMismatch`, `disjointness`. */ readonly checkContracts?: boolean; } //#endregion //#region src/aggregate/types.d.ts interface ContractAtOptions { readonly refName?: string; } type ContractAtResult = { readonly provenance: 'snapshot'; readonly hash: string; readonly contractJson: unknown; readonly contractDts: string; readonly contract: Contract; } | { readonly provenance: 'graph-node'; readonly sourceDir: string; readonly hash: string; readonly contractJson: unknown; readonly contractDts: string; readonly contract: Contract; }; /** * One contract space — app or extension — as a member of a * {@link ContractSpaceAggregate}. Every member has the same shape. * * A member is a tolerant snapshot of one space's on-disk state, not a * validated value: `packages` is the raw migration-package list as read * from disk (a hash- or invariants-mismatched package is retained here; * a genuinely unparseable one is omitted), and integrity is judged * separately by {@link ContractSpaceAggregate.checkIntegrity}. * * - `spaceId`: `'app'` for the application, otherwise the extension's * id (validated against `[a-z][a-z0-9_-]{0,63}`). * - `packages`: raw on-disk migration packages, as read; never * integrity-validated at load. * - `refs`: the user-authored refs under `migrations//refs/*.json`. * - `headRef`: the system head ref read from * `migrations//refs/head.json`, or `null` when absent * (represented as a `headRefMissing` violation, never fatal). The app * member's head ref is always synthesised from its live contract's * storage hash, so it is never `null`. * - `graph()`: the migration graph this space's packages induce — * lazily reconstructed on first call and memoised. Pure structure: a * `from === to` self-edge is represented, not rejected. * - `contract()`: the deserialized contract for this member — lazily * produced on first call and memoised. For the app it is the live * contract the caller supplied; for an extension it is the on-disk * `migrations//contract.json` run through the family's * `deserializeContract`. Throws if the on-disk contract is missing or * undeserializable (surfaced as `contractUnreadable` by `checkIntegrity` * under `checkContracts`); callers gate before querying it. * - `contractAt(hash, opts?)`: materializes the contract at an arbitrary * graph node — when `opts.refName` is set, prefer the ref's paired * snapshot; else find the package whose `metadata.to === hash` and read * its `end-contract.*`. Lazy per `(hash, refName?)` memoisation; throws * typed {@link MigrationToolsError} values compatible with CLI mappers. */ interface ContractSpaceMember { readonly spaceId: string; readonly packages: readonly OnDiskMigrationPackage[]; readonly refs: Refs; readonly headRef: ContractSpaceHeadRecord | null; graph(): MigrationGraph; contract(): Contract; contractAt(hash: string, opts?: ContractAtOptions): Promise; } /** * Tolerant, queryable snapshot of a project's on-disk migration state: * the app contract space plus every extension contract space, each a * {@link ContractSpaceMember}. * * Produced once per CLI invocation by `loadContractSpaceAggregate`. * Building the aggregate never throws on disk content; every consumer * obtains spaces / packages / refs / graphs from this one value rather * than re-deriving them from disk. * * - `targetId`: the app contract's target; every member is expected to * share it (a mismatch surfaces as a `targetMismatch` violation under * `checkContracts`). * - `app` / `extensions`: retained as fields for the existing planner / * verifier / runner consumers. `extensions` is sorted alphabetically * by `spaceId` (the apply-ordering convention). * - `listSpaces()` / `hasSpace()` / `space()` / `spaces()`: the query * surface the read commands consume — `app` first, then extension ids * lex-ascending. * - `checkIntegrity()`: judges the loaded model and returns every * violation (never bailing at the first). Config/contract-dependent * checks run only when the matching {@link IntegrityQueryOptions} opt * is set. */ interface ContractSpaceAggregate { readonly targetId: string; readonly app: ContractSpaceMember; readonly extensions: readonly ContractSpaceMember[]; listSpaces(): readonly string[]; hasSpace(id: string): boolean; space(id: string): ContractSpaceMember | undefined; spaces(): readonly ContractSpaceMember[]; checkIntegrity(opts?: IntegrityQueryOptions): readonly IntegrityViolation[]; } //#endregion //#region src/aggregate/aggregate.d.ts /** * Resolve a member's head ref, asserting it is present. The apply/verify * engine only runs after `checkIntegrity` has refused on `headRefMissing`, * so a member reaching the planner / verifier without a head ref is a * programming error (the integrity gate was skipped), not a user-facing * state. The app member's head ref is always synthesised, so this only * ever guards an ungated extension space. */ declare function requireHeadRef(member: ContractSpaceMember): ContractSpaceHeadRecord; /** * Build a {@link ContractSpaceMember} with lazily-memoised `graph()`, * `contract()`, and `contractAt()` facets. * * `graph()` reconstructs the migration graph from `packages` on first * call and caches it. `contract()` calls `resolveContract` on first call * and caches the result; a throwing `resolveContract` (e.g. a missing or * undeserializable on-disk contract) re-throws on each call rather than * caching a value — `checkIntegrity` surfaces that as `contractUnreadable`. * `contractAt()` materializes the contract at an arbitrary graph node with * the same resolution order as plan-time ref resolution: ref snapshot first * (when `opts.refName` is set), else the matching package's `end-contract.*`. */ declare function createContractSpaceMember(args: { readonly spaceId: string; readonly packages: readonly OnDiskMigrationPackage[]; readonly refs: Refs; readonly headRef: ContractSpaceHeadRecord | null; readonly refsDir: string; readonly resolveContract: () => Contract; readonly deserializeContract: (raw: unknown) => Contract; }): ContractSpaceMember; /** * Collect the union of every namespace declared across all members of an * aggregate (app + extensions) and return a minimal object with the shape * `{ storage: { namespaces } }` suitable for passing to * `familyInstance.introspect`. * * Callers invoke this after the integrity gate (`buildContractSpaceAggregate` * with `checkContracts: true`), so every `member.contract()` call is safe — * no try/catch is needed here. */ declare function collectAggregateNamespaces(aggregate: ContractSpaceAggregate): { readonly storage: { readonly namespaces: Readonly>; }; }; /** * Assemble a {@link ContractSpaceAggregate} value from its members and a * `checkIntegrity` implementation. The query methods (`listSpaces` / * `hasSpace` / `space` / `spaces`) are derived here so every aggregate — * loader-built or test-built — shares one query surface: `app` first, * then `extensions` in the order supplied (the loader sorts them * lex-ascending by `spaceId`). */ declare function createContractSpaceAggregate(args: { readonly targetId: string; readonly app: ContractSpaceMember; readonly extensions: readonly ContractSpaceMember[]; readonly checkIntegrity: (opts?: IntegrityQueryOptions) => readonly IntegrityViolation[]; }): ContractSpaceAggregate; //#endregion //#region src/aggregate/check-integrity.d.ts /** * One space's load-time facts that `checkIntegrity` judges: the loaded * member, the load-time problems `readMigrationsDir` surfaced for it, and * whether it is the app space (the app head ref is synthesised, so the * head-ref checks are skipped for it). */ interface IntegritySpaceState { readonly member: ContractSpaceMember; readonly problems: readonly PackageLoadProblem[]; /** Per-ref problems: a user ref `*.json` that exists but is unparseable. */ readonly refProblems: readonly RefLoadProblem[]; /** * The space's `refs/head.json` problem when it exists but is unparseable. * `null` means the head ref was read cleanly or is genuinely absent — * the absent case is judged `headRefMissing`, the corrupt case here is * judged `refUnreadable` (and suppresses `headRefMissing`). * * Always `null` for the app space — the app head ref is synthesised from * the live contract, so there is no on-disk `head.json` to read or fail on. */ readonly headRefProblem: RefLoadProblem | null; readonly isApp: boolean; } interface IntegrityComputationInput { readonly targetId: string; readonly spaces: readonly IntegritySpaceState[]; } /** * Walk the loaded model and return **every** integrity violation — never * bailing at the first. Structurally-derivable violations (load-time * problems, self-edges, missing / unreachable head refs) are always * produced; layout-drift checks require `declaredExtensions`, and * contract / target / disjointness checks require `checkContracts`. */ declare function computeIntegrityViolations(input: IntegrityComputationInput, opts?: IntegrityQueryOptions): readonly IntegrityViolation[]; declare function loadProblemToViolation(spaceId: string, problem: PackageLoadProblem): IntegrityViolation; //#endregion //#region src/aggregate/loader.d.ts /** * Inputs for {@link loadContractSpaceAggregate}. * * Construction reads migration **state** from disk (`migrations//` * packages + refs + head refs). The app's *live* contract is not a disk * artefact — in Prisma Next it is always compiled from the project's * central contract, so the caller always has it and threads it in as * `appContract`. `deserializeContract` is held and called lazily only for * the on-disk extension contracts (`migrations//contract.json`). */ interface LoadAggregateInput { readonly migrationsDir: string; readonly deserializeContract: (raw: unknown) => Contract; readonly appContract: Contract; } /** * Build a tolerant, queryable {@link ContractSpaceAggregate} from on-disk * migration state plus the caller's live app contract. * * Building **never throws on disk content**: a hash- or * invariants-mismatched package is retained, an unparseable package is * omitted, a missing extension head ref leaves `headRef: null`, and an * unreadable on-disk contract defers its failure to `member.contract()`. * Every such problem is judged by {@link ContractSpaceAggregate.checkIntegrity} * rather than aborting the load. The only rejections are catastrophic I/O * (a `migrations/` that exists but is unreadable for reasons other than * absence). * * The app space's head ref is synthesised from the live contract's * storage hash (the app contract is authored independently of the * migration graph), and `app.contract()` returns the supplied contract. * Extension spaces read their contract, refs, and head ref from disk. */ declare function loadContractSpaceAggregate(input: LoadAggregateInput): Promise; //#endregion //#region src/aggregate/marker-types.d.ts /** * Structural shape the aggregate planner / verifier accept for marker * rows. Mirrors `family.readAllMarkers(...)` outputs across SQL and * Mongo families: a `(storageHash, invariants)` pair plus an optional * `profileHash` the verifier uses to align the marker with the * destination contract's profile envelope. * * Typed structurally so `migration-tools` stays framework-neutral; SQL * and Mongo families pass their typed `ContractMarkerRecord` through * unchanged. */ interface ContractMarkerRecordLike { readonly storageHash: string; readonly invariants: readonly string[]; readonly profileHash?: string; } //#endregion //#region src/aggregate/planner-types.d.ts /** * Caller-provided policy for {@link planMigration}. Today this carries * just one knob: * * - `ignoreGraphFor`: `Set`. For listed members, the planner * forces the **synth** strategy (synthesise a plan from the contract * IR via `familyInstance.createPlanner(...).plan(...)`) regardless of * whether a graph is available. The CLI's daily-driver `db init` / * `db update` pipelines pass `new Set([aggregate.app.spaceId])` to * keep today's app-space behaviour: the user's authored * `migrations/` directory is **not** walked for the app member, the * plan is synthesised on the fly. Extension members are walked. * * Listing a member here whose `headRef.invariants` is non-empty is * a `policyConflict` — synth cannot satisfy authored invariants. */ interface CallerPolicy { readonly ignoreGraphFor: ReadonlySet; } /** * Snapshot of the live database state the planner needs to drive * strategy selection. * * - `markersBySpaceId`: per-space marker rows. Absent entry = no * marker yet (greenfield space). The planner treats the marker's * `storageHash` as the graph-walk's `from` node, falling back to * {@link import('../constants').EMPTY_CONTRACT_HASH} when absent. * - `schemaIntrospection`: the family's full live schema IR. Fed into * the synth strategy after per-space pre-projection via * {@link import('./project-schema-to-space').projectSchemaToSpace}. * * Callers (CLI commands) gather this via the family's * `readAllMarkers` + `introspect` calls before invoking the planner. * The planner itself does not touch the database. */ interface AggregateCurrentDBState { readonly markersBySpaceId: ReadonlyMap; readonly schemaIntrospection: unknown; } /** * Inputs to {@link planMigration}. * * The planner is target-agnostic but family-aware: per-member synth * delegates to the family's `createPlanner(adapter).plan(...)`, * which is why `adapter`, `migrations` (the * `TargetMigrationsCapability`), and `frameworkComponents` are all * threaded through. (`frameworkComponents` is passed verbatim into * `planner.plan(...)` per ADR 212; the planner does not interpret it.) * * The planner does **not** receive a `targetId` separately — * it reads `aggregate.targetId` and stamps it onto every emitted * `MigrationPlan` from construction. No placeholder, no patch step. */ interface PlannerInput { readonly aggregate: ContractSpaceAggregate; readonly currentDBState: AggregateCurrentDBState; readonly adapter: ControlAdapterInstance; readonly migrations: TargetMigrationsCapability>; readonly frameworkComponents: ReadonlyArray>; readonly callerPolicy: CallerPolicy; readonly operationPolicy: MigrationOperationPolicy; } /** * Per-member output of the planner. The runner ingests this * shape directly via a thin `toRunnerInput` adapter at the CLI. * * - `plan`: ready-to-execute `MigrationPlan` with `targetId` already * set from `aggregate.targetId`. * - `displayOps`: same operation list, surfaced separately so plan-mode * output can render without touching the runner-bound `plan`. * - `destinationContract`: the typed contract value the runner uses * for post-apply verification. For the app member, the user's * contract; for extension members, the on-disk `contract.json`. * - `strategy`: which strategy produced this plan (`'graph-walk'` or * `'synth'`). Surfaced for diagnostics; not consumed by the runner. */ /** * Per-edge metadata for the chain assembled by the graph-walk * strategy. Lets `migrate` surface a per-migration `applied[]` * entry (preserving the `migrationsApplied` count semantics) without * re-walking the graph. * * `synth`-produced plans leave this absent — synthesised plans don't * have authored edges to surface. */ interface AggregateMigrationEdgeRef { readonly migrationHash: string; readonly dirName: string; readonly from: string; readonly to: string; readonly operationCount: number; } interface PerSpacePlan { readonly plan: MigrationPlan; readonly displayOps: readonly MigrationPlanOperation[]; readonly destinationContract: Contract; readonly strategy: 'graph-walk' | 'synth'; readonly warnings?: readonly MigrationPlannerConflict[]; /** * Per-edge breakdown of the chain. Graph-walk plans carry one entry per * authored edge; synth and at-head plans carry a single synthesised edge. */ readonly migrationEdges: readonly AggregateMigrationEdgeRef[]; /** * Path decision data the strategy used to select the chain * (alternative count, tie-break reasons, required/satisfied * invariants, per-edge invariants). Populated by the graph-walk * strategy; absent for synth-produced plans. * * `migrate` surfaces this for the app member as * `MigrateSuccess.pathDecision` (back-compat with single- * space callers). */ readonly pathDecision?: PathDecision; } interface PlannerSuccess { readonly perSpace: ReadonlyMap; /** * `applyOrder` is the order the runner must walk per-space inputs. * Mirrors the existing `concatenateSpaceApplyInputs` convention: * extensions alphabetically by `spaceId`, then the app. Tests assert * on `MigrationRunnerFailure.failingSpace`, which is positional in * the runner's input array — preserving the literal ordering keeps * `failingSpace` attribution byte-for-byte. */ readonly applyOrder: readonly string[]; } /** * Discriminated failure variants for {@link planMigration}. Each * variant short-circuits the plan; per-member errors carry the * `spaceId` so the CLI can surface a precise envelope. */ type PlannerError = { readonly kind: 'extensionPathUnreachable'; readonly spaceId: string; readonly target: string; } | { readonly kind: 'extensionPathUnsatisfiable'; readonly spaceId: string; readonly missingInvariants: readonly string[]; } | { readonly kind: 'appSynthFailure'; readonly spaceId: string; readonly conflicts: readonly MigrationPlannerConflict[]; } | { readonly kind: 'policyConflict'; readonly spaceId: string; readonly detail: string; }; type PlannerOutput = Result; //#endregion //#region src/aggregate/planner.d.ts /** * Plan a migration across every member of a {@link ContractSpaceAggregate}. * * Strategy selection per member, in order; first match wins: * * 1. If `callerPolicy.ignoreGraphFor.has(member.spaceId)`: * - If `member.headRef.invariants` is empty → synth. * - Else → `policyConflict` (synth cannot satisfy authored invariants). * 2. Else if `member.graph()` is non-empty AND graph-walk * succeeds → graph-walk. * 3. Else if `member.headRef.invariants` is empty → synth. * 4. Else → graph-walk failure → `extensionPathUnreachable` / * `extensionPathUnsatisfiable`. * * Output `applyOrder` is `[...aggregate.extensions.map(spaceId), aggregate.app.spaceId]` * — extensions alphabetical, then app — matching today's * `concatenateSpaceApplyInputs` ordering. This preserves * `MigrationRunnerFailure.failingSpace` attribution byte-for-byte. * * Every emitted `MigrationPlan` has `targetId = aggregate.targetId`. * No placeholder cast; no patch step. */ declare function planMigration(input: PlannerInput): Promise; //#endregion //#region src/aggregate/project-schema-to-space.d.ts /** * Project the **introspected live schema** to the slice claimed by a * single contract-space member. * * "Schema" here means the live introspected database state — the * planner / verifier sees this object as a `MongoSchemaIR` (Mongo) or * `SqlSchemaIR` (SQL). It is **not** a database schema in the SQL * `CREATE SCHEMA` sense, nor a contract-space namespace. The * function's job is to filter that introspected state down to the * elements claimed by one space, so a per-space verify pass doesn't * see another space's storage as "extras". * * Returns the same `schema` value with every top-level storage element * (table or collection) claimed by **other** members of the aggregate * removed. Elements not claimed by any member flow through unchanged — * the planner / verifier sees them as orphans (extras in strict mode). * * Used by: * * - The aggregate planner's **synth strategy**: when synthesising a * plan against a member's contract, the live schema must be projected * to that member's slice so the planner doesn't treat elements claimed * by other members as "extras" and emit destructive ops to drop them. * - The aggregate verifier's **schemaCheck**: projects per member so the * single-contract verify only sees the slice claimed by the member it * is checking. Closes the architectural concern that a multi-member * deployment makes each member's elements look like extras to every * other member's verify pass. * * **Duck-typing semantics**: the helper operates on `unknown` for the * schema and falls through structurally if the shape doesn't match. * Two storage shapes are recognised today: * * - SQL families expose `storage.tables: Record` on * contracts and the introspected schema mirrors the same record shape. * Pruning iterates the record entries. * - Mongo exposes `storage.collections: Record` on * contracts; the introspected `MongoSchemaIR` exposes * `collections: ReadonlyArray<{name: string, ...}>`. Pruning iterates * the array on the schema side and the record's keys on the * other-member side. * * Schemas of unrecognised shape are returned unchanged. The function * never imports family classes (`SqlSchemaIR`, `MongoSchemaIR`); the * projected schema is a plain object — `{...schema, tables: pruned}` or * `{...schema, collections: pruned}` — that downstream consumers * duck-type. A future family with a different storage shape gets the * schema returned unchanged rather than blowing up the aggregate * planner. * * Record-shape detection guards against arrays (`!Array.isArray`) so * an unrecognised array-shaped value falls through unchanged rather * than being pruned by numeric keys. */ declare function projectSchemaToSpace(schema: unknown, member: ContractSpaceMember, otherMembers: ReadonlyArray): unknown; //#endregion //#region src/aggregate/strategies/graph-walk.d.ts /** * Outcome variants for the graph-walk strategy. Mirrors * {@link import('../../compute-extension-space-apply-path').ExtensionSpaceApplyPathOutcome} * but operates against the member's lazily-reconstructed `graph()` * instead of re-reading from disk. The aggregate planner converts * these into {@link import('../planner-types').PlannerError} * variants. */ type GraphWalkOutcome = { readonly kind: 'ok'; readonly result: PerSpacePlan; } | { readonly kind: 'unreachable'; } | { readonly kind: 'unsatisfiable'; readonly missing: readonly string[]; }; interface GraphWalkStrategyInputs { readonly aggregateTargetId: string; readonly member: ContractSpaceMember; readonly currentMarker: ContractMarkerRecordLike | null; /** * Optional ref name to decorate the resulting `PathDecision`. Used by * `migrate` to surface the user-supplied `--to ` in * structured-progress events and invariant-path error envelopes. The * strategy itself does not interpret it. */ readonly refName?: string; } /** * Walk a member's hydrated migration graph from the live marker to * `member.headRef.hash`, covering every required invariant. * * Pure synchronous function — no I/O. The aggregate's loader has * already integrity-checked every package and reconstructed the graph; * this strategy just looks up ops by `migrationHash` and assembles a * `MigrationPlan` with `targetId` set from the aggregate (no * placeholder cast). * * Required invariants are computed as `headRef.invariants \ marker.invariants` * — the marker already declares some invariants satisfied; the path * only needs to provide the remainder. Mirrors today's * `computeExtensionSpaceApplyPath` semantics. */ declare function graphWalkStrategy(input: GraphWalkStrategyInputs): GraphWalkOutcome; //#endregion //#region src/aggregate/synth-migration-edge.d.ts declare function buildSynthMigrationEdge(args: { readonly currentMarkerStorageHash: string | null | undefined; readonly destinationStorageHash: string; readonly operationCount: number; }): AggregateMigrationEdgeRef; //#endregion //#region src/aggregate/verifier.d.ts /** * Caller policy for the verifier. Today's only knob is * `mode`: `strict` treats orphan elements (live tables not claimed by * any aggregate member) as errors; `lenient` treats them as * informational. Maps directly to `db verify --strict`. */ interface VerifierInput { readonly aggregate: ContractSpaceAggregate; readonly markersBySpaceId: ReadonlyMap; readonly schemaIntrospection: unknown; readonly mode: 'strict' | 'lenient'; /** * Caller-supplied per-space schema verifier. The CLI wires this to * the family's `verifySqlSchema` (SQL) / equivalent (other * families). The verifier projects the schema to the * member's slice via {@link projectSchemaToSpace} before invoking * the callback, so single-contract semantics are preserved. * * Typed structurally with a generic `TSchemaResult` so the * migration-tools layer doesn't depend on the SQL family's * `VerifySqlSchemaResult`. CLI callers pass the family's type * through unchanged. */ readonly verifySchemaForMember: (projectedSchema: unknown, member: ContractSpaceMember, mode: 'strict' | 'lenient') => TSchemaResult; } /** * Marker-check result per member. Mirrors the four cases the * `verifyContractSpaces` primitive surfaces today, plus an `'absent'` * case for greenfield spaces (no marker row written yet — `db init` * not run). */ type MarkerCheckResult = { readonly kind: 'ok'; } | { readonly kind: 'absent'; } | { readonly kind: 'hashMismatch'; readonly markerHash: string; readonly expected: string; } | { readonly kind: 'missingInvariants'; readonly missing: readonly string[]; }; interface MarkerCheckSection { readonly perSpace: ReadonlyMap; readonly orphanMarkers: readonly { readonly spaceId: string; readonly row: ContractMarkerRecordLike; }[]; } /** * A live storage element (today: a top-level table) not claimed by any * member of the aggregate. The verifier always reports these; * the caller decides what to do — `db verify --strict` treats them as * errors, the lenient default treats them as informational. * * Today only `kind: 'table'` exists. The discriminated shape leaves * room for orphan columns / indexes / sequences in the future without * breaking the type contract. */ type OrphanElement = { readonly kind: 'table'; readonly name: string; }; interface SchemaCheckSection { readonly perSpace: ReadonlyMap; /** * Live elements present in the introspected schema that are not * claimed by **any** aggregate member. Sorted alphabetically by name. */ readonly orphanElements: readonly OrphanElement[]; } interface VerifierSuccess { readonly markerCheck: MarkerCheckSection; readonly schemaCheck: SchemaCheckSection; } type VerifierError = { readonly kind: 'introspectionFailure'; readonly detail: string; }; type VerifierOutput = Result, VerifierError>; /** * Verify a {@link ContractSpaceAggregate} against the live database * state. Bundles two checks: * * - `markerCheck` per member: compare the live marker row against the * member's `headRef.hash` + `headRef.invariants`. Absence is a * distinct kind, not an error (callers — `db verify` strict vs * `db init` precondition — choose how to interpret it). * - `schemaCheck` per member: project the live schema to the slice * the member claims via {@link projectSchemaToSpace}, then delegate * to the caller-supplied `verifySchemaForMember`. The pre-projection * means the family's single-contract verifier no longer sees other * members' tables as `extras`, so a multi-member deployment never * surfaces cross-member tables as orphaned schema elements. * * `markerCheck.orphanMarkers` lists every marker row whose `space` is * not a member of the aggregate. `db verify` callers reject orphans; * future tooling may not. * * Pure synchronous function; no I/O. The caller (CLI) gathers * `markersBySpaceId` and `schemaIntrospection` ahead of the call. */ declare function verifyMigration(input: VerifierInput): VerifierOutput; //#endregion 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 }; //# sourceMappingURL=aggregate.d.mts.map