import { gy as NodeId, a5 as NodeType, d0 as JsonValue, e as GraphDef, b_ as EngineRevision, fy as EdgeId, gB as NodeKinds, fX as GetNodeType, G as GraphIdentityConfig, aN as TypeGraphError, hd as TypeGraphErrorOptions, g as GraphBackend, fZ as GraphAnnotations, d1 as KindAnnotations, gr as MetaEdge, a4 as AnyEdgeType, bB as DeleteBehavior, e3 as TemporalMode, I as IndexDeclaration, cC as GraphExtensionVersion, c9 as ExtensionNodeDef, c3 as ExtensionEdgeDef, ce as ExtensionOntologyRelation, c7 as ExtensionIndex } from '../types-BynPp5kU.js'; export { C as ContributionDiagnostic, a as ContributionDiagnosticState, b as ContributionRepairEntry, c as ContributionRepairResult } from '../types-BynPp5kU.js'; import { b as Store, bn as IdentityAssertionWriteFacade, bL as Node, dL as TransactionContext, ek as EDGE_TEMPORAL_READ_NAMES, g as IdentityFacade, el as IDENTITY_READ_NAMES, E as EvolutionPlan, dT as UniqueIntrospection } from '../store-C8ZPl7OW.js'; export { B as BatchReadBuilder, C as CompiledOneStatementRead } from '../store-C8ZPl7OW.js'; import { I as IngestionImportTarget } from '../ingestion-import-target-B8EU6ug2.js'; import { R as Result } from '../result-DWo6mUVz.js'; export { i as isErr, a as isOk, u as unwrap } from '../result-DWo6mUVz.js'; import { z } from 'zod'; import '../searchable-KKXrPet3.js'; import '../resolve-DV0Iposp.js'; /** * The composite MERGE IDENTITY key for a node: the pair `(kind, id)`. * * TypeGraph node identity is the PAIR `(kind, id)` — a bare id string is NOT unique * on its own (a `Patient` and an `Encounter` may both carry the id "x" as two * DISTINCT committed nodes; ids are caller-supplied). Every place the merge pipeline * groups, clusters, de-dupes, repoints, retypes, or deletes BY NODE IDENTITY must * key on this pair — never the bare id — or two different-kind nodes that happen to * share an id string silently fuse into one cluster (wrong merge, dropped node, * incoherent commit) and the §6.4-A base guard is bypassed. * * Represented as a NUL-joined string (a branded {@link MergeKey}) so it doubles as a * `Map`/`Set` key and a deterministic ordering key. `kind` is a schema identifier * (NUL-free), so the FIRST NUL unambiguously delimits kind from id even when a * caller-supplied id itself contains a NUL byte. This matches the `(kind, id)` * separator the commit-time write guard already uses. * * {@link compareMergeKeys} orders by the bare id FIRST (kind only breaks a same-id * tie), so the merge's "minimum-id survivor" / id-sorted-members semantics are * preserved unchanged for the common single-kind cluster — the composite key changes * WHICH nodes share an identity, never the ordering among genuinely distinct ids. */ /** * A composite `(kind, id)` node-identity key. Branded so it cannot be confused with * a bare {@link NodeId} at the type level — the whole point is that the two are NOT * interchangeable as identities. */ type MergeKey = string & { readonly __mergeKey: unique symbol; }; /** A complete graph-merge node identity. */ type EntityRef = Readonly<{ kind: string; id: NodeId; }>; /** Structured attribution for one candidate-recall path. */ type MatchSource = Readonly<{ kind: "block"; sourceId: string; }> | Readonly<{ kind: "unique"; sourceId: string; constraintName: string; }> | Readonly<{ kind: "baseUnique"; sourceId: string; constraintName: string; }> | Readonly<{ kind: "baseIndex"; sourceId: string; indexName: string; }> | Readonly<{ kind: "keyless"; sourceId: string; }> | Readonly<{ kind: "retype"; sourceId: string; }> | Readonly<{ kind: "custom"; sourceId: string; metadata?: JsonValue | undefined; }>; /** JSON-safe description of the strategy that actually scored a pair. */ type MatchStrategy = Readonly<{ kind: "fulltext"; fields: readonly string[]; }> | Readonly<{ kind: "vector"; fields: readonly string[]; }> | Readonly<{ kind: "hybrid"; fields: readonly string[]; weights: Readonly<{ vector: number; fulltext: number; }>; }> | Readonly<{ kind: "custom"; }>; /** Serializable explanation for one accepted identity edge. */ type MatchEvidence = Readonly<{ a: EntityRef; b: EntityRef; sources: readonly MatchSource[]; decision: "definitional"; }> | Readonly<{ a: EntityRef; b: EntityRef; sources: readonly MatchSource[]; decision: "scored"; strategy: MatchStrategy; score: number; threshold: number; }>; /** One opt-in scorer observation, retained independently of cluster membership. */ type CandidateDiagnostic = Readonly<{ evidence: Extract>; scoreDecision: "accepted" | "rejected"; reason?: "noComparableValues"; clusterDisposition?: "retained" | Readonly<{ kind: "excluded"; reason: "diameter" | "baseAmbiguity"; }>; }> | Readonly<{ evidence: Extract>; scoreDecision: "accepted"; clusterDisposition: Readonly<{ kind: "excluded"; reason: "diameter" | "baseAmbiguity"; }>; }>; /** Bounded public diagnostic collection assembled by the merge planner. */ type CandidateDiagnostics = Readonly<{ entries: readonly CandidateDiagnostic[]; total: number; limit: number; truncated: boolean; }>; /** * Core type model for the graph-merge primitive. * * Finalized against TypeGraph's real generic machinery: the design's illustrative * `Node` / `NodeId>` collapse onto TypeGraph's public * `Node` / `Edge` / `NodeId` / `EdgeId` (which are themselves branded * over `NodeType` / `EdgeType`). The merge surface is parameterized over * `G extends GraphDef` so `Store` and `GraphBranch` thread the caller's * concrete graph definition end-to-end. * * This module is pure type declarations plus the two branding helpers — no * runtime merge logic. */ /** * Opaque identifier for a branch (working copy) of a base store. Branded so a * raw string cannot be passed where a deliberately-minted branch id is required. */ type BranchId = string & Readonly<{ readonly __brand: "BranchId"; }>; /** * Opaque token identifying the immutable `base@V` a branch was forked from. * Combines a schema hash with a staleness component. Branded so it cannot be * confused with an arbitrary string. The second component is a * durable revision anchor for stores with revision tracking enabled and a * compatibility content fingerprint otherwise. */ type BaseVersion = string & Readonly<{ readonly __brand: "BaseVersion"; }>; /** * Mints a {@link BranchId} from a raw string. Centralizes the brand cast so the * unsafe assertion lives in exactly one place. */ declare function asBranchId(value: string): BranchId; /** * Mints a {@link BaseVersion} from a raw string. Centralizes the brand cast so * the unsafe assertion lives in exactly one place. */ declare function asBaseVersion(value: string): BaseVersion; /** * A working-copy handle for one branch: its id, the `base@V` it forked from, and * a {@link Store} over the branch's own backend. */ type GraphBranch = Readonly<{ id: BranchId; base: BaseVersion; store: Store; /** * The branch store's committed schema row `(version, hash)` captured AT * FORK. The merge requires the branch's CURRENT committed schema to still * equal this anchor: any schema operation on the branch after forking — * including a round-trip that restores the original document hash — * advances the version and is refused, so its row side effects can never * be projected into a merge as bare data changes. `undefined` inside the * tuple-less field means the clone committed no schema row (unmanaged * stores); absent entirely on hand-built branch objects, where the merge * falls back to comparing the branch's hash against the fork source's. */ schemaAnchor?: Readonly<{ version: number; hash: string; }> | undefined; /** * Releases the branch's working-copy backend — the composed close a * {@link WorkingCopyStrategy} built (e.g. a forked working copy's * connection AND its host-level fork, see `forkedWorkingCopyStrategy`). * Idempotent the same way {@link IngestionBranch.close} is: both coalesce * concurrent calls onto one release of the working copy's backend and make * a completed release final, so a backend whose own `close` is not * idempotent is still released exactly once; a release that FAILED is * retried by the next call rather than cached. `branch()` sets this; a * hand-built `GraphBranch` (the merge primitive's own committed-target * stand-in, `tests/`-only fixtures) must supply one too — a no-op when the object does not own a disposable * backend at all. */ close: () => Promise; /** * The engine revision the working copy's `lineage` source reported right * after `branch()` cloned it, before any write — the baseline `state-diff.ts`'s * `diffAgainstBase` and `staging.ts`'s `stageBranches` measure this branch's * OWN changes against when pruning the merge diff (see `LineageDelta`). The * key is PRESENT only when a lineage source answered at fork time; it is * ABSENT both when the working copy resolved no `lineage` at all (no backend * `lineage`, no `history: true` capture) and on a hand-built branch object — * either way, the merge always diffs this branch in full. */ forkRevision?: EngineRevision | undefined; }>; declare const INGESTION_BRANCH_BRAND: unique symbol; /** * Node collections exposed by an {@link IngestionBranch}. They retain normal * validation, reads, and staging writes, but omit APIs that claim a declared * uniqueness constraint exists on the relaxed physical working copy. */ type IngestionNodeCollections = Readonly<{ [K in keyof Store["nodes"]]-?: Pick["nodes"][K], "create" | "getById" | "getByIds" | "update" | "updateWhere" | "delete" | "hardDelete" | "find" | "count" | "createFromRecord" | "upsertById" | "upsertByIdFromRecord" | "bulkCreate" | "bulkUpsertById" | "bulkInsert" | "bulkDelete" | "bulkFindByIndex">; }>; /** * Opaque handle for an untrusted ingestion working copy. * * The ordinary {@link Store} is intentionally absent: callers may stage and * inspect graph data through the typed collections, then pass this handle to * merge planning, but cannot access schema evolution, transactions, or runtime * internals. `close()` releases the private working-copy backend. */ type IngestionBranch = IngestionImportTarget & Readonly<{ [INGESTION_BRANCH_BRAND]: true; id: BranchId; base: BaseVersion; nodes: IngestionNodeCollections; edges: Store["edges"]; close: () => Promise; }> & ("identity" extends keyof Store ? Readonly<{ identity: IdentityAssertionWriteFacade; }> : Readonly>); /** A normal branch or an opaque ingestion branch accepted by merge entrypoints. */ type MergeBranch = GraphBranch | IngestionBranch; /** * Options for {@link GraphBranch} creation. `id` is optional — when omitted a * fresh id is generated. */ type BranchOptions = Readonly<{ id?: BranchId; }>; /** * Turns text into an embedding vector. Injected via {@link MergeOptions.embedder} * and used by the `vector` / `hybrid` similarity strategies to score candidate * pairs by cosine IN MEMORY — the staged candidate nodes are unindexed in the * working copy, so a backend ANN index cannot score them pairwise (see * `scorePair`). Exact in-memory cosine over real model vectors is both the right * scale for bounded candidate dedup and deterministic, which the merge contract * requires. * * Batched and async: given N texts it returns N vectors in the SAME order, each a * fixed-dimension `Float32Array` (every vector a given embedder returns shares one * length — the model's embedding dimension). The function MUST be deterministic — * the same text always yields the same vector — because the whole merge is * order-independent and reproducible. Vectors need NOT be pre-normalized; cosine * scoring normalizes internally. * * The concrete local model lives in the CONSUMER (the harness ships an * all-MiniLM-L6-v2 embedder); this package depends only on the function shape, so * it stays model-agnostic and lean inside the TypeGraph core package. */ type Embedder = (texts: readonly string[]) => Promise; /** * Pluggable per-kind similarity strategy (design §8). * * - `vector` / `hybrid` score candidate pairs by cosine over an injected * {@link Embedder} ({@link MergeOptions.embedder}), computed in memory; they * fail with `SimilarityUnavailableError` when no embedder is configured. * - `fulltext` and `custom` run with ZERO embeddings — the cross-DB-safe * default. `fulltext` uses an in-memory Sørensen–Dice trigram scorer (T6). * * The generic mirrors the design's `SimilarityStrategy`: `K` constrains the * `custom` score function's node arguments to the resolved kind. */ type SimilarityStrategy = Readonly<{ kind: "hybrid"; fields: readonly string[]; weights?: Readonly<{ vector?: number; fulltext?: number; }>; readonly __graph?: G; }> | Readonly<{ kind: "vector"; field: string; readonly __graph?: G; }> | Readonly<{ kind: "fulltext"; fields: readonly string[]; readonly __graph?: G; }> | Readonly<{ kind: "custom"; score: (a: Node, b: Node) => number; readonly __graph?: G; }>; /** * Per-kind entity-resolution configuration. */ type ResolveConfig = Readonly<{ /** * Cheap exact-equality blocking key, evaluated before similarity to bound the * O(n²) candidate comparisons. Returning `undefined` places the node in the * shared `"unblocked"` bucket (compared all-vs-all within its kind). * * STAGED-vs-staged only: it is an arbitrary JS function, so it cannot be queried * against the committed base. To recall committed entities by a block key * (new-vs-base, the `baseKey` source §6.2), declare the key as a TypeGraph node * index and name it via {@link ResolveConfig.blockIndex} instead. */ block?: (node: Node) => string | undefined; /** * Name of a declared TypeGraph node index (`defineNodeIndex`) whose key is this * kind's NEW-vs-BASE block key (design §6.2). When set and the new-vs-base scope is * driven, the `baseKey` source issues an indexed `bulkFindByIndex` lookup of * committed nodes sharing each staged node's index key and proposes them as scored * candidate pairs (a shared block key is a candidate, not a definitional match). * * The index keys on real fields (a field-set + scope + optional partial-`where`), so * only a FIELD-SET block key migrates here; a transform key (`slice`/`soundex`/…) * stays on the staged-only {@link block}. Unused on the public snapshot `merge()` * path. An undeclared name surfaces a typed error at lookup time. */ blockIndex?: string; /** * Bounded coarse candidate generation for the NO-KEY case (design §6.2, the * `keyless` source). A node whose {@link block} returns `undefined` (and has no * unique signature) lands in the shared `"unblocked"` bucket, which is otherwise * compared ALL-vs-all — an O(n²) cliff that `maxComparisonsPerKind` then truncates * to id-only. Set `keyless` to bound that bucket by single-pass SORTED-NEIGHBOURHOOD * instead: the unblocked nodes are sorted by their similarity-field text (tie-broken * by id) and each is proposed only against its next `window` neighbours — O(n·window), * deterministic. Unset preserves today's all-vs-all behaviour. Only the `"unblocked"` * bucket is affected; keyed `block()` buckets are unchanged. */ keyless?: Readonly<{ /** Forward-neighbour window: each unblocked node is paired with its next `window` * neighbours in the sort. Must be a positive integer. Larger → more recall, more * comparisons (→ all-vs-all as `window` ≥ bucket size). */ window: number; }>; /** Similarity strategy (design §8). */ similarity: SimilarityStrategy; /** Candidate-merge threshold in `[0, 1]`. */ threshold: number; }>; /** * A resolved cluster of node ids that the merge collapses into one canonical * survivor. */ type ResolvedCluster = Readonly<{ members: readonly NodeId[]; }>; /** * Policy for resolving conflicting property values across cluster members. * * - `"flag"` keeps the canonical's value and records a {@link PropertyConflict} * without auto-resolving. * - `"lastWriteWins"` picks by the stable branch/logical total order — NEVER * wall-clock arrival. * - `"provenanceWeighted"` picks by per-branch trust weight. * - A function delegates the decision, returning the surviving {@link JsonValue}. */ type PropertyConflictPolicy = "flag" | "lastWriteWins" | "provenanceWeighted" | ((conflict: PropertyConflict) => JsonValue); /** * Policy for resolving an inherited node that is deleted by one branch and * modified by another (design §6.2). * * - `"deleteWins"` — the node is finally DELETED; the modification is discarded. * - `"modifyWins"` — the node is RESURRECTED; the modification survives. * - `"flag"` (default) — the **modification SURVIVES in the merged output** (as * with `"modifyWins"`) AND an **unresolved {@link DeleteModifyConflict} is * recorded** in `report.deleteModifyConflicts` for human review. `"flag"` is * therefore NOT neutral — it keeps data and surfaces the disagreement, on the * posture that a merge must never silently destroy the only branch still * carrying data. Choose `"deleteWins"` to honor the delete by default instead. */ type DeleteModifyPolicy = "deleteWins" | "modifyWins" | "flag"; /** * Behavior when `maxComparisonsPerKind` is exceeded for a kind. * * - `"error"` fails the merge with a typed error (default). * - `"mergeByIdOnly"` skips similarity for that kind, emits no candidate edges, * and records a report warning. */ type ComparisonCeilingPolicy = "error" | "mergeByIdOnly"; /** * Opt-in retention policy for candidate-level scoring diagnostics. The limit is * a deterministic global ceiling over the canonically ordered scored pairs; * planning still evaluates candidates according to the normal comparison * ceiling, then retains at most this many accepted/rejected decisions. */ type CandidateDiagnosticsOptions = Readonly<{ limit: number; }>; /** * Ontology type-reconciliation mode. `"off"` is a no-op (default); `"ontology"` * collapses compatible types to the most-specific via the public subClassOf * closure (T2a / T10). */ type ReconcileTypesMode = "ontology" | "off"; /** * Map of node kind name → its {@link ResolveConfig}. Keys are constrained to the * graph's node kinds (`keyof G["nodes"]`), so a typo or a kind that does not * belong to the graph is a COMPILE error rather than a silently-ignored config * (which would let those nodes merge by id only without warning). Each kind's * config is bound to that kind's concrete `NodeType`, so `block(node)` and the * `custom` scorer see the right node shape. All keys are optional: kinds omitted * from this map merge by ID only (new fork nodes added as-is, no fuzzy * resolution). For the default unparameterized `GraphDef` the keys widen back to * `string`. */ type ResolveMap = Readonly]: ResolveConfig>; }>>; /** * Caller-facing options for {@link merge}. All fields are optional with frozen * defaults applied by `normalizeMergeOptions` (see `options.ts`). */ type MergeOptions = Readonly<{ /** Per-kind entity resolution. Omitted kinds merge by ID only. */ resolve?: ResolveMap; /** Reconcile differing types across forks. Default `"off"`. */ reconcileTypes?: ReconcileTypesMode; /** Property-conflict policy for staged-vs-staged disagreements. Default `"flag"`. */ onPropertyConflict?: PropertyConflictPolicy; /** * Property-conflict policy for BASE↔branch disagreements in a new-vs-base merge * (§6.4-C). DISTINCT from {@link onPropertyConflict} and DOES NOT inherit it: * `onPropertyConflict` can be `"lastWriteWins"` / `"provenanceWeighted"` / a * function, any of which would let a fuzzy branch match silently OVERWRITE * committed data. Default `"flag"` keeps the committed base value (and records the * conflict). Mirrors how `onDeleteModifyConflict` is kept separate. Only consulted * when a cluster contains a base member; the staged path never uses it. */ onBasePropertyConflict?: PropertyConflictPolicy; /** Delete/modify-conflict policy. Default `"flag"`. */ onDeleteModifyConflict?: DeleteModifyPolicy; /** Comparison-ceiling behavior. Default `"error"`. */ onComparisonCeiling?: ComparisonCeilingPolicy; /** * Deterministic survivor selection within a cluster. Default: the member with * the lexicographically-minimal node id. */ canonical?: (cluster: ResolvedCluster) => NodeId; /** Populate the report-only provenance index. Default `true`. */ provenance?: boolean; /** * Persist provenance ON-GRAPH: after the commit, upsert one `{branch, sourceId}` * row per contribution into a sidecar provenance graph on the target's backend * (queryable via `openProvenanceStore` / `readProvenance`). Default `false` * (report-only). Best-effort and post-commit — a persistence failure surfaces as * a {@link MergeReport.warnings} entry, never a failed merge. */ persistProvenance?: boolean; /** * Local embedder for `vector` / `hybrid` similarity (in-memory cosine over the * staged candidate pairs). Required ONLY when a kind's resolve strategy is * `vector` or `hybrid`; `fulltext` / `custom` ignore it. A vector/hybrid * strategy with no embedder configured fails with a typed * {@link import("./errors").SimilarityUnavailableError}. */ embedder?: Embedder; /** Merge receiver. Default: the base `store`, written transactionally. */ target?: Store; /** Safety ceiling on candidate comparisons per kind. Default: unbounded. */ maxComparisonsPerKind?: number; /** * Retain bounded accepted/rejected scored-pair diagnostics. Omitted by * default so ordinary plans and reports contain only decisive evidence. */ candidateDiagnostics?: CandidateDiagnosticsOptions; /** * Optional single-link diameter guard. When set, clusters whose pairwise * distance exceeds it are split by the deterministic drop-weakest rule (T8). */ clusterMaxDiameter?: number; /** * Explicit stable branch order used by `lastWriteWins` / tie-breaking. When * omitted, branch ids sorted lexicographically are used. NEVER wall-clock. */ branchOrder?: readonly BranchId[]; /** * Per-branch trust weights consulted ONLY by the `"provenanceWeighted"` * property-conflict policy ({@link onPropertyConflict} / * {@link onBasePropertyConflict}): when branches disagree on a property value, * the value contributed by the highest-weight branch wins. Ties fall back to * {@link branchOrder} (then canonical value order); branches absent from the map * default to weight `0`. Ignored by every other policy. Keyed by * {@link BranchId}, like {@link branchOrder}. A non-empty map is required when * either property-conflict policy is `"provenanceWeighted"`; otherwise option * validation refuses the merge rather than silently changing policy. */ provenanceWeights?: ReadonlyMap; }>; /** * Object-form arguments for {@link mergeIncremental} (§6.6). The two same-typed * stores are NAMED so `forkPoint` (the frozen ancestor the branches forked from, the * diff reference) and `target` (the live committed graph that base lookups and the * commit land on) cannot be swapped. The target is deliberately absent from the * options type because the named `target` argument is authoritative. */ type MergeIncrementalArgs = Readonly<{ forkPoint: Store; target: Store; branches: readonly MergeBranch[]; options?: Omit, "target">; }>; /** * Records that a set of fork node ids resolved to a single canonical survivor. */ type EntityResolution = Readonly<{ canonicalId: NodeId; memberIds: readonly NodeId[]; kind: string; branchOrigins: readonly BranchId[]; /** Deterministic minimal accepted-edge witness for this resolution. */ decisiveEdges: readonly MatchEvidence[]; }>; /** * One candidate value contributing to a property conflict, tagged by its origin * branch. */ type ConflictingValue = Readonly<{ branchId: BranchId; value: JsonValue; }>; /** * A property whose value differed across cluster members (or across the two * collapsed edges for an edge conflict). `resolution` records the value the * policy selected. */ type PropertyConflict = Readonly<{ entityId: NodeId | EdgeId; kind: string; property: string; values: readonly ConflictingValue[]; resolution: JsonValue; readonly __graph?: G; }>; /** * An inherited node OR edge deleted by one branch and modified by another, with * the resolution the {@link DeleteModifyPolicy} produced. `entityId` is a * {@link NodeId} for a node conflict and an {@link EdgeId} for an edge conflict. */ type DeleteModifyConflict = Readonly<{ entityId: NodeId | EdgeId; kind: string; deletedBy: BranchId; modifiedBy: BranchId; resolution: DeleteModifyPolicy; }>; /** * Records that a cluster's mixed member kinds were collapsed to a single * canonical (most-specific) type via ontology reconciliation. */ type TypeReconciliation = Readonly<{ entityId: NodeId; fromTypes: readonly string[]; toType: string; /** Accepted ontology-retype witness, when emitted by graph merge. */ decisiveEdges?: readonly MatchEvidence[]; }>; /** * An item omitted from the merged result (e.g. an edge whose endpoint was * deleted, an incompatible-typed cluster member, or an identity assertion that * lost the survivor rule to an equivalent assertion from another branch). * * Discriminated on `kind` so each variant keeps its own id type: node and edge * ids are branded, while an identity assertion is named by the ledger's plain * assertion id (it is not a graph entity and carries no brand). */ type DroppedItem = Readonly<{ kind: "node"; id: NodeId; reason: string; }> | Readonly<{ kind: "edge"; id: EdgeId; reason: string; }> | Readonly<{ kind: "identity"; id: string; reason: string; }>; /** * The {@link ValidityEndResolution.precedence} of an entry the INCREMENTAL TARGET * decided rather than the merge: the destination had already moved this row's end * before the merge ran, so every branch claim was discarded and no write was staged. */ declare const VALIDITY_END_TARGET_PRECEDENCE: "target"; /** * One inherited row whose end-of-validity the merge RESOLVED: the explicit set or * clear that stands and every branch that claimed a change for the row (including * the ones whose claim lost arbitration). * * `id` is bare because `entity` + `kind` already disambiguate it — a node and an * edge, or two kinds, that share an id string are distinct entries. */ type ValidityEndResolution = Readonly<{ entity: "node" | "edge"; kind: string; id: string; /** Every branch that claimed a change, sorted; length > 1 means arbitration. */ claimedBy: readonly BranchId[]; /** * Present only as {@link VALIDITY_END_TARGET_PRECEDENCE}, marking an entry the * merge did NOT decide: the incremental target had already changed this end, so * the set/clear fields describe the target's own committed state, every claim in * `claimedBy` was discarded, and nothing was written or credited for the row. * * ABSENT means the merge decided the change — `validTo` or `clearValidTo` names * what it wrote and `claimedBy` names the claims it arbitrated between. A consumer * that ignores the field therefore keeps reading the entries it always read. */ precedence?: typeof VALIDITY_END_TARGET_PRECEDENCE; }> & (Readonly<{ /** The canonical instant the merge set, or the target already held. */ validTo: string; clearValidTo?: never; }> | Readonly<{ /** Marks a resolution that reopened the row by clearing its upper bound. */ clearValidTo: true; validTo?: never; }>); /** * A `(kind, id)` node identity as surfaced in the merge report. Node identity is the * PAIR, never the bare id (a `Doctor` and a `SpecialistDoctor` can share an id string), * so report shapes that name nodes carry both halves. */ type ReportNodeIdentity = Readonly<{ kind: string; id: NodeId; }>; /** * An AMBIGUOUS new-vs-base match (design §6.4-A): a connected component that * bridged ≥2 distinct committed base entities (directly, `baseA ~ new ~ baseB`, or * through staged hops, `baseA ~ new1 ~ new2 ~ baseB`). `baseIds` are the committed * entities the component spanned; `memberIds` are all of its members. Both are full * `(kind, id)` identities — the guard keys on the composite identity, so a component * spanning two SAME-id/different-kind bases stays distinguishable in the report. The * base↔base collapse is ALWAYS REFUSED — the component is split so the committed * entities stay separate. Reported regardless of how the component split. (A * deliberate-collapse trust path is deferred until committed-entity re-keying + edge * repoint exist; §6.4-C.) */ type BaseAmbiguity = Readonly<{ baseIds: readonly ReportNodeIdentity[]; memberIds: readonly ReportNodeIdentity[]; }>; /** * The contribution one branch made to the merged result. Returned by * {@link ProvenanceIndex.byBranch}. EXPLICITLY in-memory / report-only for P0 — * no on-graph prop tagging (deferred to the AgentFS phase). */ type BranchProvenance = Readonly<{ nodeIds: readonly NodeId[]; edgeIds: readonly EdgeId[]; }>; /** * Report-only, in-memory provenance index. `byBranch` answers "which * nodes/edges did this branch contribute to the merged result?". */ type ProvenanceIndex = Readonly<{ byBranch: (branchId: BranchId) => BranchProvenance; }>; /** * One `{branch, sourceId}` → canonical contribution — the unit of provenance. * * The in-memory {@link ProvenanceIndex} collapses these to `branch → {canonical * ids}`; the full record (which keeps the contributing `sourceId` and kind) is what * `persistProvenance` writes to the sidecar provenance graph. `sourceId` is the * fork-local id the contribution had in its branch BEFORE the merge collapsed it to * `canonicalId` (equal to `canonicalId` for an in-place modification). */ type ProvenanceRecord = Readonly<{ role: "node" | "edge"; canonicalId: string; canonicalKind: string; branchId: BranchId; sourceId: string; }>; /** * What the merge actually wrote to the target: node and edge counts plus the * identity-ledger effects. `identity.asserted` counts rows the applier * CREATED — planned assertions the target already held (idempotent exact or * semantic-pair matches, the normal incremental case) are excluded — and * `identity.retracted` counts rows the applier ENDED, excluding already-ended * or unknown ids. Assertions dropped by the survivor rule are enumerated in * {@link MergeReport.dropped} rather than counted here. */ type MergedCounts = Readonly<{ nodes: number; edges: number; identity: Readonly<{ asserted: number; retracted: number; }>; }>; /** * The full result of a {@link merge}: counts, every resolution/conflict/ * reconciliation/drop, and the report-only provenance index. */ type MergeReport = Readonly<{ merged: MergedCounts; resolutions: readonly EntityResolution[]; conflicts: readonly PropertyConflict[]; deleteModifyConflicts: readonly DeleteModifyConflict[]; typeReconciliations: readonly TypeReconciliation[]; dropped: readonly DroppedItem[]; /** * Every inherited row whose END-OF-VALIDITY the merge resolved, with the end * update that stands and the branches that claimed it. A set carries `validTo`; * a reopening carries `clearValidTo: true`. * * Reported because the resolution is silent by design: two branches ending the * same row at different instants are not in conflict (an ending is a monotone * claim, like a deletion), so the earliest end is taken without a * `PropertyConflict`. This list is how a caller sees that arbitration happened. * It includes the rows where the arbitration discarded EVERY claim because the * incremental target had already moved the end — those carry * `precedence: "target"` and staged no write. Window deltas the commit CANNOT * apply appear in {@link MergeReport.dropped} instead, with reason * `"window-not-applicable"`. */ validityEnds: readonly ValidityEndResolution[]; /** * Ambiguous new-vs-base matches (§6.4-A): components that bridged ≥2 committed * base entities. Empty on the staged-vs-staged snapshot path. */ baseAmbiguities: readonly BaseAmbiguity[]; provenance: ProvenanceIndex; /** * Non-fatal advisories from the merge — comparison-ceiling skips and, when * `persistProvenance` is set, a best-effort provenance-persistence failure (the * graph still committed). Empty on a clean merge. */ warnings: readonly string[]; /** Bounded accepted/rejected scored-pair diagnostics when explicitly enabled. */ candidateDiagnostics?: CandidateDiagnostics; /** * Present only when `persistProvenance` ran and SUCCEEDED: the sidecar provenance * graph id and how many `{branch, sourceId}` rows were upserted. Absent when * persistence was off or failed (a failure adds a {@link MergeReport.warnings}). */ provenancePersisted?: Readonly<{ graphId: string; count: number; }>; }>; declare const NODE_READ_NAMES: readonly ["getById", "getByIds", "find", "count", "findByConstraint", "bulkFindByConstraint", "bulkFindByIndex"]; /** Transaction-bound reads available before applying a fenced merge plan. */ type MergePlanReadContext = Readonly<{ nodes: Readonly<{ [K in keyof TransactionContext["nodes"]]: Pick["nodes"][K], (typeof NODE_READ_NAMES)[number]>; }>; edges: Readonly<{ [K in keyof TransactionContext["edges"]]: Pick["edges"][K], (typeof EDGE_TEMPORAL_READ_NAMES)[number]>; }>; }> & (G["identity"] extends GraphIdentityConfig ? Readonly<{ identity: Pick, (typeof IDENTITY_READ_NAMES)[number]>; }> : Readonly>); /** Plan effects inside an uncommitted transaction; excludes callback writes. */ type MergePlanApplied = Readonly<{ merged: MergedCounts; }>; /** * Work composed with merge application in its own protected transaction. Both * callbacks may be replayed up to three times on a transaction conflict: * await all work, use only the supplied context, perform no external effects. * See {@link file://../backend/capabilities/retried-unit.ts runRetriedUnit} * for the full replay contract this binds to. Throw/reject to abort; * returning a value (including a Result) is refused. */ type MergePlanApplyOptions = Readonly<{ /** Runs after the target fence is checked, before plan writes. Reads only. */ beforeApply?: (reads: MergePlanReadContext) => Promise; /** Runs after plan writes, before capture flush and commit. */ afterApply?: (tx: TransactionContext, applied: MergePlanApplied) => Promise; }>; /** * `base@V` stamping. * * A {@link BaseVersion} is the immutable token a branch is forked from. It must * change whenever either the schema OR the live content of the base store * changes, so that `merge()`'s precondition check (T11) can reject a branch that * forked from a divergent base. * * The token is two stable components joined by a separator: * * 1. A **schema hash** — `computeSchemaHash(serializeSchema(graph, version))`. * This is content-addressed (the public `computeSchemaHash` deliberately * excludes the version number and `generatedAt`, so it is stable across * re-saves of the same schema). * 2. An anchor, chosen by ONE precedence every caller of * {@link computeBaseVersion} shares: * a. A **revision anchor** when the Store has `revisionTracking` (or * `history`) enabled — a durable random per-graph origin plus the * monotonic revision clock. This is O(1) to read and changes after * every successful Store write; the origin prevents independent * stores with coincident timestamps from sharing an anchor. * b. Otherwise, an **engine anchor** when `resolveLineage(store)` yields * a `lineage` (necessarily the BACKEND's own — a store with no * revision tracking never captures history, so the recorded-relations * lineage is unreachable here; see `store/recorded-capture/lineage.ts`). * The anchor pairs the SAME durable per-graph revision-origin nonce * the revision anchor uses (ensured here too, at mint time, on this * store's backend) with the engine's opaque whole-database revision * — origin-namespaced for the identical reason the revision anchor * is: two independent databases whose engines both happen to report * the same revision string (a fresh counter starting at "r1") would * otherwise mint indistinguishable engine anchors, making a branch * forked from one database look mergeable into the other. Both * reads are O(1). It is engine-wide rather than per-graph, which is * why re-validating it (see * `graph-merge/merge.ts`'s `assertTargetUnchanged` and * `assertForkPointUnchanged`) cannot stop at a raw inequality: a * revision bump from a commit to an UNRELATED graph on the same * engine must not fail this graph's merge, so a mismatch is only * a real divergence once `lineage.changesSince` confirms this * graph's own rows moved. `LineageDelta` names only node and edge * keys, not identity assertions: an engine-anchored store that * changes ONLY its current identity assertions between plan and * commit — no node or edge row touched — mints an empty delta and * is tolerated as unchanged. The content-fingerprint fallback below * does not share this gap (its fingerprint folds identity * assertions in directly), and revision-anchored stores do not * either (any Store write, identity-only included, advances the * shared revision clock the anchor reads). Closing it would mean * teaching `LineageDelta` a THIRD dimension, or re-checking * identity assertions on the side the way `assertTargetUnchanged` * already re-checks the schema half — neither is done today. * c. Otherwise, the compatibility fallback: a **content fingerprint**, a * SHA-256 digest (truncated to a fixed-width hex string) of every * LIVE node and edge over the base store (`id`, `updated_at`, the * bitemporal `valid_from`/`valid_to`, and canonicalized `props`; * edges also carry their endpoint ids), sorted by id, so two stores * with identical live content fingerprint identically regardless of * row enumeration order or insertion order. Props AND validity are * folded in so the token changes on a content or validity edit even * when `updated_at` ties at millisecond granularity. Current * identity assertions are folded in too (see * `computeContentComponent`), which is exactly what the engine * anchor above does not do. Hashing keeps the token fixed-width * instead of growing linearly with store size. * * The token MUST be computed off the ORIGINAL base store, never off a clone: * `exportGraph`/`importGraph` regenerate `created_at`/`updated_at`, so a clone's * fingerprint would not match its source. (See the working-copy fidelity note in * T4.) * * `computeBaseVersion` is async because schema hashing, revision reads, and the * compatibility live-content enumeration go through async TypeGraph internals. * The design's synchronous illustrative signature does not survive contact with * the real store surface. */ /** * Computes the immutable `base@V` token for a store. Combines the schema hash * with a durable revision anchor when tracking is enabled, otherwise with the * compatibility live-content fingerprint. * * MUST be called on the ORIGINAL base store, not a clone (clones regenerate * timestamps and would fingerprint differently when the compatibility path is * in use). */ declare function computeBaseVersion(store: Store): Promise; /** * Error hierarchy for the graph-merge primitive. * * Every error extends the publicly-exported {@link TypeGraphError}, so consumers * can use the same `isTypeGraphError`/category machinery they already use for * TypeGraph itself. Each subclass carries a stable machine-readable `code`, a * fixed `ErrorCategory`, and a cause chain for debugging. */ /** * Machine-readable error codes for the merge primitive. Stable identifiers so * callers can branch on `error.code` without string-matching messages. */ declare const MERGE_ERROR_CODES: { readonly merge: "GRAPH_MERGE_ERROR"; readonly invalidOptions: "GRAPH_MERGE_INVALID_OPTIONS"; readonly branch: "GRAPH_MERGE_BRANCH_ERROR"; readonly similarityUnavailable: "GRAPH_MERGE_SIMILARITY_UNAVAILABLE"; readonly conflict: "GRAPH_MERGE_CONFLICT"; readonly constraintConflict: "GRAPH_MERGE_CONSTRAINT_CONFLICT"; readonly identityConflict: "GRAPH_MERGE_IDENTITY_CONFLICT"; readonly baseVersionMismatch: "GRAPH_MERGE_BASE_VERSION_MISMATCH"; readonly planCapability: "GRAPH_MERGE_PLAN_CAPABILITY"; readonly planInvalid: "GRAPH_MERGE_PLAN_INVALID"; readonly planVersionUnsupported: "GRAPH_MERGE_PLAN_VERSION_UNSUPPORTED"; readonly planDigestMismatch: "GRAPH_MERGE_PLAN_DIGEST_MISMATCH"; readonly planTargetMismatch: "GRAPH_MERGE_PLAN_TARGET_MISMATCH"; readonly planSchemaMismatch: "GRAPH_MERGE_PLAN_SCHEMA_MISMATCH"; readonly planOriginMismatch: "GRAPH_MERGE_PLAN_ORIGIN_MISMATCH"; readonly planStale: "GRAPH_MERGE_PLAN_STALE"; readonly planningStale: "GRAPH_MERGE_PLANNING_STALE"; readonly candidateSource: "GRAPH_MERGE_CANDIDATE_SOURCE"; readonly evidence: "GRAPH_MERGE_EVIDENCE"; readonly candidateWriteSet: "GRAPH_MERGE_CANDIDATE_WRITE_SET"; readonly review: "GRAPH_MERGE_REVIEW"; readonly operation: "GRAPH_MERGE_OPERATION"; readonly operationRequest: "GRAPH_MERGE_OPERATION_REQUEST"; readonly operationConflict: "GRAPH_MERGE_OPERATION_CONFLICT"; readonly operationUnsupported: "GRAPH_MERGE_OPERATION_UNSUPPORTED"; readonly operationEvidence: "GRAPH_MERGE_OPERATION_EVIDENCE"; readonly operationUndelivered: "GRAPH_MERGE_OPERATION_UNDELIVERED"; }; /** * Options shared by every merge error. Mirrors the relevant subset of * TypeGraphError's options while making `cause`/`details`/`suggestion` * uniformly optional at the merge-error boundary. */ type MergeErrorOptions = Readonly<{ details?: Record; suggestion?: string; cause?: unknown; }>; /** * Generic failure raised while computing or committing a merge. The catch-all * for the orchestrator (comparison-ceiling overruns, commit failures, etc.). */ declare class MergeError extends TypeGraphError { protected static readonly errorCategory: TypeGraphErrorOptions["category"]; constructor(message: string, options?: MergeErrorOptions); } /** Raised when caller-supplied merge options are invalid or unsupported. */ declare class InvalidMergeOptionsError extends MergeError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_INVALID_OPTIONS"; constructor(message: string, options?: MergeErrorOptions); } /** Invalid, unsupported, or unavailable evidence for durable merge review. */ declare class MergeReviewError extends MergeError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_REVIEW"; constructor(message: string, options?: MergeErrorOptions); } /** * Failure raised while creating a working-copy branch of a base store * (clone/export/import failures, backend construction failures). */ declare class BranchError extends TypeGraphError { constructor(message: string, options?: MergeErrorOptions); } /** * Raised when a `vector`/`hybrid` similarity strategy is requested but no * {@link import("./types").Embedder} was configured (`MergeOptions.embedder` is * absent). The `vector`/`hybrid` scorers compute cosine over real embeddings in * memory, so an embedder is mandatory for them; `fulltext`/`custom` need none. */ declare class SimilarityUnavailableError extends MergeError { readonly code: "GRAPH_MERGE_SIMILARITY_UNAVAILABLE"; constructor(message: string, options?: MergeErrorOptions); } /** * Raised when a conflict cannot be resolved by the configured policy and the * caller has opted into hard-failing rather than flagging. */ declare class MergeConflictError extends MergeError { readonly code: "GRAPH_MERGE_CONFLICT"; constructor(message: string, options?: MergeErrorOptions); } /** Details copied from the deterministic store constraint that refused commit. */ type MergeConstraintConflictErrorDetails = Readonly<{ /** Stable code of the underlying store constraint error. */ constraintCode: string; /** Class name of the underlying store constraint error. */ constraintErrorName: string; /** Constraint-specific fields, also copied onto this details object. */ constraintDetails: Readonly>; [key: string]: unknown; }>; /** Raised when a resolved merge would commit a graph that violates a constraint. */ declare class MergeConstraintConflictError extends MergeError { protected static readonly errorCategory = "constraint"; readonly code: "GRAPH_MERGE_CONSTRAINT_CONFLICT"; readonly category: "constraint"; readonly cause: TypeGraphError; readonly details: MergeConstraintConflictErrorDetails; constructor(cause: TypeGraphError); } /** Raised when identity branches contain opposing or retract/reassert truth. */ declare class IdentityMergeConflictError extends MergeError { readonly code: "GRAPH_MERGE_IDENTITY_CONFLICT"; constructor(message: string, options?: MergeErrorOptions); } /** * Raised by the `merge()` precondition check when a branch's `base@V` token * does not match the merge target's current base version (the branch forked * from a divergent schema or content fingerprint). */ declare class BaseVersionMismatchError extends MergeError { readonly code: "GRAPH_MERGE_BASE_VERSION_MISMATCH"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a target cannot provide the durable plan/apply guarantees. */ declare class MergePlanCapabilityError extends MergeError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_PLAN_CAPABILITY"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a serialized plan is structurally or semantically malformed. */ declare class InvalidMergePlanError extends MergeError { protected static readonly errorCategory = "user"; readonly code: string; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a plan uses a wire format this library version cannot read. */ declare class UnsupportedMergePlanVersionError extends InvalidMergePlanError { readonly code: "GRAPH_MERGE_PLAN_VERSION_UNSUPPORTED"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a plan's canonical content no longer matches its digest. */ declare class MergePlanDigestMismatchError extends InvalidMergePlanError { readonly code: "GRAPH_MERGE_PLAN_DIGEST_MISMATCH"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a plan names a different target graph. */ declare class MergePlanTargetMismatchError extends InvalidMergePlanError { readonly code: "GRAPH_MERGE_PLAN_TARGET_MISMATCH"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a plan was produced for another active schema. */ declare class MergePlanSchemaMismatchError extends InvalidMergePlanError { readonly code: "GRAPH_MERGE_PLAN_SCHEMA_MISMATCH"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a plan belongs to an independently-created revision clock. */ declare class MergePlanOriginMismatchError extends InvalidMergePlanError { readonly code: "GRAPH_MERGE_PLAN_ORIGIN_MISMATCH"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when the target revision no longer equals the plan's fence. */ declare class StaleMergePlanError extends MergeError { readonly code: string; constructor(message: string, options?: MergeErrorOptions); } /** Raised when the target moved while a plan was being computed. */ declare class MergePlanningStaleError extends StaleMergePlanError { readonly code: "GRAPH_MERGE_PLANNING_STALE"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a built-in candidate source cannot produce attributed output. */ declare class CandidateSourceError extends MergeError { readonly code: "GRAPH_MERGE_CANDIDATE_SOURCE"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a serialized candidate write set cannot be validated or staged. */ declare class CandidateWriteSetError extends MergeError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_CANDIDATE_WRITE_SET"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when match evidence is invalid or contains a non-finite score. */ declare class MatchEvidenceError extends MergeError { readonly code: "GRAPH_MERGE_EVIDENCE"; constructor(message: string, options?: MergeErrorOptions); } /** * Generic operational failure raised while orchestrating a durable-branch * operation, such as a strategy transport or host failure. */ declare class DurableOperationError extends MergeError { readonly code: string; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a durable-operation request or descriptor is invalid. */ declare class DurableOperationRequestError extends DurableOperationError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_OPERATION_REQUEST"; constructor(message: string, options?: MergeErrorOptions); } /** * Raised when an idempotency key is reused with a different operation digest. * The previously committed operation is returned untouched; the new request is * refused before any graph mutation or evidence write. */ declare class DurableOperationConflictError extends DurableOperationError { protected static readonly errorCategory = "constraint"; readonly code: "GRAPH_MERGE_OPERATION_CONFLICT"; constructor(message: string, options?: MergeErrorOptions); } /** * Raised when a host cannot provide the atomic mutation-plus-evidence * guarantee. It carries the dimensions the host cannot honor. The portable * fallback is refusal; TypeGraph never emulates atomicity with callbacks or * best effort. */ declare class DurableOperationUnsupportedError extends DurableOperationError { protected static readonly errorCategory = "user"; readonly code: "GRAPH_MERGE_OPERATION_UNSUPPORTED"; constructor(message: string, options?: MergeErrorOptions); } /** Raised when a host returns malformed or request-inconsistent evidence. */ declare class DurableOperationEvidenceError extends DurableOperationError { readonly code: "GRAPH_MERGE_OPERATION_EVIDENCE"; constructor(message: string, options?: MergeErrorOptions); } /** * Raised when archive/destroy is fenced by undelivered operation evidence. * * Extends {@link BranchError} so the established `destroyDurableBranch` result * type already transports it: a strategy that refuses destruction while * undelivered evidence remains preserves that refusal to the caller instead of * having it flattened into a generic branch failure. */ declare class DurableEvidenceUndeliveredError extends BranchError { readonly code: "GRAPH_MERGE_OPERATION_UNDELIVERED"; constructor(message: string, options?: MergeErrorOptions); } /** * Pluggable working-copy strategy: how `branch()` produces an isolated, * independently-mutable copy of a base store. * * The P0 default is a faithful CLONE via streamed public interchange * ({@link cloneWorkingCopyStrategy}): `exportGraphStream` the base, then * `importGraphStream` into a fresh store on a caller-provided backend. IDs are * preserved by interchange, so the diff engine (T3) can key on stable ids across * base and fork. This leverages public entrypoints only, needs zero schema * changes, and behaves identically across SQLite and Postgres. * * INTERCHANGE FIDELITY LIMITATION (verified, design §13.x): the interchange * `meta` schema has no `deletedAt` field, so a base row that is already * soft-deleted would round-trip into the clone as LIVE (its tombstone lost). A * resurrected row would then read as a spurious `new` node in the fork's diff — * the base row is non-live, so `diffNodeKind` takes its `!isLive(base)` branch and * reports the (live, clone-resurrected) row as an addition — silently re-creating a * deleted node on commit. We therefore export with `includeDeleted: false`: the * clone carries only the base's LIVE state, exactly what `branch()` needs. The * merge state-diff is still computed against the ORIGINAL base store (live rows * only) as the immutable reference, never against the clone (clones regenerate * `created_at`/`updated_at`, which would otherwise destabilize `base@V`). * * `includeTemporal: true` carries `validFrom`/`validTo` through unchanged, * preserving the base's exact valid-time window on the clone: create-time * paths default an omitted `validFrom` to the row's own creation instant * (see #240) — except for a BORN-ENDED row, whose stated `validTo` at or before * the write instant leaves it with no lower bound at all (see #407) — and * export/import round-trip a still-open-left `valid_from` (a born-ended row, or * one that predates the #240 fix) as an explicit `null` rather than silently * dropping it — see `InterchangeNodeSchema.validFrom`'s doc. * Without either half of this, the clone's re-import would re-stamp the * affected base rows to the CLONE's creation instant instead — narrowing * their validity window and making `asOf` reads on the fork diverge from * identical reads on the base for any instant between the row's real * creation and the clone. * * Undeclared properties are the same class of stored live state. * `validateStore()` treats them as healthy semi-structured data. The clone * therefore imports with `onUnknownProperty: "allow"` — interchange's * fidelity-preserving strategy — so those keys survive the round trip. * `"error"` would refuse to branch a graph analysis already reports as clean. * `"strip"` would drop the keys on the fork, and the merge diff against the * original base would invent deletions the caller never made. * * Logical-namespace (copy-on-write within one backend, no full data copy) is a * future strategy slot — see the `WorkingCopyStrategy` interface — deferred past * P0. * * A second bundled strategy, {@link forkedWorkingCopyStrategy}, targets a * fork-capable host instead: the working copy is a database-level fork (a file * copy, a `CREATE DATABASE ... TEMPLATE`, a hosting product's branch call) * rather than a streamed-interchange replay, so none of the fidelity * limitations above apply to it — see its own doc comment. */ /** * How `branch()` materializes a working copy of a base store. * * `create` receives the live base store and the {@link BaseVersion} `branch()` * already stamped off it, and returns a fresh, independently mutable * {@link Store} over the SAME graph definition, seeded with the base's current * state. Mutating the returned store MUST NOT affect the base. * * `base` is a convenience for a strategy that needs to re-validate the * working copy against the exact token the branch records: {@link forkedWorkingCopyStrategy} * fences the fork against it instead of recomputing the base's own version a * second time. A strategy that has no such check (the clone strategy, which * builds its working copy directly from `baseStore` rather than from an * independent copy) can ignore the parameter. * * The single method is the only extension point: alternative strategies * (e.g. a future logical-namespace copy-on-write within one backend) implement * the same contract. */ type WorkingCopyStrategy = Readonly<{ create: (baseStore: Store, base: BaseVersion) => Promise>; }>; /** * Factory for a caller-provided backend. `branch()` stays backend-agnostic by * delegating backend construction to the caller: the clone strategy calls this * once per `create()` to obtain the fresh backend that backs the working copy. * * Returning a promise lets async backends (e.g. PGlite, which boots an * in-process Postgres engine) be constructed lazily at branch time. * * The returned backend MUST be EMPTY (no rows for the base graph): the clone * seeds it from the base via `importGraphStream` with `onConflict: "error"`, so a * pre-existing row is surfaced as a {@link BranchError} rather than silently * skipped (which would leave the working copy diverging from the base). * When the source store uses `revisionTracking`, the backend must also satisfy * that option's transactional revision-clock requirements because the clone * preserves the source's branchability contract. */ type MakeBackend = () => Promise; /** * The P0 default working-copy strategy: faithful clone via streamed interchange. * * On each `create(baseStore)`: * 1. `exportGraphStream(baseStore, { includeMeta: true, includeTemporal: true, * includeDeleted: false })` — `includeMeta: true` carries * `created_at`/`updated_at`; `includeTemporal: true` carries * `validFrom`/`validTo` so the clone's valid-time window matches the base's * exactly (see the fidelity note above); `includeDeleted: false` keeps the * clone to LIVE rows only. Shipping soft-deleted rows is unsafe: the meta * schema has no `deletedAt`, so they would import as live and resurrect on * the fork's diff (see the fidelity note above). `branch()` only needs the * base's live state. * 2. Create a fresh store over the caller-provided backend with the SAME graph * definition via `createStoreWithSchema`. * 3. `importGraphStream(freshStore, data, { onConflict: "error", * onUnknownProperty: "allow", ... })` — ids are preserved so the diff * engine can key on them. `onConflict: "error"` requires the backend to be * EMPTY: a pre-existing row is a contract violation that must surface * loudly, never be silently skipped (a skipped row would leave the clone * diverging from the base, so the fork's diff would report phantom * modifications/deletions). `onUnknownProperty: "allow"` carries undeclared * properties through (see the fidelity note above). A streamed chunk that * reports per-row errors throws (default `onStreamChunkError: "abort"`); a * materialized import returns `{ success, errors }`. Either failure fails * the branch. * * The backend `makeBackend()` returns is opened here, so any failure AFTER it is * created closes it before rethrowing — only the success path hands the backend * (via the returned store) to the caller, who then owns its lifecycle. * * @param makeBackend - Constructs the fresh, EMPTY backend the working copy is * built on. */ declare function cloneWorkingCopyStrategy(makeBackend: MakeBackend): WorkingCopyStrategy; /** * A host-level handle to a forked database, produced by * {@link ForkedWorkingCopyOptions.fork} and released by its own `dispose`. * * `dispose` is OPTIONAL: some hosts have nothing left to release beyond the * connection `connect` opens on the fork (already composed into the returned * working copy's backend — see {@link forkedWorkingCopyStrategy}), while others * (a temporary file, a database created for this fork alone) need an explicit * teardown. */ type ForkHandle = Readonly<{ dispose?: () => Promise; }>; /** * Configuration for {@link forkedWorkingCopyStrategy}. */ type ForkedWorkingCopyOptions = Readonly<{ /** * Produces a host-level fork of the database `baseStore` is on — the * caller's own fork API call (a file copy, a `CREATE DATABASE ... TEMPLATE`, * a hosting product's branch-database call). The fork MUST be the base at * the instant it is taken: `create()` asserts this by comparing * `computeBaseVersion` between the fork and the base and refuses otherwise * (see {@link forkedWorkingCopyStrategy}). That comparison proves base-token * equality (schema plus a revision anchor, or a live-content fingerprint) — * see `computeBaseVersion`'s own doc comment for exactly what it does and * does not cover — not a byte-for-byte audit of the fork; the FORK * MECHANISM is what is trusted for physical fidelity. */ fork: (baseStore: Store) => Promise; /** * Opens a backend on the fork `fork` produced. The returned backend MUST be * an INDEPENDENT connection, never the base's own backend or one that * shares its connection: `create()` refuses before wrapping when the * connected backend is `===` the base's backend, is derived from it (or it * from the connected backend) through `deriveBackend`, or shares its * serialized transaction resource (two wrappers over the same underlying * connection) — see {@link forkedWorkingCopyStrategy}'s aliasing check. This * catches a `connect` that mistakenly hands back a cached factory's * existing backend; it CANNOT catch a fresh backend built over the base's * own connection pool when that pool audits as independent (a default-size * `pg.Pool`, for example) — a pooled checkout is genuinely a different * connection from the pool's perspective, so nothing here can tell it apart * from a real fork's connection short of the caller's own knowledge of * their topology. * * The returned backend's own table bindings (`backend.tableNames`) MUST * also agree with the base's resolved SQL schema (`baseStore.revisionSchema` * — the same schema the fork's store resolves to via * {@link forkStoreOptions}). A fork is the SAME physical database as the * base, so this is normally automatic (a backend factory bound to the * base's custom names, if any, opens correctly on the fork too); `create()` * still checks it and refuses with a {@link BranchError}, closing the * backend first, when the two disagree — a backend bound to the wrong table * names reads and writes through tables the fork's rows were never written * to. */ connect: (fork: TFork) => Promise; }>; /** * Working-copy strategy for a fork-capable host: `fork(baseStore)` asks the * host to produce a complete, independent copy of the underlying database — * not a public-interchange replay — and `connect(fork)` opens a backend on * that copy. * * Unlike {@link cloneWorkingCopyStrategy}, the working copy is never built * through `exportGraphStream`/`importGraphStream`, so none of that strategy's * interchange-fidelity limitations apply here: soft-deleted rows keep their * tombstones, `created_at`/`updated_at` and the `version` column carry over * unchanged, and — when the base has `history` enabled — the recorded * relations the fork physically carries answer `asOfRecorded` for instants * before the fork, which a clone cannot (streamed interchange never carries * recorded history). * * `create(baseStore, base)`: * 1. `fork(baseStore)` — the host-level fork call. * 2. `connect(fork)` — opens a backend on the fork. A failure here disposes * the fork before rethrowing (mirroring the clone strategy's * own-failure cleanup); a dispose failure never masks the original * error. * 3. The connected backend is checked for ALIASING the base's own backend * by `forkAliasesBase` — object identity with the base's backend, * derivation lineage in either direction (`isBackendDerivedFrom`), or a * shared serialized transaction resource * (`sharesSerializedTransactionResource`, `transaction-resource.ts`'s * existing owner of "two wrappers on one connection"). Without this, a * `connect()` that hands back the base's own backend (a cached factory * keyed by database name, say) would pass every later fence — the * table-name check, the base@V check both trivially agree with * themselves — while every fork write actually mutates the base and * closing the "fork" actually closes the base. An alias refuses BEFORE * wrapping: only the fork is disposed (never the connected backend — it * is the base's) before `create()` throws a {@link BranchError} naming * `connect()`. * 4. The connected backend's `close` is composed with the fork's `dispose` * through `wrapWithManagedClose` (a `deriveBackend` overlay, never a * spread), so the caller's single `close()` on the resulting store's * backend releases both the connection and the fork. * 5. `baseStore.revisionSchema` — the base's own resolved SQL schema getter * (an explicit `schema` option, or `backend.tableNames` otherwise; never * re-derived by hand here) — is compared, table by table, against * `createSqlSchema(connectedBackend.tableNames)`. A fork is the same * physical database as the base, so a backend bound to different table * names — typically the defaults, when `connect()` did not reconstruct * the base's custom bindings — would read and write through tables the * fork's rows were never written to. A mismatch closes the backend * (releasing both the connection and the fork) before refusing with a * {@link BranchError}. * 6. A fresh `Store` is attached with `createStore` — a zero-DDL attach, * since the fork already carries the base's schema and rows — using * {@link forkStoreOptions}. * 7. `computeBaseVersion(forkStore)` is compared against `base` — the * token `branch()` already stamped off the ORIGINAL base store, passed * in rather than recomputed here: comparing against the caller's own * token (instead of a second, independently computed one) means an * untracked base's content fingerprint is computed exactly once per * branch. Equality here proves base-token equality — schema plus a * revision anchor, or a live-content fingerprint — at the instant the * fork was taken; it is NOT a byte-for-byte physical audit (see * {@link ForkedWorkingCopyOptions.fork}'s doc comment for what the * fingerprint deliberately omits and why that is the fork mechanism's * contract, not this assertion's). A mismatch closes the backend * (releasing both the connection and the fork, mirroring step 5's * composition) before refusing with a {@link BranchError}. * * @param options - `{ fork, connect }` — see {@link ForkedWorkingCopyOptions}. */ declare function forkedWorkingCopyStrategy(options: ForkedWorkingCopyOptions): WorkingCopyStrategy; /** * `branch()` — fork an isolated, independently-mutable working copy of a base * store (design §7.1). * * A branch is a {@link GraphBranch}: a fresh {@link BranchId}, the immutable * `base@V` token the copy forked from (computed off the ORIGINAL base store via * {@link computeBaseVersion}, never off the clone), a {@link Store} over the * branch's own backend seeded with the base's live state, and — when the * working copy resolves a `lineage` source — the fork-time engine revision * (`forkRevision`) that anchors this branch's half of the pruned merge diff. * * The copy mechanism is pluggable behind {@link WorkingCopyStrategy}. The P0 * default is the faithful streamed-interchange clone * ({@link cloneWorkingCopyStrategy}), * which keeps this primitive backend-agnostic: the caller supplies a * `makeBackend` factory, and `branch()` never names a concrete backend. */ /** * Creates an isolated working-copy branch of `baseStore`. * * Stamps the `base@V` token off the original base store, mints (or accepts) a * {@link BranchId}, and materializes the working copy via the resolved strategy. * The default strategy is a faithful clone over a fresh backend produced by * `makeBackend`; pass an explicit `strategy` to override (e.g. a future * logical-namespace copy-on-write). * * Returns a {@link Result}: success yields the {@link GraphBranch}; any failure * (base-version stamping, backend construction, streamed interchange) is wrapped in a * {@link BranchError} with the underlying cause attached. Errors are returned, * never thrown — this is internal-logic surface (the caller converts to a thrown * error at the framework boundary). * * @param baseStore - The store to fork. Remains untouched. * @param makeBackend - Factory for the working copy's backend (keeps the * primitive backend-agnostic). Used only by the default clone strategy; ignored * when an explicit `strategy` is supplied. * @param options - Optional `{ id }` to set an explicit branch id. * @param strategy - Optional working-copy strategy override. */ declare function branch(baseStore: GraphBranch["store"], makeBackend: MakeBackend, options?: BranchOptions, strategy?: WorkingCopyStrategy): Promise, BranchError>>; declare const MERGE_PLAN_FORMAT_VERSION: 1; declare const MERGE_PLAN_DIGEST_ALGORITHM: "sha256"; type MergePlanEntityRef = Readonly<{ kind: string; id: string; }>; type MergePlanSchemaFence = Readonly<{ managed: boolean; version: number; hash: string; }>; type MergePlanRevisionFence = Readonly<{ origin: string; revision: string | null; }>; type MergePlanTargetFence = Readonly<{ graphId: string; schema: MergePlanSchemaFence; revision: MergePlanRevisionFence; }>; type MergePlanBranchAnchor = Readonly<{ branchId: string; baseVersion: string; }>; type MergePlanAnchors = Readonly<{ kind: "snapshot"; base: Readonly<{ graphId: string; baseVersion: string; }>; branches: readonly MergePlanBranchAnchor[]; }> | Readonly<{ kind: "incremental"; forkPoint: Readonly<{ graphId: string; baseVersion: string; schema: MergePlanSchemaFence; }>; branches: readonly MergePlanBranchAnchor[]; }>; type MergePlanNodeDelete = MergePlanEntityRef; type MergePlanNodeUpsert = Readonly<{ kind: string; id: string; setProps: Readonly>; unsetProps: readonly string[]; validFrom?: string | null | undefined; validTo?: string | undefined; }>; type MergePlanEdgeDelete = MergePlanEntityRef; type MergePlanEdgeUpsert = Readonly<{ kind: string; id: string; from: MergePlanEntityRef; to: MergePlanEntityRef; setProps: Readonly>; unsetProps: readonly string[]; validFrom?: string | null | undefined; validTo?: string | undefined; }>; type MergePlanIdentityAssertion = Readonly<{ id: string; relation: "same" | "different"; a: MergePlanEntityRef; b: MergePlanEntityRef; validFrom: string; validTo?: string | undefined; endedBy?: MergePlanEntityRef | undefined; }>; type MergePlanWrites = Readonly<{ nodeDeletes: readonly MergePlanNodeDelete[]; nodeUpserts: readonly MergePlanNodeUpsert[]; edgeDeletes: readonly MergePlanEdgeDelete[]; edgeUpserts: readonly MergePlanEdgeUpsert[]; identityAssertions: readonly MergePlanIdentityAssertion[]; identityRetractions: readonly MergePlanIdentityAssertion[]; }>; type MergePlanProposedSummary = Readonly<{ nodes: Readonly<{ upserts: number; deletions: number; }>; edges: Readonly<{ upserts: number; deletions: number; }>; identity: Readonly<{ assertions: number; retractions: number; }>; }>; type MergePlanCanonicalMapping = Readonly<{ member: MergePlanEntityRef; canonical: MergePlanEntityRef; }>; type MergePlanRetype = Readonly<{ entity: MergePlanEntityRef; toKind: string; }>; type MergePlanGuards = Readonly<{ canonicalMappings: readonly MergePlanCanonicalMapping[]; retypes: readonly MergePlanRetype[]; deletedNodes: readonly MergePlanEntityRef[]; incremental?: Readonly<{ tombstoneResurrection: "refuse"; lossyUpdates: "refuse"; edgeIdentity: "preserve"; }>; }>; type MergePlanMatchSource = Readonly<{ kind: "block"; sourceId: string; }> | Readonly<{ kind: "unique"; sourceId: string; constraintName: string; }> | Readonly<{ kind: "baseUnique"; sourceId: string; constraintName: string; }> | Readonly<{ kind: "baseIndex"; sourceId: string; indexName: string; }> | Readonly<{ kind: "keyless"; sourceId: string; }> | Readonly<{ kind: "retype"; sourceId: string; }> | Readonly<{ kind: "custom"; sourceId: string; metadata?: JsonValue | undefined; }>; type MergePlanSimilarityStrategy = Readonly<{ kind: "fulltext" | "vector"; fields: readonly string[]; }> | Readonly<{ kind: "hybrid"; fields: readonly string[]; weights: Readonly<{ vector: number; fulltext: number; }>; }> | Readonly<{ kind: "custom"; }>; type MergePlanMatchEvidence = Readonly<{ a: MergePlanEntityRef; b: MergePlanEntityRef; sources: readonly MergePlanMatchSource[]; decision: "definitional"; }> | Readonly<{ a: MergePlanEntityRef; b: MergePlanEntityRef; sources: readonly MergePlanMatchSource[]; decision: "scored"; strategy: MergePlanSimilarityStrategy; score: number; threshold: number; }>; type MergePlanEntityResolution = Readonly<{ canonicalId: string; memberIds: readonly string[]; kind: string; branchOrigins: readonly string[]; decisiveEdges: readonly MergePlanMatchEvidence[]; }>; type MergePlanCandidateDiagnostic = Readonly<{ evidence: MergePlanMatchEvidence; scoreDecision: "accepted" | "rejected"; reason?: "noComparableValues" | undefined; clusterDisposition?: "retained" | Readonly<{ kind: "excluded"; reason: "diameter" | "baseAmbiguity"; }> | undefined; }>; type MergePlanDiagnostics = Readonly<{ entries: readonly MergePlanCandidateDiagnostic[]; total: number; limit: number; truncated: boolean; }>; type MergePlanTypeReconciliation = Readonly<{ entityId: string; fromTypes: readonly string[]; toType: string; decisiveEdges?: readonly MergePlanMatchEvidence[] | undefined; }>; type MergePlanReview = Readonly<{ resolutions: readonly MergePlanEntityResolution[]; conflicts: readonly JsonValue[]; deleteModifyConflicts: readonly JsonValue[]; typeReconciliations: readonly MergePlanTypeReconciliation[]; dropped: readonly JsonValue[]; validityEnds: readonly JsonValue[]; baseAmbiguities: readonly JsonValue[]; provenanceRecords: readonly JsonValue[]; warnings: readonly string[]; diagnostics?: MergePlanDiagnostics | undefined; }>; type MergePlanProvenanceOptions = Readonly<{ includeInReport: boolean; persist: boolean; }>; type MergePlanDigest = Readonly<{ algorithm: typeof MERGE_PLAN_DIGEST_ALGORITHM; value: string; }>; type MergePlanArtifactV1 = Readonly<{ formatVersion: typeof MERGE_PLAN_FORMAT_VERSION; digest: MergePlanDigest; mode: "snapshot" | "incremental"; target: MergePlanTargetFence; anchors: MergePlanAnchors; proposed: MergePlanProposedSummary; writes: MergePlanWrites; guards: MergePlanGuards; review: MergePlanReview; provenance: MergePlanProvenanceOptions; }>; /** Current public merge-plan artifact type. */ type MergePlanArtifact = MergePlanArtifactV1; type MergePlanArtifactV1Input = Omit; /** Current JSON wire version emitted and accepted for candidate write sets. */ declare const CANDIDATE_WRITE_SET_FORMAT_VERSION: 1; /** Target schema identity carried by a candidate document. */ declare const CandidateWriteSetTargetSchema: z.ZodObject<{ graphId: z.ZodString; schemaVersion: z.ZodNumber; schemaHash: z.ZodString; }, z.core.$strip>; type CandidateWriteSetTarget = z.infer; /** * JSON-safe, source-attributed candidate writes accepted by * {@link planCandidateWriteSet}. * * `sourceId` becomes the existing merge pipeline's branch attribution. Entity * ids remain the per-candidate source ids in provenance records. Every temporal * lower bound is explicit so replaying identical JSON cannot acquire a new * import-time timestamp and change the resulting plan digest. */ declare const CandidateWriteSetSchema: z.ZodObject<{ formatVersion: z.ZodLiteral<1>; sourceId: z.ZodString; target: z.ZodObject<{ graphId: z.ZodString; schemaVersion: z.ZodNumber; schemaHash: z.ZodString; }, z.core.$strip>; nodes: z.ZodArray; validFrom: z.ZodNullable; validTo: z.ZodOptional; }, z.core.$strip>>; edges: z.ZodArray; to: z.ZodObject<{ kind: z.ZodString; id: z.ZodString; }, z.core.$strip>; properties: z.ZodDefault>; validFrom: z.ZodNullable; validTo: z.ZodOptional; }, z.core.$strip>>; identity: z.ZodOptional; mode: z.ZodEnum<{ state: "state"; archival: "archival"; }>; assertions: z.ZodArray; a: z.ZodObject<{ kind: z.ZodString; id: z.ZodString; }, z.core.$strip>; b: z.ZodObject<{ kind: z.ZodString; id: z.ZodString; }, z.core.$strip>; validFrom: z.ZodISODateTime; validTo: z.ZodOptional; endedBy: z.ZodOptional>; }, z.core.$strip>>; }, z.core.$strip>>; }, z.core.$strip>; type CandidateWriteSet = z.infer; /** Object-form arguments for branch-free candidate planning. */ type PlanCandidateWriteSetArgs = Readonly<{ target: Store; makeBackend: MakeBackend; writeSet: unknown; options?: Omit, "target">; }>; /** Object-form arguments for candidate planning against a planned evolution. */ type PlanCandidateWriteSetForEvolutionArgs = Omit, "target"> & Readonly<{ target: Store; evolutionPlan: EvolutionPlan; }>; /** Captures the schema identity a candidate write set must name. */ declare function captureCandidateWriteSetTarget(target: Store): Promise; /** * Captures the schema identity a candidate write set must name after a planned * evolution commits. The plan remains nonserializable; this JSON-safe target * identity lets a caller author and review candidate data before that commit. */ declare function captureCandidateWriteSetTargetForEvolution(target: Store, evolutionPlan: EvolutionPlan): CandidateWriteSetTarget; /** * Plans one serializable candidate write set against the current accepted graph. * * The adapter creates no durable branch and never mutates `target`. It stages in * a disposable ingestion working copy, delegates to `planMergeIncremental`, and * closes that working copy on success, refusal, or throw. The returned artifact * is the ordinary versioned/digested {@link MergePlanArtifact}; no parallel * conflict format or scoring implementation exists. */ declare function planCandidateWriteSet(args: PlanCandidateWriteSetArgs): Promise>; /** * Plans a serializable candidate write set against the graph a reviewed * evolution will produce. * * Candidate data is staged in an isolated working copy of the resulting graph, * then resolved against accepted target sources through the evolution-aware * incremental planner. The returned ordinary merge artifact carries the * resulting schema fence, so * `withEvolvedTransaction()` and `applyMergePlanInTransaction()` can commit * schema and accepted candidate writes in one caller transaction and revision. */ declare function planCandidateWriteSetForEvolution(args: PlanCandidateWriteSetForEvolutionArgs): Promise>; declare const MERGE_REVIEW_FORMAT_VERSION: 1; /** Application-owned identity of policy code and all opaque/external dependencies. */ type MergeReviewPolicy = Readonly<{ id: string; /** Explicit evidence; use an empty object only when there are no such dependencies. */ context: JsonValue; }>; /** A fingerprint of an observed row, or an expected absence. */ type MergeReviewRow = MergePlanEntityRef & Readonly<{ role: "node" | "edge"; /** Absent means this reference did not exist at review time. */ digest?: string | undefined; }>; /** Conservative baseline: all original rows and the complete identity ledger. */ type MergeReviewBaseline = Readonly<{ rows: readonly MergeReviewRow[]; identityDigest: string; }>; /** * Immutable review evidence, distinct from its single-use execution plan. * V1 supports candidate write sets only. Authenticate stored artifacts separately. */ type MergeReviewArtifact = Readonly<{ formatVersion: typeof MERGE_REVIEW_FORMAT_VERSION; kind: "candidate-write-set"; digest: MergePlanDigest; writeSet: CandidateWriteSet; policy: MergeReviewPolicy; options: JsonValue; plan: MergePlanArtifact; baseline: MergeReviewBaseline; }>; /** Structured reason to refuse approval reuse; paths name fields in the review. */ type MergeReviewDifference = Readonly<{ category: "target" | "policy" | "baseline" | "plan"; path: string; entity?: MergePlanEntityRef & Readonly<{ role: "node" | "edge"; }>; }>; /** Compatibility is evidence for application policy, never an authorization decision. */ type MergeReviewRevalidation = Readonly<{ status: "compatible"; reviewDigest: MergePlanDigest; plan: MergePlanArtifact; }> | Readonly<{ status: "changed" | "incompatible"; reviewDigest: MergePlanDigest; differences: readonly MergeReviewDifference[]; /** Present when a fresh plan was computed; it requires a new review. */ plan?: MergePlanArtifact; }>; type PlanCandidateWriteSetReviewArgs = PlanCandidateWriteSetArgs & Readonly<{ policy: MergeReviewPolicy; }>; type RevalidateCandidateWriteSetReviewArgs = Omit, "writeSet"> & Readonly<{ review: unknown; }>; /** Capture a durable review, with planning and baseline reads under one fence. */ declare function planCandidateWriteSetReview(args: PlanCandidateWriteSetReviewArgs): Promise>; /** * Replan the retained input and relate it to its original review. Never writes * the target, edits an old plan, or authorizes execution. Apply a compatible * result with applyMergePlan(), retaining its final transactional revision fence. */ declare function revalidateCandidateWriteSetReview(args: RevalidateCandidateWriteSetReviewArgs): Promise>; /** * Durable-branch operations: a generic, backend-neutral facility for a durable * host to combine an opaque graph mutation with immutable operation evidence in * ONE host transaction. * * The facility is deliberately the same shape as the optional host-native merge * command ({@link import("./durable-merge").applyDurableMergePlan}): TypeGraph * owns descriptor validation, sealed-origin attestation, request * canonicalization, and evidence validation; the host owns the database * mechanics. A strategy that cannot combine the mutation and its evidence in a * single atomic unit returns `unsupported` BEFORE touching the host, and * TypeGraph refuses rather than emulating atomicity with callbacks or best * effort. * * WHAT IS OPAQUE. Both `metadata` and `mutation` are JSON-safe host values. * TypeGraph never interprets their application fields; it canonicalizes them to * derive {@link DurableBranchOperation.operationDigest} and otherwise carries * them through untouched. `metadata` is retained as evidence; `mutation` is the * host's own description of the graph change it must apply (for example a * serialized statement or a host-defined command) atomically with the evidence * row. * * IDEMPOTENCY. The digest is derived from the complete request content * (`mutation` plus `metadata`) with the repository's canonical JSON serializer. * The strategy is handed the digest and MUST treat `(idempotencyKey)` as the * unique key: identical key AND digest returns the previously committed * evidence without re-applying; identical key with a different digest fails * with {@link DurableOperationConflictError} and mutates nothing. * * DELIVERY AND DESTRUCTION. Evidence is delivered explicitly via * {@link markDurableOperationDelivered}. Archive/destroy is fenced on * undelivered evidence: a strategy MUST refuse destruction while undelivered * evidence remains, and the refusal is preserved through * {@link import("./durable-branch").destroyDurableBranch} as a * {@link DurableEvidenceUndeliveredError}. Concurrent `operate` and `destroy` * are serialized by the host's own transaction: either the operation commits * first (destroy observes undelivered evidence and refuses) or destroy commits * first (the operation fails against the removed allocation). No partial state * is ever observable. * * CURSORS. {@link scanDurableOperations} returns evidence in a stable total * order the strategy defines (commit order, ties broken deterministically). * `cursor` is an opaque continuation token; pass it back as `after` to resume. * A missing `cursor` means the scan reached the end. */ /** Default page size for {@link scanDurableOperations}. */ declare const DURABLE_OPERATION_SCAN_DEFAULT_LIMIT = 100; /** Largest page a single {@link scanDurableOperations} call may request. */ declare const DURABLE_OPERATION_SCAN_MAX_LIMIT = 1000; /** * The dimensions whose absence a strategy reports through the `unsupported` * outcome. Each names a guarantee TypeGraph will not fake. */ type DurableOperationUnsupportedDimension = "atomicMutation" | "evidenceStore" | "host"; /** * The caller's operation request. `idempotencyKey` identifies the operation; * `mutation` is the host's opaque, JSON-safe description of the graph change; * `metadata` is opaque, JSON-safe host evidence TypeGraph never interprets. */ type DurableBranchOperationRequest = Readonly<{ idempotencyKey: string; metadata: JsonValue; mutation: JsonValue; }>; /** * The canonical operation handed to the strategy: the request plus the * TypeGraph-derived digest the strategy must use for idempotency. */ type DurableBranchOperation = Readonly<{ idempotencyKey: string; operationDigest: string; metadata: JsonValue; mutation: JsonValue; }>; /** * A branch's content coordinates at one point. `base` is the * merge-visible base-version fingerprint (as produced by * `computeBaseVersion`); `revision` is the engine revision when the working * copy resolves lineage. */ type DurableBranchCoordinates = Readonly<{ base: BaseVersion; revision?: EngineRevision | undefined; }>; /** * Immutable evidence of one committed operation. `delivered` is the only * mutating dimension, and it moves in one direction (`false` → `true`) under * {@link DurableOperationCapability.markDelivered}. A newly `applied` * operation must return `false`; an exact `replayed` operation returns its * current committed delivery state. */ type DurableBranchOperationEvidence = Readonly<{ idempotencyKey: string; operationDigest: string; metadata: JsonValue; mutation: JsonValue; before: DurableBranchCoordinates; after: DurableBranchCoordinates; delivered: boolean; }>; /** One stable-order page of evidence returned by {@link scanDurableOperations}. */ type DurableOperationScan = Readonly<{ operations: readonly DurableBranchOperationEvidence[]; /** Opaque continuation token; absent when the scan reached the end. */ cursor?: string | undefined; }>; /** Outcome of an atomic operation attempt. */ type DurableOperationOutcome = Readonly<{ outcome: "applied" | "replayed"; evidence: DurableBranchOperationEvidence; }> | Readonly<{ outcome: "unsupported"; dimensions: readonly [ DurableOperationUnsupportedDimension, ...DurableOperationUnsupportedDimension[] ]; }>; /** * The optional host capability behind `DurableWorkingCopyStrategy.operations`. * * Every member receives the opaque locator AND the caller's expected origin, so * the host attests the sealed origin exactly as it does for reopen, destroy, * and native merge. TypeGraph validates the descriptor before any member is * called. */ type DurableOperationCapability = Readonly<{ /** * Atomically applies `request.mutation` and records evidence, or returns * `unsupported` having executed no host SQL or mutation. * * The host MUST: * 1. attest `expectedOrigin` against the allocation `descriptor` names; * 2. return the previously committed evidence unchanged when * `(idempotencyKey, operationDigest)` matches a committed operation, * applying nothing; * 3. refuse with {@link DurableOperationConflictError} when the key exists * with a different digest, applying nothing; and * 4. otherwise apply the mutation and undelivered evidence in ONE * transaction, returning `outcome: "applied"` with `delivered: false`. */ operate: (args: Readonly<{ descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; request: DurableBranchOperation; }>) => Promise; /** Reads one operation's evidence, or `undefined` when never committed. */ get: (args: Readonly<{ descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; idempotencyKey: string; }>) => Promise; /** * Reads evidence in the strategy's stable total order. `after` resumes from * a previous page's `cursor`; `limit` bounds the page. */ scan: (args: Readonly<{ descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; after?: string | undefined; limit: number; }>) => Promise; /** * Marks one operation delivered. MUST be idempotent: marking an * already-delivered operation returns the same evidence and writes nothing. * Returns `undefined` when the operation does not exist. */ markDelivered: (args: Readonly<{ descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; idempotencyKey: string; }>) => Promise; /** Whether any committed evidence is still undelivered. */ hasUndelivered: (args: Readonly<{ descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; }>) => Promise; }>; /** * Derives the operation digest from its canonical content. The digest covers * the complete request except the idempotency key, so reusing a key with a * different mutation OR different metadata conflicts. */ declare function computeDurableOperationDigest(request: DurableBranchOperationRequest): Promise; /** * Atomically applies an opaque graph mutation and commits its evidence through * the strategy's optional `operations.operate` capability. * * Descriptor format/type/version validation and the sealed-origin attestation * are exactly those of reopen, destroy, and native merge: TypeGraph validates * the envelope and hands the caller's expected origin to the host, which * attests it inside its own transaction. A strategy without the capability * yields the `unsupported` outcome with no host call. */ declare function operateDurableBranch(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy, request: DurableBranchOperationRequest): Promise>; /** * Reads one operation's evidence. Returns `undefined` when the operation was * never committed. A strategy without evidence access is an explicit typed * refusal. */ declare function getDurableOperation(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy, idempotencyKey: string): Promise>; /** * Reads evidence in a stable order. `after` resumes from a previous page's * `cursor`; `limit` defaults to {@link DURABLE_OPERATION_SCAN_DEFAULT_LIMIT} * and may not exceed {@link DURABLE_OPERATION_SCAN_MAX_LIMIT}. The returned * `cursor` is absent at the end of the scan. */ declare function scanDurableOperations(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy, options?: Readonly<{ after?: string | undefined; limit?: number | undefined; }>): Promise>; /** * Marks one operation delivered, idempotently. Marking an already-delivered * operation returns the same evidence without writing. Returns `undefined` when * the operation does not exist. */ declare function markDurableOperationDelivered(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy, idempotencyKey: string): Promise>; /** * Reports whether any committed evidence is still undelivered. Archive/destroy * must fence on this; the strategy enforces the fence atomically, this is the * queryable half. */ declare function durableBranchHasUndeliveredEvidence(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy): Promise>; /** * Durable working-copy branches: a JSON-serializable descriptor for a * PERSISTENT working copy plus reopen / destroy operations over it. * * `branch()` produces an {@link GraphBranch} whose store/close handle lives * only in the process that minted it. A durable branch instead pairs the normal * {@link GraphBranch} with a {@link DurableBranchDescriptor} — a plain JSON * document the caller can store anywhere — so a LATER process can reconnect to * the SAME mutated working copy without cloning the base and without keeping an * in-memory map of open handles. * * The descriptor has two halves: * * - TypeGraph-owned fences: `kind`/`version`, the owning `graphId`, the * branch id, the `base@V` token the working copy forked from, the at-fork * schema anchor (explicitly absent for an unmanaged store), and the * at-fork engine revision when the working copy resolved `lineage`. * - An opaque, strategy-defined `store` locator. TypeGraph never interprets * it and never assumes a database URL, product, or dialect. * * TAMPER MODEL: the descriptor is a document the caller stores and later hands * back, so every TypeGraph-owned fence in it is UNTRUSTED. The durable host is * the authority: at seal time it persists the {@link DurableBranchOrigin} that * TypeGraph captured at the fork, and at reopen it ATTESTS the complete origin * it holds. Reopen refuses unless every descriptor fence equals the attested * origin — a tampered `graphId`/`definitionHash`/`base`/`branchId`/ * `forkRevision`/`schemaAnchor`, including DELETING `schemaAnchor` from the * envelope, cannot relabel a fork, because the host's own record is the * reference. `destroy` is verified the same way before it deletes (see * {@link DurableWorkingCopyStrategy.destroy}), so swapping one working copy's * locator for another's cannot destroy the wrong allocation. * * DEFINITION IDENTITY is part of that origin and is INDEPENDENT of the optional * committed `schemaAnchor`: the host attests the `graphId` AND a version-blind * {@link getGraphDefinitionHash} of the caller's fork-time definition. An * unmanaged working copy (one that committed no schema row, so its * `schemaAnchor` is absent) therefore still refuses descriptor `graphId` * relabeling, reopening with a different `graphId`, and — the case a missing * anchor used to let through — a SAME-ID graph whose definition hashes * differently. Definition identity is the fork-time caller definition; the * branch's CURRENT committed schema may legitimately evolve after forking, so * reopen never compares the live schema row to the fork-time identity. * * The host lifecycle is split deliberately. `GraphBranch.close()` releases the * process's CONNECTION to the working copy — it must never delete it. Explicit * teardown is a separate strategy operation, {@link DurableWorkingCopyStrategy.destroy}, * surfaced through {@link destroyDurableBranch}. This keeps the ephemeral * {@link ForkHandle.dispose}-deletes-the-fork contract out of the durable path, * where "the process closed its connection" and "the working copy is gone" are * different events. * * The at-fork schema anchor is IMMUTABLE FORK METADATA, never a statement about * the working copy's CURRENT schema: a branch may legitimately evolve its * committed schema after forking, and reopen must still succeed. Reopen therefore * never compares the live schema row to the anchor; it compares the descriptor's * anchor to the host's, and the caller's graph definition to the attested * definition hash. The merge path separately refuses a branch whose LIVE schema * moved (see `merge.ts`'s at-fork drift guard); reopen is not that gate. * * Backend-specific mechanics remain entirely within the strategy. */ /** * A strategy-defined, JSON-serializable locator for one PERSISTENT working * copy. TypeGraph treats it as opaque data: it is carried inside a * {@link DurableBranchDescriptor} and handed back to the strategy on reopen and * destroy, never inspected. It must survive `JSON.parse(JSON.stringify(...))` * unchanged. It MUST be a non-secret identifier: TypeGraph returns it to the * caller. Connection strings, credentials, bearer tokens, and other secrets do * not belong here; keep those in strategy-owned configuration and resolve this * locator there. TypeGraph deliberately omits it from cleanup error details. */ type DurableStoreDescriptor = JsonValue; /** * The write-access guarantee a strategy acquired for one opened working copy. * * `engine-fenced` means the database provides sound cross-client isolation and * change fencing for the full Store planning/apply access pattern, across every * connection and process that could mutate the working copy. * `exclusive` means the host acquired an allocation-wide writer lease before * returning. That lease MUST exclude every other process and backend instance, * not merely serialize calls through one in-memory queue. TypeGraph releases it * after the Store backend closes; a failed release is retried by the next * `GraphBranch.close()` call. * * A backend that provides only `caller-serialized` access MUST use `exclusive`: * each backend instance owns a different in-process queue, so that declaration * alone does not serialize two durable reopen handles or two processes. */ type DurableWorkingCopyAccess = Readonly<{ kind: "engine-fenced"; }> | Readonly<{ kind: "exclusive"; leaseId: string; release: () => Promise; }>; /** Why an authoritative native merge attempt could not safely run. */ type NativeDurableMergeUnsupportedDimension = "branchOrigin" | "graphScope" | "nativeConflicts" | "planSemantics" | "targetFence"; /** * Result of a host-native merge optimization attempt. * * `unsupported` proves that NO native merge SQL or host mutation ran; TypeGraph * then executes the complete portable plan application. `applied` proves the * strategy atomically validated every dimension named by * {@link DurableWorkingCopyStrategy.merge} and applied exactly the approved * plan. A refusal or uncertain/partial execution throws instead of returning * `unsupported`, because falling back after a possible native write would * double-apply the plan. */ type NativeDurableMergeResult = Readonly<{ outcome: "applied"; merged: MergedCounts; warnings?: readonly string[] | undefined; }> | Readonly<{ outcome: "unsupported"; dimensions: readonly [ NativeDurableMergeUnsupportedDimension, ...NativeDurableMergeUnsupportedDimension[] ]; }>; /** * The complete immutable TypeGraph origin of one durable working copy — every * TypeGraph-owned fork fence, with NO dependence on the descriptor: the graph * id and version-blind graph-definition hash identifying the fork-time caller * definition, the branch id, the `base@V` token it forked from, the at-fork * schema anchor (`undefined` meaning the working copy committed no schema row — * an EXPLICIT absent, so a descriptor that simply omits the field still * disagrees with a host that persisted one), and the at-fork engine revision * (`undefined` when the working copy resolved no lineage). * * `graphId` and `definitionHash` are REQUIRED and carry the definition identity * even when `schemaAnchor` is absent: an unmanaged working copy still has to * reject relabeling and same-id divergent definitions. The host persists this * at seal time and attests it at reopen/destroy; it is the reference every * descriptor fence is compared against. */ type DurableBranchOrigin = Readonly<{ graphId: string; definitionHash: string; branchId: BranchId; base: BaseVersion; schemaAnchor: Readonly<{ version: number; hash: string; }> | undefined; forkRevision: EngineRevision | undefined; }>; /** * The durable envelope for a branch: the TypeGraph-owned fences a reopen * re-validates plus the strategy's opaque store locator. * * `kind`/`version` identify the strategy's descriptor FORMAT. `graphId` and * `definitionHash` bind the descriptor to one fork-time graph definition, and * `branchId` to one working copy. `base`, `schemaAnchor` and `forkRevision` are * the same at-fork fences a live {@link GraphBranch} carries, captured when the * branch was created. * * The fences are untrusted on reopen — see the module doc's tamper model. * `schemaAnchor` is PRESENT with value `undefined` when the working copy * committed no schema row (an unmanaged store), mirroring `branch()`'s own * representation; JSON storage drops the key, and the host's own attestation * restores the distinction on reopen. */ type DurableBranchDescriptor = Readonly<{ /** Stable strategy type tag; must equal the reopening strategy's `type`. */ kind: string; /** Strategy descriptor format version; must equal the strategy's `version`. */ version: number; /** The graph id the working copy belongs to. */ graphId: string; /** * The version-blind graph-definition hash of the caller's fork-time * definition. Attested by the host, so it fences a same-id divergent * definition even for an unmanaged working copy with no `schemaAnchor`. */ definitionHash: string; /** The TypeGraph branch id the working copy is identified by. */ branchId: BranchId; /** The immutable `base@V` token the working copy forked from. */ base: BaseVersion; /** The strategy's opaque, JSON-serializable locator for the working copy. */ store: TStoreDescriptor; /** The at-fork committed schema `(version, hash)`; `undefined` when unmanaged. */ schemaAnchor?: Readonly<{ version: number; hash: string; }> | undefined; /** The at-fork engine revision, when the working copy resolves `lineage`. */ forkRevision?: EngineRevision | undefined; }>; /** * The host-owned half of a durable working copy: how a persistent working copy * is allocated, sealed, reconnected to, and explicitly destroyed. * * The create -> seal/abort protocol has explicit ownership: * * 1. `create` allocates the persistent working copy and returns a mutable * {@link Store} over it plus the opaque locator. Once `create` resolves, * TypeGraph owns the allocation and the returned store. * 2. TypeGraph captures the fork state off the store and calls `seal` with * the complete {@link DurableBranchOrigin}. The host MUST persist that * origin durably before `seal` resolves — it is what later attestations * compare a descriptor against. * 3. If capturing OR sealing fails, TypeGraph calls `abort`: the host releases * the just-created allocation (deleting it) so no orphan survives. `abort` * is only ever called on an allocation this same `create` produced, so it * need not verify identity; it MUST tolerate a partially-sealed allocation. * An `abort` failure does NOT mask the original capture/seal failure: * TypeGraph returns a {@link BranchError} preserving that original failure * as its `cause` and reports `details.allocationAborted: false`. The opaque * locator and raw cleanup error are deliberately NOT copied into error * details, where application logging could disclose host credentials or * other strategy-private data. Operator tooling can use the safe TypeGraph * branch id supplied to `create` to identify the orphan. * * `reopen` reconnects to an EXISTING working copy identified by `descriptor` * without cloning, and returns the complete origin the host PERSISTED for that * locator. TypeGraph refuses when any descriptor fence disagrees with that * attested origin. A reopen failure (missing or deleted store, unreachable * host) throws; the strategy must not leave an opened backend behind when it * throws. * * `destroy` is the ONLY operation that may delete or archive the persistent * working copy. It receives the locator AND the caller's expected origin and * MUST verify, atomically with respect to its own persistence, that the origin * stored for that locator equals `expectedOrigin` before deleting — otherwise a * descriptor whose locator was swapped for another working copy's would destroy * the wrong allocation. A mismatch refuses without deleting. Closing the * returned branch's `close()` releases just the connection and must leave the * working copy reopenable. */ type DurableWorkingCopyStrategy = Readonly<{ type: string; version: number; create: (baseStore: Store, base: BaseVersion, branchId: BranchId) => Promise; descriptor: TStoreDescriptor; access: DurableWorkingCopyAccess; }>>; seal: (descriptor: TStoreDescriptor, origin: DurableBranchOrigin) => Promise; abort: (descriptor: TStoreDescriptor) => Promise; reopen: (graph: G, descriptor: TStoreDescriptor) => Promise; origin: DurableBranchOrigin; access: DurableWorkingCopyAccess; }>>; destroy: (descriptor: TStoreDescriptor, expectedOrigin: DurableBranchOrigin) => Promise; /** * Optional authoritative host-native merge optimization. * * Before returning `applied`, the strategy MUST, atomically with the native * merge operation: * * 1. attest `expectedOrigin` against the same allocation `branch.store` is * connected to; * 2. validate `plan.target` on the exact target branch/session the host will * merge into; * 3. prove the host-native diff contains exactly `plan.writes`, including all * TypeGraph sidecars and no rows belonging to another graph or application; * 4. prove the plan needs no canonicalization, repointing, identity, callback, * provenance, or other semantic work the native merge would bypass; and * 5. report the actual applied counts. * * A whole-database merge primitive therefore qualifies only for an allocation * whose complete physical diff is owned by this graph and is byte-for-byte * equivalent to the approved TypeGraph plan. If any dimension cannot be * proven, return `unsupported` BEFORE executing host SQL; TypeGraph will apply * the plan through its portable transaction path. */ merge?: ((args: Readonly<{ target: Store; branch: GraphBranch; descriptor: TStoreDescriptor; expectedOrigin: DurableBranchOrigin; plan: MergePlanArtifactV1; }>) => Promise) | undefined; /** * Optional atomic operation + evidence capability. * * When present, {@link import("./durable-operation").operateDurableBranch} * commits the host's opaque graph mutation and its immutable evidence in one * host transaction, keyed by idempotency. `destroy` MUST additionally refuse * to remove the allocation while undelivered evidence remains, throwing * {@link DurableEvidenceUndeliveredError}; closing a branch handle still only * releases the connection. * * A strategy that cannot provide the atomic guarantee MUST omit this * capability (or return `unsupported` from `operate`) rather than emulating * atomicity with callbacks or best effort. See `durable-operation.ts`. */ operations?: DurableOperationCapability | undefined; }>; /** * A normal {@link GraphBranch} paired with the serializable descriptor that * lets a later process reopen the SAME working copy. `branch` behaves exactly * like a `branch()` result — plan/merge APIs and `close()` are unchanged. */ type DurableBranch = Readonly<{ branch: GraphBranch; descriptor: DurableBranchDescriptor; }>; /** * Creates a durable working-copy branch of `baseStore`. * * Stamps the `base@V` token off the base, mints (or accepts) a {@link BranchId}, * delegates materialization to `strategy.create`, captures the graph id and * version-blind definition hash, the at-fork schema anchor, and the engine * revision, then SEALS the complete origin into the host before returning the * normal {@link GraphBranch} together with its JSON-serializable * {@link DurableBranchDescriptor}. * * Returns a {@link Result}; any failure is wrapped in a {@link BranchError}. * Once `strategy.create` resolves, the working copy's store and persistent * allocation belong to this function: a capture or seal failure closes the * store and calls `strategy.abort`, so this never returns an unrecoverable * success and never leaves an orphan. * * @param baseStore - The store to fork. Remains untouched. * @param strategy - The durable working-copy strategy owning the host mechanics. * @param options - Optional `{ id }` to set an explicit branch id. */ declare function branchDurable(baseStore: Store, strategy: DurableWorkingCopyStrategy, options?: BranchOptions): Promise, BranchError>>; /** * Reconnects to an existing durable working copy and reconstructs the normal * {@link GraphBranch} for it. * * Validates, in order: descriptor shape/type/version, graph id agreement, * strategy reconnect, store graph id, and — the load-bearing step — every * descriptor fence against the complete origin the host attests. A tampered * `graphId`/`definitionHash`/`branchId`/`base`/`schemaAnchor`/`forkRevision`, * including a DELETED `schemaAnchor`, is refused here; the host's persisted * record is the reference, never the descriptor. Finally the caller's graph * definition must hash to the attested fork-time definition AND agree on graph * id (a different graph definition, even one reusing the graph id, is not the * branch that was forked). Because the definition identity is attested * independently of `schemaAnchor`, this holds for an unmanaged working copy * with no committed schema row. * * The working copy's CURRENT committed schema is deliberately NOT compared to * the anchor: a branch may evolve its schema after forking and must remain * reopenable — the anchor is immutable fork metadata, not current schema. * * Every refusal is a typed {@link BranchError}, and any backend the strategy * opened is closed before the refusal is returned. The persistent working copy * is NEVER deleted here. * * @param graph - The graph definition the working copy was built with. * @param descriptor - The serialized descriptor returned by {@link branchDurable}. * @param strategy - The SAME strategy that produced `descriptor`. */ declare function reopenDurableBranch(graph: G, descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy): Promise, BranchError>>; /** * Explicitly destroys (deletes or archives) the persistent working copy the * descriptor names. This is the ONLY operation that may do so; closing a * reopened branch's `close()` never reaches here. * * The complete descriptor origin is passed to the strategy alongside the * locator and MUST be verified against the host's persisted origin before * deletion, so a descriptor whose locator was swapped for another working * copy's cannot destroy the wrong allocation. * * Returns a {@link Result}: a malformed/wrong-strategy descriptor or a strategy * failure (including an identity mismatch) is a typed {@link BranchError}. After * a successful destroy, reopening the same descriptor fails. */ declare function destroyDurableBranch(descriptor: DurableBranchDescriptor, strategy: DurableWorkingCopyStrategy): Promise>; /** * Applies an approved merge plan through an optional host-native merge command, * with the ordinary portable applier as the complete fallback. * * The native command is an optimization attempt, never a second source of merge * semantics. TypeGraph validates the serialized plan and durable envelope first. * The strategy may return `applied` only after atomically proving and honoring * every dimension in `DurableWorkingCopyStrategy.merge`; `unsupported` means it * executed no host mutation, so the full portable plan is safe to run. */ /** Arguments for {@link applyDurableMergePlan}. */ type ApplyDurableMergePlanArgs = Readonly<{ target: Store; branch: GraphBranch; descriptor: DurableBranchDescriptor; strategy: DurableWorkingCopyStrategy; plan: MergePlanArtifact; options?: MergePlanApplyOptions> | undefined; }>; /** * Applies an approved durable-branch plan, preferring a proven-equivalent * host-native merge and otherwise using {@link applyMergePlan} unchanged. * * Native merge is deliberately skipped when callbacks or persisted provenance * are requested. Those dimensions belong to TypeGraph's transaction and * sidecar owners; a raw database branch merge cannot silently drop them. */ declare function applyDurableMergePlan(args: ApplyDurableMergePlanArgs): Promise, MergeError>>; /** * Forks an isolated branch from an evolution plan's resulting graph, before * the caller opens its schema-write transaction. The original Store remains * pinned to its baseline; planMergeForEvolution checks its durable fence. */ declare function branchForEvolution(store: Store, plan: EvolutionPlan, makeBackend: MakeBackend, options?: BranchOptions): Promise, BranchError | MergePlanCapabilityError>>; /** * Constraint-aware working copies for untrusted ingestion. * * An ingestion branch persists a mechanically-derived schema with node * uniqueness declarations removed. That lets aliases reach merge planning, * where canonical candidate generation and final resolved-write validation use * the canonical graph's constraints. Every other working-copy constraint stays * active during staging. */ /** * Creates an isolated ingestion branch whose node uniqueness constraints are * deferred until the resolved merge write set is applied. * * The returned handle deliberately exposes no ordinary Store. Its typed node * and edge collections are sufficient to stage and inspect incoming data, and * merge entrypoints accept the handle directly. Call `close()` when the working * copy is no longer needed. */ declare function ingestionBranch(baseStore: GraphBranch["store"], makeBackend: MakeBackend, options?: BranchOptions): Promise, BranchError>>; /** * The shared SCORING stage (design §4, the single match-decision point). * * Candidate generation is three layers — sources → scoring → reconciler (§4). * This module is the MIDDLE layer: it turns the candidate PROPOSALS every source * emits into the {@link CandidateEdge} set the reconciler consumes, applying the * EXACT same scorer + threshold regardless of which source proposed a pair. A * source proposes (recall); scoring disposes (the match decision). * * Two proposal kinds enter: * * - {@link CandidatePair}s — unscored `(a, b)` node pairs from any source. They * are deduped by canonical `(a, b)` and each scored EXACTLY ONCE by * {@link scorePair}; only pairs clearing the kind's threshold become edges. * - FORCED {@link CandidateEdge}s — DEFINITIONAL matches (a shared unique value) * that BYPASS scoring entirely, emitted at {@link FORCED_MATCH_SCORE}. A forced * pair is never also fuzzy-scored: forced `(a, b)` keys are reserved first, so * a fuzzy pair proposing the same endpoints is dropped before scoring. * * This was previously fused into `candidate-gen.ts`'s `generateCandidates` (which * scored AND thresholded inline); naming scoring as its own stage is what makes * "the scorer — not a source — decides matches" concrete (§4). `generateCandidates` * now composes the bucket sources over this stage. * * Determinism: the emitted edge set is a pure function of the proposal SETS — pairs * are deduped by canonical `(a, b)`, scored by the symmetric {@link scorePair}, and * the final list is sorted by `(a, b)`, so neither the order proposals arrive in * nor the directionality of a pair affects the result. * * The {@link ComparisonCeilingPolicy} bounds only the FUZZY scoring work (the * embedder step for vector/hybrid); FORCED edges are definitional, not * similarity-based, so they are emitted regardless of the ceiling: * * - `"error"` — exceeding the ceiling fails with a typed {@link MergeError}. * - `"mergeByIdOnly"` — fuzzy similarity is SKIPPED for the kind (no * threshold-scored edges), FORCED edges are still emitted, * and a {@link CandidateWarning} is recorded. */ /** * An undirected candidate-merge edge between two nodes that should merge. * Endpoints are stored in ascending id order (`a < b`) so the edge has a single * canonical representation. Fuzzy edges carry their similarity score; FORCED * (definitional) edges carry {@link FORCED_MATCH_SCORE}. */ type CandidateEdge = Readonly<{ a: MergeKey; b: MergeKey; /** Internal drop-weakest rank. Definitional 1 is never copied to evidence. */ score: number; evidence: MatchEvidence; }>; /** * An unscored candidate pair a source proposes for scoring: the canonical * endpoint ids `(a, b)` (`a < b`) plus the two node objects the scorer reads * fields off of. `left`/`right` carry the nodes whose ids are `a`/`b` * respectively, but {@link scorePair} is symmetric so their roles are * interchangeable for scoring. */ type CandidatePair = Readonly<{ a: MergeKey; b: MergeKey; left: Node; right: Node; sources: readonly MatchSource[]; }>; /** Builds a durable, reviewable snapshot merge plan without mutating the target. */ declare function planMerge(store: Store, branchInputs: readonly MergeBranch[], optionsInput?: MergeOptions): Promise>; /** * Plans a merge against the graph produced by a reviewed evolution plan. * Durable data and revision evidence is still captured from the original * target; the schema fence names the version the caller will apply first. */ declare function planMergeForEvolution(store: Store, evolutionPlan: EvolutionPlan, branchInputs: readonly MergeBranch[], optionsInput?: MergeOptions): Promise>; /** Builds a durable, reviewable incremental merge plan without mutating the target. */ declare function planMergeIncremental(args: MergeIncrementalArgs): Promise>; /** Validates and atomically applies an approved serialized merge plan. */ declare function applyMergePlan(target: Store, input: MergePlanArtifact, options?: MergePlanApplyOptions>): Promise, MergeError>>; /** * Applies an approved serialized merge plan through a caller-owned transaction. * `tx` must belong to a currently active callback of `target`; retained contexts * and contexts created by another Store are refused. Apply the plan before any * graph writes in that transaction, because pending writes are not represented by * the plan's durable revision fence. * * The caller owns commit, rollback, and whole-transaction retry. This function * opens no transaction and throws on every failure so the surrounding callback * rejects rather than accidentally committing partial work. Plans requesting * persisted provenance are refused because the sidecar cannot yet be enlisted in * this caller-owned transaction. */ declare function applyMergePlanInTransaction(target: Store, tx: TransactionContext>, input: MergePlanArtifact): Promise>; /** * Merges a set of branches back into a target store (design §7.2). * * Validates that every branch forked from the target's current `base@V`, stages * the union of their diffs, resolves entities / conflicts / types through the * T3–T10 phases, and commits the merged result to `target` (default: the base * `store`) in a single transaction. Returns a {@link MergeReport} on success. * * This is the SNAPSHOT entry point: candidate generation runs the staged sources * only (`exactKey`, `unique`) — it never resolves a staged node against the * committed base. New-vs-base resolution is the separate {@link mergeAgainstBase} * scope, which has a weaker `base@V` contract. * * Errors are RETURNED (never thrown) as a typed {@link MergeError} subclass: * `BaseVersionMismatchError` for the precondition, `MergeError` for a * comparison-ceiling overrun / commit failure, `SimilarityUnavailableError` for a * `vector`/`hybrid` strategy with no configured vector strategy. * * @param store The base store the branches forked from. Used as the default merge * target and as the immutable diff reference. * @param branches The branches to merge. ORDER DOES NOT AFFECT THE RESULT — the * report and committed graph are identical across any permutation. * @param optionsInput Caller-facing {@link MergeOptions}; normalized internally. */ declare function merge(store: Store, branchInputs: readonly MergeBranch[], optionsInput?: MergeOptions): Promise, MergeError>>; /** * Incremental merge — the public fork-point-vs-live-target entry point (design * §6.4-B / §6.6). It treats `forkPoint` as the immutable ancestor, folds the live * `target` in as a preferred committed branch, resolves branch additions against * committed rows, and propagates inherited node/edge modifications and deletions * through the same three-way merge planner. * * Object-form args so the two same-typed stores (`forkPoint`, `target`) cannot be * swapped. The named `target` is authoritative; an untyped caller that also * supplies `options.target` is refused rather than silently ignored. * * Preconditions (typed errors): every branch forked from `forkPoint` * (`branch.base === computeBaseVersion(forkPoint)`); `forkPoint` and `target` share a * schema hash (schema drift is fatal; target CONTENT may have advanced); and * `onBasePropertyConflict` is `"flag"` (keep-base for committed-row conflicts). * * The fork-point precondition is not merely an entry check: it is re-verified * inside the commit transaction, so `forkPoint` must stay immutable for the * duration of the call. A write to it while the merge is in flight makes every * branch diff describe an ancestor that no longer exists, and is refused with * `BaseVersionMismatchError` rather than committed (see * {@link assertForkPointUnchanged}). The TARGET, by contrast, may advance * throughout — that is what "incremental" means. */ declare function mergeIncremental(args: MergeIncrementalArgs): Promise, MergeError>>; /** * Validation + default-application for {@link MergeOptions}. * * The zod schema validates the scalar / enum surface (thresholds, ceilings, * enums) and applies the frozen P0 defaults. Function- and store-valued fields * (`canonical`, a function `onPropertyConflict`, `target`, per-kind `block` / * `custom.score`, `branchOrder`) are not meaningfully validatable by zod, so they * are threaded through unchanged after the scalar surface validates. * * `normalizeMergeOptions` is the single entry point: it returns a * {@link NormalizedMergeOptions} with every default resolved, so downstream * phases never branch on `undefined`. */ /** * Frozen P0 defaults. Exported so tests and downstream phases assert against the * same constants rather than re-typing literals. */ declare const MERGE_OPTION_DEFAULTS: { readonly reconcileTypes: "off"; readonly onPropertyConflict: "flag"; readonly onBasePropertyConflict: "flag"; readonly onDeleteModifyConflict: "flag"; readonly onComparisonCeiling: "error"; readonly provenance: true; readonly persistProvenance: false; }; /** * Fully-normalized merge options: every default resolved, the (validated) * pass-through fields attached. Downstream phases consume this, never the raw * {@link MergeOptions}. */ type NormalizedMergeOptions = Readonly<{ resolve: Readonly>>; reconcileTypes: ReconcileTypesMode; onPropertyConflict: PropertyConflictPolicy; onBasePropertyConflict: PropertyConflictPolicy; onDeleteModifyConflict: DeleteModifyPolicy; onComparisonCeiling: ComparisonCeilingPolicy; provenance: boolean; persistProvenance: boolean; canonical?: (cluster: ResolvedCluster) => ReturnType["canonical"]>>; embedder?: Embedder; target?: MergeOptions["target"]; maxComparisonsPerKind?: number; clusterMaxDiameter?: number; candidateDiagnostics?: CandidateDiagnosticsOptions; branchOrder?: readonly BranchId[]; provenanceWeights?: ReadonlyMap; }>; /** * Validates and normalizes {@link MergeOptions}, applying every P0 default. * * Throws (not a `Result`) on invalid scalar input — option validation is a * caller-boundary concern, surfaced as a thrown error per project conventions; * `merge()` converts it back to a typed `MergeError` at its own boundary. * * @throws if a threshold is outside `[0, 1]`, `maxComparisonsPerKind` is * negative/non-integer, or `clusterMaxDiameter` is non-positive. */ declare function normalizeMergeOptions(options?: MergeOptions): NormalizedMergeOptions; /** The Provenance node: one row per `{branch, sourceId}` → canonical contribution. */ declare const Provenance: Readonly<{ kind: "Provenance"; schema: z.ZodObject<{ targetGraphId: z.ZodString; role: z.ZodEnum<{ node: "node"; edge: "edge"; }>; canonicalId: z.ZodString; canonicalKind: z.ZodString; branchId: z.ZodString; sourceId: z.ZodString; }, z.core.$strip>; description: string | undefined; annotations: KindAnnotations | undefined; __nodeType: true; }>; /** * Derives the sidecar graph id for a target graph. Suffixing the target's own id * keeps each target graph's provenance in its own `graphId`-namespaced tables on a * shared backend, while a single `Provenance` schema serves all of them. */ declare function provenanceGraphId(targetGraphId: string): string; /** The schema written by releases before durable sidecar ownership markers. */ declare function buildProvenanceGraph(targetGraphId: string): Readonly<{ id: string; annotations: GraphAnnotations | undefined; nodes: { readonly Provenance: { readonly type: Readonly<{ kind: "Provenance"; schema: z.ZodObject<{ targetGraphId: z.ZodString; role: z.ZodEnum<{ node: "node"; edge: "edge"; }>; canonicalId: z.ZodString; canonicalKind: z.ZodString; branchId: z.ZodString; sourceId: z.ZodString; }, z.core.$strip>; description: string | undefined; annotations: KindAnnotations | undefined; __nodeType: true; }>; }; }; edges: {}; ontology: readonly Readonly<{ metaEdge: MetaEdge; from: NodeType | AnyEdgeType | string; to: NodeType | AnyEdgeType | string; }>[]; identity: undefined; defaults: Readonly<{ onNodeDelete: DeleteBehavior; temporalMode: TemporalMode; }>; indexes: readonly IndexDeclaration[] | undefined; extension: Readonly<{ version?: GraphExtensionVersion; annotations?: GraphAnnotations; nodes?: Readonly>; edges?: Readonly>; ontology?: readonly ExtensionOntologyRelation[]; indexes?: readonly ExtensionIndex[]; }> | undefined; deprecatedKinds: ReadonlySet; __graphDef: true; }>; /** * Public view of the sidecar graph. The ownership kind is deliberately hidden: * it is framework metadata, not provenance data or an application collection. */ type ProvenanceGraph = ReturnType; /** A persisted provenance node (the queryable record). */ type ProvenanceNode = Node; /** * Opens the provenance store for a target — OPENING OR CREATING, never merely * reading. On a free graph id this claims the ownership marker and registers the * sidecar schema; on an occupied one it throws. There is no read-only entry * point: a tool that wants to inspect an existing sidecar without creating one * must decide for itself (e.g. by checking `backend.getActiveSchema` for * {@link provenanceGraphId}) before calling this. * * Pass the target Store in ordinary application code; callers that do not have * its GraphDef may instead pass the backend and target graph id. * * Idempotent in the sense that matters for the persist/query path: repeated calls * converge on one sidecar and write no second marker. It shares the backend with * the target, so the caller must NOT close it separately — closing the shared * backend is the target owner's job. */ declare function openProvenanceStore(target: Store): Promise>; /** * Opens (or creates — see above) a provenance store without a target GraphDef, * for callers that hold only the backend and the target's graph id. */ declare function openProvenanceStore(backend: GraphBackend, targetGraphId: string): Promise>; /** * Upserts one `Provenance` node per record into the sidecar store, keyed by the * deterministic id (re-running the same merge is a no-op upsert, never a * duplicate). Returns the row count written. The caller wraps this for best-effort * behavior — a failure here must not fail an already-committed merge. * * Records that hash to the SAME id are collapsed before the batch: the id is the * contribution's identity, so they are one row by definition — and a single * `bulkUpsertById` batch cannot create the same id twice. Collapsing here is what * makes the returned number the rows actually written for ANY caller, whatever * shape its record list arrived in. */ declare function persistProvenanceRecords(store: Store, targetGraphId: string, records: readonly ProvenanceRecord[]): Promise; /** Filter for {@link readProvenance}. Each field, when set, narrows the result. */ type ProvenanceQuery = Readonly<{ branchId?: BranchId | string; canonicalId?: string; role?: "node" | "edge"; }>; /** * Reads persisted provenance back, filtered and stably ordered. The sidecar is a * normal typed graph, so this is a thin ergonomic wrapper over * `store.nodes.Provenance.find()` (filtered in memory — provenance volumes are * modest; a query-builder `where` is the scale path). Answers "which canonical * entities did branch X contribute to?" and "who contributed canonical Y?". */ declare function readProvenance(store: Store, query?: ProvenanceQuery): Promise; /** * A committed BASE node a source pulled into the cluster universe (design §4 * member contribution / §6.4-D). It carries the same `(id, kind, props)` a staged * member does, plus a reserved `"base"` origin so the reconciler can enforce * base-id-wins (§6.4-C) and tag provenance with the base sentinel (§6.4-D). EMPTY * for staged-only sources (`exactKey`, `unique`). */ type BaseMember = Readonly<{ id: NodeId; kind: string; props: Readonly>; origin: "base"; validFrom?: string; validTo?: string; }>; /** * What a candidate source emits for one kind: fuzzy `pairs` to score, FORCED * (definitional) edges to pass through unscored, and the committed `baseMembers` * it pulled into scope. */ type SourceResult = Readonly<{ pairs: readonly CandidatePair[]; forcedEdges: readonly CandidateEdge[]; baseMembers: readonly BaseMember[]; }>; /** * The minimal node-collection surface a base-querying source needs: the public * `bulkFindByConstraint` (typegraph 0.29.0). It computes each item's constraint key * from its props, returns the live committed match per item in INPUT ORDER * (`undefined` for misses, soft-deleted excluded), and is indexed by the `uniques` * table PK — so graph-merge never reconstructs constraint keys itself. A runtime, * kind-string-keyed view (like the commit's `TxNodes`) so a source can dispatch on * a kind string without threading the caller's concrete `Store` generic. */ type BaseNodeLookup = Readonly<{ bulkFindByConstraint: (constraintName: string, items: readonly Readonly<{ props: Record; }>[]) => Promise | undefined)[]>; /** * The non-unique sibling (typegraph 0.30): for each item, the live committed nodes * sharing its declared-INDEX key (computed from props), returned per item in input * order, each inner array id-sorted, soft-deleted excluded. `limitPerInput` bounds * per-item fan-out (id-ordered, so the cap is deterministic). Candidate retrieval — * NOT a uniqueness/identity guarantee — so `baseKey` emits scored pairs, not forced * edges. */ bulkFindByIndex: (indexName: string, items: readonly Readonly<{ props: Record; }>[], options?: Readonly<{ limitPerInput?: number; }>) => Promise[])[]>; }>; /** Runtime, kind-string-keyed view of a store's node collections for base lookups. */ type BaseLookupStore = Readonly<{ nodes: Readonly>; }>; /** * The per-kind input a source generates over. `blocks` is the UNION `blockNodes` * result (`block()` key + per-constraint signatures) the staged sources read. * * The remaining fields are present only when a BASE-querying source (`baseUnique` / * `baseKey`, §6.2) is driven: the kind's materialized staged new `nodes` (the lookup * items), its `uniqueConstraints` (for `baseUnique`), the declared `blockIndex` name * (for `baseKey`, when the kind configured one), and the committed `store` to query * against. Staged-only sources (`exactKey`, `unique`) ignore them, so the public * `merge()` candidate path leaves them unset. */ type SourceScope = Readonly<{ kind: string; blocks: ReadonlyMap[]>; nodes?: readonly Node[]; uniqueConstraints?: readonly UniqueIntrospection[]; blockIndex?: string; /** When set, `exactKey` bounds the no-key (`"unblocked"`) bucket by sorted- * neighbourhood instead of all-vs-all (the `keyless` source, §6.2). */ keyless?: KeylessConfig; store?: BaseLookupStore; }>; /** * A candidate source (design §4): proposes pairs (recall) + definitional forced * edges, and supplies the base members it pulled into scope. The `id` attributes * a source in reports and pins its determinism level (§7). */ type CandidateSource = Readonly<{ readonly id: string; generate(scope: SourceScope): Promise; }>; /** * The bounded coarse source for the NO-KEY case (design §6.2, `keyless`): which * unblocked nodes to compare, and how far. `window` is the forward-neighbour count; * `sortFields` is the kind's similarity text fields, so the SORTED-NEIGHBOURHOOD sort * groups lexically-similar values adjacently (the same text the scorer reads). */ type KeylessConfig = Readonly<{ window: number; sortFields: readonly string[]; }>; export { type ApplyDurableMergePlanArgs, type BaseAmbiguity, type BaseNodeLookup, type BaseVersion, BaseVersionMismatchError, BranchError, type BranchId, type BranchOptions, type BranchProvenance, CANDIDATE_WRITE_SET_FORMAT_VERSION, type CandidateDiagnostic, type CandidateDiagnostics, type CandidateDiagnosticsOptions, type CandidateSource, CandidateSourceError, type CandidateWriteSet, CandidateWriteSetError, CandidateWriteSetSchema, type CandidateWriteSetTarget, CandidateWriteSetTargetSchema, type ComparisonCeilingPolicy, type ConflictingValue, DURABLE_OPERATION_SCAN_DEFAULT_LIMIT, DURABLE_OPERATION_SCAN_MAX_LIMIT, type DeleteModifyConflict, type DeleteModifyPolicy, type DroppedItem, type DurableBranch, type DurableBranchCoordinates, type DurableBranchDescriptor, type DurableBranchOperation, type DurableBranchOperationEvidence, type DurableBranchOperationRequest, type DurableBranchOrigin, DurableEvidenceUndeliveredError, type DurableOperationCapability, DurableOperationConflictError, DurableOperationError, DurableOperationEvidenceError, type DurableOperationOutcome, DurableOperationRequestError, type DurableOperationScan, type DurableOperationUnsupportedDimension, DurableOperationUnsupportedError, type DurableStoreDescriptor, type DurableWorkingCopyAccess, type DurableWorkingCopyStrategy, type Embedder, type EntityRef, type EntityResolution, type ForkHandle, type ForkedWorkingCopyOptions, type GraphBranch, IdentityAssertionWriteFacade, IdentityMergeConflictError, type IngestionBranch, IngestionImportTarget, type IngestionNodeCollections, InvalidMergeOptionsError, InvalidMergePlanError, type KeylessConfig, MERGE_ERROR_CODES, MERGE_OPTION_DEFAULTS, MERGE_PLAN_DIGEST_ALGORITHM, MERGE_PLAN_FORMAT_VERSION, MERGE_REVIEW_FORMAT_VERSION, type MakeBackend, type MatchEvidence, MatchEvidenceError, type MatchSource, type MatchStrategy, type MergeBranch, MergeConflictError, MergeConstraintConflictError, type MergeConstraintConflictErrorDetails, MergeError, type MergeIncrementalArgs, type MergeOptions, type MergePlanAnchors, type MergePlanApplied, type MergePlanApplyOptions, type MergePlanArtifact, type MergePlanArtifactV1, type MergePlanArtifactV1Input, type MergePlanBranchAnchor, type MergePlanCandidateDiagnostic, type MergePlanCanonicalMapping, MergePlanCapabilityError, type MergePlanDiagnostics, type MergePlanDigest, MergePlanDigestMismatchError, type MergePlanEdgeDelete, type MergePlanEdgeUpsert, type MergePlanEntityRef, type MergePlanEntityResolution, type MergePlanGuards, type MergePlanIdentityAssertion, type MergePlanMatchEvidence, type MergePlanMatchSource, type MergePlanNodeDelete, type MergePlanNodeUpsert, MergePlanOriginMismatchError, type MergePlanProposedSummary, type MergePlanProvenanceOptions, type MergePlanReadContext, type MergePlanRetype, type MergePlanReview, type MergePlanRevisionFence, type MergePlanSchemaFence, MergePlanSchemaMismatchError, type MergePlanSimilarityStrategy, type MergePlanTargetFence, MergePlanTargetMismatchError, type MergePlanTypeReconciliation, type MergePlanWrites, MergePlanningStaleError, type MergeReport, type MergeReviewArtifact, type MergeReviewBaseline, type MergeReviewDifference, MergeReviewError, type MergeReviewPolicy, type MergeReviewRevalidation, type MergeReviewRow, type MergedCounts, type NativeDurableMergeResult, type NativeDurableMergeUnsupportedDimension, type NormalizedMergeOptions, type PlanCandidateWriteSetArgs, type PlanCandidateWriteSetForEvolutionArgs, type PlanCandidateWriteSetReviewArgs, type PropertyConflict, type PropertyConflictPolicy, type ProvenanceGraph, type ProvenanceIndex, type ProvenanceNode, type ProvenanceQuery, type ProvenanceRecord, type ReconcileTypesMode, type ResolveConfig, type ResolveMap, type ResolvedCluster, Result, type RevalidateCandidateWriteSetReviewArgs, type SimilarityStrategy, SimilarityUnavailableError, type SourceScope, StaleMergePlanError, type TypeReconciliation, UnsupportedMergePlanVersionError, VALIDITY_END_TARGET_PRECEDENCE, type ValidityEndResolution, type WorkingCopyStrategy, applyDurableMergePlan, applyMergePlan, applyMergePlanInTransaction, asBaseVersion, asBranchId, branch, branchDurable, branchForEvolution, captureCandidateWriteSetTarget, captureCandidateWriteSetTargetForEvolution, cloneWorkingCopyStrategy, computeBaseVersion, computeDurableOperationDigest, destroyDurableBranch, durableBranchHasUndeliveredEvidence, forkedWorkingCopyStrategy, getDurableOperation, ingestionBranch, markDurableOperationDelivered, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, operateDurableBranch, persistProvenanceRecords, planCandidateWriteSet, planCandidateWriteSetForEvolution, planCandidateWriteSetReview, planMerge, planMergeForEvolution, planMergeIncremental, provenanceGraphId, readProvenance, reopenDurableBranch, revalidateCandidateWriteSetReview, scanDurableOperations };