@graphorin/memory 0.6.0 → 0.7.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 (227) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +24 -7
  3. package/dist/conflict/index.js +0 -1
  4. package/dist/conflict/pipeline.js +0 -1
  5. package/dist/conflict/pipeline.js.map +1 -1
  6. package/dist/conflict/stages/stage3-heuristic-regex.js +0 -1
  7. package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -1
  8. package/dist/conflict/types.d.ts +1 -1
  9. package/dist/conflict/types.js.map +1 -1
  10. package/dist/consolidator/index.js +2 -0
  11. package/dist/consolidator/index.js.map +1 -1
  12. package/dist/consolidator/lock.js +7 -1
  13. package/dist/consolidator/lock.js.map +1 -1
  14. package/dist/consolidator/phases/deep.js +19 -12
  15. package/dist/consolidator/phases/deep.js.map +1 -1
  16. package/dist/consolidator/phases/induce.d.ts.map +1 -1
  17. package/dist/consolidator/phases/induce.js +2 -3
  18. package/dist/consolidator/phases/induce.js.map +1 -1
  19. package/dist/consolidator/phases/reflect.js +35 -8
  20. package/dist/consolidator/phases/reflect.js.map +1 -1
  21. package/dist/consolidator/phases/standard.js +199 -28
  22. package/dist/consolidator/phases/standard.js.map +1 -1
  23. package/dist/consolidator/reconcile.js +16 -15
  24. package/dist/consolidator/reconcile.js.map +1 -1
  25. package/dist/consolidator/runtime.d.ts.map +1 -1
  26. package/dist/consolidator/runtime.js +129 -47
  27. package/dist/consolidator/runtime.js.map +1 -1
  28. package/dist/consolidator/scheduler.d.ts +17 -3
  29. package/dist/consolidator/scheduler.d.ts.map +1 -1
  30. package/dist/consolidator/scheduler.js.map +1 -1
  31. package/dist/consolidator/types.d.ts +30 -1
  32. package/dist/consolidator/types.d.ts.map +1 -1
  33. package/dist/consolidator/types.js +10 -0
  34. package/dist/consolidator/types.js.map +1 -1
  35. package/dist/context-engine/compaction/clear-tool-results.d.ts +1 -1
  36. package/dist/context-engine/compaction/clear-tool-results.js +1 -1
  37. package/dist/context-engine/compaction/clear-tool-results.js.map +1 -1
  38. package/dist/context-engine/compaction/compactor.d.ts +1 -0
  39. package/dist/context-engine/compaction/compactor.d.ts.map +1 -1
  40. package/dist/context-engine/compaction/compactor.js +32 -8
  41. package/dist/context-engine/compaction/compactor.js.map +1 -1
  42. package/dist/context-engine/compaction/hooks/types.d.ts +1 -1
  43. package/dist/context-engine/compaction/index.d.ts +1 -0
  44. package/dist/context-engine/compaction/templates/marker.d.ts +33 -0
  45. package/dist/context-engine/compaction/templates/marker.d.ts.map +1 -0
  46. package/dist/context-engine/compaction/templates/marker.js +34 -0
  47. package/dist/context-engine/compaction/templates/marker.js.map +1 -0
  48. package/dist/context-engine/compaction/templates/summary-9-section.d.ts +1 -1
  49. package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -1
  50. package/dist/context-engine/compaction/templates/summary-9-section.js +4 -3
  51. package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -1
  52. package/dist/context-engine/engine.d.ts +7 -176
  53. package/dist/context-engine/engine.d.ts.map +1 -1
  54. package/dist/context-engine/engine.js +0 -2
  55. package/dist/context-engine/engine.js.map +1 -1
  56. package/dist/context-engine/index.d.ts +8 -49
  57. package/dist/context-engine/io-types.d.ts +144 -0
  58. package/dist/context-engine/io-types.d.ts.map +1 -0
  59. package/dist/context-engine/locale-packs/types.d.ts +1 -1
  60. package/dist/context-engine/locale-packs/types.js.map +1 -1
  61. package/dist/context-engine/privacy-filter.d.ts +1 -2
  62. package/dist/context-engine/privacy-filter.d.ts.map +1 -1
  63. package/dist/context-engine/privacy-filter.js +1 -2
  64. package/dist/context-engine/privacy-filter.js.map +1 -1
  65. package/dist/errors/index.d.ts +2 -2
  66. package/dist/errors/index.js +2 -2
  67. package/dist/errors/index.js.map +1 -1
  68. package/dist/facade.d.ts +43 -52
  69. package/dist/facade.d.ts.map +1 -1
  70. package/dist/facade.js +5 -3
  71. package/dist/facade.js.map +1 -1
  72. package/dist/graph/entity-resolver.js +1 -1
  73. package/dist/graph/entity-resolver.js.map +1 -1
  74. package/dist/index.d.ts +17 -15
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +5 -7
  77. package/dist/index.js.map +1 -1
  78. package/dist/internal/envelope.js +57 -0
  79. package/dist/internal/envelope.js.map +1 -0
  80. package/dist/internal/injection-heuristics.js +0 -0
  81. package/dist/internal/injection-heuristics.js.map +1 -1
  82. package/dist/internal/llm-json.js +40 -0
  83. package/dist/internal/llm-json.js.map +1 -0
  84. package/dist/internal/storage-adapter.d.ts +23 -10
  85. package/dist/internal/storage-adapter.d.ts.map +1 -1
  86. package/dist/memory-interface.d.ts +131 -0
  87. package/dist/memory-interface.d.ts.map +1 -0
  88. package/dist/package.js +6 -0
  89. package/dist/package.js.map +1 -0
  90. package/dist/search/iterative.d.ts.map +1 -1
  91. package/dist/search/iterative.js +2 -3
  92. package/dist/search/iterative.js.map +1 -1
  93. package/dist/search/query-transform.d.ts.map +1 -1
  94. package/dist/search/query-transform.js +2 -3
  95. package/dist/search/query-transform.js.map +1 -1
  96. package/dist/tiers/episodic-memory.js +3 -3
  97. package/dist/tiers/episodic-memory.js.map +1 -1
  98. package/dist/tiers/index.d.ts +2 -2
  99. package/dist/tiers/insight-memory.js +1 -1
  100. package/dist/tiers/insight-memory.js.map +1 -1
  101. package/dist/tiers/procedural-memory.d.ts +1 -1
  102. package/dist/tiers/procedural-memory.js +2 -2
  103. package/dist/tiers/procedural-memory.js.map +1 -1
  104. package/dist/tiers/semantic-memory.d.ts +58 -4
  105. package/dist/tiers/semantic-memory.d.ts.map +1 -1
  106. package/dist/tiers/semantic-memory.js +103 -20
  107. package/dist/tiers/semantic-memory.js.map +1 -1
  108. package/dist/tools/block-tools.d.ts +19 -57
  109. package/dist/tools/block-tools.d.ts.map +1 -1
  110. package/dist/tools/block-tools.js.map +1 -1
  111. package/dist/tools/fact-tools.d.ts +53 -214
  112. package/dist/tools/fact-tools.d.ts.map +1 -1
  113. package/dist/tools/fact-tools.js +3 -2
  114. package/dist/tools/fact-tools.js.map +1 -1
  115. package/dist/tools/recall-tools.d.ts +34 -175
  116. package/dist/tools/recall-tools.d.ts.map +1 -1
  117. package/dist/tools/recall-tools.js +5 -4
  118. package/dist/tools/recall-tools.js.map +1 -1
  119. package/dist/tools/runbook-tools.d.ts +15 -58
  120. package/dist/tools/runbook-tools.d.ts.map +1 -1
  121. package/dist/tools/runbook-tools.js.map +1 -1
  122. package/dist/tools/types.d.ts +1 -1
  123. package/package.json +18 -17
  124. package/src/conflict/index.ts +29 -0
  125. package/src/conflict/locale-packs/en.ts +142 -0
  126. package/src/conflict/locale-packs/index.ts +17 -0
  127. package/src/conflict/locale-packs/types.ts +138 -0
  128. package/src/conflict/pipeline.ts +371 -0
  129. package/src/conflict/stages/helpers.ts +65 -0
  130. package/src/conflict/stages/stage1-exact-dedup.ts +40 -0
  131. package/src/conflict/stages/stage2-embedding-three-zone.ts +54 -0
  132. package/src/conflict/stages/stage3-heuristic-regex.ts +51 -0
  133. package/src/conflict/stages/stage4-subject-predicate.ts +46 -0
  134. package/src/conflict/stages/stage5-defer-to-deep.ts +34 -0
  135. package/src/conflict/types.ts +263 -0
  136. package/src/consolidator/budget.ts +312 -0
  137. package/src/consolidator/decay.ts +246 -0
  138. package/src/consolidator/dlq.ts +61 -0
  139. package/src/consolidator/errors.ts +87 -0
  140. package/src/consolidator/idempotency.ts +27 -0
  141. package/src/consolidator/index.ts +269 -0
  142. package/src/consolidator/lock.ts +141 -0
  143. package/src/consolidator/noise-filter.ts +235 -0
  144. package/src/consolidator/phases/deep.ts +308 -0
  145. package/src/consolidator/phases/induce.ts +423 -0
  146. package/src/consolidator/phases/learned-context.ts +233 -0
  147. package/src/consolidator/phases/light.ts +166 -0
  148. package/src/consolidator/phases/reflect.ts +504 -0
  149. package/src/consolidator/phases/standard.ts +1002 -0
  150. package/src/consolidator/reconcile.ts +273 -0
  151. package/src/consolidator/runtime.ts +1049 -0
  152. package/src/consolidator/scheduler.ts +182 -0
  153. package/src/consolidator/triggers.ts +134 -0
  154. package/src/consolidator/types.ts +622 -0
  155. package/src/context-engine/annotations.ts +161 -0
  156. package/src/context-engine/auto-recall.ts +92 -0
  157. package/src/context-engine/compaction/clear-tool-results.ts +232 -0
  158. package/src/context-engine/compaction/compactor.ts +403 -0
  159. package/src/context-engine/compaction/hooks/reanchor-persona-block.ts +55 -0
  160. package/src/context-engine/compaction/hooks/reanchor-pinned-facts.ts +66 -0
  161. package/src/context-engine/compaction/hooks/reanchor-project-rules.ts +57 -0
  162. package/src/context-engine/compaction/hooks/reanchor-recent-results.ts +116 -0
  163. package/src/context-engine/compaction/hooks/types.ts +68 -0
  164. package/src/context-engine/compaction/index.ts +60 -0
  165. package/src/context-engine/compaction/templates/marker.ts +33 -0
  166. package/src/context-engine/compaction/templates/summary-9-section.ts +223 -0
  167. package/src/context-engine/compaction/thresholds.ts +107 -0
  168. package/src/context-engine/compaction/types.ts +255 -0
  169. package/src/context-engine/engine.ts +970 -0
  170. package/src/context-engine/index.ts +118 -0
  171. package/src/context-engine/io-types.ts +162 -0
  172. package/src/context-engine/locale-packs/en.ts +107 -0
  173. package/src/context-engine/locale-packs/index.ts +19 -0
  174. package/src/context-engine/locale-packs/resolver.ts +197 -0
  175. package/src/context-engine/locale-packs/types.ts +177 -0
  176. package/src/context-engine/metadata.ts +114 -0
  177. package/src/context-engine/preambles/inbound-en.ts +19 -0
  178. package/src/context-engine/privacy-filter.ts +190 -0
  179. package/src/context-engine/templates/base-en.ts +19 -0
  180. package/src/context-engine/templates/composer.ts +91 -0
  181. package/src/context-engine/token-budget.ts +319 -0
  182. package/src/context-engine/token-counter.ts +157 -0
  183. package/src/errors/index.ts +273 -0
  184. package/src/facade.ts +750 -0
  185. package/src/graph/entity-resolver.ts +364 -0
  186. package/src/graph/index.ts +24 -0
  187. package/src/index.ts +259 -0
  188. package/src/internal/contextualize.ts +173 -0
  189. package/src/internal/embedder-binding.ts +53 -0
  190. package/src/internal/envelope.ts +70 -0
  191. package/src/internal/id.ts +23 -0
  192. package/src/internal/injection-heuristics.ts +0 -0
  193. package/src/internal/llm-json.ts +38 -0
  194. package/src/internal/spans.ts +35 -0
  195. package/src/internal/storage-adapter.ts +963 -0
  196. package/src/memory-interface.ts +158 -0
  197. package/src/migration/embedder-migration.ts +237 -0
  198. package/src/migration/index.ts +13 -0
  199. package/src/search/explain.ts +123 -0
  200. package/src/search/fit-weights.ts +109 -0
  201. package/src/search/graph-ppr.ts +38 -0
  202. package/src/search/index.ts +55 -0
  203. package/src/search/iterative.ts +658 -0
  204. package/src/search/query-transform.ts +285 -0
  205. package/src/search/rrf.ts +225 -0
  206. package/src/search/trust.ts +55 -0
  207. package/src/search/types.ts +50 -0
  208. package/src/tiers/episodic-memory.ts +463 -0
  209. package/src/tiers/index.ts +50 -0
  210. package/src/tiers/insight-memory.ts +208 -0
  211. package/src/tiers/procedural-memory.ts +482 -0
  212. package/src/tiers/semantic-memory.ts +1729 -0
  213. package/src/tiers/session-memory.ts +271 -0
  214. package/src/tiers/shared-memory.ts +62 -0
  215. package/src/tiers/working-memory.ts +368 -0
  216. package/src/tools/block-tools.ts +172 -0
  217. package/src/tools/fact-tools.ts +473 -0
  218. package/src/tools/index.ts +109 -0
  219. package/src/tools/recall-tools.ts +303 -0
  220. package/src/tools/runbook-tools.ts +107 -0
  221. package/src/tools/taint.ts +39 -0
  222. package/src/tools/types.ts +37 -0
  223. package/dist/conflict/locale-packs/index.js +0 -4
  224. package/dist/context-engine/compaction/index.js +0 -10
  225. package/dist/context-engine/index.d.ts.map +0 -1
  226. package/dist/context-engine/index.js +0 -25
  227. package/dist/context-engine/locale-packs/index.js +0 -4
@@ -0,0 +1,963 @@
1
+ import type {
2
+ EmbedderProvider,
3
+ EntityRole,
4
+ Episode,
5
+ EpisodicMemoryStore,
6
+ Fact,
7
+ GraphEntity,
8
+ Insight,
9
+ MemoryHit,
10
+ MemoryOwner,
11
+ MemoryStatus,
12
+ MemoryStore,
13
+ Message,
14
+ MessageRef,
15
+ ProceduralMemoryStore,
16
+ Rule,
17
+ SemanticMemoryStore,
18
+ SessionListOptions,
19
+ SessionMemoryStore,
20
+ SessionScope,
21
+ SharedMemoryStore,
22
+ WorkingMemoryStore,
23
+ } from '@graphorin/core';
24
+
25
+ /**
26
+ * Shape of the embedding payload threaded through the optional
27
+ * embedded write helpers exposed by adapters such as
28
+ * `@graphorin/store-sqlite`. Matches the storage adapter's
29
+ * `SqliteMemoryWriteOptions` byte-for-byte but is declared
30
+ * structurally here so `@graphorin/memory` does not import the
31
+ * storage package directly.
32
+ *
33
+ * @stable
34
+ */
35
+ export interface EmbeddedWriteOptions {
36
+ readonly embedding?: {
37
+ readonly embedderId: string;
38
+ readonly vector: Float32Array;
39
+ };
40
+ /**
41
+ * Contextual-retrieval index text (P1-3). When supplied, the adapter
42
+ * indexes its lexical (FTS) surface against this context-prepended
43
+ * text while persisting the canonical `text` unchanged. Absent ⇒ the
44
+ * canonical text is indexed (pre-P1-3 behaviour).
45
+ */
46
+ readonly indexText?: string;
47
+ }
48
+
49
+ /**
50
+ * Extension of the typed `EpisodicMemoryStore` with optional
51
+ * embedding-aware helpers + lifecycle helpers that storage adapters
52
+ * may expose.
53
+ *
54
+ * @stable
55
+ */
56
+ export interface EpisodicMemoryStoreExt extends EpisodicMemoryStore {
57
+ putWithEmbedding?(episode: Episode, options: EmbeddedWriteOptions): Promise<void>;
58
+ searchVector?(
59
+ scope: SessionScope,
60
+ embedding: Float32Array,
61
+ embedderId: string,
62
+ topK: number,
63
+ /** Point-in-time filter (`started_at <= asOf`, ISO-8601). P0-2. */
64
+ asOf?: string,
65
+ /** Include quarantined episodes (validation/inspector path). P1-4. */
66
+ includeQuarantined?: boolean,
67
+ ): Promise<ReadonlyArray<MemoryHit<Episode>>>;
68
+ /**
69
+ * Mark an episode archived. Soft-archive - the row stays for replay.
70
+ * W-154: with `scope`, adapters no-op unless the row belongs to it.
71
+ */
72
+ archive?(id: string, reason?: string, scope?: SessionScope): Promise<void>;
73
+ /**
74
+ * Most-recent episodes by end time (newest first), with no FTS / vector
75
+ * query - recency, not relevance (MCON-1). Powers `EpisodicMemory.recent()`
76
+ * and the deep-phase reflection gate. The default `@graphorin/store-sqlite`
77
+ * adapter implements it.
78
+ */
79
+ listRecent?(
80
+ scope: SessionScope,
81
+ limit: number,
82
+ options?: { includeQuarantined?: boolean },
83
+ ): Promise<ReadonlyArray<Episode>>;
84
+ /**
85
+ * Set an episode's retrieval-trust `status` (MCON-2) - promote a quarantined
86
+ * (auto-formed) episode into default recall or re-quarantine an active one,
87
+ * with a `memory_history` audit row. Powers {@link EpisodicMemory.validate}.
88
+ */
89
+ setStatus?(
90
+ id: string,
91
+ status: MemoryStatus,
92
+ reason?: string,
93
+ scope?: SessionScope,
94
+ ): Promise<void>;
95
+ /**
96
+ * Count the recall-eligible episodes for the scope (CE-5) - a `COUNT(*)`,
97
+ * never materialising rows. Powers honest `metadata()` counts.
98
+ */
99
+ count?(scope: SessionScope): Promise<number>;
100
+ }
101
+
102
+ /**
103
+ * Extension of the typed `SemanticMemoryStore` with optional
104
+ * embedding-aware helpers + lifecycle helpers that storage adapters
105
+ * may expose.
106
+ *
107
+ * @stable
108
+ */
109
+ export interface SemanticMemoryStoreExt extends SemanticMemoryStore {
110
+ rememberWithEmbedding?(fact: Fact, options: EmbeddedWriteOptions): Promise<void>;
111
+ searchVector?(
112
+ scope: SessionScope,
113
+ embedding: Float32Array,
114
+ embedderId: string,
115
+ topK: number,
116
+ /**
117
+ * Point-in-time filter applied after KNN: only facts whose
118
+ * validity interval contains `asOf` (ISO-8601) survive. P0-2.
119
+ */
120
+ asOf?: string,
121
+ /**
122
+ * Include quarantined facts in the KNN result (validation /
123
+ * inspector path). Default reads exclude them. P1-4.
124
+ */
125
+ includeQuarantined?: boolean,
126
+ /**
127
+ * Include superseded / validity-expired facts. Default reads
128
+ * evaluate validity at NOW (memory-retrieval-01).
129
+ */
130
+ includeSuperseded?: boolean,
131
+ /**
132
+ * Retrieval-time principal filter (D3). Rows with no stored owner
133
+ * are treated as `'user'`. Absent ⇒ no owner filter.
134
+ */
135
+ owner?: MemoryOwner | ReadonlyArray<MemoryOwner>,
136
+ ): Promise<ReadonlyArray<MemoryHit<Fact>>>;
137
+ /** Lookup a single fact by id (returns `null` when absent or soft-deleted). */
138
+ get?(id: string): Promise<Fact | null>;
139
+ /**
140
+ * Set a fact's retrieval-trust `status` and write a `memory_history`
141
+ * audit row (P1-4). Promotes a quarantined fact to `active` (the
142
+ * validation path) or re-quarantines an active one. Never touches
143
+ * content / embedding / tombstone - quarantine is a retrieval gate.
144
+ * Powers {@link SemanticMemory.validate}; the default
145
+ * `@graphorin/store-sqlite` adapter implements it.
146
+ */
147
+ setStatus?(
148
+ factId: string,
149
+ status: MemoryStatus,
150
+ reason?: string,
151
+ scope?: SessionScope,
152
+ ): Promise<void>;
153
+ /**
154
+ * Count the recall-eligible facts for the scope (CE-5) - a `COUNT(*)` with
155
+ * the default recall filters (live, non-archived, non-quarantined), never
156
+ * materialising rows. Powers honest `metadata()` counts.
157
+ */
158
+ count?(scope: SessionScope): Promise<number>;
159
+ /**
160
+ * Hard-delete a fact (GDPR path). The audit log row is preserved
161
+ * but the row itself + every per-embedder vec0 entry is removed.
162
+ * Distinct from {@link SemanticMemoryStore.forget} (soft-delete).
163
+ */
164
+ purge?(id: string, reason?: string, scope?: SessionScope): Promise<void>;
165
+ /**
166
+ * W-019: record a PENDING supersede link - set `newId.supersedes =
167
+ * oldId` WITHOUT closing the old fact's validity interval. Used when
168
+ * a supersede's successor lands quarantined: the old fact must stay
169
+ * in default recall until the successor is validated, at which point
170
+ * {@link SemanticMemory.validate} completes the closure via
171
+ * {@link SemanticMemoryStore.supersede}. No schema change - the
172
+ * `supersedes` column already exists.
173
+ */
174
+ linkPendingSupersede?(newId: string, oldId: string): Promise<void>;
175
+ /**
176
+ * Walk the bi-temporal supersede chain that `factId` belongs to and
177
+ * return every fact in it, oldest → newest (by `validFrom`),
178
+ * including superseded / soft-deleted rows so callers can answer
179
+ * "how did this fact change over time". Scope-guarded and
180
+ * cycle-safe; returns `[]` for an unknown id. Powers
181
+ * {@link SemanticMemory.history} (P0-2). The default
182
+ * `@graphorin/store-sqlite` adapter implements it.
183
+ */
184
+ historyOf?(scope: SessionScope, factId: string): Promise<ReadonlyArray<Fact>>;
185
+ }
186
+
187
+ /**
188
+ * Single message tuple returned by
189
+ * {@link SessionMemoryStoreExt.listMessagesSince}. The optional
190
+ * `tokenCount` field is the value cached in the storage layer
191
+ * (DEC-131); `null` indicates the cache is empty.
192
+ *
193
+ * @stable
194
+ */
195
+ export interface SessionMessageRecord {
196
+ readonly id: string;
197
+ readonly sequence: number;
198
+ readonly createdAt: string;
199
+ readonly tokenCount: number | null;
200
+ readonly message: Message;
201
+ }
202
+
203
+ /**
204
+ * Extension of the typed `SessionMemoryStore` with optional
205
+ * token-cache + vector-search + cursor-aware reader helpers that
206
+ * storage adapters may expose.
207
+ *
208
+ * @stable
209
+ */
210
+ export interface SessionMemoryStoreExt extends SessionMemoryStore {
211
+ searchVector?(
212
+ scope: SessionScope,
213
+ embedding: Float32Array,
214
+ embedderId: string,
215
+ topK: number,
216
+ ): Promise<ReadonlyArray<MemoryHit>>;
217
+ /**
218
+ * Sum of `session_messages.token_count` for the supplied scope.
219
+ * Returns `null` when the cache is empty / partially populated so
220
+ * callers can fall back to a heuristic. Surfaced per DEC-131.
221
+ */
222
+ totalCachedTokens?(scope: SessionScope): Promise<number | null>;
223
+ /**
224
+ * List messages for the supplied scope past the optional
225
+ * `lastMessageId` cursor, oldest-first, capped at `limit`. Used by
226
+ * the consolidator's standard phase to advance the per-scope
227
+ * idempotency cursor without rereading already-processed turns.
228
+ */
229
+ listMessagesSince?(
230
+ scope: SessionScope,
231
+ lastMessageId: string | null,
232
+ limit: number,
233
+ ): Promise<ReadonlyArray<SessionMessageRecord>>;
234
+ /**
235
+ * Count the live messages in the scoped session (CE-5) - a `COUNT(*)`, never
236
+ * materialising rows; `0` for a user-only scope. Powers honest `metadata()`
237
+ * counts instead of `list(...)`-materialising up to 1000 rows.
238
+ */
239
+ count?(scope: SessionScope): Promise<number>;
240
+ }
241
+
242
+ /**
243
+ * Optional extension surface for storage adapters' embedder registry.
244
+ * The interface is structural so any adapter that matches the shape
245
+ * works.
246
+ *
247
+ * @stable
248
+ */
249
+ export interface EmbeddingMetaRegistryLike {
250
+ registerOrReturn(input: {
251
+ readonly id: string;
252
+ readonly embedderKind: string;
253
+ readonly model: string;
254
+ readonly dim: number;
255
+ readonly distanceMetric?: 'cosine' | 'dot' | 'euclidean';
256
+ readonly configHash: string;
257
+ readonly notes?: string | null;
258
+ }): { readonly id: string };
259
+ get(id: string): unknown | null;
260
+ assertKnown(id: string): void;
261
+ retire(id: string, retiredAt?: number): void;
262
+ listAll(): ReadonlyArray<{ readonly id: string; readonly retiredAt: number | null }>;
263
+ listActive(): ReadonlyArray<{ readonly id: string; readonly retiredAt: number | null }>;
264
+ }
265
+
266
+ /**
267
+ * Stable lowercase identifier for the pipeline stage that produced a
268
+ * conflict decision. Mirrored byte-for-byte by
269
+ * `@graphorin/store-sqlite`'s `ConflictPipelineStage`.
270
+ *
271
+ * @stable
272
+ */
273
+ export type ConflictAuditStage =
274
+ | 'exact-dedup'
275
+ | 'embedding-three-zone'
276
+ | 'heuristic-regex'
277
+ | 'subject-predicate'
278
+ | 'defer-to-deep';
279
+
280
+ /**
281
+ * Final pipeline outcome recorded against the candidate fact. Matches
282
+ * the storage adapter's `ConflictPipelineDecision` exactly.
283
+ * `'judge-unparseable'` closes a pending row whose deep-phase judge
284
+ * call repeatedly failed (MCON-9) so it stops being re-billed forever.
285
+ *
286
+ * @stable
287
+ */
288
+ export type ConflictAuditDecision =
289
+ | 'admit'
290
+ | 'dedup'
291
+ | 'supersede'
292
+ | 'pending'
293
+ | 'judge-unparseable';
294
+
295
+ /**
296
+ * Single audit row written by `runConflictPipeline(...)`. The optional
297
+ * `ConflictMemoryStoreExt.recordDecision` accepts this shape; the
298
+ * default `@graphorin/store-sqlite` implementation persists it into
299
+ * the `fact_conflicts` table introduced by Phase 10b.
300
+ *
301
+ * @stable
302
+ */
303
+ export interface ConflictAuditInputLike {
304
+ readonly scope: SessionScope;
305
+ readonly candidateId: string;
306
+ readonly existingId?: string;
307
+ readonly decision: ConflictAuditDecision;
308
+ readonly stage: ConflictAuditStage;
309
+ readonly detectionZone?: string;
310
+ readonly similarity?: number;
311
+ readonly reason?: string;
312
+ readonly detectedBy?: string;
313
+ }
314
+
315
+ /**
316
+ * Pending-queue payload - Stage 5 (defer-to-deep) hands the row over
317
+ * to the deep-phase LLM judge (Phase 10c).
318
+ *
319
+ * @stable
320
+ */
321
+ export interface PendingConflictInputLike {
322
+ readonly scope: SessionScope;
323
+ readonly factId: string;
324
+ readonly candidateText: string;
325
+ readonly stage: ConflictAuditStage;
326
+ readonly reason?: string;
327
+ /** Top-K conflicting existing fact ids surfaced by Stage 2. */
328
+ readonly conflictingIds?: ReadonlyArray<string>;
329
+ }
330
+
331
+ /**
332
+ * Read-back shape returned by `listPending(...)`.
333
+ *
334
+ * @stable
335
+ */
336
+ export interface PendingConflictRowLike {
337
+ readonly id: number;
338
+ readonly scopeUserId: string;
339
+ readonly factId: string;
340
+ readonly candidateText: string;
341
+ readonly stage: string;
342
+ readonly reason: string | null;
343
+ readonly enqueuedAt: number;
344
+ readonly attemptedAt: number | null;
345
+ readonly resolvedAt: number | null;
346
+ readonly decision: string | null;
347
+ /** Top-K conflicting existing fact ids; empty when omitted at enqueue. */
348
+ readonly conflictingIds: ReadonlyArray<string>;
349
+ }
350
+
351
+ /**
352
+ * Optional storage extension surfacing the audit + pending queue
353
+ * tables Phase 10b owns. Adapters that opt out leave the property
354
+ * undefined; the conflict pipeline degrades gracefully (no audit, no
355
+ * deferred queue, but every other stage still functions).
356
+ *
357
+ * @stable
358
+ */
359
+ export interface ConflictMemoryStoreExt {
360
+ recordDecision(input: ConflictAuditInputLike): Promise<{
361
+ readonly id: number;
362
+ readonly detectedAt: number;
363
+ }>;
364
+ enqueuePending(input: PendingConflictInputLike): Promise<{ readonly id: number }>;
365
+ listPending(scope: SessionScope, limit?: number): Promise<ReadonlyArray<PendingConflictRowLike>>;
366
+ markResolved(id: number, decision: ConflictAuditDecision): Promise<void>;
367
+ /**
368
+ * Stamp `attemptedAt` on a pending row whose judge call failed
369
+ * (MCON-9). The deep phase closes the row as `'judge-unparseable'`
370
+ * on the NEXT failure, so a poisoned row is billed at most twice.
371
+ * Optional - without it the deep phase falls back to skip-and-retry.
372
+ */
373
+ markAttempted?(id: number, attemptedAt?: number): Promise<void>;
374
+ }
375
+
376
+ /**
377
+ * Persisted per-scope consolidator state row mirrored byte-for-byte
378
+ * by `@graphorin/store-sqlite`'s `consolidator_state` table. The lock
379
+ * fields (`activeLockHeldBy` / `activeLockAcquiredAt`) are populated
380
+ * while a phase is running and cleared when it finishes; the cursor
381
+ * fields advance as the standard phase processes a batch of
382
+ * messages.
383
+ *
384
+ * @stable
385
+ */
386
+ export interface ConsolidatorStateRow {
387
+ readonly scope: SessionScope;
388
+ readonly lastProcessedMessageId: string | null;
389
+ readonly lastPhase: 'light' | 'standard' | 'deep' | null;
390
+ readonly lastCompletedAt: number | null;
391
+ readonly nextEligibleAt: number | null;
392
+ readonly activeLockHeldBy: string | null;
393
+ readonly activeLockAcquiredAt: number | null;
394
+ /**
395
+ * `ended_at` (epoch ms) of the newest episode the deep-phase reflection
396
+ * pass has already reflected on (MCON-13). A later pass accumulates
397
+ * importance only from strictly-newer episodes; `null` ⇒ nothing reflected
398
+ * yet.
399
+ */
400
+ readonly reflectionWatermark: number | null;
401
+ }
402
+
403
+ /**
404
+ * Patch shape accepted by
405
+ * {@link ConsolidatorMemoryStoreExt.upsertState}. Every field is
406
+ * optional so callers may advance the cursor and the run stamp
407
+ * independently. `null` clears a column; `undefined` leaves it
408
+ * untouched.
409
+ *
410
+ * @stable
411
+ */
412
+ export interface ConsolidatorStatePatch {
413
+ readonly lastProcessedMessageId?: string | null;
414
+ readonly lastPhase?: 'light' | 'standard' | 'deep' | null;
415
+ readonly lastCompletedAt?: number | null;
416
+ readonly nextEligibleAt?: number | null;
417
+ readonly activeLockHeldBy?: string | null;
418
+ readonly activeLockAcquiredAt?: number | null;
419
+ readonly reflectionWatermark?: number | null;
420
+ }
421
+
422
+ /**
423
+ * Phase invocation audit row written to `consolidator_runs`. The
424
+ * accompanying `id` is generated by the caller so a partial / failed
425
+ * run can be reconciled by replay.
426
+ *
427
+ * @stable
428
+ */
429
+ export interface ConsolidatorRunInput {
430
+ readonly id: string;
431
+ readonly scope: SessionScope;
432
+ readonly triggerKind: 'turn' | 'idle' | 'cron' | 'event' | 'budget' | 'manual';
433
+ readonly phase: 'light' | 'standard' | 'deep';
434
+ readonly startedAt: number;
435
+ }
436
+
437
+ /** @stable */
438
+ export interface ConsolidatorRunFinish {
439
+ readonly id: string;
440
+ readonly finishedAt: number;
441
+ readonly status: 'completed' | 'failed' | 'deferred' | 'partial';
442
+ readonly llmTokensUsed?: number;
443
+ readonly llmCostUsd?: number | null;
444
+ readonly factsCreated?: number;
445
+ readonly factsUpdated?: number;
446
+ readonly conflictsResolved?: number;
447
+ readonly noiseFilteredCount?: number;
448
+ readonly emptyExtractions?: number;
449
+ /** Episodes auto-formed by the run (P1-2 / MCON-17). */
450
+ readonly episodesFormed?: number;
451
+ /** Insights synthesized by the run's reflection pass (P1-1 / MCON-17). */
452
+ readonly insightsCreated?: number;
453
+ readonly errorMessage?: string | null;
454
+ readonly retryCount?: number;
455
+ }
456
+
457
+ /** @stable */
458
+ export interface DlqBatchInput {
459
+ readonly id: string;
460
+ readonly consolidatorRunId: string | null;
461
+ readonly scope: SessionScope;
462
+ readonly messageIds: ReadonlyArray<string>;
463
+ readonly errorKind: string;
464
+ readonly errorMessage: string;
465
+ readonly failedAt: number;
466
+ readonly nextRetryAt: number;
467
+ readonly retryCount: number;
468
+ /**
469
+ * Phase that failed (MCON-10) so `drainDlq` replays the SAME phase
470
+ * instead of inferring (the old inference hard-coded `'standard'`).
471
+ * Absent / `null` ⇒ legacy row, replayed as `'standard'`.
472
+ */
473
+ readonly phase?: 'light' | 'standard' | 'deep' | null;
474
+ }
475
+
476
+ /** @stable */
477
+ export interface DlqBatchRow {
478
+ readonly id: string;
479
+ readonly consolidatorRunId: string | null;
480
+ readonly scope: SessionScope;
481
+ readonly messageIds: ReadonlyArray<string>;
482
+ readonly errorKind: string;
483
+ readonly errorMessage: string;
484
+ readonly failedAt: number;
485
+ readonly nextRetryAt: number | null;
486
+ readonly retryCount: number;
487
+ /** Phase that failed (MCON-10); `null`/absent ⇒ legacy row. */
488
+ readonly phase?: 'light' | 'standard' | 'deep' | null;
489
+ }
490
+
491
+ /**
492
+ * Optional consolidator-state surface every storage adapter exposes
493
+ * for Phase 10c. Mirrors the `consolidator_state`,
494
+ * `consolidator_runs`, and `consolidator_failed_batches` tables
495
+ * shipped in Phase 05's migration 009. Adapters that do not
496
+ * implement the surface degrade gracefully - the consolidator runs
497
+ * in stateless mode (no DLQ, no cursor persistence) and emits a
498
+ * one-shot WARN.
499
+ *
500
+ * @stable
501
+ */
502
+ export interface ConsolidatorMemoryStoreExt {
503
+ getState(scope: SessionScope): Promise<ConsolidatorStateRow | null>;
504
+ upsertState(scope: SessionScope, patch: ConsolidatorStatePatch): Promise<ConsolidatorStateRow>;
505
+ /**
506
+ * Atomically claim the per-scope lock. Returns `true` when the
507
+ * row was either unlocked, owned by `runId`, or stale (the held
508
+ * timestamp is older than `maxAgeMs`); `false` otherwise. The
509
+ * `now` argument allows the lock manager to inject a deterministic
510
+ * clock during tests.
511
+ */
512
+ acquireLock(scope: SessionScope, runId: string, now: number, maxAgeMs: number): Promise<boolean>;
513
+ releaseLock(scope: SessionScope, runId: string): Promise<void>;
514
+
515
+ recordRunStart(input: ConsolidatorRunInput): Promise<void>;
516
+ recordRunFinish(finish: ConsolidatorRunFinish): Promise<void>;
517
+ listRecentRuns(
518
+ scope: SessionScope,
519
+ limit?: number,
520
+ ): Promise<
521
+ ReadonlyArray<{
522
+ readonly id: string;
523
+ readonly phase: 'light' | 'standard' | 'deep';
524
+ readonly status: string;
525
+ readonly startedAt: number;
526
+ readonly finishedAt: number | null;
527
+ readonly llmCostUsd: number | null;
528
+ readonly llmTokensUsed: number;
529
+ readonly factsCreated: number;
530
+ readonly factsUpdated: number;
531
+ }>
532
+ >;
533
+
534
+ enqueueFailedBatch(input: DlqBatchInput): Promise<void>;
535
+ /**
536
+ * Claim every DLQ row whose `nextRetryAt` is at or before `now`,
537
+ * up to `limit`. Returns the rows in failed-at order so the
538
+ * oldest backlog drains first.
539
+ */
540
+ claimReadyBatches(
541
+ scope: SessionScope,
542
+ now: number,
543
+ limit?: number,
544
+ ): Promise<ReadonlyArray<DlqBatchRow>>;
545
+ /** Mark the row succeeded - removes it from the DLQ. */
546
+ markBatchSucceeded(id: string): Promise<void>;
547
+ /**
548
+ * Schedule the next retry attempt. The caller computes
549
+ * `nextRetryAt` so the backoff schedule is centralized in the
550
+ * consolidator.
551
+ */
552
+ rescheduleBatch(id: string, retryCount: number, nextRetryAt: number): Promise<void>;
553
+ /**
554
+ * Mark the row exhausted (`retryCount` exceeded the configured
555
+ * cap). The row stays in the DLQ for operator inspection.
556
+ * Implementations MUST clear `nextRetryAt` so the row is no
557
+ * longer eligible for `claimReadyBatches`. The optional
558
+ * `retryCount` argument is recorded against the row so the
559
+ * persisted count reflects the final attempt that triggered the
560
+ * exhaustion.
561
+ */
562
+ markBatchExhausted(id: string, errorMessage: string, retryCount?: number): Promise<void>;
563
+ listFailedBatches(scope: SessionScope, limit?: number): Promise<ReadonlyArray<DlqBatchRow>>;
564
+ }
565
+
566
+ /**
567
+ * Decay-aware extension of the typed `SemanticMemoryStore`. Phase
568
+ * 10c's light phase reads the strength + last-accessed columns and
569
+ * archives facts whose retention curve falls below the configured
570
+ * threshold. Adapters that do not maintain decay columns may omit
571
+ * the surface entirely - the light phase skips the archive step
572
+ * with an INFO log.
573
+ *
574
+ * @stable
575
+ */
576
+ export interface DecayMemoryStoreExt {
577
+ /**
578
+ * List facts for the scope ordered by `lastAccessedAt` ASC so the
579
+ * caller can apply Ebbinghaus retention without scanning the
580
+ * whole table. `limit` defaults to `1000`.
581
+ *
582
+ * Archived rows are EXCLUDED by default (MCON-6) - they never receive
583
+ * access bumps, so they would pin the LRU head and saturate the decay
584
+ * window, structurally stopping threshold-archiving and capacity
585
+ * eviction for live facts. Inspection paths pass
586
+ * `{ includeArchived: true }`.
587
+ *
588
+ * `importance` / `status` / `provenance` (X-1) feed the multi-signal
589
+ * salience score that orders capacity-bounded eviction.
590
+ */
591
+ listForDecay(
592
+ scope: SessionScope,
593
+ limit?: number,
594
+ opts?: { readonly includeArchived?: boolean },
595
+ ): Promise<
596
+ ReadonlyArray<{
597
+ readonly id: string;
598
+ readonly text: string;
599
+ readonly strength: number;
600
+ readonly lastAccessedAt: number | null;
601
+ readonly createdAt: number;
602
+ readonly archived: boolean;
603
+ /** Importance hint in `[0, 1]`; `null` when unscored (X-1). */
604
+ readonly importance: number | null;
605
+ /** Retrieval-trust state (P1-4): `'active'` | `'quarantined'`. */
606
+ readonly status: string;
607
+ /** Trust-provenance tag (P1-4); `null` for first-party rows. */
608
+ readonly provenance: string | null;
609
+ /**
610
+ * Monotonic retrieval-access counter (D3, migration 027). Feeds
611
+ * the opt-in `accessReinforcement` salience weight. Optional -
612
+ * adapters without the column omit it (treated as `0`).
613
+ */
614
+ readonly accessCount?: number;
615
+ }>
616
+ >;
617
+ /**
618
+ * Soft-archive a fact (sets `archived = 1`). The audit row in
619
+ * `memory_history` records the archive event.
620
+ */
621
+ archiveFact(id: string, reason?: string, scope?: SessionScope): Promise<void>;
622
+ /**
623
+ * Record a retrieval access for the given facts (MRET-7): stamp
624
+ * `lastAccessedAt` and reinforce `strength` (implementation-capped).
625
+ * Optional - adapters without decay columns may omit it; callers
626
+ * MUST treat failures as non-fatal (the read path never breaks on a
627
+ * bookkeeping write).
628
+ */
629
+ markAccessed?(
630
+ ids: ReadonlyArray<string>,
631
+ accessedAt?: number,
632
+ scope?: SessionScope,
633
+ ): Promise<void>;
634
+ /**
635
+ * Narrow decay-column read for exactly the given fact ids (MRET-8) -
636
+ * powers per-search decay re-ranking without the old O(scope)
637
+ * 1000-row window read. Optional; absent ⇒ the tier falls back to
638
+ * `listForDecay`.
639
+ */
640
+ listDecaySignals?(ids: ReadonlyArray<string>): Promise<
641
+ ReadonlyArray<{
642
+ readonly id: string;
643
+ readonly strength: number;
644
+ readonly lastAccessedAt: number | null;
645
+ readonly createdAt: number;
646
+ }>
647
+ >;
648
+ }
649
+
650
+ /** Options accepted by {@link InsightMemoryStoreExt.list}. */
651
+ export interface InsightListOptions {
652
+ readonly limit?: number;
653
+ /** Include quarantined insights (validation / inspector path). */
654
+ readonly includeQuarantined?: boolean;
655
+ }
656
+
657
+ /** Options accepted by {@link InsightMemoryStoreExt.search}. */
658
+ export interface InsightSearchStoreOptions {
659
+ readonly topK?: number;
660
+ /** Include quarantined insights (validation / inspector path). */
661
+ readonly includeQuarantined?: boolean;
662
+ }
663
+
664
+ /**
665
+ * Optional storage extension for the reflection `insights` table
666
+ * (P1-1). The consolidator's reflection pass inserts quarantined,
667
+ * cited insights here; the thin `InsightMemory` read surface lists /
668
+ * searches them; the ExpeL salience loop bumps + prunes them. Search is
669
+ * FTS-only by design - insights are a soft, rank-capped inspector
670
+ * surface, not primary recall.
671
+ *
672
+ * Adapters that opt out leave the property undefined; reflection then
673
+ * degrades to a no-op (it never writes) and `InsightMemory`
674
+ * search/list return empty. The default `@graphorin/store-sqlite`
675
+ * adapter implements it.
676
+ *
677
+ * @stable
678
+ */
679
+ export interface InsightMemoryStoreExt {
680
+ /** Persist a synthesized insight (idempotent on `id`). */
681
+ insert(insight: Insight): Promise<void>;
682
+ /** Most-recent insights for the scope (newest first). */
683
+ list(scope: SessionScope, opts?: InsightListOptions): Promise<ReadonlyArray<Insight>>;
684
+ /** FTS keyword search over insight text. */
685
+ search(
686
+ scope: SessionScope,
687
+ query: string,
688
+ opts?: InsightSearchStoreOptions,
689
+ ): Promise<ReadonlyArray<MemoryHit<Insight>>>;
690
+ /** Lookup a single insight by id (`null` when absent / pruned). */
691
+ get?(id: string): Promise<Insight | null>;
692
+ /**
693
+ * Set an insight's retrieval-trust `status` (MCON-2) - promote a quarantined
694
+ * (reflection) insight or re-quarantine an active one, with a
695
+ * `memory_history` audit row. Powers {@link InsightMemory.validate}.
696
+ */
697
+ setStatus?(
698
+ id: string,
699
+ status: MemoryStatus,
700
+ reason?: string,
701
+ scope?: SessionScope,
702
+ ): Promise<void>;
703
+ /**
704
+ * Adjust an insight's ExpeL salience by `delta`, clamped at 0. The
705
+ * floor is the value at which {@link prune} removes it.
706
+ */
707
+ bumpSalience(id: string, delta: number, reason?: string): Promise<void>;
708
+ /**
709
+ * Soft-delete every salience-0 insight for the scope (the ExpeL
710
+ * forgetting step). Returns the number pruned. Tombstone only -
711
+ * pruned insights stay auditable.
712
+ */
713
+ prune(scope: SessionScope): Promise<number>;
714
+ }
715
+
716
+ /**
717
+ * Extension of the typed `ProceduralMemoryStore` with the optional
718
+ * promotion helper that storage adapters may expose (MCON-2).
719
+ *
720
+ * @stable
721
+ */
722
+ export interface ProceduralMemoryStoreExt extends ProceduralMemoryStore {
723
+ /**
724
+ * Set a rule's retrieval-trust `status` - promote a quarantined (induced)
725
+ * procedure into `activate()` or re-quarantine an active one, with a
726
+ * `memory_history` audit row. Powers {@link ProceduralMemory.validate}.
727
+ */
728
+ setStatus?(
729
+ id: string,
730
+ status: MemoryStatus,
731
+ reason?: string,
732
+ scope?: SessionScope,
733
+ ): Promise<void>;
734
+ /**
735
+ * Lexical runbook search over rule text (D3, migration 028) - content
736
+ * recall for "find the procedure for this task", as opposed to
737
+ * predicate activation. Quarantined (unvalidated induced) procedures
738
+ * are excluded unless the inspector opts in. Optional - adapters
739
+ * without the index omit it and {@link ProceduralMemory.search} falls
740
+ * back to an in-memory lexical scan over `list(...)`.
741
+ */
742
+ search?(
743
+ scope: SessionScope,
744
+ query: string,
745
+ opts?: { readonly topK?: number; readonly includeQuarantined?: boolean },
746
+ ): Promise<ReadonlyArray<MemoryHit<Rule>>>;
747
+ /**
748
+ * Record one demonstrated successful reuse of a rule and return the
749
+ * new counter value (MCON-2 part 4). Powers
750
+ * promotion-by-demonstrated-success via
751
+ * {@link ProceduralMemory.recordOutcome}. Optional - adapters without
752
+ * the counter simply never auto-promote.
753
+ */
754
+ recordSuccess?(id: string): Promise<number>;
755
+ }
756
+
757
+ /** Find-or-create payload for {@link GraphMemoryStoreExt.upsertEntity}. */
758
+ export interface EntityUpsertInput {
759
+ /** Display name as first observed. */
760
+ readonly name: string;
761
+ /** Folded key for lexical dedup + the canonical unique index. */
762
+ readonly normalizedName: string;
763
+ /** Optional name embedding (back-filled on a hit that lacked one). */
764
+ readonly vector?: Float32Array;
765
+ /** Embedder that produced {@link EntityUpsertInput.vector}. */
766
+ readonly embedderId?: string;
767
+ }
768
+
769
+ /**
770
+ * A canonical {@link GraphEntity} returned with its name embedding so the
771
+ * resolver can run cosine dedup in-process (entity counts are small).
772
+ */
773
+ export interface EntityWithEmbedding extends GraphEntity {
774
+ readonly vector: Float32Array | null;
775
+ readonly embedderId: string | null;
776
+ }
777
+
778
+ /** One row of the append-only merge / unmerge audit ledger (P2-1). */
779
+ export interface EntityMergeRecord {
780
+ readonly id: string;
781
+ readonly userId: string;
782
+ readonly kind: 'merge' | 'unmerge';
783
+ readonly fromEntityId: string;
784
+ readonly intoEntityId: string | null;
785
+ readonly reason?: string;
786
+ readonly createdAt: string;
787
+ }
788
+
789
+ /** Options for {@link GraphMemoryStoreExt.expandOneHop}. */
790
+ export interface ExpandHopsStoreOptions {
791
+ /** Traversal depth (default `1`). */
792
+ readonly maxHops?: number;
793
+ /** Max neighbours to return (default `60`). */
794
+ readonly limit?: number;
795
+ /** Include quarantined neighbours (validation / inspector path). */
796
+ readonly includeQuarantined?: boolean;
797
+ /** Point-in-time filter, ISO-8601 (same semantics as fact search). */
798
+ readonly asOf?: string;
799
+ /**
800
+ * Include superseded / validity-expired neighbours. Default reads
801
+ * evaluate validity at NOW (memory-retrieval-01).
802
+ */
803
+ readonly includeSuperseded?: boolean;
804
+ }
805
+
806
+ /**
807
+ * Optional storage extension for the lightweight in-SQLite relation
808
+ * graph (P2-1). Owns the canonical `entities` table, the `fact_entities`
809
+ * mapping, and the append-only `entity_merges` ledger. The entity
810
+ * *resolution policy* (lexical + embedding dedup, optional LLM
811
+ * adjudication) lives in `@graphorin/memory`; this surface is the pure
812
+ * persistence + the recursive-CTE traversal.
813
+ *
814
+ * Adapters that opt out leave the property undefined; entity resolution
815
+ * on write degrades to a no-op and `search({ expandHops })` skips
816
+ * expansion. The default `@graphorin/store-sqlite` adapter implements it.
817
+ *
818
+ * @stable
819
+ */
820
+ export interface GraphMemoryStoreExt {
821
+ /** Find-or-create the canonical (root) entity for the normalized name. */
822
+ upsertEntity(scope: SessionScope, input: EntityUpsertInput): Promise<string>;
823
+ /** Link a fact's subject / object to a canonical entity (idempotent). */
824
+ linkFactEntity(factId: string, entityId: string, role: EntityRole): Promise<void>;
825
+ /** Candidate entities for the resolver (roots only unless `includeMerged`). */
826
+ listEntities(
827
+ scope: SessionScope,
828
+ opts?: { readonly includeMerged?: boolean; readonly limit?: number },
829
+ ): Promise<ReadonlyArray<EntityWithEmbedding>>;
830
+ /**
831
+ * Uncapped indexed lookup of the canonical root for an exact normalized
832
+ * name. Lets the resolver dedup an exact alias of an arbitrarily-old
833
+ * entity without scanning (and deserializing) the bounded
834
+ * {@link listEntities} candidate window (CS-11). Optional: stores without
835
+ * it fall back to the capped lexical scan inside `resolveEntityDecision`.
836
+ */
837
+ findEntityByNormalizedName?(
838
+ scope: SessionScope,
839
+ normalizedName: string,
840
+ ): Promise<EntityWithEmbedding | null>;
841
+ /** Lookup one entity by id (any merge state). */
842
+ getEntity(scope: SessionScope, id: string): Promise<GraphEntity | null>;
843
+ /** Follow `mergedInto` to the canonical root id. */
844
+ resolveCanonical(scope: SessionScope, id: string): Promise<string>;
845
+ /** Merge `fromId` into `intoId`'s root; auditable + reversible. */
846
+ mergeEntities(
847
+ scope: SessionScope,
848
+ fromId: string,
849
+ intoId: string,
850
+ reason?: string,
851
+ ): Promise<void>;
852
+ /** Reverse a merge: make `id` a root again + record an audit row. */
853
+ unmergeEntity(scope: SessionScope, id: string, reason?: string): Promise<void>;
854
+ /** The append-only merge / unmerge ledger, newest first. */
855
+ listMerges(
856
+ scope: SessionScope,
857
+ opts?: { readonly limit?: number },
858
+ ): Promise<ReadonlyArray<EntityMergeRecord>>;
859
+ /** Expand seed facts to neighbours sharing a canonical entity (one-hop CTE). */
860
+ expandOneHop(
861
+ scope: SessionScope,
862
+ seedFactIds: ReadonlyArray<string>,
863
+ opts?: ExpandHopsStoreOptions,
864
+ ): Promise<ReadonlyArray<Fact>>;
865
+ /**
866
+ * PPR-lite graded expansion (D5): like {@link expandOneHop} but returns
867
+ * each neighbour with its minimum hop `depth` from the seeds, so the
868
+ * tier can weight it by damped spreading activation. Optional - stores
869
+ * without it fall back to flat one-hop expansion.
870
+ */
871
+ expandActivation?(
872
+ scope: SessionScope,
873
+ seedFactIds: ReadonlyArray<string>,
874
+ opts?: ExpandHopsStoreOptions,
875
+ ): Promise<ReadonlyArray<{ readonly fact: Fact; readonly depth: number }>>;
876
+ /**
877
+ * Exact entity-match retriever (D5): facts linked to the canonical
878
+ * entity for `normalizedName`. Optional. Powers a precise
879
+ * "facts about <entity>" candidate leg.
880
+ */
881
+ factsForEntityName?(
882
+ scope: SessionScope,
883
+ normalizedName: string,
884
+ opts?: ExpandHopsStoreOptions,
885
+ ): Promise<ReadonlyArray<Fact>>;
886
+ }
887
+
888
+ /**
889
+ * Composite shape every `@graphorin/memory` consumer must supply at
890
+ * construction time. Mirrors the typed `MemoryStore` from
891
+ * `@graphorin/core` but widens the per-tier sub-store types with the
892
+ * optional embedding-aware extension methods.
893
+ *
894
+ * Concrete adapters (most notably `@graphorin/store-sqlite`)
895
+ * implement every member by construction; in-memory test doubles
896
+ * implement the minimum and leave the optional members undefined.
897
+ *
898
+ * @stable
899
+ */
900
+ export interface MemoryStoreAdapter
901
+ extends Omit<MemoryStore, 'session' | 'episodic' | 'semantic' | 'procedural'> {
902
+ readonly session: SessionMemoryStoreExt;
903
+ readonly episodic: EpisodicMemoryStoreExt;
904
+ readonly semantic: SemanticMemoryStoreExt & Partial<DecayMemoryStoreExt>;
905
+ readonly procedural: ProceduralMemoryStoreExt;
906
+ /**
907
+ * Optional conflict audit + pending queue surface. Defined on the
908
+ * default `@graphorin/store-sqlite` adapter, omitted on the
909
+ * minimal in-memory test doubles.
910
+ *
911
+ * @stable
912
+ */
913
+ readonly conflicts?: ConflictMemoryStoreExt;
914
+ /**
915
+ * Optional consolidator state + runs + DLQ surface. Defined on
916
+ * the default `@graphorin/store-sqlite` adapter; in-memory test
917
+ * doubles may opt in via the fixture.
918
+ *
919
+ * @stable
920
+ */
921
+ readonly consolidator?: ConsolidatorMemoryStoreExt;
922
+ /**
923
+ * Optional reflection insight surface (P1-1). Defined on the default
924
+ * `@graphorin/store-sqlite` adapter; omitted ⇒ reflection is a no-op
925
+ * and `InsightMemory` reads return empty.
926
+ *
927
+ * @stable
928
+ */
929
+ readonly insights?: InsightMemoryStoreExt;
930
+ /**
931
+ * Optional relation-graph surface (P2-1). Defined on the default
932
+ * `@graphorin/store-sqlite` adapter; omitted ⇒ entity resolution on
933
+ * write is a no-op and `search({ expandHops })` skips expansion.
934
+ *
935
+ * @stable
936
+ */
937
+ readonly graph?: GraphMemoryStoreExt;
938
+ }
939
+
940
+ /**
941
+ * Re-export of session memory shape we use locally for narrower
942
+ * types inside the facade.
943
+ *
944
+ * @internal
945
+ */
946
+ export type SessionListResult = ReadonlyArray<Message>;
947
+
948
+ export type {
949
+ EmbedderProvider,
950
+ Episode,
951
+ EpisodicMemoryStore,
952
+ Fact,
953
+ Insight,
954
+ Message,
955
+ MessageRef,
956
+ ProceduralMemoryStore,
957
+ SemanticMemoryStore,
958
+ SessionListOptions,
959
+ SessionMemoryStore,
960
+ SessionScope,
961
+ SharedMemoryStore,
962
+ WorkingMemoryStore,
963
+ };