@remnic/core 9.3.742 → 9.3.744

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 (262) hide show
  1. package/dist/access-boundary.d.ts +6 -6
  2. package/dist/access-boundary.js +10 -10
  3. package/dist/access-cli.js +29 -29
  4. package/dist/access-http.d.ts +6 -6
  5. package/dist/access-http.js +15 -15
  6. package/dist/access-mcp.d.ts +6 -6
  7. package/dist/access-mcp.js +14 -14
  8. package/dist/access-operations-batch.js +12 -12
  9. package/dist/access-operations.d.ts +6 -6
  10. package/dist/access-operations.js +13 -13
  11. package/dist/{access-service-K8n12dXu.d.ts → access-service-OT3Gk79W.d.ts} +3 -3
  12. package/dist/access-service.d.ts +6 -6
  13. package/dist/access-service.js +9 -9
  14. package/dist/access-surface-catalog.d.ts +6 -6
  15. package/dist/action-confidence.d.ts +1 -1
  16. package/dist/active-memory-bridge.d.ts +1 -1
  17. package/dist/active-memory-bridge.js +3 -3
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/behavior-learner.d.ts +1 -1
  20. package/dist/behavior-signals.d.ts +1 -1
  21. package/dist/bootstrap.d.ts +5 -4
  22. package/dist/briefing.d.ts +1 -1
  23. package/dist/buffer-surprise-report.d.ts +1 -1
  24. package/dist/buffer.d.ts +1 -1
  25. package/dist/buffer.js +2 -2
  26. package/dist/calibration.d.ts +1 -1
  27. package/dist/capabilities.d.ts +10 -5
  28. package/dist/capabilities.js +1 -1
  29. package/dist/{catalog-_Bap6vfD.d.ts → catalog-CX0CjOaf.d.ts} +1 -1
  30. package/dist/causal-behavior.d.ts +1 -1
  31. package/dist/causal-consolidation.d.ts +1 -1
  32. package/dist/causal-consolidation.js +2 -2
  33. package/dist/causal-trajectory-graph.d.ts +1 -1
  34. package/dist/{chunk-X5PMDVY4.js → chunk-3EA5LIFJ.js} +4 -4
  35. package/dist/{chunk-YNHRWFAP.js → chunk-4DLFJJOQ.js} +2 -2
  36. package/dist/{chunk-WIMKOTNY.js → chunk-5QANTTY2.js} +2 -2
  37. package/dist/{chunk-AM7YKD7V.js → chunk-5UNSGRCR.js} +5 -5
  38. package/dist/{chunk-Y6PNYJVO.js → chunk-A2KKLCOS.js} +2 -2
  39. package/dist/{chunk-O4IWVWSW.js → chunk-AVBT5WEW.js} +3 -3
  40. package/dist/{chunk-QUNH5UZH.js → chunk-BYLC4DKI.js} +2 -2
  41. package/dist/{chunk-UOVDO6TC.js → chunk-CHELXDTO.js} +3 -3
  42. package/dist/{chunk-TQQN64J2.js → chunk-DBSMLRTO.js} +2 -2
  43. package/dist/{chunk-EZZUNKMJ.js → chunk-DYK27X7V.js} +3 -3
  44. package/dist/{chunk-K2N6WIZM.js → chunk-E7RGJQWP.js} +2 -2
  45. package/dist/{chunk-M4WI23X3.js → chunk-EEKDRAWX.js} +2 -2
  46. package/dist/{chunk-GFJ5ABKS.js → chunk-G5FP7VSQ.js} +11 -11
  47. package/dist/{chunk-BE6NEQLF.js → chunk-HAZVVOYT.js} +3 -3
  48. package/dist/{chunk-OT5K26NG.js → chunk-HM6UJPPO.js} +2 -2
  49. package/dist/{chunk-PI4JHLDD.js → chunk-IP5SANO2.js} +2 -2
  50. package/dist/{chunk-WHEF76BQ.js → chunk-JRZV3767.js} +2 -2
  51. package/dist/{chunk-OS5RKJOH.js → chunk-JZ7P26GF.js} +2 -2
  52. package/dist/{chunk-Y62QPRKV.js → chunk-K5LLP4CY.js} +2 -2
  53. package/dist/{chunk-C3Z5YJSM.js → chunk-LOPZ2DWR.js} +2 -2
  54. package/dist/{chunk-BJPL5WAL.js → chunk-MXDG6SRH.js} +3 -3
  55. package/dist/{chunk-UYYSOMS2.js → chunk-NBP3YHHS.js} +4 -4
  56. package/dist/{chunk-USHVHI6J.js → chunk-NNL4LJAD.js} +3 -3
  57. package/dist/{chunk-GPX5E36D.js → chunk-OSMBC3JU.js} +2 -2
  58. package/dist/{chunk-OUSOMUFV.js → chunk-PE6XR4GG.js} +2 -2
  59. package/dist/{chunk-CMPXLMC3.js → chunk-PI23H7FV.js} +3 -3
  60. package/dist/{chunk-WGDE2TJP.js → chunk-QOGXUNWL.js} +4 -4
  61. package/dist/{chunk-ELL5VYXC.js → chunk-RNWWAS5V.js} +3 -3
  62. package/dist/{chunk-7HUGLMSW.js → chunk-SODQQCAZ.js} +1013 -821
  63. package/dist/chunk-SODQQCAZ.js.map +1 -0
  64. package/dist/{chunk-JMMSVRF4.js → chunk-TQPSOTC7.js} +7 -7
  65. package/dist/{chunk-AX4TRSRE.js → chunk-U5WVRMCA.js} +2 -2
  66. package/dist/{chunk-7ADHJ6SU.js → chunk-VE54E6RP.js} +4 -4
  67. package/dist/{chunk-G7Q4D2G3.js → chunk-VSF7AAGE.js} +1 -3
  68. package/dist/chunk-VSF7AAGE.js.map +1 -0
  69. package/dist/{chunk-OVYBENIJ.js → chunk-W3M34XT4.js} +3 -3
  70. package/dist/{chunk-NHJYUIII.js → chunk-WPLRJ4XM.js} +7 -7
  71. package/dist/{chunk-UEIF7RWQ.js → chunk-XEADGIAA.js} +6 -6
  72. package/dist/{cli-BEOLy1xo.d.ts → cli-BQiTZ7Zs.d.ts} +3 -3
  73. package/dist/cli.d.ts +6 -6
  74. package/dist/cli.js +21 -21
  75. package/dist/compounding/engine.d.ts +1 -1
  76. package/dist/compounding/engine.js +3 -3
  77. package/dist/compounding/preference-consolidator.d.ts +1 -1
  78. package/dist/compression-optimizer.d.ts +1 -1
  79. package/dist/config.d.ts +1 -1
  80. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  81. package/dist/connectors/codex-materialize.d.ts +1 -1
  82. package/dist/connectors/index.d.ts +1 -1
  83. package/dist/connectors/index.js +2 -2
  84. package/dist/consolidation-provenance-check.d.ts +1 -1
  85. package/dist/consolidation-undo.d.ts +1 -1
  86. package/dist/contradiction/index.d.ts +1 -1
  87. package/dist/contradiction/index.js +2 -2
  88. package/dist/{contradiction-scan-UERKJESC.js → contradiction-scan-3FJYWS3G.js} +3 -3
  89. package/dist/conversation-index/backend.d.ts +1 -1
  90. package/dist/conversation-index/chunker.d.ts +1 -1
  91. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  92. package/dist/conversation-index/indexer.d.ts +1 -1
  93. package/dist/conversation-index/search.d.ts +1 -1
  94. package/dist/day-summary.d.ts +1 -1
  95. package/dist/day-summary.js +2 -2
  96. package/dist/delinearize.d.ts +1 -1
  97. package/dist/direct-answer-wiring.d.ts +1 -1
  98. package/dist/direct-answer.d.ts +1 -1
  99. package/dist/embedding-fallback.d.ts +1 -1
  100. package/dist/embedding-fallback.js +2 -2
  101. package/dist/enrichment/index.d.ts +1 -1
  102. package/dist/entity-retrieval.d.ts +1 -1
  103. package/dist/entity-retrieval.js +2 -2
  104. package/dist/entity-schema.d.ts +1 -1
  105. package/dist/explicit-capture.d.ts +5 -4
  106. package/dist/explicit-capture.js +2 -2
  107. package/dist/extraction-faithfulness.d.ts +1 -1
  108. package/dist/extraction-judge-telemetry.d.ts +1 -1
  109. package/dist/extraction-judge-training.d.ts +1 -1
  110. package/dist/extraction-judge.d.ts +1 -1
  111. package/dist/extraction.d.ts +1 -1
  112. package/dist/extraction.js +4 -4
  113. package/dist/fallback-llm.d.ts +1 -1
  114. package/dist/{first-start-migration-GQ3UQNIL.js → first-start-migration-4I3VDSYS.js} +2 -2
  115. package/dist/graph-dashboard-diff.d.ts +1 -1
  116. package/dist/graph-dashboard-key.d.ts +1 -1
  117. package/dist/graph-dashboard-parser.d.ts +1 -1
  118. package/dist/graph-edge-reinforcement.d.ts +1 -1
  119. package/dist/graph-snapshot.d.ts +1 -1
  120. package/dist/graph.d.ts +1 -1
  121. package/dist/identity-continuity.d.ts +1 -1
  122. package/dist/importance.d.ts +1 -1
  123. package/dist/index.d.ts +10 -10
  124. package/dist/index.js +36 -36
  125. package/dist/intent.d.ts +1 -1
  126. package/dist/lcm/engine.d.ts +1 -1
  127. package/dist/lcm/index.d.ts +1 -1
  128. package/dist/lcm/tools.d.ts +1 -1
  129. package/dist/lifecycle.d.ts +1 -1
  130. package/dist/live-connectors-runner.d.ts +1 -1
  131. package/dist/local-llm.d.ts +1 -1
  132. package/dist/local-llm.js +2 -2
  133. package/dist/local-model-endpoint.d.ts +1 -1
  134. package/dist/maintenance/memory-governance.d.ts +1 -1
  135. package/dist/mcp-memory-inspector-app.d.ts +6 -6
  136. package/dist/memory-action-policy.d.ts +1 -1
  137. package/dist/memory-cache.d.ts +1 -1
  138. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  139. package/dist/memory-projection-store.d.ts +1 -1
  140. package/dist/memory-provenance.d.ts +1 -1
  141. package/dist/memory-worth-outcomes.d.ts +1 -1
  142. package/dist/models-json.d.ts +1 -1
  143. package/dist/namespaces/migrate.d.ts +2 -2
  144. package/dist/namespaces/migrate.js +6 -6
  145. package/dist/namespaces/principal.d.ts +1 -1
  146. package/dist/namespaces/principal.js +2 -2
  147. package/dist/namespaces/search.d.ts +1 -1
  148. package/dist/namespaces/search.js +4 -4
  149. package/dist/namespaces/storage.d.ts +2 -2
  150. package/dist/namespaces/storage.js +2 -2
  151. package/dist/native-knowledge.d.ts +1 -1
  152. package/dist/operator-toolkit.d.ts +1 -1
  153. package/dist/operator-toolkit.js +11 -11
  154. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  155. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  156. package/dist/orchestration/maintenance.d.ts +2 -2
  157. package/dist/orchestration/maintenance.js +6 -6
  158. package/dist/{orchestrator-Dr-1v5EL.d.ts → orchestrator-BPQGHpJz.d.ts} +263 -31
  159. package/dist/orchestrator.d.ts +5 -4
  160. package/dist/orchestrator.js +24 -24
  161. package/dist/patterns-cli.d.ts +1 -1
  162. package/dist/policy-runtime.d.ts +1 -1
  163. package/dist/provenance.d.ts +1 -1
  164. package/dist/qmd-recall-cache.d.ts +1 -1
  165. package/dist/qmd.d.ts +1 -1
  166. package/dist/recall-disclosure-escalation.d.ts +1 -1
  167. package/dist/recall-explain-renderer.d.ts +1 -1
  168. package/dist/recall-planner-llm.d.ts +1 -1
  169. package/dist/recall-state.d.ts +1 -1
  170. package/dist/recall-tag-filter.d.ts +1 -1
  171. package/dist/recall-xray-cli.d.ts +1 -1
  172. package/dist/recall-xray-renderer.d.ts +1 -1
  173. package/dist/recall-xray.d.ts +1 -1
  174. package/dist/resolve-auth-token.d.ts +1 -1
  175. package/dist/retrieval-agents.d.ts +1 -1
  176. package/dist/retrieval-tiers.d.ts +1 -1
  177. package/dist/routing/engine.d.ts +1 -1
  178. package/dist/routing/store.d.ts +1 -1
  179. package/dist/search/embed-helper.d.ts +1 -1
  180. package/dist/search/embed-helper.js +2 -2
  181. package/dist/search/factory.d.ts +1 -1
  182. package/dist/search/factory.js +3 -3
  183. package/dist/search/index.d.ts +1 -1
  184. package/dist/search/index.js +3 -3
  185. package/dist/search/lancedb-backend.d.ts +1 -1
  186. package/dist/search/meilisearch-backend.d.ts +1 -1
  187. package/dist/search/noop-backend.d.ts +1 -1
  188. package/dist/search/orama-backend.d.ts +1 -1
  189. package/dist/search/port.d.ts +1 -1
  190. package/dist/search/remote-backend.d.ts +1 -1
  191. package/dist/{semantic-consolidation-DsIEiCka.d.ts → semantic-consolidation-ByzGwC9c.d.ts} +1 -1
  192. package/dist/semantic-consolidation.d.ts +2 -2
  193. package/dist/semantic-consolidation.js +2 -2
  194. package/dist/semantic-rule-verifier.d.ts +1 -1
  195. package/dist/session-observer-bands.d.ts +1 -1
  196. package/dist/session-observer-state.d.ts +1 -1
  197. package/dist/shared-context/manager.d.ts +1 -1
  198. package/dist/shared-context/manager.js +2 -2
  199. package/dist/signal.d.ts +1 -1
  200. package/dist/storage.d.ts +1 -1
  201. package/dist/summarizer.d.ts +1 -1
  202. package/dist/summarizer.js +3 -3
  203. package/dist/summary-snapshot.d.ts +1 -1
  204. package/dist/temporal-supersession.d.ts +1 -1
  205. package/dist/temporal-validity.d.ts +1 -1
  206. package/dist/threading.d.ts +1 -1
  207. package/dist/tier-migration.d.ts +1 -1
  208. package/dist/tier-routing.d.ts +1 -1
  209. package/dist/{tier-stats-CSKL7BDG.js → tier-stats-5XF4UBRQ.js} +2 -2
  210. package/dist/topics.d.ts +1 -1
  211. package/dist/transcript.d.ts +1 -1
  212. package/dist/trust-score-stage.d.ts +1 -1
  213. package/dist/trust-score.d.ts +1 -1
  214. package/dist/{types-CglNn2V-.d.ts → types-5Jik3r4G.d.ts} +1 -1
  215. package/dist/types.d.ts +1 -1
  216. package/dist/utility-runtime.d.ts +1 -1
  217. package/package.json +2 -2
  218. package/src/capabilities.test.ts +0 -2
  219. package/src/capabilities.ts +7 -6
  220. package/src/orchestration/contradiction-linking-coordinator.ts +336 -0
  221. package/src/orchestration/graph-recall-coordinator.ts +471 -0
  222. package/src/orchestration/recall-section-coordinator.ts +349 -0
  223. package/src/orchestrator.ts +97 -741
  224. package/dist/chunk-7HUGLMSW.js.map +0 -1
  225. package/dist/chunk-G7Q4D2G3.js.map +0 -1
  226. /package/dist/{chunk-X5PMDVY4.js.map → chunk-3EA5LIFJ.js.map} +0 -0
  227. /package/dist/{chunk-YNHRWFAP.js.map → chunk-4DLFJJOQ.js.map} +0 -0
  228. /package/dist/{chunk-WIMKOTNY.js.map → chunk-5QANTTY2.js.map} +0 -0
  229. /package/dist/{chunk-AM7YKD7V.js.map → chunk-5UNSGRCR.js.map} +0 -0
  230. /package/dist/{chunk-Y6PNYJVO.js.map → chunk-A2KKLCOS.js.map} +0 -0
  231. /package/dist/{chunk-O4IWVWSW.js.map → chunk-AVBT5WEW.js.map} +0 -0
  232. /package/dist/{chunk-QUNH5UZH.js.map → chunk-BYLC4DKI.js.map} +0 -0
  233. /package/dist/{chunk-UOVDO6TC.js.map → chunk-CHELXDTO.js.map} +0 -0
  234. /package/dist/{chunk-TQQN64J2.js.map → chunk-DBSMLRTO.js.map} +0 -0
  235. /package/dist/{chunk-EZZUNKMJ.js.map → chunk-DYK27X7V.js.map} +0 -0
  236. /package/dist/{chunk-K2N6WIZM.js.map → chunk-E7RGJQWP.js.map} +0 -0
  237. /package/dist/{chunk-M4WI23X3.js.map → chunk-EEKDRAWX.js.map} +0 -0
  238. /package/dist/{chunk-GFJ5ABKS.js.map → chunk-G5FP7VSQ.js.map} +0 -0
  239. /package/dist/{chunk-BE6NEQLF.js.map → chunk-HAZVVOYT.js.map} +0 -0
  240. /package/dist/{chunk-OT5K26NG.js.map → chunk-HM6UJPPO.js.map} +0 -0
  241. /package/dist/{chunk-PI4JHLDD.js.map → chunk-IP5SANO2.js.map} +0 -0
  242. /package/dist/{chunk-WHEF76BQ.js.map → chunk-JRZV3767.js.map} +0 -0
  243. /package/dist/{chunk-OS5RKJOH.js.map → chunk-JZ7P26GF.js.map} +0 -0
  244. /package/dist/{chunk-Y62QPRKV.js.map → chunk-K5LLP4CY.js.map} +0 -0
  245. /package/dist/{chunk-C3Z5YJSM.js.map → chunk-LOPZ2DWR.js.map} +0 -0
  246. /package/dist/{chunk-BJPL5WAL.js.map → chunk-MXDG6SRH.js.map} +0 -0
  247. /package/dist/{chunk-UYYSOMS2.js.map → chunk-NBP3YHHS.js.map} +0 -0
  248. /package/dist/{chunk-USHVHI6J.js.map → chunk-NNL4LJAD.js.map} +0 -0
  249. /package/dist/{chunk-GPX5E36D.js.map → chunk-OSMBC3JU.js.map} +0 -0
  250. /package/dist/{chunk-OUSOMUFV.js.map → chunk-PE6XR4GG.js.map} +0 -0
  251. /package/dist/{chunk-CMPXLMC3.js.map → chunk-PI23H7FV.js.map} +0 -0
  252. /package/dist/{chunk-WGDE2TJP.js.map → chunk-QOGXUNWL.js.map} +0 -0
  253. /package/dist/{chunk-ELL5VYXC.js.map → chunk-RNWWAS5V.js.map} +0 -0
  254. /package/dist/{chunk-JMMSVRF4.js.map → chunk-TQPSOTC7.js.map} +0 -0
  255. /package/dist/{chunk-AX4TRSRE.js.map → chunk-U5WVRMCA.js.map} +0 -0
  256. /package/dist/{chunk-7ADHJ6SU.js.map → chunk-VE54E6RP.js.map} +0 -0
  257. /package/dist/{chunk-OVYBENIJ.js.map → chunk-W3M34XT4.js.map} +0 -0
  258. /package/dist/{chunk-NHJYUIII.js.map → chunk-WPLRJ4XM.js.map} +0 -0
  259. /package/dist/{chunk-UEIF7RWQ.js.map → chunk-XEADGIAA.js.map} +0 -0
  260. /package/dist/{contradiction-scan-UERKJESC.js.map → contradiction-scan-3FJYWS3G.js.map} +0 -0
  261. /package/dist/{first-start-migration-GQ3UQNIL.js.map → first-start-migration-4I3VDSYS.js.map} +0 -0
  262. /package/dist/{tier-stats-CSKL7BDG.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Contradiction-linking coordinator — extracted from the orchestrator (issue #1526).
3
+ *
4
+ * Owns the write-path semantic-analysis subsystem: contradiction detection
5
+ * (QMD similarity search + LLM verification), deferred contradiction
6
+ * auto-resolve (#1645 — retires superseded memories only after the new write's
7
+ * tombstone status is known), and memory link suggestion. Behavior-preserving
8
+ * move from orchestrator.ts — no logic changes; the orchestrator constructs one
9
+ * instance and keeps thin delegating methods so existing call sites (writeMemory
10
+ * fact-write branches) continue to work.
11
+ *
12
+ * Config, storage, search, namespace resolution, and the extraction engine are
13
+ * accessed through getter callbacks (not captured at construction) so that
14
+ * post-construction reassignment of the orchestrator's live fields is honored.
15
+ * This mirrors the RecallRerankCoordinator / ConversationIndexCoordinator
16
+ * accessor pattern.
17
+ */
18
+
19
+ import type {
20
+ MemoryLink,
21
+ PluginConfig,
22
+ QmdSearchResult,
23
+ } from "../types.js";
24
+ // StorageManager type comes from the package barrel (type-only) so this
25
+ // module does not add a direct storage.ts import (ratchet #1533).
26
+ import type { StorageManager } from "../index.js";
27
+ import type { ExtractionEngine } from "../extraction.js";
28
+ import { log } from "../logger.js";
29
+ import { resolveIndexingCapabilities } from "../capabilities.js";
30
+ import { deindexMemory } from "../temporal-index.js";
31
+
32
+ /** Result type of {@link ContradictionLinkingCoordinator.checkForContradiction}. */
33
+ export interface ContradictionResult {
34
+ supersededId: string;
35
+ confidence: number;
36
+ reason: string;
37
+ supersededPath: string;
38
+ supersededCreated: string;
39
+ supersededTags: string[];
40
+ }
41
+
42
+ /**
43
+ * Subset of {@link ContradictionResult} used by
44
+ * {@link ContradictionLinkingCoordinator.applyDeferredContradictionResolve}.
45
+ * The deferred resolve runs AFTER writeMemory and only needs the supersede
46
+ * target fields (not confidence, which the caller already consumed).
47
+ */
48
+ export interface ContradictionResolveTarget {
49
+ supersededId: string;
50
+ reason: string;
51
+ supersededPath: string;
52
+ supersededCreated: string;
53
+ supersededTags: string[];
54
+ }
55
+
56
+ /**
57
+ * Coordinator for the contradiction-detection + memory-linking subsystem.
58
+ *
59
+ * The three methods mirror the orchestrator's former private methods
60
+ * `checkForContradiction`, `applyDeferredContradictionResolve`, and
61
+ * `suggestLinksForMemory` byte-for-byte in logic.
62
+ */
63
+ export class ContradictionLinkingCoordinator {
64
+ private readonly getConfig: () => PluginConfig;
65
+ private readonly isSearchAvailable: () => boolean;
66
+ private readonly searchAcrossNamespaces: (options: {
67
+ query: string;
68
+ namespaces?: string[];
69
+ maxResults?: number;
70
+ mode?: "search" | "hybrid" | "bm25" | "vector";
71
+ }) => Promise<QmdSearchResult[]>;
72
+ private readonly extractMemoryIdsFromResults: (
73
+ results: QmdSearchResult[],
74
+ ) => string[];
75
+ private readonly namespaceFromPath: (p: string) => string;
76
+ private readonly storageForNamespace: (
77
+ namespace: string,
78
+ ) => Promise<StorageManager>;
79
+ private readonly getExtraction: () => ExtractionEngine;
80
+
81
+ constructor(options: {
82
+ getConfig: () => PluginConfig;
83
+ isSearchAvailable: () => boolean;
84
+ searchAcrossNamespaces: (options: {
85
+ query: string;
86
+ namespaces?: string[];
87
+ maxResults?: number;
88
+ mode?: "search" | "hybrid" | "bm25" | "vector";
89
+ }) => Promise<QmdSearchResult[]>;
90
+ extractMemoryIdsFromResults: (results: QmdSearchResult[]) => string[];
91
+ namespaceFromPath: (p: string) => string;
92
+ storageForNamespace: (namespace: string) => Promise<StorageManager>;
93
+ getExtraction: () => ExtractionEngine;
94
+ }) {
95
+ this.getConfig = options.getConfig;
96
+ this.isSearchAvailable = options.isSearchAvailable;
97
+ this.searchAcrossNamespaces = options.searchAcrossNamespaces;
98
+ this.extractMemoryIdsFromResults = options.extractMemoryIdsFromResults;
99
+ this.namespaceFromPath = options.namespaceFromPath;
100
+ this.storageForNamespace = options.storageForNamespace;
101
+ this.getExtraction = options.getExtraction;
102
+ }
103
+
104
+ /**
105
+ * Check if a new memory contradicts an existing one.
106
+ * Uses QMD to find similar memories, then LLM to verify contradiction.
107
+ */
108
+ async checkForContradiction(
109
+ content: string,
110
+ category: string,
111
+ namespaceScope: string,
112
+ ): Promise<ContradictionResult | null> {
113
+ if (!this.isSearchAvailable()) return null;
114
+
115
+ const config = this.getConfig();
116
+
117
+ // Search for similar memories
118
+ const results = await this.searchAcrossNamespaces({
119
+ query: content,
120
+ namespaces: [namespaceScope],
121
+ maxResults: 5,
122
+ mode: "search",
123
+ });
124
+
125
+ for (const result of results) {
126
+ // Check similarity threshold
127
+ if (result.score < config.contradictionSimilarityThreshold) {
128
+ continue;
129
+ }
130
+
131
+ // Get the existing memory
132
+ const memoryId = this.extractMemoryIdsFromResults([result])[0];
133
+ if (!memoryId) continue;
134
+
135
+ const resultNamespace = this.namespaceFromPath(result.path);
136
+ if (resultNamespace !== namespaceScope) continue;
137
+ const resultStorage = await this.storageForNamespace(resultNamespace);
138
+ const existingMemory = await resultStorage.getMemoryById(memoryId);
139
+ if (!existingMemory) continue;
140
+
141
+ // Skip memories already resolved or explicitly forgotten. Other
142
+ // non-active statuses remain valid contradiction candidates.
143
+ if (
144
+ existingMemory.frontmatter.status === "superseded" ||
145
+ existingMemory.frontmatter.status === "forgotten"
146
+ ) {
147
+ continue;
148
+ }
149
+
150
+ // Verify contradiction with LLM
151
+ const extraction = this.getExtraction();
152
+ const verification = await extraction.verifyContradiction(
153
+ { content, category },
154
+ {
155
+ id: existingMemory.frontmatter.id,
156
+ content: existingMemory.content,
157
+ category: existingMemory.frontmatter.category,
158
+ created: existingMemory.frontmatter.created,
159
+ },
160
+ );
161
+
162
+ if (!verification) continue;
163
+
164
+ // Check if it's a real contradiction with high confidence
165
+ if (
166
+ verification.isContradiction &&
167
+ verification.confidence >= config.contradictionMinConfidence
168
+ ) {
169
+ // When the LLM says the existing memory is newer (whichIsNewer ===
170
+ // "first") the incoming fact is the stale one in both resolve modes —
171
+ // log and continue so the caller never marks contradictionDetected and
172
+ // the semantic-skip gate can discard the outdated write normally.
173
+ if (verification.whichIsNewer === "first") {
174
+ log.info(
175
+ `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory — existing is newer, incoming fact is stale`,
176
+ );
177
+ continue;
178
+ }
179
+
180
+ // The new fact is newer than the existing one. When auto-resolve is
181
+ // enabled, the caller retires the old memory AFTER the new write lands
182
+ // and its tombstone status is known (#1645: defer auto-resolve until
183
+ // tombstone status is known — a tombstone-blocked new write must not
184
+ // retire the only active copy, leaving neither memory active). When
185
+ // disabled, the old memory stays active for manual review. The
186
+ // contradiction info is returned in both cases so the caller can apply
187
+ // the deferred retire post-write.
188
+
189
+ // Return the contradiction info regardless of auto-resolve setting.
190
+ // The caller uses this to set `contradictionDetected=true` which
191
+ // prevents the semantic-skip guard from silently dropping a
192
+ // legitimately contradictory update (the regression this fixes).
193
+ log.info(
194
+ `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`,
195
+ );
196
+ return {
197
+ supersededId: existingMemory.frontmatter.id,
198
+ confidence: verification.confidence,
199
+ reason: verification.reasoning,
200
+ supersededPath: existingMemory.path,
201
+ supersededCreated: existingMemory.frontmatter.created,
202
+ supersededTags: existingMemory.frontmatter.tags ?? [],
203
+ };
204
+ }
205
+ }
206
+
207
+ return null;
208
+ }
209
+
210
+ /**
211
+ * #1645: Complete the deferred contradiction auto-resolve after writeMemory
212
+ * returns and the new write's tombstone status is known. Retires the old
213
+ * memory + deindexes it ONLY when the new write is genuinely active (not
214
+ * tombstone-blocked / pending_review). A blocked write must not retire the
215
+ * only active copy — deferring here closes the "contradictionAutoResolve
216
+ * supersedes before tombstone status is known" defect class.
217
+ */
218
+ async applyDeferredContradictionResolve(
219
+ contradiction: ContradictionResolveTarget | null | undefined,
220
+ storage: StorageManager,
221
+ newMemoryId: string,
222
+ postWriteGuard: boolean,
223
+ ): Promise<void> {
224
+ const config = this.getConfig();
225
+ // #1645 yG2: clear the pre-write `supersedes` link from a blocked row so
226
+ // it doesn't claim to supersede a still-active memory (best-effort).
227
+ if (postWriteGuard && contradiction && config.contradictionAutoResolve) {
228
+ try {
229
+ const blockedRow = await storage.getMemoryById(newMemoryId);
230
+ if (blockedRow?.frontmatter?.supersedes) {
231
+ await storage.writeMemoryFrontmatter(blockedRow, { supersedes: undefined });
232
+ }
233
+ } catch (err) {
234
+ log.warn(
235
+ `contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`,
236
+ );
237
+ }
238
+ }
239
+ if (
240
+ !contradiction ||
241
+ !config.contradictionAutoResolve ||
242
+ postWriteGuard
243
+ ) {
244
+ return;
245
+ }
246
+ try {
247
+ await storage.supersedeMemory(
248
+ contradiction.supersededId,
249
+ newMemoryId,
250
+ contradiction.reason,
251
+ );
252
+ if (
253
+ resolveIndexingCapabilities(config).queryAwareIndexing &&
254
+ contradiction.supersededPath
255
+ ) {
256
+ deindexMemory(
257
+ config.memoryDir,
258
+ contradiction.supersededPath,
259
+ contradiction.supersededCreated,
260
+ contradiction.supersededTags,
261
+ );
262
+ }
263
+ } catch (err) {
264
+ log.warn(
265
+ `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`,
266
+ );
267
+ }
268
+ }
269
+
270
+ // ---------------------------------------------------------------------------
271
+ // Memory Linking (Phase 3A)
272
+ // ---------------------------------------------------------------------------
273
+
274
+ /**
275
+ * Suggest links for a new memory based on similar existing memories.
276
+ */
277
+ async suggestLinksForMemory(
278
+ content: string,
279
+ category: string,
280
+ namespaceScope: string,
281
+ ): Promise<MemoryLink[]> {
282
+ if (!this.isSearchAvailable()) return [];
283
+
284
+ // Search for related memories
285
+ const results = await this.searchAcrossNamespaces({
286
+ query: content,
287
+ namespaces: [namespaceScope],
288
+ maxResults: 5,
289
+ mode: "search",
290
+ });
291
+ if (results.length === 0) return [];
292
+
293
+ // Get full memory details for candidates
294
+ const candidates: Array<{ id: string; content: string; category: string }> =
295
+ [];
296
+ for (const result of results) {
297
+ const memoryId = this.extractMemoryIdsFromResults([result])[0];
298
+ if (!memoryId) continue;
299
+
300
+ const resultNamespace = this.namespaceFromPath(result.path);
301
+ if (resultNamespace !== namespaceScope) continue;
302
+ const resultStorage = await this.storageForNamespace(resultNamespace);
303
+ const memory = await resultStorage.getMemoryById(memoryId);
304
+ if (
305
+ memory &&
306
+ memory.frontmatter.status !== "superseded" &&
307
+ memory.frontmatter.status !== "forgotten"
308
+ ) {
309
+ candidates.push({
310
+ id: memory.frontmatter.id,
311
+ content: memory.content,
312
+ category: memory.frontmatter.category,
313
+ });
314
+ }
315
+ }
316
+
317
+ if (candidates.length === 0) return [];
318
+
319
+ // Ask LLM for link suggestions
320
+ const extraction = this.getExtraction();
321
+ const suggestions = await extraction.suggestLinks(
322
+ { content, category },
323
+ candidates,
324
+ );
325
+
326
+ if (!suggestions || suggestions.links.length === 0) return [];
327
+
328
+ // Convert to MemoryLink format
329
+ return suggestions.links.map((link) => ({
330
+ targetId: link.targetId,
331
+ linkType: link.linkType,
332
+ strength: link.strength,
333
+ reason: link.reason || undefined,
334
+ }));
335
+ }
336
+ }