@nicia-ai/typegraph 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/README.md +39 -0
  2. package/dist/backend/postgres/index.cjs +21 -20
  3. package/dist/backend/postgres/index.d.cts +6 -6
  4. package/dist/backend/postgres/index.d.ts +6 -6
  5. package/dist/backend/postgres/index.js +11 -10
  6. package/dist/backend/postgres/pglite.cjs +16 -15
  7. package/dist/backend/postgres/pglite.cjs.map +1 -1
  8. package/dist/backend/postgres/pglite.d.cts +3 -3
  9. package/dist/backend/postgres/pglite.d.ts +3 -3
  10. package/dist/backend/postgres/pglite.js +11 -10
  11. package/dist/backend/postgres/pglite.js.map +1 -1
  12. package/dist/backend/sqlite/index.cjs +18 -18
  13. package/dist/backend/sqlite/index.d.cts +12 -7
  14. package/dist/backend/sqlite/index.d.ts +12 -7
  15. package/dist/backend/sqlite/index.js +9 -9
  16. package/dist/backend/sqlite/libsql.cjs +14 -14
  17. package/dist/backend/sqlite/libsql.d.cts +3 -3
  18. package/dist/backend/sqlite/libsql.d.ts +3 -3
  19. package/dist/backend/sqlite/libsql.js +10 -10
  20. package/dist/backend/sqlite/local.cjs +17 -16
  21. package/dist/backend/sqlite/local.cjs.map +1 -1
  22. package/dist/backend/sqlite/local.d.cts +9 -3
  23. package/dist/backend/sqlite/local.d.ts +9 -3
  24. package/dist/backend/sqlite/local.js +12 -11
  25. package/dist/backend/sqlite/local.js.map +1 -1
  26. package/dist/{chunk-7KLVFWXR.js → chunk-2HZGWCB4.js} +121 -497
  27. package/dist/chunk-2HZGWCB4.js.map +1 -0
  28. package/dist/chunk-2YMGNYXY.js +40 -0
  29. package/dist/chunk-2YMGNYXY.js.map +1 -0
  30. package/dist/chunk-2ZY4K43M.js +90 -0
  31. package/dist/chunk-2ZY4K43M.js.map +1 -0
  32. package/dist/chunk-3EUKJEQ3.js +77 -0
  33. package/dist/chunk-3EUKJEQ3.js.map +1 -0
  34. package/dist/chunk-3JBJEYWE.cjs +604 -0
  35. package/dist/chunk-3JBJEYWE.cjs.map +1 -0
  36. package/dist/{chunk-A4H6QMV4.js → chunk-4A4GUZTQ.js} +15 -11
  37. package/dist/chunk-4A4GUZTQ.js.map +1 -0
  38. package/dist/{chunk-F2Q76CQ4.cjs → chunk-54JVNOAQ.cjs} +5 -37
  39. package/dist/chunk-54JVNOAQ.cjs.map +1 -0
  40. package/dist/{chunk-KGAJ5HFO.cjs → chunk-5CN7B4CZ.cjs} +17 -98
  41. package/dist/chunk-5CN7B4CZ.cjs.map +1 -0
  42. package/dist/{chunk-XTQHSOIC.cjs → chunk-5DTPBFX5.cjs} +88 -87
  43. package/dist/chunk-5DTPBFX5.cjs.map +1 -0
  44. package/dist/chunk-6G35I3VW.cjs +40 -0
  45. package/dist/chunk-6G35I3VW.cjs.map +1 -0
  46. package/dist/{chunk-UPBXUOW7.cjs → chunk-6RMLO5O4.cjs} +19 -64
  47. package/dist/chunk-6RMLO5O4.cjs.map +1 -0
  48. package/dist/chunk-6SA7UIQJ.cjs +94 -0
  49. package/dist/chunk-6SA7UIQJ.cjs.map +1 -0
  50. package/dist/chunk-6ZR4QC3O.cjs +12 -0
  51. package/dist/{chunk-Q3ZZLU3O.cjs.map → chunk-6ZR4QC3O.cjs.map} +1 -1
  52. package/dist/chunk-73KASJGO.cjs +52 -0
  53. package/dist/chunk-73KASJGO.cjs.map +1 -0
  54. package/dist/{chunk-R2LA6MKR.cjs → chunk-7JGLPAFV.cjs} +8 -8
  55. package/dist/{chunk-R2LA6MKR.cjs.map → chunk-7JGLPAFV.cjs.map} +1 -1
  56. package/dist/chunk-A3W7QG7K.js +45 -0
  57. package/dist/chunk-A3W7QG7K.js.map +1 -0
  58. package/dist/{chunk-Q5ASTPM4.cjs → chunk-ASYQDPPU.cjs} +19 -19
  59. package/dist/{chunk-Q5ASTPM4.cjs.map → chunk-ASYQDPPU.cjs.map} +1 -1
  60. package/dist/{chunk-IE2TPFBT.js → chunk-ATTXBMAX.js} +4 -74
  61. package/dist/chunk-ATTXBMAX.js.map +1 -0
  62. package/dist/chunk-AW4A3P5A.cjs +51 -0
  63. package/dist/chunk-AW4A3P5A.cjs.map +1 -0
  64. package/dist/{chunk-ZYQEXGYC.cjs → chunk-CIINW6PS.cjs} +92 -87
  65. package/dist/chunk-CIINW6PS.cjs.map +1 -0
  66. package/dist/{chunk-UP4QAJND.cjs → chunk-FLOI7QOT.cjs} +66 -65
  67. package/dist/chunk-FLOI7QOT.cjs.map +1 -0
  68. package/dist/{chunk-7V335GHG.cjs → chunk-FLRCVI2G.cjs} +12 -2
  69. package/dist/chunk-FLRCVI2G.cjs.map +1 -0
  70. package/dist/{chunk-HKN622O4.js → chunk-GKFWM3DS.js} +4 -32
  71. package/dist/chunk-GKFWM3DS.js.map +1 -0
  72. package/dist/chunk-HTGDWIDE.cjs +89 -0
  73. package/dist/chunk-HTGDWIDE.cjs.map +1 -0
  74. package/dist/{chunk-OGUH56BB.js → chunk-IJORSAC3.js} +6 -42
  75. package/dist/chunk-IJORSAC3.js.map +1 -0
  76. package/dist/{chunk-G6P3OVDY.cjs → chunk-JIEJCTDS.cjs} +18 -2
  77. package/dist/chunk-JIEJCTDS.cjs.map +1 -0
  78. package/dist/{chunk-NZ5PMBTG.js → chunk-K5P5OZXS.js} +12 -3
  79. package/dist/chunk-K5P5OZXS.js.map +1 -0
  80. package/dist/{chunk-HM6XMR3E.cjs → chunk-KTIEB7VH.cjs} +42 -32
  81. package/dist/chunk-KTIEB7VH.cjs.map +1 -0
  82. package/dist/chunk-LJLMDDCW.js +282 -0
  83. package/dist/chunk-LJLMDDCW.js.map +1 -0
  84. package/dist/{chunk-Z36W5WUM.js → chunk-MAQJYNJR.js} +3 -3
  85. package/dist/{chunk-Z36W5WUM.js.map → chunk-MAQJYNJR.js.map} +1 -1
  86. package/dist/{chunk-N3VVQDMA.js → chunk-MXE2U3EX.js} +3 -3
  87. package/dist/{chunk-N3VVQDMA.js.map → chunk-MXE2U3EX.js.map} +1 -1
  88. package/dist/{chunk-4K6IHUW6.cjs → chunk-N2MBPTAF.cjs} +14 -14
  89. package/dist/{chunk-4K6IHUW6.cjs.map → chunk-N2MBPTAF.cjs.map} +1 -1
  90. package/dist/{chunk-CUZGBWFT.js → chunk-O4VUR6SI.js} +3 -3
  91. package/dist/{chunk-CUZGBWFT.js.map → chunk-O4VUR6SI.js.map} +1 -1
  92. package/dist/chunk-RZ4DH4E7.cjs +15832 -0
  93. package/dist/chunk-RZ4DH4E7.cjs.map +1 -0
  94. package/dist/chunk-SAJSMR2B.js +35 -0
  95. package/dist/chunk-SAJSMR2B.js.map +1 -0
  96. package/dist/{chunk-RU5BBUU2.cjs → chunk-SFFJ2IKN.cjs} +71 -67
  97. package/dist/chunk-SFFJ2IKN.cjs.map +1 -0
  98. package/dist/{chunk-Y52UNT66.js → chunk-STP7QVUB.js} +8 -7
  99. package/dist/chunk-STP7QVUB.js.map +1 -0
  100. package/dist/chunk-THX25XW6.js +590 -0
  101. package/dist/chunk-THX25XW6.js.map +1 -0
  102. package/dist/{chunk-MB363HT5.js → chunk-TQOYM4LN.js} +18 -3
  103. package/dist/chunk-TQOYM4LN.js.map +1 -0
  104. package/dist/chunk-UIFEEPME.js +15787 -0
  105. package/dist/chunk-UIFEEPME.js.map +1 -0
  106. package/dist/{chunk-GPUNAJFH.js → chunk-UJ4V3YUQ.js} +3 -3
  107. package/dist/{chunk-GPUNAJFH.js.map → chunk-UJ4V3YUQ.js.map} +1 -1
  108. package/dist/{chunk-C2RWFIYP.cjs → chunk-V4IQYOQ4.cjs} +127 -511
  109. package/dist/chunk-V4IQYOQ4.cjs.map +1 -0
  110. package/dist/chunk-VMEWZU2N.cjs +287 -0
  111. package/dist/chunk-VMEWZU2N.cjs.map +1 -0
  112. package/dist/{chunk-3DTLDGIM.js → chunk-VZX2KSY3.js} +14 -9
  113. package/dist/chunk-VZX2KSY3.js.map +1 -0
  114. package/dist/{chunk-BMDF2S7S.js → chunk-WYTUF3QO.js} +3 -3
  115. package/dist/{chunk-BMDF2S7S.js.map → chunk-WYTUF3QO.js.map} +1 -1
  116. package/dist/{chunk-MRMD7S7E.js → chunk-XKJQQQVR.js} +9 -8
  117. package/dist/chunk-XKJQQQVR.js.map +1 -0
  118. package/dist/{chunk-SFNUHFON.js → chunk-YCV72E6L.js} +25 -19
  119. package/dist/chunk-YCV72E6L.js.map +1 -0
  120. package/dist/{chunk-VGU26WIU.cjs → chunk-YQGLVWB2.cjs} +4 -4
  121. package/dist/{chunk-VGU26WIU.cjs.map → chunk-YQGLVWB2.cjs.map} +1 -1
  122. package/dist/{ddl-BwH00BB6.d.ts → ddl-BJcPrB4L.d.ts} +3 -3
  123. package/dist/{ddl-D3o-RmsV.d.cts → ddl-CPZ7mB7X.d.cts} +3 -3
  124. package/dist/{extension-types-CwHV-Uk4.d.ts → extension-types-D1k0inWU.d.cts} +1 -1
  125. package/dist/{extension-types-CwHV-Uk4.d.cts → extension-types-D1k0inWU.d.ts} +1 -1
  126. package/dist/graph-extension/index.cjs +19 -19
  127. package/dist/graph-extension/index.d.cts +5 -16
  128. package/dist/graph-extension/index.d.ts +5 -16
  129. package/dist/graph-extension/index.js +4 -4
  130. package/dist/graph-merge/index.cjs +3822 -0
  131. package/dist/graph-merge/index.cjs.map +1 -0
  132. package/dist/graph-merge/index.d.cts +1191 -0
  133. package/dist/graph-merge/index.d.ts +1191 -0
  134. package/dist/graph-merge/index.js +3791 -0
  135. package/dist/graph-merge/index.js.map +1 -0
  136. package/dist/{index-CapHwi1a.d.ts → index-BEK0VtNB.d.ts} +11 -3
  137. package/dist/{index-jPPexxM5.d.cts → index-C8sSTErx.d.cts} +11 -3
  138. package/dist/index.cjs +365 -15732
  139. package/dist/index.cjs.map +1 -1
  140. package/dist/index.d.cts +12 -11
  141. package/dist/index.d.ts +12 -11
  142. package/dist/index.js +27 -15533
  143. package/dist/index.js.map +1 -1
  144. package/dist/indexes/index.cjs +32 -28
  145. package/dist/indexes/index.d.cts +5 -5
  146. package/dist/indexes/index.d.ts +5 -5
  147. package/dist/indexes/index.js +8 -4
  148. package/dist/interchange/index.cjs +50 -593
  149. package/dist/interchange/index.cjs.map +1 -1
  150. package/dist/interchange/index.d.cts +5 -5
  151. package/dist/interchange/index.d.ts +5 -5
  152. package/dist/interchange/index.js +3 -589
  153. package/dist/interchange/index.js.map +1 -1
  154. package/dist/{manager-BUugwCYz.d.ts → manager-By-WEd8M.d.ts} +3 -3
  155. package/dist/{manager-DpIpn1HQ.d.cts → manager-Np7VVSlE.d.cts} +3 -3
  156. package/dist/{materialize-indexes-lkawaDor.d.ts → materialize-indexes-CAGhqPHQ.d.ts} +1 -1
  157. package/dist/{materialize-indexes-oanE3RU0.d.cts → materialize-indexes-DEYkU-wr.d.cts} +1 -1
  158. package/dist/{postgres-CQL9UIn2.d.cts → postgres-4J2tmauh.d.cts} +1 -1
  159. package/dist/{postgres-CcRLaxz0.d.ts → postgres-BdIb7tS_.d.ts} +1 -1
  160. package/dist/profiler/index.cjs +9 -9
  161. package/dist/profiler/index.d.cts +7 -7
  162. package/dist/profiler/index.d.ts +7 -7
  163. package/dist/profiler/index.js +2 -2
  164. package/dist/result-DWo6mUVz.d.cts +37 -0
  165. package/dist/result-DWo6mUVz.d.ts +37 -0
  166. package/dist/schema/index.cjs +33 -32
  167. package/dist/schema/index.cjs.map +1 -1
  168. package/dist/schema/index.d.cts +7 -7
  169. package/dist/schema/index.d.ts +7 -7
  170. package/dist/schema/index.js +10 -9
  171. package/dist/schema/index.js.map +1 -1
  172. package/dist/{sqlite-Rj3xu4It.d.cts → sqlite-Gatk_iw_.d.cts} +1 -1
  173. package/dist/{sqlite-CZDFUfHS.d.ts → sqlite-aM_PAz-O.d.ts} +1 -1
  174. package/dist/{store-B43FpOVX.d.cts → store-DuCbdqsh.d.cts} +84 -44
  175. package/dist/{store-De0Y33wP.d.ts → store-MloRPwb9.d.ts} +84 -44
  176. package/dist/{types-DXCSyxac.d.cts → types-BKQljXom.d.ts} +18 -2
  177. package/dist/{types-CmAT-Z47.d.ts → types-C1CYxWrL.d.cts} +18 -2
  178. package/dist/{types-Bwlp_yvu.d.cts → types-DoByHGyU.d.cts} +2 -2
  179. package/dist/{types-B5GSeE3t.d.ts → types-K3vpaJAL.d.ts} +2 -2
  180. package/dist/{where-CP4qGIHd.d.ts → where-Dt49bvo6.d.ts} +2 -2
  181. package/dist/{where-2dsyYt3d.d.cts → where-DydZjGOb.d.cts} +2 -2
  182. package/package.json +6 -1
  183. package/dist/chunk-3DTLDGIM.js.map +0 -1
  184. package/dist/chunk-7KLVFWXR.js.map +0 -1
  185. package/dist/chunk-7V335GHG.cjs.map +0 -1
  186. package/dist/chunk-A4H6QMV4.js.map +0 -1
  187. package/dist/chunk-C2RWFIYP.cjs.map +0 -1
  188. package/dist/chunk-F2Q76CQ4.cjs.map +0 -1
  189. package/dist/chunk-G6P3OVDY.cjs.map +0 -1
  190. package/dist/chunk-HKN622O4.js.map +0 -1
  191. package/dist/chunk-HM6XMR3E.cjs.map +0 -1
  192. package/dist/chunk-IE2TPFBT.js.map +0 -1
  193. package/dist/chunk-KGAJ5HFO.cjs.map +0 -1
  194. package/dist/chunk-MB363HT5.js.map +0 -1
  195. package/dist/chunk-MRMD7S7E.js.map +0 -1
  196. package/dist/chunk-NZ5PMBTG.js.map +0 -1
  197. package/dist/chunk-OGUH56BB.js.map +0 -1
  198. package/dist/chunk-Q3ZZLU3O.cjs +0 -12
  199. package/dist/chunk-RU5BBUU2.cjs.map +0 -1
  200. package/dist/chunk-SFNUHFON.js.map +0 -1
  201. package/dist/chunk-UP4QAJND.cjs.map +0 -1
  202. package/dist/chunk-UPBXUOW7.cjs.map +0 -1
  203. package/dist/chunk-XTQHSOIC.cjs.map +0 -1
  204. package/dist/chunk-Y52UNT66.js.map +0 -1
  205. package/dist/chunk-ZYQEXGYC.cjs.map +0 -1
@@ -0,0 +1,1191 @@
1
+ import { G as GraphDef, t as NodeKinds, u as GetNodeType } from '../manager-Np7VVSlE.cjs';
2
+ import { S as Store, N as Node, U as UniqueIntrospection } from '../store-DuCbdqsh.cjs';
3
+ import { d as NodeId, N as NodeType, e as EdgeId, J as JsonValue, f as KindAnnotations, g as EdgeType, D as DeleteBehavior, T as TemporalMode, h as GraphExtensionVersion, i as ExtensionNodeDef, j as ExtensionEdgeDef, k as ExtensionOntologyRelation, l as ExtensionIndex } from '../extension-types-D1k0inWU.cjs';
4
+ import { T as TypeGraphError } from '../index-C8sSTErx.cjs';
5
+ import { R as Result } from '../result-DWo6mUVz.cjs';
6
+ export { i as isErr, a as isOk, u as unwrap } from '../result-DWo6mUVz.cjs';
7
+ import { G as GraphBackend, M as MetaEdge, I as IndexDeclaration } from '../types-C1CYxWrL.cjs';
8
+ import { z } from 'zod';
9
+ import 'drizzle-orm';
10
+ import '../materialize-indexes-DEYkU-wr.cjs';
11
+ import 'drizzle-orm/pg-core';
12
+ import 'drizzle-orm/sqlite-core';
13
+
14
+ /**
15
+ * Core type model for the graph-merge primitive.
16
+ *
17
+ * Finalized against TypeGraph's real generic machinery: the design's illustrative
18
+ * `Node<G, K>` / `NodeId<NodeKinds<G>>` collapse onto TypeGraph's public
19
+ * `Node` / `Edge` / `NodeId<NodeType>` / `EdgeId` (which are themselves branded
20
+ * over `NodeType` / `EdgeType`). The merge surface is parameterized over
21
+ * `G extends GraphDef` so `Store<G>` and `GraphBranch<G>` thread the caller's
22
+ * concrete graph definition end-to-end.
23
+ *
24
+ * This module is pure type declarations plus the two branding helpers — no
25
+ * runtime merge logic.
26
+ */
27
+
28
+ /**
29
+ * Opaque identifier for a branch (working copy) of a base store. Branded so a
30
+ * raw string cannot be passed where a deliberately-minted branch id is required.
31
+ */
32
+ type BranchId = string & Readonly<{
33
+ readonly __brand: "BranchId";
34
+ }>;
35
+ /**
36
+ * Opaque token identifying the immutable `base@V` a branch was forked from.
37
+ * Combines a schema hash with a content fingerprint (computed in T3). Branded so
38
+ * it cannot be confused with an arbitrary string.
39
+ */
40
+ type BaseVersion = string & Readonly<{
41
+ readonly __brand: "BaseVersion";
42
+ }>;
43
+ /**
44
+ * Mints a {@link BranchId} from a raw string. Centralizes the brand cast so the
45
+ * unsafe assertion lives in exactly one place.
46
+ */
47
+ declare function asBranchId(value: string): BranchId;
48
+ /**
49
+ * Mints a {@link BaseVersion} from a raw string. Centralizes the brand cast so
50
+ * the unsafe assertion lives in exactly one place.
51
+ */
52
+ declare function asBaseVersion(value: string): BaseVersion;
53
+ /**
54
+ * A working-copy handle for one branch: its id, the `base@V` it forked from, and
55
+ * a {@link Store} over the branch's own backend.
56
+ */
57
+ type GraphBranch<G extends GraphDef> = Readonly<{
58
+ id: BranchId;
59
+ base: BaseVersion;
60
+ store: Store<G>;
61
+ }>;
62
+ /**
63
+ * Options for {@link GraphBranch} creation. `id` is optional — when omitted a
64
+ * fresh id is generated.
65
+ */
66
+ type BranchOptions = Readonly<{
67
+ id?: BranchId;
68
+ }>;
69
+ /**
70
+ * Turns text into an embedding vector. Injected via {@link MergeOptions.embedder}
71
+ * and used by the `vector` / `hybrid` similarity strategies to score candidate
72
+ * pairs by cosine IN MEMORY — the staged candidate nodes are unindexed in the
73
+ * working copy, so a backend ANN index cannot score them pairwise (see
74
+ * `scorePair`). Exact in-memory cosine over real model vectors is both the right
75
+ * scale for bounded candidate dedup and deterministic, which the merge contract
76
+ * requires.
77
+ *
78
+ * Batched and async: given N texts it returns N vectors in the SAME order, each a
79
+ * fixed-dimension `Float32Array` (every vector a given embedder returns shares one
80
+ * length — the model's embedding dimension). The function MUST be deterministic —
81
+ * the same text always yields the same vector — because the whole merge is
82
+ * order-independent and reproducible. Vectors need NOT be pre-normalized; cosine
83
+ * scoring normalizes internally.
84
+ *
85
+ * The concrete local model lives in the CONSUMER (the harness ships an
86
+ * all-MiniLM-L6-v2 embedder); this package depends only on the function shape, so
87
+ * it stays model-agnostic and lean inside the TypeGraph core package.
88
+ */
89
+ type Embedder = (texts: readonly string[]) => Promise<readonly Float32Array[]>;
90
+ /**
91
+ * Pluggable per-kind similarity strategy (design §8).
92
+ *
93
+ * - `vector` / `hybrid` score candidate pairs by cosine over an injected
94
+ * {@link Embedder} ({@link MergeOptions.embedder}), computed in memory; they
95
+ * fail with `SimilarityUnavailableError` when no embedder is configured.
96
+ * - `fulltext` and `custom` run with ZERO embeddings — the cross-DB-safe
97
+ * default. `fulltext` uses an in-memory Sørensen–Dice trigram scorer (T6).
98
+ *
99
+ * The generic mirrors the design's `SimilarityStrategy<G, K>`: `K` constrains the
100
+ * `custom` score function's node arguments to the resolved kind.
101
+ */
102
+ type SimilarityStrategy<G extends GraphDef = GraphDef, K extends NodeType = NodeType> = Readonly<{
103
+ kind: "hybrid";
104
+ fields: readonly string[];
105
+ weights?: Readonly<{
106
+ vector?: number;
107
+ fulltext?: number;
108
+ }>;
109
+ readonly __graph?: G;
110
+ }> | Readonly<{
111
+ kind: "vector";
112
+ field: string;
113
+ readonly __graph?: G;
114
+ }> | Readonly<{
115
+ kind: "fulltext";
116
+ fields: readonly string[];
117
+ readonly __graph?: G;
118
+ }> | Readonly<{
119
+ kind: "custom";
120
+ score: (a: Node<K>, b: Node<K>) => number;
121
+ readonly __graph?: G;
122
+ }>;
123
+ /**
124
+ * Per-kind entity-resolution configuration.
125
+ */
126
+ type ResolveConfig<G extends GraphDef = GraphDef, K extends NodeType = NodeType> = Readonly<{
127
+ /**
128
+ * Cheap exact-equality blocking key, evaluated before similarity to bound the
129
+ * O(n²) candidate comparisons. Returning `undefined` places the node in the
130
+ * shared `"unblocked"` bucket (compared all-vs-all within its kind).
131
+ *
132
+ * STAGED-vs-staged only: it is an arbitrary JS function, so it cannot be queried
133
+ * against the committed base. To recall committed entities by a block key
134
+ * (new-vs-base, the `baseKey` source §6.2), declare the key as a TypeGraph node
135
+ * index and name it via {@link ResolveConfig.blockIndex} instead.
136
+ */
137
+ block?: (node: Node<K>) => string | undefined;
138
+ /**
139
+ * Name of a declared TypeGraph node index (`defineNodeIndex`) whose key is this
140
+ * kind's NEW-vs-BASE block key (design §6.2). When set and the new-vs-base scope is
141
+ * driven, the `baseKey` source issues an indexed `bulkFindByIndex` lookup of
142
+ * committed nodes sharing each staged node's index key and proposes them as scored
143
+ * candidate pairs (a shared block key is a candidate, not a definitional match).
144
+ *
145
+ * The index keys on real fields (a field-set + scope + optional partial-`where`), so
146
+ * only a FIELD-SET block key migrates here; a transform key (`slice`/`soundex`/…)
147
+ * stays on the staged-only {@link block}. Unused on the public snapshot `merge()`
148
+ * path. An undeclared name surfaces a typed error at lookup time.
149
+ */
150
+ blockIndex?: string;
151
+ /**
152
+ * Bounded coarse candidate generation for the NO-KEY case (design §6.2, the
153
+ * `keyless` source). A node whose {@link block} returns `undefined` (and has no
154
+ * unique signature) lands in the shared `"unblocked"` bucket, which is otherwise
155
+ * compared ALL-vs-all — an O(n²) cliff that `maxComparisonsPerKind` then truncates
156
+ * to id-only. Set `keyless` to bound that bucket by single-pass SORTED-NEIGHBOURHOOD
157
+ * instead: the unblocked nodes are sorted by their similarity-field text (tie-broken
158
+ * by id) and each is proposed only against its next `window` neighbours — O(n·window),
159
+ * deterministic. Unset preserves today's all-vs-all behaviour. Only the `"unblocked"`
160
+ * bucket is affected; keyed `block()` buckets are unchanged.
161
+ */
162
+ keyless?: Readonly<{
163
+ /** Forward-neighbour window: each unblocked node is paired with its next `window`
164
+ * neighbours in the sort. Must be a positive integer. Larger → more recall, more
165
+ * comparisons (→ all-vs-all as `window` ≥ bucket size). */
166
+ window: number;
167
+ }>;
168
+ /** Similarity strategy (design §8). */
169
+ similarity: SimilarityStrategy<G, K>;
170
+ /** Candidate-merge threshold in `[0, 1]`. */
171
+ threshold: number;
172
+ }>;
173
+ /**
174
+ * A resolved cluster of node ids that the merge collapses into one canonical
175
+ * survivor.
176
+ */
177
+ type ResolvedCluster = Readonly<{
178
+ members: readonly NodeId<NodeType>[];
179
+ }>;
180
+ /**
181
+ * Policy for resolving conflicting property values across cluster members.
182
+ *
183
+ * - `"flag"` keeps the canonical's value and records a {@link PropertyConflict}
184
+ * without auto-resolving.
185
+ * - `"lastWriteWins"` picks by the stable branch/logical total order — NEVER
186
+ * wall-clock arrival.
187
+ * - `"provenanceWeighted"` picks by per-branch trust weight.
188
+ * - A function delegates the decision, returning the surviving {@link JsonValue}.
189
+ */
190
+ type PropertyConflictPolicy<G extends GraphDef = GraphDef> = "flag" | "lastWriteWins" | "provenanceWeighted" | ((conflict: PropertyConflict<G>) => JsonValue);
191
+ /**
192
+ * Policy for resolving an inherited node that is deleted by one branch and
193
+ * modified by another (design §6.2).
194
+ *
195
+ * - `"deleteWins"` — the node is finally DELETED; the modification is discarded.
196
+ * - `"modifyWins"` — the node is RESURRECTED; the modification survives.
197
+ * - `"flag"` (default) — the **modification SURVIVES in the merged output** (as
198
+ * with `"modifyWins"`) AND an **unresolved {@link DeleteModifyConflict} is
199
+ * recorded** in `report.deleteModifyConflicts` for human review. `"flag"` is
200
+ * therefore NOT neutral — it keeps data and surfaces the disagreement, on the
201
+ * posture that a merge must never silently destroy the only branch still
202
+ * carrying data. Choose `"deleteWins"` to honor the delete by default instead.
203
+ */
204
+ type DeleteModifyPolicy = "deleteWins" | "modifyWins" | "flag";
205
+ /**
206
+ * Behavior when `maxComparisonsPerKind` is exceeded for a kind.
207
+ *
208
+ * - `"error"` fails the merge with a typed error (default).
209
+ * - `"mergeByIdOnly"` skips similarity for that kind, emits no candidate edges,
210
+ * and records a report warning.
211
+ */
212
+ type ComparisonCeilingPolicy = "error" | "mergeByIdOnly";
213
+ /**
214
+ * Ontology type-reconciliation mode. `"off"` is a no-op (default); `"ontology"`
215
+ * collapses compatible types to the most-specific via the public subClassOf
216
+ * closure (T2a / T10).
217
+ */
218
+ type ReconcileTypesMode = "ontology" | "off";
219
+ /**
220
+ * Map of node kind name → its {@link ResolveConfig}. Keys are constrained to the
221
+ * graph's node kinds (`keyof G["nodes"]`), so a typo or a kind that does not
222
+ * belong to the graph is a COMPILE error rather than a silently-ignored config
223
+ * (which would let those nodes merge by id only without warning). Each kind's
224
+ * config is bound to that kind's concrete `NodeType`, so `block(node)` and the
225
+ * `custom` scorer see the right node shape. All keys are optional: kinds omitted
226
+ * from this map merge by ID only (new fork nodes added as-is, no fuzzy
227
+ * resolution). For the default unparameterized `GraphDef` the keys widen back to
228
+ * `string`.
229
+ */
230
+ type ResolveMap<G extends GraphDef = GraphDef> = Readonly<Partial<{
231
+ [K in NodeKinds<G>]: ResolveConfig<G, GetNodeType<G, K>>;
232
+ }>>;
233
+ /**
234
+ * Caller-facing options for {@link merge}. All fields are optional with frozen
235
+ * defaults applied by `normalizeMergeOptions` (see `options.ts`).
236
+ */
237
+ type MergeOptions<G extends GraphDef = GraphDef> = Readonly<{
238
+ /** Per-kind entity resolution. Omitted kinds merge by ID only. */
239
+ resolve?: ResolveMap<G>;
240
+ /** Reconcile differing types across forks. Default `"off"`. */
241
+ reconcileTypes?: ReconcileTypesMode;
242
+ /** Property-conflict policy for staged-vs-staged disagreements. Default `"flag"`. */
243
+ onPropertyConflict?: PropertyConflictPolicy<G>;
244
+ /**
245
+ * Property-conflict policy for BASE↔branch disagreements in a new-vs-base merge
246
+ * (§6.4-C). DISTINCT from {@link onPropertyConflict} and DOES NOT inherit it:
247
+ * `onPropertyConflict` can be `"lastWriteWins"` / `"provenanceWeighted"` / a
248
+ * function, any of which would let a fuzzy branch match silently OVERWRITE
249
+ * committed data. Default `"flag"` keeps the committed base value (and records the
250
+ * conflict). Mirrors how `onDeleteModifyConflict` is kept separate. Only consulted
251
+ * when a cluster contains a base member; the staged path never uses it.
252
+ */
253
+ onBasePropertyConflict?: PropertyConflictPolicy<G>;
254
+ /** Delete/modify-conflict policy. Default `"flag"`. */
255
+ onDeleteModifyConflict?: DeleteModifyPolicy;
256
+ /** Comparison-ceiling behavior. Default `"error"`. */
257
+ onComparisonCeiling?: ComparisonCeilingPolicy;
258
+ /**
259
+ * Deterministic survivor selection within a cluster. Default: the member with
260
+ * the lexicographically-minimal node id.
261
+ */
262
+ canonical?: (cluster: ResolvedCluster) => NodeId<NodeType>;
263
+ /** Populate the report-only provenance index. Default `true`. */
264
+ provenance?: boolean;
265
+ /**
266
+ * Persist provenance ON-GRAPH: after the commit, upsert one `{branch, sourceId}`
267
+ * row per contribution into a sidecar provenance graph on the target's backend
268
+ * (queryable via `openProvenanceStore` / `readProvenance`). Default `false`
269
+ * (report-only). Best-effort and post-commit — a persistence failure surfaces as
270
+ * a {@link MergeReport.warnings} entry, never a failed merge.
271
+ */
272
+ persistProvenance?: boolean;
273
+ /**
274
+ * Local embedder for `vector` / `hybrid` similarity (in-memory cosine over the
275
+ * staged candidate pairs). Required ONLY when a kind's resolve strategy is
276
+ * `vector` or `hybrid`; `fulltext` / `custom` ignore it. A vector/hybrid
277
+ * strategy with no embedder configured fails with a typed
278
+ * {@link import("./errors").SimilarityUnavailableError}.
279
+ */
280
+ embedder?: Embedder;
281
+ /** Merge receiver. Default: the base `store`, written transactionally. */
282
+ target?: Store<G>;
283
+ /** Safety ceiling on candidate comparisons per kind. Default: unbounded. */
284
+ maxComparisonsPerKind?: number;
285
+ /**
286
+ * Optional single-link diameter guard. When set, clusters whose pairwise
287
+ * distance exceeds it are split by the deterministic drop-weakest rule (T8).
288
+ */
289
+ clusterMaxDiameter?: number;
290
+ /**
291
+ * Explicit stable branch order used by `lastWriteWins` / tie-breaking. When
292
+ * omitted, branch ids sorted lexicographically are used. NEVER wall-clock.
293
+ */
294
+ branchOrder?: readonly BranchId[];
295
+ /**
296
+ * Per-branch trust weights consulted ONLY by the `"provenanceWeighted"`
297
+ * property-conflict policy ({@link onPropertyConflict} /
298
+ * {@link onBasePropertyConflict}): when branches disagree on a property value,
299
+ * the value contributed by the highest-weight branch wins. Ties fall back to
300
+ * {@link branchOrder} (then canonical value order); branches absent from the map
301
+ * default to weight `0`. Ignored by every other policy. Keyed by
302
+ * {@link BranchId}, like {@link branchOrder}. Without this map,
303
+ * `"provenanceWeighted"` has no weights to consult and degrades to
304
+ * `"lastWriteWins"` semantics.
305
+ */
306
+ provenanceWeights?: ReadonlyMap<BranchId, number>;
307
+ }>;
308
+ /**
309
+ * Object-form arguments for {@link mergeIncremental} (§6.6). The two same-typed
310
+ * stores are NAMED so `forkPoint` (the frozen ancestor the branches forked from, the
311
+ * diff reference) and `target` (the live committed graph that base lookups and the
312
+ * commit land on) cannot be swapped. `options.target` is ignored — `target` is the
313
+ * explicit arg.
314
+ */
315
+ type MergeIncrementalArgs<G extends GraphDef = GraphDef> = Readonly<{
316
+ forkPoint: Store<G>;
317
+ target: Store<G>;
318
+ branches: readonly GraphBranch<G>[];
319
+ options?: MergeOptions<G>;
320
+ }>;
321
+ /**
322
+ * Records that a set of fork node ids resolved to a single canonical survivor.
323
+ */
324
+ type EntityResolution = Readonly<{
325
+ canonicalId: NodeId<NodeType>;
326
+ memberIds: readonly NodeId<NodeType>[];
327
+ kind: string;
328
+ branchOrigins: readonly BranchId[];
329
+ }>;
330
+ /**
331
+ * One candidate value contributing to a property conflict, tagged by its origin
332
+ * branch.
333
+ */
334
+ type ConflictingValue = Readonly<{
335
+ branchId: BranchId;
336
+ value: JsonValue;
337
+ }>;
338
+ /**
339
+ * A property whose value differed across cluster members (or across the two
340
+ * collapsed edges for an edge conflict). `resolution` records the value the
341
+ * policy selected.
342
+ */
343
+ type PropertyConflict<G extends GraphDef = GraphDef> = Readonly<{
344
+ entityId: NodeId<NodeType> | EdgeId;
345
+ kind: string;
346
+ property: string;
347
+ values: readonly ConflictingValue[];
348
+ resolution: JsonValue;
349
+ readonly __graph?: G;
350
+ }>;
351
+ /**
352
+ * An inherited node OR edge deleted by one branch and modified by another, with
353
+ * the resolution the {@link DeleteModifyPolicy} produced. `entityId` is a
354
+ * {@link NodeId} for a node conflict and an {@link EdgeId} for an edge conflict.
355
+ */
356
+ type DeleteModifyConflict = Readonly<{
357
+ entityId: NodeId<NodeType> | EdgeId;
358
+ kind: string;
359
+ deletedBy: BranchId;
360
+ modifiedBy: BranchId;
361
+ resolution: DeleteModifyPolicy;
362
+ }>;
363
+ /**
364
+ * Records that a cluster's mixed member kinds were collapsed to a single
365
+ * canonical (most-specific) type via ontology reconciliation.
366
+ */
367
+ type TypeReconciliation = Readonly<{
368
+ entityId: NodeId<NodeType>;
369
+ fromTypes: readonly string[];
370
+ toType: string;
371
+ }>;
372
+ /**
373
+ * An item omitted from the merged result (e.g. an edge whose endpoint was
374
+ * deleted, or an incompatible-typed cluster member).
375
+ */
376
+ type DroppedItem = Readonly<{
377
+ kind: "edge" | "node";
378
+ id: NodeId<NodeType> | EdgeId;
379
+ reason: string;
380
+ }>;
381
+ /**
382
+ * A `(kind, id)` node identity as surfaced in the merge report. Node identity is the
383
+ * PAIR, never the bare id (a `Doctor` and a `SpecialistDoctor` can share an id string),
384
+ * so report shapes that name nodes carry both halves.
385
+ */
386
+ type ReportNodeIdentity = Readonly<{
387
+ kind: string;
388
+ id: NodeId<NodeType>;
389
+ }>;
390
+ /**
391
+ * An AMBIGUOUS new-vs-base match (design §6.4-A): a connected component that
392
+ * bridged ≥2 distinct committed base entities (directly, `baseA ~ new ~ baseB`, or
393
+ * through staged hops, `baseA ~ new1 ~ new2 ~ baseB`). `baseIds` are the committed
394
+ * entities the component spanned; `memberIds` are all of its members. Both are full
395
+ * `(kind, id)` identities — the guard keys on the composite identity, so a component
396
+ * spanning two SAME-id/different-kind bases stays distinguishable in the report. The
397
+ * base↔base collapse is ALWAYS REFUSED — the component is split so the committed
398
+ * entities stay separate. Reported regardless of how the component split. (A
399
+ * deliberate-collapse trust path is deferred until committed-entity re-keying + edge
400
+ * repoint exist; §6.4-C.)
401
+ */
402
+ type BaseAmbiguity = Readonly<{
403
+ baseIds: readonly ReportNodeIdentity[];
404
+ memberIds: readonly ReportNodeIdentity[];
405
+ }>;
406
+ /**
407
+ * The contribution one branch made to the merged result. Returned by
408
+ * {@link ProvenanceIndex.byBranch}. EXPLICITLY in-memory / report-only for P0 —
409
+ * no on-graph prop tagging (deferred to the AgentFS phase).
410
+ */
411
+ type BranchProvenance = Readonly<{
412
+ nodeIds: readonly NodeId<NodeType>[];
413
+ edgeIds: readonly EdgeId[];
414
+ }>;
415
+ /**
416
+ * Report-only, in-memory provenance index. `byBranch` answers "which
417
+ * nodes/edges did this branch contribute to the merged result?".
418
+ */
419
+ type ProvenanceIndex = Readonly<{
420
+ byBranch: (branchId: BranchId) => BranchProvenance;
421
+ }>;
422
+ /**
423
+ * One `{branch, sourceId}` → canonical contribution — the unit of provenance.
424
+ *
425
+ * The in-memory {@link ProvenanceIndex} collapses these to `branch → {canonical
426
+ * ids}`; the full record (which keeps the contributing `sourceId` and kind) is what
427
+ * `persistProvenance` writes to the sidecar provenance graph. `sourceId` is the
428
+ * fork-local id the contribution had in its branch BEFORE the merge collapsed it to
429
+ * `canonicalId` (equal to `canonicalId` for an in-place modification).
430
+ */
431
+ type ProvenanceRecord = Readonly<{
432
+ role: "node" | "edge";
433
+ canonicalId: string;
434
+ canonicalKind: string;
435
+ branchId: BranchId;
436
+ sourceId: string;
437
+ }>;
438
+ /**
439
+ * The full result of a {@link merge}: counts, every resolution/conflict/
440
+ * reconciliation/drop, and the report-only provenance index.
441
+ */
442
+ type MergeReport<G extends GraphDef = GraphDef> = Readonly<{
443
+ merged: Readonly<{
444
+ nodes: number;
445
+ edges: number;
446
+ }>;
447
+ resolutions: readonly EntityResolution[];
448
+ conflicts: readonly PropertyConflict<G>[];
449
+ deleteModifyConflicts: readonly DeleteModifyConflict[];
450
+ typeReconciliations: readonly TypeReconciliation[];
451
+ dropped: readonly DroppedItem[];
452
+ /**
453
+ * Ambiguous new-vs-base matches (§6.4-A): components that bridged ≥2 committed
454
+ * base entities. Empty on the staged-vs-staged snapshot path.
455
+ */
456
+ baseAmbiguities: readonly BaseAmbiguity[];
457
+ provenance: ProvenanceIndex;
458
+ /**
459
+ * Non-fatal advisories from the merge — comparison-ceiling skips and, when
460
+ * `persistProvenance` is set, a best-effort provenance-persistence failure (the
461
+ * graph still committed). Empty on a clean merge.
462
+ */
463
+ warnings: readonly string[];
464
+ /**
465
+ * Present only when `persistProvenance` ran and SUCCEEDED: the sidecar provenance
466
+ * graph id and how many `{branch, sourceId}` rows were upserted. Absent when
467
+ * persistence was off or failed (a failure adds a {@link MergeReport.warnings}).
468
+ */
469
+ provenancePersisted?: Readonly<{
470
+ graphId: string;
471
+ count: number;
472
+ }>;
473
+ }>;
474
+
475
+ /**
476
+ * `base@V` stamping.
477
+ *
478
+ * A {@link BaseVersion} is the immutable token a branch is forked from. It must
479
+ * change whenever either the schema OR the live content of the base store
480
+ * changes, so that `merge()`'s precondition check (T11) can reject a branch that
481
+ * forked from a divergent base.
482
+ *
483
+ * The token is two stable components joined by a separator:
484
+ *
485
+ * 1. A **schema hash** — `computeSchemaHash(serializeSchema(graph, version))`.
486
+ * This is content-addressed (the public `computeSchemaHash` deliberately
487
+ * excludes the version number and `generatedAt`, so it is stable across
488
+ * re-saves of the same schema).
489
+ * 2. A **content fingerprint** — a SHA-256 digest (truncated to a fixed-width
490
+ * hex string) of every LIVE node and edge over the base store (`id`,
491
+ * `updated_at`, the bitemporal `valid_from`/`valid_to`, and canonicalized
492
+ * `props`; edges also carry their endpoint ids), sorted by id, so two stores
493
+ * with identical live content fingerprint identically regardless of row
494
+ * enumeration order or insertion order. Props AND validity are folded in so
495
+ * the token changes on a content or validity edit even when `updated_at` ties
496
+ * at millisecond granularity. Hashing keeps the token fixed-width instead of
497
+ * growing linearly with store size.
498
+ *
499
+ * The token MUST be computed off the ORIGINAL base store, never off a clone:
500
+ * `exportGraph`/`importGraph` regenerate `created_at`/`updated_at`, so a clone's
501
+ * fingerprint would not match its source. (See the working-copy fidelity note in
502
+ * T4.)
503
+ *
504
+ * `computeBaseVersion` is async because schema hashing and live-content
505
+ * enumeration go through async TypeGraph internals. The design's synchronous
506
+ * illustrative signature does not survive contact with the real store surface.
507
+ */
508
+
509
+ /**
510
+ * Computes the immutable `base@V` token for a store. Combines the schema hash
511
+ * with a live-content fingerprint into a single branded {@link BaseVersion}.
512
+ *
513
+ * MUST be called on the ORIGINAL base store, not a clone (clones regenerate
514
+ * timestamps and would fingerprint differently).
515
+ */
516
+ declare function computeBaseVersion<G extends GraphDef>(store: Store<G>): Promise<BaseVersion>;
517
+
518
+ /**
519
+ * Error hierarchy for the graph-merge primitive.
520
+ *
521
+ * Every error extends the publicly-exported {@link TypeGraphError}, so consumers
522
+ * can use the same `isTypeGraphError`/category machinery they already use for
523
+ * TypeGraph itself. Each subclass carries a stable machine-readable `code`, a
524
+ * fixed `ErrorCategory`, and a cause chain for debugging.
525
+ */
526
+ /**
527
+ * Machine-readable error codes for the merge primitive. Stable identifiers so
528
+ * callers can branch on `error.code` without string-matching messages.
529
+ */
530
+ declare const MERGE_ERROR_CODES: {
531
+ readonly merge: "GRAPH_MERGE_ERROR";
532
+ readonly branch: "GRAPH_MERGE_BRANCH_ERROR";
533
+ readonly similarityUnavailable: "GRAPH_MERGE_SIMILARITY_UNAVAILABLE";
534
+ readonly conflict: "GRAPH_MERGE_CONFLICT";
535
+ readonly baseVersionMismatch: "GRAPH_MERGE_BASE_VERSION_MISMATCH";
536
+ };
537
+ /**
538
+ * Options shared by every merge error. Mirrors the relevant subset of
539
+ * TypeGraphError's options while making `cause`/`details`/`suggestion`
540
+ * uniformly optional at the merge-error boundary.
541
+ */
542
+ type MergeErrorOptions = Readonly<{
543
+ details?: Record<string, unknown>;
544
+ suggestion?: string;
545
+ cause?: unknown;
546
+ }>;
547
+ /**
548
+ * Generic failure raised while computing or committing a merge. The catch-all
549
+ * for the orchestrator (comparison-ceiling overruns, commit failures, etc.).
550
+ */
551
+ declare class MergeError extends TypeGraphError {
552
+ constructor(message: string, options?: MergeErrorOptions);
553
+ }
554
+ /**
555
+ * Failure raised while creating a working-copy branch of a base store
556
+ * (clone/export/import failures, backend construction failures).
557
+ */
558
+ declare class BranchError extends TypeGraphError {
559
+ constructor(message: string, options?: MergeErrorOptions);
560
+ }
561
+ /**
562
+ * Raised when a `vector`/`hybrid` similarity strategy is requested but no
563
+ * {@link import("./types").Embedder} was configured (`MergeOptions.embedder` is
564
+ * absent). The `vector`/`hybrid` scorers compute cosine over real embeddings in
565
+ * memory, so an embedder is mandatory for them; `fulltext`/`custom` need none.
566
+ */
567
+ declare class SimilarityUnavailableError extends MergeError {
568
+ readonly code: "GRAPH_MERGE_SIMILARITY_UNAVAILABLE";
569
+ constructor(message: string, options?: MergeErrorOptions);
570
+ }
571
+ /**
572
+ * Raised when a conflict cannot be resolved by the configured policy and the
573
+ * caller has opted into hard-failing rather than flagging.
574
+ */
575
+ declare class MergeConflictError extends MergeError {
576
+ readonly code: "GRAPH_MERGE_CONFLICT";
577
+ constructor(message: string, options?: MergeErrorOptions);
578
+ }
579
+ /**
580
+ * Raised by the `merge()` precondition check when a branch's `base@V` token
581
+ * does not match the merge target's current base version (the branch forked
582
+ * from a divergent schema or content fingerprint).
583
+ */
584
+ declare class BaseVersionMismatchError extends MergeError {
585
+ readonly code: "GRAPH_MERGE_BASE_VERSION_MISMATCH";
586
+ constructor(message: string, options?: MergeErrorOptions);
587
+ }
588
+
589
+ /**
590
+ * Pluggable working-copy strategy: how `branch()` produces an isolated,
591
+ * independently-mutable copy of a base store.
592
+ *
593
+ * The P0 default is a faithful CLONE via the public interchange API
594
+ * ({@link cloneWorkingCopyStrategy}): `exportGraph` the base, then `importGraph`
595
+ * into a fresh store on a caller-provided backend. IDs are preserved by
596
+ * interchange, so the diff engine (T3) can key on stable ids across base and
597
+ * fork. This leverages public entrypoints only, needs zero schema changes, and
598
+ * behaves identically across SQLite and Postgres.
599
+ *
600
+ * INTERCHANGE FIDELITY LIMITATION (verified, design §13.x): the interchange
601
+ * `meta` schema has no `deletedAt` field, so a base row that is already
602
+ * soft-deleted would round-trip into the clone as LIVE (its tombstone lost). A
603
+ * resurrected row would then read as a spurious `new` node in the fork's diff —
604
+ * the base row is non-live, so `diffNodeKind` takes its `!isLive(base)` branch and
605
+ * reports the (live, clone-resurrected) row as an addition — silently re-creating a
606
+ * deleted node on commit. We therefore export with `includeDeleted: false`: the
607
+ * clone carries only the base's LIVE state, exactly what `branch()` needs. The
608
+ * merge state-diff is still computed against the ORIGINAL base store (live rows
609
+ * only) as the immutable reference, never against the clone (clones regenerate
610
+ * `created_at`/`updated_at`, which would otherwise destabilize `base@V`).
611
+ *
612
+ * Logical-namespace (copy-on-write within one backend, no full data copy) is a
613
+ * future strategy slot — see the `WorkingCopyStrategy` interface — deferred past
614
+ * P0.
615
+ */
616
+
617
+ /**
618
+ * How `branch()` materializes a working copy of a base store.
619
+ *
620
+ * `create` receives the live base store and returns a fresh, independently
621
+ * mutable {@link Store} over the SAME graph definition, seeded with the base's
622
+ * current state. Mutating the returned store MUST NOT affect the base.
623
+ *
624
+ * The single method is the only extension point: alternative strategies
625
+ * (e.g. a future logical-namespace copy-on-write within one backend) implement
626
+ * the same contract.
627
+ */
628
+ type WorkingCopyStrategy<G extends GraphDef> = Readonly<{
629
+ create: (baseStore: Store<G>) => Promise<Store<G>>;
630
+ }>;
631
+ /**
632
+ * Factory for a caller-provided backend. `branch()` stays backend-agnostic by
633
+ * delegating backend construction to the caller: the clone strategy calls this
634
+ * once per `create()` to obtain the fresh backend that backs the working copy.
635
+ *
636
+ * Returning a promise lets async backends (e.g. PGlite, which boots an
637
+ * in-process Postgres engine) be constructed lazily at branch time.
638
+ *
639
+ * The returned backend MUST be EMPTY (no rows for the base graph): the clone
640
+ * seeds it from the base via `importGraph` with `onConflict: "error"`, so a
641
+ * pre-existing row is surfaced as a {@link BranchError} rather than silently
642
+ * skipped (which would leave the working copy diverging from the base).
643
+ */
644
+ type MakeBackend = () => Promise<GraphBackend>;
645
+ /**
646
+ * The P0 default working-copy strategy: faithful clone via export/import.
647
+ *
648
+ * On each `create(baseStore)`:
649
+ * 1. `exportGraph(baseStore, { includeMeta: true, includeDeleted: false })` —
650
+ * `includeMeta: true` carries `created_at`/`updated_at`; `includeDeleted:
651
+ * false` keeps the clone to LIVE rows only. Shipping soft-deleted rows is
652
+ * unsafe: the meta schema has no `deletedAt`, so they would import as live and
653
+ * resurrect on the fork's diff (see the fidelity note above). `branch()` only
654
+ * needs the base's live state.
655
+ * 2. Create a fresh store over the caller-provided backend with the SAME graph
656
+ * definition via `createStoreWithSchema`.
657
+ * 3. `importGraph(freshStore, data, { onConflict: "error", ... })` — ids are
658
+ * preserved so the diff engine can key on them. `onConflict: "error"`
659
+ * requires the backend to be EMPTY: a pre-existing row is a contract
660
+ * violation that must surface loudly, never be silently skipped (a skipped
661
+ * row would leave the clone diverging from the base, so the fork's diff would
662
+ * report phantom modifications/deletions). `importGraph` RETURNS
663
+ * `{ success, errors }` rather than throwing on a per-row rejection, so its
664
+ * result is checked and any failure fails the branch.
665
+ *
666
+ * The backend `makeBackend()` returns is opened here, so any failure AFTER it is
667
+ * created closes it before rethrowing — only the success path hands the backend
668
+ * (via the returned store) to the caller, who then owns its lifecycle.
669
+ *
670
+ * @param makeBackend - Constructs the fresh, EMPTY backend the working copy is
671
+ * built on.
672
+ */
673
+ declare function cloneWorkingCopyStrategy<G extends GraphDef>(makeBackend: MakeBackend): WorkingCopyStrategy<G>;
674
+
675
+ /**
676
+ * `branch()` — fork an isolated, independently-mutable working copy of a base
677
+ * store (design §7.1).
678
+ *
679
+ * A branch is a {@link GraphBranch}: a fresh {@link BranchId}, the immutable
680
+ * `base@V` token the copy forked from (computed off the ORIGINAL base store via
681
+ * {@link computeBaseVersion}, never off the clone), and a {@link Store} over the
682
+ * branch's own backend seeded with the base's live state.
683
+ *
684
+ * The copy mechanism is pluggable behind {@link WorkingCopyStrategy}. The P0
685
+ * default is the faithful export/import clone ({@link cloneWorkingCopyStrategy}),
686
+ * which keeps this primitive backend-agnostic: the caller supplies a
687
+ * `makeBackend` factory, and `branch()` never names a concrete backend.
688
+ */
689
+
690
+ /**
691
+ * Creates an isolated working-copy branch of `baseStore`.
692
+ *
693
+ * Stamps the `base@V` token off the original base store, mints (or accepts) a
694
+ * {@link BranchId}, and materializes the working copy via the resolved strategy.
695
+ * The default strategy is a faithful clone over a fresh backend produced by
696
+ * `makeBackend`; pass an explicit `strategy` to override (e.g. a future
697
+ * logical-namespace copy-on-write).
698
+ *
699
+ * Returns a {@link Result}: success yields the {@link GraphBranch}; any failure
700
+ * (base-version stamping, backend construction, export/import) is wrapped in a
701
+ * {@link BranchError} with the underlying cause attached. Errors are returned,
702
+ * never thrown — this is internal-logic surface (the caller converts to a thrown
703
+ * error at the framework boundary).
704
+ *
705
+ * @param baseStore - The store to fork. Remains untouched.
706
+ * @param makeBackend - Factory for the working copy's backend (keeps the
707
+ * primitive backend-agnostic). Used only by the default clone strategy; ignored
708
+ * when an explicit `strategy` is supplied.
709
+ * @param options - Optional `{ id }` to set an explicit branch id.
710
+ * @param strategy - Optional working-copy strategy override.
711
+ */
712
+ declare function branch<G extends GraphDef>(baseStore: GraphBranch<G>["store"], makeBackend: MakeBackend, options?: BranchOptions, strategy?: WorkingCopyStrategy<G>): Promise<Result<GraphBranch<G>, BranchError>>;
713
+
714
+ /**
715
+ * The composite MERGE IDENTITY key for a node: the pair `(kind, id)`.
716
+ *
717
+ * TypeGraph node identity is the PAIR `(kind, id)` — a bare id string is NOT unique
718
+ * on its own (a `Patient` and an `Encounter` may both carry the id "x" as two
719
+ * DISTINCT committed nodes; ids are caller-supplied). Every place the merge pipeline
720
+ * groups, clusters, de-dupes, repoints, retypes, or deletes BY NODE IDENTITY must
721
+ * key on this pair — never the bare id — or two different-kind nodes that happen to
722
+ * share an id string silently fuse into one cluster (wrong merge, dropped node,
723
+ * incoherent commit) and the §6.4-A base guard is bypassed.
724
+ *
725
+ * Represented as a NUL-joined string (a branded {@link MergeKey}) so it doubles as a
726
+ * `Map`/`Set` key and a deterministic ordering key. `kind` is a schema identifier
727
+ * (NUL-free), so the FIRST NUL unambiguously delimits kind from id even when a
728
+ * caller-supplied id itself contains a NUL byte. This matches the `(kind, id)`
729
+ * separator the commit-time write guard already uses.
730
+ *
731
+ * {@link compareMergeKeys} orders by the bare id FIRST (kind only breaks a same-id
732
+ * tie), so the merge's "minimum-id survivor" / id-sorted-members semantics are
733
+ * preserved unchanged for the common single-kind cluster — the composite key changes
734
+ * WHICH nodes share an identity, never the ordering among genuinely distinct ids.
735
+ */
736
+
737
+ /**
738
+ * A composite `(kind, id)` node-identity key. Branded so it cannot be confused with
739
+ * a bare {@link NodeId} at the type level — the whole point is that the two are NOT
740
+ * interchangeable as identities.
741
+ */
742
+ type MergeKey = string & {
743
+ readonly __mergeKey: unique symbol;
744
+ };
745
+
746
+ /**
747
+ * The shared SCORING stage (design §4, the single match-decision point).
748
+ *
749
+ * Candidate generation is three layers — sources → scoring → reconciler (§4).
750
+ * This module is the MIDDLE layer: it turns the candidate PROPOSALS every source
751
+ * emits into the {@link CandidateEdge} set the reconciler consumes, applying the
752
+ * EXACT same scorer + threshold regardless of which source proposed a pair. A
753
+ * source proposes (recall); scoring disposes (the match decision).
754
+ *
755
+ * Two proposal kinds enter:
756
+ *
757
+ * - {@link CandidatePair}s — unscored `(a, b)` node pairs from any source. They
758
+ * are deduped by canonical `(a, b)` and each scored EXACTLY ONCE by
759
+ * {@link scorePair}; only pairs clearing the kind's threshold become edges.
760
+ * - FORCED {@link CandidateEdge}s — DEFINITIONAL matches (a shared unique value)
761
+ * that BYPASS scoring entirely, emitted at {@link FORCED_MATCH_SCORE}. A forced
762
+ * pair is never also fuzzy-scored: forced `(a, b)` keys are reserved first, so
763
+ * a fuzzy pair proposing the same endpoints is dropped before scoring.
764
+ *
765
+ * This was previously fused into `candidate-gen.ts`'s `generateCandidates` (which
766
+ * scored AND thresholded inline); naming scoring as its own stage is what makes
767
+ * "the scorer — not a source — decides matches" concrete (§4). `generateCandidates`
768
+ * now composes the bucket sources over this stage.
769
+ *
770
+ * Determinism: the emitted edge set is a pure function of the proposal SETS — pairs
771
+ * are deduped by canonical `(a, b)`, scored by the symmetric {@link scorePair}, and
772
+ * the final list is sorted by `(a, b)`, so neither the order proposals arrive in
773
+ * nor the directionality of a pair affects the result.
774
+ *
775
+ * The {@link ComparisonCeilingPolicy} bounds only the FUZZY scoring work (the
776
+ * embedder step for vector/hybrid); FORCED edges are definitional, not
777
+ * similarity-based, so they are emitted regardless of the ceiling:
778
+ *
779
+ * - `"error"` — exceeding the ceiling fails with a typed {@link MergeError}.
780
+ * - `"mergeByIdOnly"` — fuzzy similarity is SKIPPED for the kind (no
781
+ * threshold-scored edges), FORCED edges are still emitted,
782
+ * and a {@link CandidateWarning} is recorded.
783
+ */
784
+
785
+ /**
786
+ * An undirected candidate-merge edge between two nodes that should merge.
787
+ * Endpoints are stored in ascending id order (`a < b`) so the edge has a single
788
+ * canonical representation. Fuzzy edges carry their similarity score; FORCED
789
+ * (definitional) edges carry {@link FORCED_MATCH_SCORE}.
790
+ */
791
+ type CandidateEdge = Readonly<{
792
+ a: MergeKey;
793
+ b: MergeKey;
794
+ score: number;
795
+ }>;
796
+ /**
797
+ * An unscored candidate pair a source proposes for scoring: the canonical
798
+ * endpoint ids `(a, b)` (`a < b`) plus the two node objects the scorer reads
799
+ * fields off of. `left`/`right` carry the nodes whose ids are `a`/`b`
800
+ * respectively, but {@link scorePair} is symmetric so their roles are
801
+ * interchangeable for scoring.
802
+ */
803
+ type CandidatePair<K extends NodeType = NodeType> = Readonly<{
804
+ a: MergeKey;
805
+ b: MergeKey;
806
+ left: Node<K>;
807
+ right: Node<K>;
808
+ }>;
809
+
810
+ /**
811
+ * `merge()` orchestrator (design §7.2, T11).
812
+ *
813
+ * Composes every phase built in T3–T10 into one DB-agnostic primitive:
814
+ *
815
+ * 1. PRECONDITION — compute the target's `base@V` and reject any branch whose
816
+ * `base` token does not match it (`BaseVersionMismatchError`). A branch
817
+ * forked from a divergent schema or content fingerprint cannot be merged
818
+ * safely (design §5.2 / §13.6).
819
+ * 2. STAGE — `stageBranches` (T7): the provenance-tagged UNION of every
820
+ * branch's state-diff against the immutable base.
821
+ * 3. CANDIDATE-GEN — per resolved kind: build node-shaped objects from the
822
+ * staged NEW nodes, `blockNodes` (T5, folding in unique constraints from
823
+ * `introspect()`), `generateCandidates` (T6, fulltext Dice + custom; vector/
824
+ * hybrid guarded). Kinds NOT in `options.resolve` merge by id only.
825
+ * 4. CLUSTER — `connectedComponents` (T8) over the accumulated candidate edges
826
+ * and every staged new-node id, with the optional diameter guard.
827
+ * 5. CANONICALIZE — `canonicalizeCluster` (T8): min-id survivor + commutative
828
+ * property union under the stable, non-wall-clock conflict policy.
829
+ * 6. DELETE/MODIFY — `resolveDeleteModify` (T8a): the authoritative final
830
+ * liveness of every inherited node + the delete/modify conflicts.
831
+ * 7. TYPE-RECONCILE — `reconcileTypes` (T10) over the public-closure glue when
832
+ * `reconcileTypes: "ontology"`; otherwise a no-op.
833
+ * 8. EDGE REPOINT — `repointEdges` (T9): repoint every staged edge onto its
834
+ * cluster canonical, drop edges to finally-deleted endpoints, dedupe + union
835
+ * edge props under the same conflict policy.
836
+ * 9. COMMIT — apply everything to `target` (default = base store) in a single
837
+ * `store.transaction` when the backend is transactional, else non-atomically
838
+ * with a report warning (out of the P0 acceptance path — SQLite + Postgres
839
+ * are both transactional).
840
+ * 10. REPORT — assemble the {@link MergeReport} with merged counts, every
841
+ * resolution / conflict / reconciliation / drop, and the in-memory
842
+ * {@link ProvenanceIndex}. With `persistProvenance`, ALSO upsert the
843
+ * `{branch, sourceId}` records to a sidecar provenance graph (post-commit,
844
+ * best-effort — a failure surfaces as a report warning, never a failed merge).
845
+ *
846
+ * DETERMINISM: every phase is order-independent (pure functions over the
847
+ * unordered branch / staged sets, with a branch order captured ONCE for
848
+ * conflict resolution), so shuffling `branches` yields a deep-equal report and an
849
+ * identical committed graph. T12 proves this with a fast-check shuffle property.
850
+ */
851
+
852
+ /**
853
+ * Merges a set of branches back into a target store (design §7.2).
854
+ *
855
+ * Validates that every branch forked from the target's current `base@V`, stages
856
+ * the union of their diffs, resolves entities / conflicts / types through the
857
+ * T3–T10 phases, and commits the merged result to `target` (default: the base
858
+ * `store`) in a single transaction. Returns a {@link MergeReport} on success.
859
+ *
860
+ * This is the SNAPSHOT entry point: candidate generation runs the staged sources
861
+ * only (`exactKey`, `unique`) — it never resolves a staged node against the
862
+ * committed base. New-vs-base resolution is the separate {@link mergeAgainstBase}
863
+ * scope, which has a weaker `base@V` contract.
864
+ *
865
+ * Errors are RETURNED (never thrown) as a typed {@link MergeError} subclass:
866
+ * `BaseVersionMismatchError` for the precondition, `MergeError` for a
867
+ * comparison-ceiling overrun / commit failure, `SimilarityUnavailableError` for a
868
+ * `vector`/`hybrid` strategy with no configured vector strategy.
869
+ *
870
+ * @param store The base store the branches forked from. Used as the default merge
871
+ * target and as the immutable diff reference.
872
+ * @param branches The branches to merge. ORDER DOES NOT AFFECT THE RESULT — the
873
+ * report and committed graph are identical across any permutation.
874
+ * @param optionsInput Caller-facing {@link MergeOptions}; normalized internally.
875
+ */
876
+ declare function merge<G extends GraphDef>(store: Store<G>, branches: readonly GraphBranch<G>[], optionsInput?: MergeOptions<G>): Promise<Result<MergeReport<G>, MergeError>>;
877
+ /**
878
+ * Incremental merge — the public fork-point-vs-live-target entry point (design
879
+ * §6.4-B / §6.6). It treats `forkPoint` as the immutable ancestor, folds the live
880
+ * `target` in as a preferred committed branch, resolves branch additions against
881
+ * committed rows, and propagates inherited node/edge modifications and deletions
882
+ * through the same three-way merge planner.
883
+ *
884
+ * Object-form args so the two same-typed stores (`forkPoint`, `target`) cannot be
885
+ * swapped. `options.target` is ignored — `target` is the explicit arg.
886
+ *
887
+ * Preconditions (typed errors): every branch forked from `forkPoint`
888
+ * (`branch.base === computeBaseVersion(forkPoint)`); `forkPoint` and `target` share a
889
+ * schema hash (schema drift is fatal; target CONTENT may have advanced); and
890
+ * `onBasePropertyConflict` is `"flag"` (keep-base for committed-row conflicts).
891
+ */
892
+ declare function mergeIncremental<G extends GraphDef>(args: MergeIncrementalArgs<G>): Promise<Result<MergeReport<G>, MergeError>>;
893
+
894
+ /**
895
+ * Validation + default-application for {@link MergeOptions}.
896
+ *
897
+ * The zod schema validates the scalar / enum surface (thresholds, ceilings,
898
+ * enums) and applies the frozen P0 defaults. Function- and store-valued fields
899
+ * (`canonical`, a function `onPropertyConflict`, `target`, per-kind `block` /
900
+ * `custom.score`, `branchOrder`) are not meaningfully validatable by zod, so they
901
+ * are threaded through unchanged after the scalar surface validates.
902
+ *
903
+ * `normalizeMergeOptions` is the single entry point: it returns a
904
+ * {@link NormalizedMergeOptions} with every default resolved, so downstream
905
+ * phases never branch on `undefined`.
906
+ */
907
+
908
+ /**
909
+ * Frozen P0 defaults. Exported so tests and downstream phases assert against the
910
+ * same constants rather than re-typing literals.
911
+ */
912
+ declare const MERGE_OPTION_DEFAULTS: {
913
+ readonly reconcileTypes: "off";
914
+ readonly onPropertyConflict: "flag";
915
+ readonly onBasePropertyConflict: "flag";
916
+ readonly onDeleteModifyConflict: "flag";
917
+ readonly onComparisonCeiling: "error";
918
+ readonly provenance: true;
919
+ readonly persistProvenance: false;
920
+ };
921
+ /**
922
+ * Fully-normalized merge options: every default resolved, the (validated)
923
+ * pass-through fields attached. Downstream phases consume this, never the raw
924
+ * {@link MergeOptions}.
925
+ */
926
+ type NormalizedMergeOptions<G extends GraphDef = GraphDef> = Readonly<{
927
+ resolve: Readonly<Record<string, ResolveConfig<G>>>;
928
+ reconcileTypes: ReconcileTypesMode;
929
+ onPropertyConflict: PropertyConflictPolicy<G>;
930
+ onBasePropertyConflict: PropertyConflictPolicy<G>;
931
+ onDeleteModifyConflict: DeleteModifyPolicy;
932
+ onComparisonCeiling: ComparisonCeilingPolicy;
933
+ provenance: boolean;
934
+ persistProvenance: boolean;
935
+ canonical?: (cluster: ResolvedCluster) => ReturnType<NonNullable<MergeOptions<G>["canonical"]>>;
936
+ embedder?: Embedder;
937
+ target?: MergeOptions<G>["target"];
938
+ maxComparisonsPerKind?: number;
939
+ clusterMaxDiameter?: number;
940
+ branchOrder?: readonly BranchId[];
941
+ provenanceWeights?: ReadonlyMap<BranchId, number>;
942
+ }>;
943
+ /**
944
+ * Validates and normalizes {@link MergeOptions}, applying every P0 default.
945
+ *
946
+ * Throws (not a `Result`) on invalid scalar input — option validation is a
947
+ * caller-boundary concern, surfaced as a thrown error per project conventions;
948
+ * `merge()` converts it back to a typed `MergeError` at its own boundary.
949
+ *
950
+ * @throws if a threshold is outside `[0, 1]`, `maxComparisonsPerKind` is
951
+ * negative/non-integer, or `clusterMaxDiameter` is non-positive.
952
+ */
953
+ declare function normalizeMergeOptions<G extends GraphDef>(options?: MergeOptions<G>): NormalizedMergeOptions<G>;
954
+
955
+ /** The Provenance node: one row per `{branch, sourceId}` → canonical contribution. */
956
+ declare const Provenance: Readonly<{
957
+ kind: "Provenance";
958
+ schema: z.ZodObject<{
959
+ targetGraphId: z.ZodString;
960
+ role: z.ZodEnum<{
961
+ node: "node";
962
+ edge: "edge";
963
+ }>;
964
+ canonicalId: z.ZodString;
965
+ canonicalKind: z.ZodString;
966
+ branchId: z.ZodString;
967
+ sourceId: z.ZodString;
968
+ }, z.core.$strip>;
969
+ description: string | undefined;
970
+ annotations: KindAnnotations | undefined;
971
+ __nodeType: true;
972
+ }>;
973
+ /**
974
+ * Derives the sidecar graph id for a target graph. Suffixing the target's own id
975
+ * keeps each target graph's provenance in its own `graphId`-namespaced tables on a
976
+ * shared backend, while a single `Provenance` schema serves all of them.
977
+ */
978
+ declare function provenanceGraphId(targetGraphId: string): string;
979
+ /** Builds the sidecar provenance graph definition for a target graph. */
980
+ declare function buildProvenanceGraph(targetGraphId: string): Readonly<{
981
+ id: string;
982
+ nodes: {
983
+ readonly Provenance: {
984
+ readonly type: Readonly<{
985
+ kind: "Provenance";
986
+ schema: z.ZodObject<{
987
+ targetGraphId: z.ZodString;
988
+ role: z.ZodEnum<{
989
+ node: "node";
990
+ edge: "edge";
991
+ }>;
992
+ canonicalId: z.ZodString;
993
+ canonicalKind: z.ZodString;
994
+ branchId: z.ZodString;
995
+ sourceId: z.ZodString;
996
+ }, z.core.$strip>;
997
+ description: string | undefined;
998
+ annotations: KindAnnotations | undefined;
999
+ __nodeType: true;
1000
+ }>;
1001
+ };
1002
+ };
1003
+ edges: {};
1004
+ ontology: readonly Readonly<{
1005
+ metaEdge: MetaEdge;
1006
+ from: NodeType | EdgeType | string;
1007
+ to: NodeType | EdgeType | string;
1008
+ }>[];
1009
+ defaults: Readonly<{
1010
+ onNodeDelete: DeleteBehavior;
1011
+ temporalMode: TemporalMode;
1012
+ }>;
1013
+ indexes: readonly IndexDeclaration[] | undefined;
1014
+ extension: Readonly<{
1015
+ version?: GraphExtensionVersion;
1016
+ nodes?: Readonly<Record<string, ExtensionNodeDef>>;
1017
+ edges?: Readonly<Record<string, ExtensionEdgeDef>>;
1018
+ ontology?: readonly ExtensionOntologyRelation[];
1019
+ indexes?: readonly ExtensionIndex[];
1020
+ }> | undefined;
1021
+ deprecatedKinds: ReadonlySet<string>;
1022
+ __graphDef: true;
1023
+ }>;
1024
+ /** The concrete sidecar provenance graph type. */
1025
+ type ProvenanceGraph = ReturnType<typeof buildProvenanceGraph>;
1026
+ /** A persisted provenance node (the queryable record). */
1027
+ type ProvenanceNode = Node<typeof Provenance>;
1028
+ /**
1029
+ * Opens — materializing the schema if needed — the provenance store for a target
1030
+ * graph on the given backend. Idempotent: safe to call before every persist/query,
1031
+ * and shares the backend with the target (so the caller must NOT close it
1032
+ * separately — closing the shared backend is the target owner's job).
1033
+ */
1034
+ declare function openProvenanceStore(backend: GraphBackend, targetGraphId: string): Promise<Store<ProvenanceGraph>>;
1035
+ /**
1036
+ * Upserts one `Provenance` node per record into the sidecar store, keyed by the
1037
+ * deterministic id (re-running the same merge is a no-op upsert, never a
1038
+ * duplicate). Returns the row count written. The caller wraps this for best-effort
1039
+ * behavior — a failure here must not fail an already-committed merge.
1040
+ */
1041
+ declare function persistProvenanceRecords(store: Store<ProvenanceGraph>, targetGraphId: string, records: readonly ProvenanceRecord[]): Promise<number>;
1042
+ /** Filter for {@link readProvenance}. Each field, when set, narrows the result. */
1043
+ type ProvenanceQuery = Readonly<{
1044
+ branchId?: BranchId | string;
1045
+ canonicalId?: string;
1046
+ role?: "node" | "edge";
1047
+ }>;
1048
+ /**
1049
+ * Reads persisted provenance back, filtered and stably ordered. The sidecar is a
1050
+ * normal typed graph, so this is a thin ergonomic wrapper over
1051
+ * `store.nodes.Provenance.find()` (filtered in memory — provenance volumes are
1052
+ * modest; a query-builder `where` is the scale path). Answers "which canonical
1053
+ * entities did branch X contribute to?" and "who contributed canonical Y?".
1054
+ */
1055
+ declare function readProvenance(store: Store<ProvenanceGraph>, query?: ProvenanceQuery): Promise<readonly ProvenanceNode[]>;
1056
+
1057
+ /**
1058
+ * Candidate SOURCES (design §4 / §6.1) — the RECALL layer of candidate generation.
1059
+ *
1060
+ * Candidate generation is three layers — sources → scoring → reconciler (§4). This
1061
+ * module is the FIRST layer: each source PROPOSES candidates and decides nothing
1062
+ * about a fuzzy match. A source emits three things:
1063
+ *
1064
+ * - `pairs` — unscored `(a, b)` node pairs handed to the shared scoring
1065
+ * stage (`scoring.ts`), which makes every fuzzy match decision.
1066
+ * - `forcedEdges` — DEFINITIONAL matches (a shared unique value) that bypass
1067
+ * scoring at {@link FORCED_MATCH_SCORE}.
1068
+ * - `baseMembers` — committed base nodes the source pulled into scope, so the
1069
+ * reconciler can seed + canonicalize a base endpoint without
1070
+ * re-querying the backend. EMPTY for staged-only sources.
1071
+ *
1072
+ * Two sources ship here — today's two blocking strategies (`blocking.ts`),
1073
+ * refactored behind the source interface:
1074
+ *
1075
+ * - {@link exactKeySource} (`exactKey`, §6.1) — the `block(node) => string`
1076
+ * bucket: same-bucket node pairs become fuzzy `pairs`. Staged-vs-staged.
1077
+ * - {@link uniqueSource} (`unique`, §6.1) — the unique-constraint signature
1078
+ * buckets: every same-signature pair is a FORCED edge (a shared unique value
1079
+ * is definitionally the same entity). Staged-vs-staged.
1080
+ *
1081
+ * Both read the SAME pre-computed `blockNodes` map off the scope (the UNION of the
1082
+ * `block()` key and the per-constraint signatures, `blocking.ts`), filtering it by
1083
+ * {@link isUniqueBucketKey}: `exactKey` owns the non-unique buckets, `unique` owns
1084
+ * the unique buckets. Sharing one blocked map (vs. re-blocking per source) keeps the
1085
+ * source split byte-identical to the old fused `generateCandidates` — a node with a
1086
+ * unique signature but no `block()` key lands ONLY in its unique bucket, never the
1087
+ * all-vs-all `unblocked` bucket.
1088
+ *
1089
+ * Determinism: the extraction visits buckets in sorted-key order over id-sorted
1090
+ * members and enumerates `i < j`, so proposals are emitted in a canonical order;
1091
+ * the scoring stage additionally dedups + sorts, so neither source's emission order
1092
+ * leaks into the merge result.
1093
+ */
1094
+
1095
+ /**
1096
+ * A committed BASE node a source pulled into the cluster universe (design §4
1097
+ * member contribution / §6.4-D). It carries the same `(id, kind, props)` a staged
1098
+ * member does, plus a reserved `"base"` origin so the reconciler can enforce
1099
+ * base-id-wins (§6.4-C) and tag provenance with the base sentinel (§6.4-D). EMPTY
1100
+ * for staged-only sources (`exactKey`, `unique`).
1101
+ */
1102
+ type BaseMember = Readonly<{
1103
+ id: NodeId<NodeType>;
1104
+ kind: string;
1105
+ props: Readonly<Record<string, JsonValue>>;
1106
+ origin: "base";
1107
+ }>;
1108
+ /**
1109
+ * What a candidate source emits for one kind: fuzzy `pairs` to score, FORCED
1110
+ * (definitional) edges to pass through unscored, and the committed `baseMembers`
1111
+ * it pulled into scope.
1112
+ */
1113
+ type SourceResult = Readonly<{
1114
+ pairs: readonly CandidatePair[];
1115
+ forcedEdges: readonly CandidateEdge[];
1116
+ baseMembers: readonly BaseMember[];
1117
+ }>;
1118
+ /**
1119
+ * The minimal node-collection surface a base-querying source needs: the public
1120
+ * `bulkFindByConstraint` (typegraph 0.29.0). It computes each item's constraint key
1121
+ * from its props, returns the live committed match per item in INPUT ORDER
1122
+ * (`undefined` for misses, soft-deleted excluded), and is indexed by the `uniques`
1123
+ * table PK — so graph-merge never reconstructs constraint keys itself. A runtime,
1124
+ * kind-string-keyed view (like the commit's `TxNodes`) so a source can dispatch on
1125
+ * a kind string without threading the caller's concrete `Store<G>` generic.
1126
+ */
1127
+ type BaseNodeLookup = Readonly<{
1128
+ bulkFindByConstraint: (constraintName: string, items: readonly Readonly<{
1129
+ props: Record<string, unknown>;
1130
+ }>[]) => Promise<readonly (Node<NodeType> | undefined)[]>;
1131
+ /**
1132
+ * The non-unique sibling (typegraph 0.30): for each item, the live committed nodes
1133
+ * sharing its declared-INDEX key (computed from props), returned per item in input
1134
+ * order, each inner array id-sorted, soft-deleted excluded. `limitPerInput` bounds
1135
+ * per-item fan-out (id-ordered, so the cap is deterministic). Candidate retrieval —
1136
+ * NOT a uniqueness/identity guarantee — so `baseKey` emits scored pairs, not forced
1137
+ * edges.
1138
+ */
1139
+ bulkFindByIndex: (indexName: string, items: readonly Readonly<{
1140
+ props: Record<string, unknown>;
1141
+ }>[], options?: Readonly<{
1142
+ limitPerInput?: number;
1143
+ }>) => Promise<readonly (readonly Node<NodeType>[])[]>;
1144
+ }>;
1145
+ /** Runtime, kind-string-keyed view of a store's node collections for base lookups. */
1146
+ type BaseLookupStore = Readonly<{
1147
+ nodes: Readonly<Record<string, BaseNodeLookup>>;
1148
+ }>;
1149
+ /**
1150
+ * The per-kind input a source generates over. `blocks` is the UNION `blockNodes`
1151
+ * result (`block()` key + per-constraint signatures) the staged sources read.
1152
+ *
1153
+ * The remaining fields are present only when a BASE-querying source (`baseUnique` /
1154
+ * `baseKey`, §6.2) is driven: the kind's materialized staged new `nodes` (the lookup
1155
+ * items), its `uniqueConstraints` (for `baseUnique`), the declared `blockIndex` name
1156
+ * (for `baseKey`, when the kind configured one), and the committed `store` to query
1157
+ * against. Staged-only sources (`exactKey`, `unique`) ignore them, so the public
1158
+ * `merge()` candidate path leaves them unset.
1159
+ */
1160
+ type SourceScope = Readonly<{
1161
+ kind: string;
1162
+ blocks: ReadonlyMap<string, readonly Node<NodeType>[]>;
1163
+ nodes?: readonly Node<NodeType>[];
1164
+ uniqueConstraints?: readonly UniqueIntrospection[];
1165
+ blockIndex?: string;
1166
+ /** When set, `exactKey` bounds the no-key (`"unblocked"`) bucket by sorted-
1167
+ * neighbourhood instead of all-vs-all (the `keyless` source, §6.2). */
1168
+ keyless?: KeylessConfig;
1169
+ store?: BaseLookupStore;
1170
+ }>;
1171
+ /**
1172
+ * A candidate source (design §4): proposes pairs (recall) + definitional forced
1173
+ * edges, and supplies the base members it pulled into scope. The `id` attributes
1174
+ * a source in reports and pins its determinism level (§7).
1175
+ */
1176
+ type CandidateSource = Readonly<{
1177
+ readonly id: string;
1178
+ generate(scope: SourceScope): Promise<SourceResult>;
1179
+ }>;
1180
+ /**
1181
+ * The bounded coarse source for the NO-KEY case (design §6.2, `keyless`): which
1182
+ * unblocked nodes to compare, and how far. `window` is the forward-neighbour count;
1183
+ * `sortFields` is the kind's similarity text fields, so the SORTED-NEIGHBOURHOOD sort
1184
+ * groups lexically-similar values adjacently (the same text the scorer reads).
1185
+ */
1186
+ type KeylessConfig = Readonly<{
1187
+ window: number;
1188
+ sortFields: readonly string[];
1189
+ }>;
1190
+
1191
+ export { type BaseAmbiguity, type BaseNodeLookup, type BaseVersion, BaseVersionMismatchError, BranchError, type BranchId, type BranchOptions, type BranchProvenance, type CandidateSource, type ComparisonCeilingPolicy, type ConflictingValue, type DeleteModifyConflict, type DeleteModifyPolicy, type DroppedItem, type Embedder, type EntityResolution, type GraphBranch, type KeylessConfig, MERGE_ERROR_CODES, MERGE_OPTION_DEFAULTS, type MakeBackend, MergeConflictError, MergeError, type MergeIncrementalArgs, type MergeOptions, type MergeReport, type NormalizedMergeOptions, type PropertyConflict, type PropertyConflictPolicy, type ProvenanceGraph, type ProvenanceIndex, type ProvenanceNode, type ProvenanceQuery, type ProvenanceRecord, type ReconcileTypesMode, type ResolveConfig, type ResolveMap, type ResolvedCluster, Result, type SimilarityStrategy, SimilarityUnavailableError, type SourceScope, type TypeReconciliation, type WorkingCopyStrategy, asBaseVersion, asBranchId, branch, cloneWorkingCopyStrategy, computeBaseVersion, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, persistProvenanceRecords, provenanceGraphId, readProvenance };