@remnic/core 9.50.3 → 9.51.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 (486) hide show
  1. package/dist/access-admin-ops-surface.d.ts +13 -11
  2. package/dist/access-admin-ops-surface.js +41 -39
  3. package/dist/access-authorization-probe.d.ts +13 -11
  4. package/dist/access-authorization-probe.js +42 -40
  5. package/dist/access-boundary.d.ts +13 -11
  6. package/dist/access-boundary.js +41 -39
  7. package/dist/access-cli.js +109 -104
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +3 -1
  10. package/dist/access-extraction-force-flush.d.ts +13 -11
  11. package/dist/access-extraction-force-flush.js +41 -39
  12. package/dist/access-health-types.d.ts +3 -1
  13. package/dist/access-http-lcm-compaction.d.ts +13 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +13 -11
  15. package/dist/access-http-offline-stream.d.ts +13 -11
  16. package/dist/access-http-query.js +41 -39
  17. package/dist/access-http.d.ts +13 -11
  18. package/dist/access-http.js +52 -50
  19. package/dist/access-identity-continuity-surface.d.ts +11 -9
  20. package/dist/access-identity-continuity-surface.js +41 -39
  21. package/dist/access-lcm-surface.d.ts +13 -11
  22. package/dist/access-lcm-surface.js +41 -39
  23. package/dist/access-mcp.d.ts +13 -11
  24. package/dist/access-mcp.js +47 -45
  25. package/dist/access-memory-search-fanout.d.ts +4 -2
  26. package/dist/{access-namespace-preflight-Dj2QolFE.d.ts → access-namespace-preflight-Ds6CGlCP.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +5 -3
  28. package/dist/access-namespace-preflight.js +41 -39
  29. package/dist/access-observe-write-surface.d.ts +13 -11
  30. package/dist/access-observe-write-surface.js +41 -39
  31. package/dist/access-offline-manifest.d.ts +11 -9
  32. package/dist/access-operations-batch.js +43 -41
  33. package/dist/access-operations.d.ts +16 -14
  34. package/dist/access-operations.js +46 -44
  35. package/dist/access-recall-concurrency.d.ts +13 -11
  36. package/dist/access-recall-concurrency.js +41 -39
  37. package/dist/access-recall-response.d.ts +13 -11
  38. package/dist/access-recall-response.js +41 -39
  39. package/dist/access-recall-surface.d.ts +13 -11
  40. package/dist/access-recall-surface.js +41 -39
  41. package/dist/access-schema.d.ts +88 -88
  42. package/dist/access-schema.js +3 -3
  43. package/dist/{access-service-DesbnTSa.d.ts → access-service-BY0KJ44c.d.ts} +7 -7
  44. package/dist/access-service-helpers.d.ts +13 -11
  45. package/dist/access-service.d.ts +13 -11
  46. package/dist/access-service.js +41 -39
  47. package/dist/access-surface-catalog.d.ts +13 -11
  48. package/dist/access-wearables-meetings-surface.d.ts +5 -3
  49. package/dist/action-confidence.d.ts +3 -1
  50. package/dist/active-memory-bridge.d.ts +3 -1
  51. package/dist/active-recall.d.ts +3 -1
  52. package/dist/active-recall.js +5 -3
  53. package/dist/active-recall.js.map +1 -1
  54. package/dist/adapters/index.js +4 -4
  55. package/dist/adapters/registry.js +2 -2
  56. package/dist/ambient-provenance.d.ts +3 -1
  57. package/dist/archive-mutation-version.d.ts +9 -0
  58. package/dist/archive-mutation-version.js +20 -0
  59. package/dist/artifact-search.d.ts +3 -1
  60. package/dist/behavior-learner.d.ts +3 -1
  61. package/dist/behavior-signals.d.ts +3 -1
  62. package/dist/bootstrap.d.ts +11 -9
  63. package/dist/briefing.d.ts +4 -2
  64. package/dist/briefing.js +10 -9
  65. package/dist/buffer-surprise-report.d.ts +3 -1
  66. package/dist/buffer-turn-helpers.d.ts +3 -1
  67. package/dist/buffer.d.ts +4 -2
  68. package/dist/buffer.js +5 -5
  69. package/dist/bulk-import/index.d.ts +5 -3
  70. package/dist/calibration.d.ts +3 -1
  71. package/dist/capabilities.d.ts +3 -1
  72. package/dist/{catalog-D-G7RgXR.d.ts → catalog-D3B4RDy1.d.ts} +1 -1
  73. package/dist/causal-behavior.d.ts +3 -1
  74. package/dist/causal-behavior.js +2 -2
  75. package/dist/causal-chain.js +2 -2
  76. package/dist/causal-consolidation.d.ts +3 -1
  77. package/dist/causal-consolidation.js +13 -12
  78. package/dist/causal-consolidation.js.map +1 -1
  79. package/dist/causal-retrieval.js +2 -2
  80. package/dist/causal-trajectory-graph.d.ts +4 -2
  81. package/dist/causal-trajectory-graph.js +2 -1
  82. package/dist/causal-trajectory-graph.js.map +1 -1
  83. package/dist/causal-trajectory.js +1 -1
  84. package/dist/{chunk-KDG2KTWW.js → chunk-33SV3E43.js} +4 -4
  85. package/dist/{chunk-2HGUDBRJ.js → chunk-37ZO6LLJ.js} +2 -2
  86. package/dist/{chunk-QW3WFHKU.js → chunk-45BRYON6.js} +2 -2
  87. package/dist/{chunk-GZICBRWK.js → chunk-4F6X3RXW.js} +2 -2
  88. package/dist/{chunk-7BAYBYY5.js → chunk-4PC4PRJE.js} +2 -2
  89. package/dist/{chunk-VJXY5ZCT.js → chunk-52UKFTUK.js} +2 -2
  90. package/dist/{chunk-ESG7Z255.js → chunk-5UDMFE3Q.js} +2 -2
  91. package/dist/{chunk-JPHEOE6Z.js → chunk-6MTSFX7A.js} +15 -15
  92. package/dist/chunk-6ZN34ISG.js +44 -0
  93. package/dist/chunk-6ZN34ISG.js.map +1 -0
  94. package/dist/{chunk-M4MP34AQ.js → chunk-AHZOMHWN.js} +1 -1
  95. package/dist/{chunk-Z3RHPGSY.js → chunk-AIUBBHSF.js} +3 -3
  96. package/dist/{chunk-S3AYIQCU.js → chunk-AXIDQG5A.js} +12 -12
  97. package/dist/{chunk-QN7NTKRC.js → chunk-AZ2QBGYB.js} +1 -1
  98. package/dist/{chunk-47J4EDGR.js → chunk-AZM4CCAC.js} +8 -8
  99. package/dist/{chunk-IXXABW5A.js → chunk-BHXYAVUM.js} +11 -5
  100. package/dist/chunk-BHXYAVUM.js.map +1 -0
  101. package/dist/{chunk-L2DPF4DF.js → chunk-BIJAWZYW.js} +54 -12
  102. package/dist/chunk-BIJAWZYW.js.map +1 -0
  103. package/dist/{chunk-LEJPSMKM.js → chunk-C5QLI33R.js} +3 -3
  104. package/dist/{chunk-SV3PSA7Y.js → chunk-CV6BBVYV.js} +5 -5
  105. package/dist/{chunk-V7X767RT.js → chunk-DCZBSE4F.js} +52 -52
  106. package/dist/chunk-FC67T4E6.js +70 -0
  107. package/dist/chunk-FC67T4E6.js.map +1 -0
  108. package/dist/{chunk-7PKFPLLZ.js → chunk-FXTYIA46.js} +2 -2
  109. package/dist/{chunk-64BHFFKZ.js → chunk-HLYR2TQL.js} +5 -5
  110. package/dist/{chunk-5C2HNJMO.js → chunk-J5LLX6IL.js} +32 -32
  111. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  112. package/dist/{chunk-PLKFO2HJ.js → chunk-JL43BVDE.js} +2 -2
  113. package/dist/{chunk-2S72LWKX.js → chunk-JYL3BVVZ.js} +2 -2
  114. package/dist/{chunk-IPLYGWQF.js → chunk-KQAFEZQX.js} +5 -5
  115. package/dist/chunk-LXY5VVGM.js +61 -0
  116. package/dist/chunk-LXY5VVGM.js.map +1 -0
  117. package/dist/{chunk-PYKKWQZ2.js → chunk-M7BXDKPR.js} +6 -6
  118. package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
  119. package/dist/{chunk-LYMNZZIM.js → chunk-NIS256NW.js} +2 -2
  120. package/dist/{chunk-67QG75MJ.js → chunk-NLK2VZYZ.js} +2 -2
  121. package/dist/{chunk-A4QMKFFO.js → chunk-O5FFBO2M.js} +14 -28
  122. package/dist/chunk-O5FFBO2M.js.map +1 -0
  123. package/dist/{chunk-JYIFGGEM.js → chunk-OUKBMQ2O.js} +2 -2
  124. package/dist/{chunk-75XOWNRS.js → chunk-OYESWJ43.js} +4 -4
  125. package/dist/{chunk-TS4AJ2GI.js → chunk-PA45XCUD.js} +3 -3
  126. package/dist/{chunk-BJYET5TX.js → chunk-PRDJMOST.js} +7 -1
  127. package/dist/chunk-PRDJMOST.js.map +1 -0
  128. package/dist/{chunk-4MBPIL4V.js → chunk-PUSLMZBQ.js} +2 -2
  129. package/dist/{chunk-RVO6TCTU.js → chunk-QCECHYZL.js} +6 -6
  130. package/dist/{chunk-GFIKG4FR.js → chunk-QGR6OVGT.js} +2 -2
  131. package/dist/{chunk-NSGU76YO.js → chunk-QHFV6VNU.js} +6 -2
  132. package/dist/chunk-QHFV6VNU.js.map +1 -0
  133. package/dist/{chunk-PDEKQWDV.js → chunk-QT2FRYI4.js} +18 -2
  134. package/dist/chunk-QT2FRYI4.js.map +1 -0
  135. package/dist/{chunk-HNZKVLAN.js → chunk-S354QO4R.js} +2 -2
  136. package/dist/{chunk-NO37MR45.js → chunk-SOEN6KCF.js} +2 -2
  137. package/dist/{chunk-FXX6RQYC.js → chunk-TPTECFWR.js} +2 -2
  138. package/dist/{chunk-GDDGZVFI.js → chunk-UEVLYVNW.js} +2 -2
  139. package/dist/{chunk-YQ4IQ2GA.js → chunk-UT5BV5OG.js} +2 -2
  140. package/dist/{chunk-LAQ33B5D.js → chunk-UU3G6GUP.js} +1 -1
  141. package/dist/chunk-UU3G6GUP.js.map +1 -0
  142. package/dist/{chunk-LNTUXKBT.js → chunk-UYYW2KPU.js} +2 -2
  143. package/dist/{chunk-BOFVT6P3.js → chunk-VBHPOWBJ.js} +175 -98
  144. package/dist/chunk-VBHPOWBJ.js.map +1 -0
  145. package/dist/{chunk-QSYL5CXK.js → chunk-VKXWK44Q.js} +3 -3
  146. package/dist/{chunk-KMWYZTIE.js → chunk-VMMQDEN5.js} +2 -2
  147. package/dist/{chunk-JB6D7EFB.js → chunk-VVG2BOKA.js} +2 -2
  148. package/dist/chunk-W5BIQOAJ.js +69 -0
  149. package/dist/chunk-W5BIQOAJ.js.map +1 -0
  150. package/dist/{chunk-V5H6OJCR.js → chunk-W5XVQFLM.js} +2 -2
  151. package/dist/{chunk-OIOZ6MOP.js → chunk-W6FNX2LP.js} +2 -2
  152. package/dist/{chunk-6QPHF6RR.js → chunk-WQM326GS.js} +2 -2
  153. package/dist/{chunk-TQFHQPWD.js → chunk-XADV5IZ3.js} +8 -8
  154. package/dist/{chunk-DATDLJAO.js → chunk-XAPMEU3K.js} +2 -2
  155. package/dist/chunk-XXSOVESA.js +42 -0
  156. package/dist/chunk-XXSOVESA.js.map +1 -0
  157. package/dist/{chunk-IK6X5QPO.js → chunk-ZHY5TMJG.js} +1193 -443
  158. package/dist/chunk-ZHY5TMJG.js.map +1 -0
  159. package/dist/{chunk-N3LL5NEU.js → chunk-ZMYDYNI4.js} +2 -2
  160. package/dist/{cli-D4vvtxjY.d.ts → cli-CnOkH9hA.d.ts} +6 -6
  161. package/dist/cli.d.ts +15 -13
  162. package/dist/cli.js +74 -70
  163. package/dist/coding/pre-action-gate.d.ts +3 -1
  164. package/dist/coding/pre-action-gate.js +2 -2
  165. package/dist/compounding/engine.d.ts +4 -2
  166. package/dist/compounding/engine.js +10 -9
  167. package/dist/compounding/preference-consolidator.d.ts +3 -1
  168. package/dist/compression-optimizer.d.ts +3 -1
  169. package/dist/config.d.ts +3 -1
  170. package/dist/config.js +5 -3
  171. package/dist/connectors/codex-materialize-runner.d.ts +3 -1
  172. package/dist/connectors/codex-materialize-runner.js +10 -9
  173. package/dist/connectors/codex-materialize.d.ts +3 -1
  174. package/dist/connectors/index.d.ts +3 -1
  175. package/dist/connectors/index.js +10 -9
  176. package/dist/consolidation-provenance-check.d.ts +4 -2
  177. package/dist/consolidation-undo.d.ts +4 -2
  178. package/dist/contradiction/index.d.ts +4 -2
  179. package/dist/contradiction-config.d.ts +29 -0
  180. package/dist/contradiction-config.js +12 -0
  181. package/dist/contradiction-config.js.map +1 -0
  182. package/dist/converge-config.d.ts +3 -1
  183. package/dist/convergence-refresh.d.ts +4 -2
  184. package/dist/convergence-refresh.js +12 -11
  185. package/dist/conversation-index/backend.d.ts +3 -1
  186. package/dist/conversation-index/chunker.d.ts +3 -1
  187. package/dist/conversation-index/faiss-adapter.d.ts +3 -1
  188. package/dist/conversation-index/indexer.d.ts +3 -1
  189. package/dist/conversation-index/search.d.ts +3 -1
  190. package/dist/corpus-watermark.d.ts +3 -1
  191. package/dist/corpus-watermark.js +21 -20
  192. package/dist/day-summary.d.ts +3 -1
  193. package/dist/delinearize.d.ts +3 -1
  194. package/dist/dependency-propagation-config.d.ts +3 -1
  195. package/dist/direct-answer-wiring.d.ts +3 -1
  196. package/dist/direct-answer.d.ts +3 -1
  197. package/dist/embedding-fallback.d.ts +3 -1
  198. package/dist/enrichment/index.d.ts +3 -1
  199. package/dist/entity-retrieval.d.ts +4 -2
  200. package/dist/entity-retrieval.js +10 -9
  201. package/dist/entity-schema.d.ts +3 -1
  202. package/dist/explicit-capture.d.ts +11 -9
  203. package/dist/explicit-capture.js +3 -2
  204. package/dist/external-wiki-access.d.ts +13 -11
  205. package/dist/external-wiki-access.js +42 -40
  206. package/dist/external-wiki-collection-registration.d.ts +3 -1
  207. package/dist/external-wiki-collection.d.ts +3 -1
  208. package/dist/external-wiki-mcp-tools.d.ts +13 -11
  209. package/dist/extraction-error-classification.d.ts +3 -1
  210. package/dist/extraction-faithfulness.d.ts +3 -1
  211. package/dist/extraction-judge-telemetry.d.ts +3 -1
  212. package/dist/extraction-judge-training.d.ts +3 -1
  213. package/dist/extraction-judge.d.ts +3 -1
  214. package/dist/extraction-liveness.d.ts +3 -1
  215. package/dist/extraction-normalization.d.ts +3 -1
  216. package/dist/extraction-prompt.d.ts +3 -1
  217. package/dist/extraction-source-grounding-rules.d.ts +3 -1
  218. package/dist/extraction-source-grounding.d.ts +3 -1
  219. package/dist/extraction.d.ts +3 -1
  220. package/dist/extraction.js +22 -21
  221. package/dist/fallback-llm.d.ts +3 -1
  222. package/dist/graph-444E-DrF.d.ts +349 -0
  223. package/dist/graph-dashboard-diff.d.ts +4 -2
  224. package/dist/graph-dashboard-key.d.ts +4 -2
  225. package/dist/graph-dashboard-parser.d.ts +4 -2
  226. package/dist/{graph-edge-decay-Z6ENALU2.js → graph-edge-decay-65KMOJWY.js} +4 -3
  227. package/dist/graph-edge-decay-65KMOJWY.js.map +1 -0
  228. package/dist/graph-edge-reinforcement.d.ts +4 -2
  229. package/dist/graph-path-reconstruction.d.ts +10 -0
  230. package/dist/graph-path-reconstruction.js +12 -0
  231. package/dist/graph-path-reconstruction.js.map +1 -0
  232. package/dist/graph-path-scoring-config.d.ts +8 -0
  233. package/dist/graph-path-scoring-config.js +10 -0
  234. package/dist/graph-path-scoring-config.js.map +1 -0
  235. package/dist/graph-path-scoring.d.ts +36 -0
  236. package/dist/graph-path-scoring.js +11 -0
  237. package/dist/graph-path-scoring.js.map +1 -0
  238. package/dist/graph-snapshot.d.ts +4 -2
  239. package/dist/graph-snapshot.js +3 -2
  240. package/dist/graph.d.ts +5 -318
  241. package/dist/graph.js +5 -1
  242. package/dist/harmonic-retrieval.js +1 -1
  243. package/dist/importance.d.ts +3 -1
  244. package/dist/importers/index.d.ts +3 -1
  245. package/dist/in-flight-reads.d.ts +3 -1
  246. package/dist/index.d.ts +696 -694
  247. package/dist/index.js +149 -144
  248. package/dist/intent.d.ts +3 -1
  249. package/dist/lcm/engine.d.ts +3 -1
  250. package/dist/lcm/engine.js +3 -3
  251. package/dist/lcm/index.d.ts +3 -1
  252. package/dist/lcm/index.js +6 -6
  253. package/dist/lcm/tools.d.ts +3 -1
  254. package/dist/lifecycle.d.ts +3 -1
  255. package/dist/live-connectors-runner.d.ts +3 -1
  256. package/dist/local-llm.d.ts +3 -1
  257. package/dist/local-model-endpoint.d.ts +3 -1
  258. package/dist/maintenance/memory-governance.d.ts +3 -1
  259. package/dist/maintenance/memory-governance.js +10 -9
  260. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +4 -2
  261. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -9
  262. package/dist/maintenance/rebuild-memory-projection.d.ts +4 -2
  263. package/dist/maintenance/rebuild-memory-projection.js +11 -10
  264. package/dist/{maintenance-ClmUVpGI.d.ts → maintenance-CKwxpdRx.d.ts} +3 -3
  265. package/dist/mcp-memory-inspector-app.d.ts +13 -11
  266. package/dist/memory-action-policy.d.ts +3 -1
  267. package/dist/memory-cache.d.ts +3 -1
  268. package/dist/memory-lifecycle-ledger-utils.d.ts +3 -1
  269. package/dist/memory-projection-store.d.ts +3 -1
  270. package/dist/memory-provenance.d.ts +3 -1
  271. package/dist/memory-snapshot.d.ts +3 -1
  272. package/dist/memory-worth-outcomes.d.ts +4 -2
  273. package/dist/models-json.d.ts +3 -1
  274. package/dist/namespaces/migrate.d.ts +5 -3
  275. package/dist/namespaces/migrate.js +20 -19
  276. package/dist/namespaces/principal.d.ts +3 -1
  277. package/dist/namespaces/search.d.ts +3 -1
  278. package/dist/namespaces/search.js +7 -7
  279. package/dist/namespaces/storage.d.ts +5 -3
  280. package/dist/namespaces/storage.js +10 -9
  281. package/dist/native-knowledge.d.ts +3 -1
  282. package/dist/offline-sync-impression-drain.d.ts +3 -1
  283. package/dist/operator-doctor-corpus.d.ts +3 -1
  284. package/dist/operator-doctor-corpus.js +22 -21
  285. package/dist/operator-doctor-replica.d.ts +3 -1
  286. package/dist/operator-toolkit.d.ts +6 -4
  287. package/dist/operator-toolkit.js +33 -29
  288. package/dist/orchestration/compression-guideline-coordinator.d.ts +4 -2
  289. package/dist/orchestration/maintenance.d.ts +6 -4
  290. package/dist/orchestration/maintenance.js +15 -14
  291. package/dist/{orchestrator-qJ07zI8H.d.ts → orchestrator-BshGam-o.d.ts} +45 -19
  292. package/dist/orchestrator.d.ts +11 -9
  293. package/dist/orchestrator.js +109 -104
  294. package/dist/patterns-cli.d.ts +3 -1
  295. package/dist/{pipeline-WFCxhHOn.d.ts → pipeline-D21Rs6gW.d.ts} +1 -1
  296. package/dist/policy-runtime.d.ts +3 -1
  297. package/dist/proactive-contention.d.ts +3 -1
  298. package/dist/provenance.d.ts +3 -1
  299. package/dist/{qmd-5tzkQ44y.d.ts → qmd-Dhle1P4X.d.ts} +1 -1
  300. package/dist/qmd-preflight.d.ts +4 -2
  301. package/dist/qmd-recall-cache.d.ts +3 -1
  302. package/dist/qmd.d.ts +4 -2
  303. package/dist/qmd.js +4 -4
  304. package/dist/recall-concurrency-config.d.ts +3 -1
  305. package/dist/recall-disclosure-escalation.d.ts +3 -1
  306. package/dist/recall-explain-renderer.d.ts +3 -1
  307. package/dist/recall-explain-renderer.js +3 -3
  308. package/dist/recall-memory-map.d.ts +3 -1
  309. package/dist/recall-planner-llm.d.ts +3 -1
  310. package/dist/recall-planner-llm.js +3 -3
  311. package/dist/recall-state.d.ts +7 -1
  312. package/dist/recall-state.js +1 -1
  313. package/dist/recall-tag-filter.d.ts +3 -1
  314. package/dist/recall-timings.d.ts +3 -1
  315. package/dist/recall-xray-cli.d.ts +3 -1
  316. package/dist/recall-xray-cli.js +4 -4
  317. package/dist/recall-xray-renderer.d.ts +3 -1
  318. package/dist/recall-xray-renderer.js +3 -3
  319. package/dist/recall-xray.d.ts +7 -1
  320. package/dist/recall-xray.js +2 -2
  321. package/dist/reconcile/cursor.d.ts +3 -1
  322. package/dist/reconcile/manifest.d.ts +3 -1
  323. package/dist/reconcile/plan.d.ts +3 -1
  324. package/dist/replay/normalizers/chatgpt.d.ts +3 -1
  325. package/dist/replay/normalizers/claude.d.ts +3 -1
  326. package/dist/replay/normalizers/openclaw.d.ts +3 -1
  327. package/dist/replay/normalizers/shared.d.ts +3 -1
  328. package/dist/replay/runner.d.ts +3 -1
  329. package/dist/replay/types.d.ts +3 -1
  330. package/dist/replica-divergence.d.ts +3 -1
  331. package/dist/replica-peers-config.d.ts +3 -1
  332. package/dist/resolve-auth-token.d.ts +3 -1
  333. package/dist/resume-bundles.js +6 -4
  334. package/dist/retrieval-agents.d.ts +4 -2
  335. package/dist/retrieval-tiers.d.ts +3 -1
  336. package/dist/routing/engine.d.ts +3 -1
  337. package/dist/routing/store.d.ts +3 -1
  338. package/dist/salvage-envelope.d.ts +3 -1
  339. package/dist/schemas.d.ts +116 -116
  340. package/dist/{scope-profiles--vfXPl3X.d.ts → scope-profiles-NzGPDXLn.d.ts} +1 -1
  341. package/dist/search/embed-helper.d.ts +3 -1
  342. package/dist/search/factory.d.ts +3 -1
  343. package/dist/search/factory.js +6 -6
  344. package/dist/search/index.d.ts +3 -1
  345. package/dist/search/index.js +12 -12
  346. package/dist/search/lancedb-backend.d.ts +3 -1
  347. package/dist/search/meilisearch-backend.d.ts +3 -1
  348. package/dist/search/noop-backend.d.ts +3 -1
  349. package/dist/search/orama-backend.d.ts +3 -1
  350. package/dist/search/port.d.ts +3 -1
  351. package/dist/search/remote-backend.d.ts +3 -1
  352. package/dist/{semantic-consolidation-BBDuP9nJ.d.ts → semantic-consolidation-DLDKvyy5.d.ts} +1 -1
  353. package/dist/semantic-consolidation.d.ts +4 -2
  354. package/dist/semantic-consolidation.js +11 -10
  355. package/dist/semantic-rule-promotion.js +10 -9
  356. package/dist/semantic-rule-verifier.d.ts +3 -1
  357. package/dist/semantic-rule-verifier.js +10 -9
  358. package/dist/{service-B8DtbpCM.d.ts → service-BIgVM7fL.d.ts} +2 -2
  359. package/dist/session-observer-bands.d.ts +3 -1
  360. package/dist/session-observer-state.d.ts +3 -1
  361. package/dist/shared-context/manager.d.ts +11 -9
  362. package/dist/signal.d.ts +3 -1
  363. package/dist/source-agent-qualifier.d.ts +3 -1
  364. package/dist/source-agent-qualifier.js +18 -17
  365. package/dist/{storage-BkYN1RIy.d.ts → storage-CVfGWqCI.d.ts} +7 -6
  366. package/dist/storage.d.ts +4 -2
  367. package/dist/storage.js +9 -8
  368. package/dist/summarizer.d.ts +3 -1
  369. package/dist/summary-snapshot.d.ts +3 -1
  370. package/dist/temporal-supersession.d.ts +4 -2
  371. package/dist/temporal-timeline-recall.d.ts +3 -1
  372. package/dist/temporal-validity.d.ts +3 -1
  373. package/dist/threading.d.ts +3 -1
  374. package/dist/tier-migration.d.ts +4 -2
  375. package/dist/tier-routing.d.ts +3 -1
  376. package/dist/topics.d.ts +3 -1
  377. package/dist/transcript.d.ts +3 -1
  378. package/dist/transfer/autodetect.js +1 -1
  379. package/dist/transfer/backup.js +1 -1
  380. package/dist/transfer/capsule-export.js +2 -2
  381. package/dist/transfer/types.d.ts +66 -66
  382. package/dist/trust-score-stage.d.ts +3 -1
  383. package/dist/trust-score.d.ts +3 -1
  384. package/dist/{types-u2s9j1uD.d.ts → types-CkiDUorT.d.ts} +10 -16
  385. package/dist/types.d.ts +3 -1
  386. package/dist/types.js +1 -1
  387. package/dist/utility-runtime.d.ts +3 -1
  388. package/dist/verified-recall.js +10 -9
  389. package/dist/write-envelope.d.ts +3 -1
  390. package/package.json +2 -2
  391. package/src/archive-mutation-version.ts +59 -0
  392. package/src/config.test.ts +45 -0
  393. package/src/config.ts +10 -30
  394. package/src/contradiction/contradiction.test.ts +86 -1
  395. package/src/contradiction-config.ts +92 -0
  396. package/src/graph-path-reconstruction.ts +91 -0
  397. package/src/graph-path-scoring-config.ts +55 -0
  398. package/src/graph-path-scoring.test.ts +238 -0
  399. package/src/graph-path-scoring.ts +77 -0
  400. package/src/graph.test.ts +225 -5
  401. package/src/graph.ts +72 -5
  402. package/src/orchestration/contradiction-linking-coordinator.ts +246 -76
  403. package/src/orchestration/contradiction-localization.integration.test.ts +1953 -0
  404. package/src/orchestration/extraction-anchor-snapshot.ts +83 -0
  405. package/src/orchestration/extraction-persist-deps.ts +8 -2
  406. package/src/orchestration/extraction-persist.ts +43 -34
  407. package/src/orchestration/graph-path-state-loader.test.ts +801 -0
  408. package/src/orchestration/graph-path-state-loader.ts +318 -0
  409. package/src/orchestration/graph-recall-coordinator.integration.test.ts +1163 -0
  410. package/src/orchestration/graph-recall-coordinator.ts +206 -29
  411. package/src/orchestration/graph-recall-seam.ts +19 -0
  412. package/src/orchestration/recall-internal-deps.ts +7 -13
  413. package/src/orchestration/recall-internal.ts +5 -0
  414. package/src/orchestration/recall-introspection.ts +9 -1
  415. package/src/orchestration/recall-search-pipeline.ts +8 -13
  416. package/src/orchestration/update-localization.test.ts +784 -0
  417. package/src/orchestration/update-localization.ts +173 -0
  418. package/src/orchestrator.ts +19 -18
  419. package/src/recall-state.test.ts +29 -1
  420. package/src/recall-state.ts +13 -0
  421. package/src/recall-xray-renderer.test.ts +45 -0
  422. package/src/recall-xray-renderer.ts +16 -0
  423. package/src/recall-xray.ts +13 -0
  424. package/src/storage/supersession-side-effects.ts +97 -0
  425. package/src/storage/tombstone-blocked-capture-sync.ts +13 -5
  426. package/src/storage-contract/cache-coherence.test.ts +299 -0
  427. package/src/storage.ts +86 -88
  428. package/src/types.ts +12 -15
  429. package/dist/chunk-A4QMKFFO.js.map +0 -1
  430. package/dist/chunk-BJYET5TX.js.map +0 -1
  431. package/dist/chunk-BOFVT6P3.js.map +0 -1
  432. package/dist/chunk-IK6X5QPO.js.map +0 -1
  433. package/dist/chunk-IXXABW5A.js.map +0 -1
  434. package/dist/chunk-L2DPF4DF.js.map +0 -1
  435. package/dist/chunk-LAQ33B5D.js.map +0 -1
  436. package/dist/chunk-NSGU76YO.js.map +0 -1
  437. package/dist/chunk-PDEKQWDV.js.map +0 -1
  438. /package/dist/{graph-edge-decay-Z6ENALU2.js.map → archive-mutation-version.js.map} +0 -0
  439. /package/dist/{chunk-KDG2KTWW.js.map → chunk-33SV3E43.js.map} +0 -0
  440. /package/dist/{chunk-2HGUDBRJ.js.map → chunk-37ZO6LLJ.js.map} +0 -0
  441. /package/dist/{chunk-QW3WFHKU.js.map → chunk-45BRYON6.js.map} +0 -0
  442. /package/dist/{chunk-GZICBRWK.js.map → chunk-4F6X3RXW.js.map} +0 -0
  443. /package/dist/{chunk-7BAYBYY5.js.map → chunk-4PC4PRJE.js.map} +0 -0
  444. /package/dist/{chunk-VJXY5ZCT.js.map → chunk-52UKFTUK.js.map} +0 -0
  445. /package/dist/{chunk-ESG7Z255.js.map → chunk-5UDMFE3Q.js.map} +0 -0
  446. /package/dist/{chunk-JPHEOE6Z.js.map → chunk-6MTSFX7A.js.map} +0 -0
  447. /package/dist/{chunk-M4MP34AQ.js.map → chunk-AHZOMHWN.js.map} +0 -0
  448. /package/dist/{chunk-Z3RHPGSY.js.map → chunk-AIUBBHSF.js.map} +0 -0
  449. /package/dist/{chunk-S3AYIQCU.js.map → chunk-AXIDQG5A.js.map} +0 -0
  450. /package/dist/{chunk-QN7NTKRC.js.map → chunk-AZ2QBGYB.js.map} +0 -0
  451. /package/dist/{chunk-47J4EDGR.js.map → chunk-AZM4CCAC.js.map} +0 -0
  452. /package/dist/{chunk-LEJPSMKM.js.map → chunk-C5QLI33R.js.map} +0 -0
  453. /package/dist/{chunk-SV3PSA7Y.js.map → chunk-CV6BBVYV.js.map} +0 -0
  454. /package/dist/{chunk-V7X767RT.js.map → chunk-DCZBSE4F.js.map} +0 -0
  455. /package/dist/{chunk-7PKFPLLZ.js.map → chunk-FXTYIA46.js.map} +0 -0
  456. /package/dist/{chunk-64BHFFKZ.js.map → chunk-HLYR2TQL.js.map} +0 -0
  457. /package/dist/{chunk-5C2HNJMO.js.map → chunk-J5LLX6IL.js.map} +0 -0
  458. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  459. /package/dist/{chunk-PLKFO2HJ.js.map → chunk-JL43BVDE.js.map} +0 -0
  460. /package/dist/{chunk-2S72LWKX.js.map → chunk-JYL3BVVZ.js.map} +0 -0
  461. /package/dist/{chunk-IPLYGWQF.js.map → chunk-KQAFEZQX.js.map} +0 -0
  462. /package/dist/{chunk-PYKKWQZ2.js.map → chunk-M7BXDKPR.js.map} +0 -0
  463. /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
  464. /package/dist/{chunk-LYMNZZIM.js.map → chunk-NIS256NW.js.map} +0 -0
  465. /package/dist/{chunk-67QG75MJ.js.map → chunk-NLK2VZYZ.js.map} +0 -0
  466. /package/dist/{chunk-JYIFGGEM.js.map → chunk-OUKBMQ2O.js.map} +0 -0
  467. /package/dist/{chunk-75XOWNRS.js.map → chunk-OYESWJ43.js.map} +0 -0
  468. /package/dist/{chunk-TS4AJ2GI.js.map → chunk-PA45XCUD.js.map} +0 -0
  469. /package/dist/{chunk-4MBPIL4V.js.map → chunk-PUSLMZBQ.js.map} +0 -0
  470. /package/dist/{chunk-RVO6TCTU.js.map → chunk-QCECHYZL.js.map} +0 -0
  471. /package/dist/{chunk-GFIKG4FR.js.map → chunk-QGR6OVGT.js.map} +0 -0
  472. /package/dist/{chunk-HNZKVLAN.js.map → chunk-S354QO4R.js.map} +0 -0
  473. /package/dist/{chunk-NO37MR45.js.map → chunk-SOEN6KCF.js.map} +0 -0
  474. /package/dist/{chunk-FXX6RQYC.js.map → chunk-TPTECFWR.js.map} +0 -0
  475. /package/dist/{chunk-GDDGZVFI.js.map → chunk-UEVLYVNW.js.map} +0 -0
  476. /package/dist/{chunk-YQ4IQ2GA.js.map → chunk-UT5BV5OG.js.map} +0 -0
  477. /package/dist/{chunk-LNTUXKBT.js.map → chunk-UYYW2KPU.js.map} +0 -0
  478. /package/dist/{chunk-QSYL5CXK.js.map → chunk-VKXWK44Q.js.map} +0 -0
  479. /package/dist/{chunk-KMWYZTIE.js.map → chunk-VMMQDEN5.js.map} +0 -0
  480. /package/dist/{chunk-JB6D7EFB.js.map → chunk-VVG2BOKA.js.map} +0 -0
  481. /package/dist/{chunk-V5H6OJCR.js.map → chunk-W5XVQFLM.js.map} +0 -0
  482. /package/dist/{chunk-OIOZ6MOP.js.map → chunk-W6FNX2LP.js.map} +0 -0
  483. /package/dist/{chunk-6QPHF6RR.js.map → chunk-WQM326GS.js.map} +0 -0
  484. /package/dist/{chunk-TQFHQPWD.js.map → chunk-XADV5IZ3.js.map} +0 -0
  485. /package/dist/{chunk-DATDLJAO.js.map → chunk-XAPMEU3K.js.map} +0 -0
  486. /package/dist/{chunk-N3LL5NEU.js.map → chunk-ZMYDYNI4.js.map} +0 -0
@@ -0,0 +1,784 @@
1
+ import { ContradictionLinkingCoordinator } from "./contradiction-linking-coordinator.js";
2
+ import type { ExtractionEngine } from "../extraction.js";
3
+ import type { QmdSearchResult, PluginConfig } from "../types.js";
4
+ import assert from "node:assert/strict";
5
+ import test from "node:test";
6
+ import { initLogger } from "../logger.js";
7
+
8
+ import {
9
+ localizeUpdateCandidates,
10
+ mergeMemorySnapshots,
11
+ type UpdateLocalizationSearchHit,
12
+ } from "./update-localization.js";
13
+ import type { MemoryFile } from "../types.js";
14
+ import type { StorageManager } from "../storage.js";
15
+
16
+ const NOW = "2026-08-08T00:00:00.000Z";
17
+
18
+ function memory(
19
+ id: string,
20
+ options: {
21
+ entityRef?: string;
22
+ category?: string;
23
+ status?: string;
24
+ omitStatus?: boolean;
25
+ created?: string;
26
+ attributes?: Record<string, string>;
27
+ content?: string;
28
+ path?: string;
29
+ archivedAt?: string;
30
+ } = {},
31
+ ): MemoryFile {
32
+ return {
33
+ path: options.path ?? `/synthetic/${id}.md`,
34
+ content: options.content ?? `content for ${id}`,
35
+ frontmatter: {
36
+ id,
37
+ category: (options.category ?? "fact") as MemoryFile["frontmatter"]["category"],
38
+ created: options.created ?? NOW,
39
+ updated: options.created ?? NOW,
40
+ source: "synthetic-test",
41
+ confidence: 0.9,
42
+ confidenceTier: "explicit",
43
+ tags: [],
44
+ ...(options.archivedAt ? { archivedAt: options.archivedAt } : {}),
45
+ ...(options.omitStatus
46
+ ? {}
47
+ : { status: (options.status ?? "active") as MemoryFile["frontmatter"]["status"] }),
48
+ ...(options.entityRef ? { entityRef: options.entityRef } : {}),
49
+ ...(options.attributes ? { structuredAttributes: options.attributes } : {}),
50
+ },
51
+ } as unknown as MemoryFile;
52
+ }
53
+
54
+ function storage(
55
+ memories: MemoryFile[],
56
+ coldMemories: MemoryFile[] = [],
57
+ memoryDir?: string,
58
+ ): StorageManager {
59
+ return {
60
+ dir: memoryDir,
61
+ readAllMemories: async () => memories,
62
+ readAllColdMemories: async () => coldMemories,
63
+ getMemoryById: async (id: string) => memories.find((entry) => entry.frontmatter.id === id) ?? null,
64
+ } as unknown as StorageManager;
65
+ }
66
+
67
+ function hit(id: string, score: number): UpdateLocalizationSearchHit {
68
+ return { id, content: `search content for ${id}`, category: "fact", score };
69
+ }
70
+
71
+ function search(...hits: Array<UpdateLocalizationSearchHit>): (query: string, limit: number) => Promise<UpdateLocalizationSearchHit[]> {
72
+ return async () => hits;
73
+ }
74
+
75
+ const options = {
76
+ anchorCandidates: 5,
77
+ searchCandidates: 5,
78
+ maxCandidates: 8,
79
+ };
80
+
81
+ test("localizes exact entity and category anchors, excluding other entities and categories", async () => {
82
+ const result = await localizeUpdateCandidates(
83
+ {
84
+ storage: storage([
85
+ memory("same", { entityRef: "person:alice" }),
86
+ memory("other-entity", { entityRef: "person:bob" }),
87
+ memory("other-category", { entityRef: "person:alice", category: "decision" }),
88
+ ]),
89
+ qmdSearch: search(),
90
+ },
91
+ { entityRef: "person:alice", category: "fact" },
92
+ "incoming",
93
+ options,
94
+ );
95
+
96
+ assert.deepEqual(result.map((candidate) => candidate.id), ["same"]);
97
+ assert.equal(result[0]?.source, "anchor");
98
+ });
99
+
100
+ test("skips anchor pass when the new fact has no entityRef", async () => {
101
+ const result = await localizeUpdateCandidates(
102
+ {
103
+ storage: storage([memory("stored", { entityRef: "person:alice" })]),
104
+ qmdSearch: search(hit("search-hit", 0.8)),
105
+ },
106
+ { category: "fact" },
107
+ "incoming",
108
+ options,
109
+ );
110
+
111
+ assert.deepEqual(result.map((candidate) => candidate.id), ["search-hit"]);
112
+ assert.equal(result[0]?.source, "search");
113
+ });
114
+
115
+ test("includes only active memories in the anchor pass", async () => {
116
+ const statuses = ["superseded", "forgotten", "archived", "pending_review", "active"];
117
+ const legacy = memory("legacy", { entityRef: "person:alice", omitStatus: true });
118
+ const result = await localizeUpdateCandidates(
119
+ {
120
+ storage: storage([
121
+ ...statuses.map((status) => memory(status, { entityRef: "person:alice", status })),
122
+ legacy,
123
+ ]),
124
+ qmdSearch: search(),
125
+ },
126
+ { entityRef: "person:alice", category: "fact" },
127
+ "incoming",
128
+ options,
129
+ );
130
+
131
+ assert.deepEqual(result.map((candidate) => candidate.id), ["active", "legacy"]);
132
+ });
133
+
134
+ test("excludes active raw status when archivedAt infers a non-active anchor", async () => {
135
+ const result = await localizeUpdateCandidates(
136
+ {
137
+ storage: storage([
138
+ memory("archived-at", {
139
+ entityRef: "person:alice",
140
+ archivedAt: "2026-08-08T00:00:00.000Z",
141
+ }),
142
+ memory("legacy", { entityRef: "person:alice", omitStatus: true }),
143
+ ]),
144
+ qmdSearch: search(),
145
+ },
146
+ { entityRef: "person:alice", category: "fact" },
147
+ "incoming",
148
+ options,
149
+ );
150
+
151
+ assert.deepEqual(result.map((candidate) => candidate.id), ["legacy"]);
152
+ });
153
+
154
+ test("excludes absent raw status when archive path infers a non-active anchor", async () => {
155
+ const result = await localizeUpdateCandidates(
156
+ {
157
+ storage: storage(
158
+ [
159
+ memory("archive-path", {
160
+ entityRef: "person:alice",
161
+ omitStatus: true,
162
+ path: "/synthetic/archive/archive-path.md",
163
+ }),
164
+ memory("legacy", { entityRef: "person:alice", omitStatus: true }),
165
+ ],
166
+ [],
167
+ "/synthetic",
168
+ ),
169
+ qmdSearch: search(),
170
+ },
171
+ { entityRef: "person:alice", category: "fact" },
172
+ "incoming",
173
+ options,
174
+ );
175
+
176
+ assert.deepEqual(result.map((candidate) => candidate.id), ["legacy"]);
177
+ });
178
+
179
+ test("prefers a valid cold copy over a hot copy with inferred archived status", async () => {
180
+ const id = "duplicate";
181
+ const result = await localizeUpdateCandidates(
182
+ {
183
+ storage: storage(
184
+ [
185
+ memory(id, {
186
+ entityRef: "person:alice",
187
+ status: "active",
188
+ archivedAt: "2026-08-08T00:00:00.000Z",
189
+ content: "hot archived copy",
190
+ }),
191
+ ],
192
+ [memory(id, { entityRef: "person:alice", status: "active", content: "cold copy" })],
193
+ ),
194
+ qmdSearch: search(),
195
+ },
196
+ { entityRef: "person:alice", category: "fact" },
197
+ "incoming",
198
+ options,
199
+ );
200
+
201
+ assert.deepEqual(result.map((candidate) => candidate.id), [id]);
202
+ assert.equal(result[0]?.content, "cold copy");
203
+ });
204
+
205
+ test("keeps the hot copy when duplicate statuses are both active", () => {
206
+ const merged = mergeMemorySnapshots(
207
+ [memory("duplicate", { content: "hot copy" })],
208
+ [memory("duplicate", { content: "cold copy" })],
209
+ );
210
+
211
+ assert.deepEqual(merged.map((entry) => entry.content), ["hot copy"]);
212
+ });
213
+
214
+ test("scores matching attribute keys before recency and reuses normalized attribute keys", async () => {
215
+ const result = await localizeUpdateCandidates(
216
+ {
217
+ storage: storage([
218
+ memory("one-key", {
219
+ entityRef: "person:alice",
220
+ attributes: { City: "Austin" },
221
+ created: "2026-08-08T00:00:00.000Z",
222
+ }),
223
+ memory("two-keys", {
224
+ entityRef: "person:alice",
225
+ attributes: { city: "Austin", "job title": "Engineer" },
226
+ created: "2020-01-01T00:00:00.000Z",
227
+ }),
228
+ ]),
229
+ qmdSearch: search(),
230
+ },
231
+ {
232
+ entityRef: "person:alice",
233
+ category: "fact",
234
+ attributes: { " CITY ": "New York", "job-title": "Manager" },
235
+ },
236
+ "incoming",
237
+ options,
238
+ );
239
+
240
+ assert.deepEqual(result.map((candidate) => candidate.id), ["two-keys", "one-key"]);
241
+ assert.equal(result[0]?.score, 2);
242
+ assert.equal(result[1]?.score, 1);
243
+ });
244
+
245
+ test("merges anchor results first and deduplicates search results by id", async () => {
246
+ const result = await localizeUpdateCandidates(
247
+ {
248
+ storage: storage([
249
+ memory("anchor", { entityRef: "person:alice" }),
250
+ memory("search-only"),
251
+ ]),
252
+ qmdSearch: search(hit("anchor", 0.99), hit("search-only", 0.8)),
253
+ },
254
+ { entityRef: "person:alice", category: "fact" },
255
+ "incoming",
256
+ options,
257
+ );
258
+
259
+ assert.deepEqual(result.map((candidate) => candidate.id), ["anchor", "search-only"]);
260
+ assert.equal(result[0]?.source, "anchor");
261
+ });
262
+
263
+ test("honors zero anchor, search, and total caps", async () => {
264
+ let calls = 0;
265
+ const qmdSearch = async () => {
266
+ calls++;
267
+ return [hit("search", 1)];
268
+ };
269
+ const deps = { storage: storage([memory("anchor", { entityRef: "person:alice" })]), qmdSearch };
270
+
271
+ assert.deepEqual(
272
+ await localizeUpdateCandidates(deps, { entityRef: "person:alice", category: "fact" }, "incoming", {
273
+ ...options,
274
+ anchorCandidates: 0,
275
+ }).then((candidates) => candidates.map((candidate) => candidate.id)),
276
+ ["search"],
277
+ );
278
+ assert.equal(calls, 1);
279
+ assert.deepEqual(
280
+ await localizeUpdateCandidates(deps, { entityRef: "person:alice", category: "fact" }, "incoming", {
281
+ ...options,
282
+ searchCandidates: 0,
283
+ }).then((candidates) => candidates.map((candidate) => candidate.id)),
284
+ ["anchor"],
285
+ );
286
+ assert.equal(calls, 1);
287
+ assert.deepEqual(
288
+ await localizeUpdateCandidates(deps, { entityRef: "person:alice", category: "fact" }, "incoming", {
289
+ ...options,
290
+ maxCandidates: 0,
291
+ }),
292
+ [],
293
+ );
294
+ assert.equal(calls, 1);
295
+ });
296
+
297
+ test("orders equal scores by id and remains deterministic across invocations", async () => {
298
+ const deps = {
299
+ storage: storage([memory("b", { entityRef: "person:alice" }), memory("a", { entityRef: "person:alice" })]),
300
+ qmdSearch: search(hit("d", 0.5), hit("c", 0.5)),
301
+ };
302
+ const anchor = { entityRef: "person:alice", category: "fact" };
303
+ const first = await localizeUpdateCandidates(deps, anchor, "incoming", options);
304
+ const second = await localizeUpdateCandidates(deps, anchor, "incoming", options);
305
+
306
+ assert.deepEqual(first, second);
307
+ assert.deepEqual(first.map((candidate) => candidate.id), ["a", "b", "c", "d"]);
308
+ });
309
+ test("orders candidates with unequal scores by descending score", async () => {
310
+ const result = await localizeUpdateCandidates(
311
+ { storage: storage([]), qmdSearch: search(hit("low", 1), hit("high", 3), hit("mid", 2)) },
312
+ { category: "fact" },
313
+ "incoming",
314
+ { ...options, anchorCandidates: 0 },
315
+ );
316
+ assert.deepEqual(result.map((candidate) => candidate.id), ["high", "mid", "low"]);
317
+ });
318
+
319
+ test("surfaces QMD failures separately from an empty search", async () => {
320
+ const anchorDeps = {
321
+ storage: storage([memory("anchor", { entityRef: "person:alice" })]),
322
+ qmdSearch: async () => {
323
+ throw new Error("qmd unavailable");
324
+ },
325
+ };
326
+ await assert.rejects(
327
+ localizeUpdateCandidates(anchorDeps, { entityRef: "person:alice", category: "fact" }, "incoming", options),
328
+ /qmd unavailable/,
329
+ );
330
+
331
+ const empty = await localizeUpdateCandidates(
332
+ { storage: storage([memory("anchor", { entityRef: "person:alice" })]), qmdSearch: search() },
333
+ { entityRef: "person:alice", category: "fact" },
334
+ "incoming",
335
+ options,
336
+ );
337
+ assert.deepEqual(empty.map((candidate) => candidate.id), ["anchor"]);
338
+ });
339
+ function qmdResult(id: string, score: number, namespace = "default"): QmdSearchResult {
340
+ return {
341
+ docid: id,
342
+ path: `/synthetic/${namespace}/${id}.md`,
343
+ snippet: `snippet for ${id}`,
344
+ score,
345
+ };
346
+ }
347
+ function coordinatorFixture(
348
+ configOverrides: Record<string, unknown> = {},
349
+ searchAvailable = true,
350
+ storageOverride?: StorageManager,
351
+ ) {
352
+ const candidate = memory("old", { entityRef: "person:alice", content: "Alice lives in Austin" });
353
+ const memories = [candidate];
354
+ const verificationCalls: Array<{ incoming: unknown; existing: unknown }> = [];
355
+ const extraction = {
356
+ verifyContradiction: async (incoming: unknown, existing: unknown) => {
357
+ verificationCalls.push({ incoming, existing });
358
+ return {
359
+ isContradiction: true,
360
+ confidence: 0.99,
361
+ reasoning: "values conflict",
362
+ whichIsNewer: "second",
363
+ };
364
+ },
365
+ } as unknown as ExtractionEngine;
366
+ const config = {
367
+ contradictionSimilarityThreshold: 0.7,
368
+ contradictionMinConfidence: 0.9,
369
+ contradictionAutoResolve: true,
370
+ contradictionLocalization: {
371
+ anchorEnabled: true,
372
+ anchorCandidates: 5,
373
+ searchCandidates: 5,
374
+ maxCandidates: 8,
375
+ },
376
+ ...configOverrides,
377
+ } as unknown as PluginConfig;
378
+ const coordinator = new ContradictionLinkingCoordinator({
379
+ getConfig: () => config,
380
+ isSearchAvailable: () => searchAvailable,
381
+ searchAcrossNamespaces: async () => [],
382
+ extractMemoryIdsFromResults: (results) => results.map((result) => result.docid),
383
+ namespaceFromPath: () => "default",
384
+ storageForNamespace: async () => storageOverride ?? storage(memories),
385
+ getExtraction: () => extraction,
386
+ });
387
+ return { coordinator, verificationCalls, candidate };
388
+ }
389
+
390
+ test("finds a contradiction from an anchor when QMD search misses it", async () => {
391
+ const { coordinator, verificationCalls, candidate } = coordinatorFixture();
392
+ const result = await coordinator.checkForContradiction(
393
+ "Alice lives in New York",
394
+ "fact",
395
+ "default",
396
+ { entityRef: "person:alice", attributes: { city: "New York" } },
397
+ );
398
+
399
+ assert.equal(result?.supersededId, candidate.frontmatter.id);
400
+ assert.equal(verificationCalls.length, 1);
401
+ });
402
+
403
+ test("verifies a legacy anchor with omitted status", async () => {
404
+ const legacyCandidate = memory("legacy-old", {
405
+ entityRef: "person:alice",
406
+ content: "Alice lives in Austin",
407
+ omitStatus: true,
408
+ });
409
+ const { coordinator } = coordinatorFixture({}, false, storage([legacyCandidate]));
410
+ const result = await coordinator.checkForContradiction(
411
+ "Alice lives in New York",
412
+ "fact",
413
+ "default",
414
+ { entityRef: "person:alice" },
415
+ );
416
+
417
+ assert.equal(result?.supersededId, legacyCandidate.frontmatter.id);
418
+ });
419
+
420
+ test("continues with anchors and warns when QMD is unavailable", async () => {
421
+ const warns: string[] = [];
422
+ initLogger({ info() {}, warn: (message) => warns.push(message), error() {}, debug() {} }, false, {
423
+ timestamps: false,
424
+ });
425
+ try {
426
+ const { coordinator, candidate } = coordinatorFixture({}, false);
427
+ const result = await coordinator.checkForContradiction(
428
+ "Alice lives in New York",
429
+ "fact",
430
+ "default",
431
+ { entityRef: "person:alice" },
432
+ );
433
+ assert.equal(result?.supersededId, candidate.frontmatter.id);
434
+ assert.equal(warns.length, 1);
435
+ assert.match(warns[0] ?? "", /QMD unavailable/);
436
+ assert.doesNotMatch(warns[0] ?? "", /Alice lives in New York|person:alice/);
437
+ } finally {
438
+ initLogger({ info() {}, warn() {}, error() {}, debug() {} });
439
+ }
440
+ });
441
+
442
+ test("localizes an active cold anchor when QMD search is unavailable", async () => {
443
+ const coldCandidate = memory("cold-old", {
444
+ entityRef: "person:alice",
445
+ content: "Alice lives in Austin",
446
+ });
447
+ const coldStorage = {
448
+ readAllMemories: async () => [],
449
+ readAllColdMemories: async () => [coldCandidate],
450
+ getMemoryById: async () => null,
451
+ } as unknown as StorageManager;
452
+ const { coordinator, verificationCalls } = coordinatorFixture(
453
+ {
454
+ contradictionLocalization: {
455
+ anchorEnabled: true,
456
+ anchorCandidates: 5,
457
+ searchCandidates: 0,
458
+ maxCandidates: 8,
459
+ },
460
+ },
461
+ false,
462
+ coldStorage,
463
+ );
464
+ const result = await coordinator.checkForContradiction(
465
+ "Alice lives in New York",
466
+ "fact",
467
+ "default",
468
+ { entityRef: "person:alice" },
469
+ );
470
+ assert.equal(result?.supersededId, coldCandidate.frontmatter.id);
471
+ assert.equal(verificationCalls.length, 1);
472
+ });
473
+
474
+ test("disabled localization preserves the legacy fixed QMD limit", async () => {
475
+ let requestedLimit = 0;
476
+ const { coordinator, candidate } = coordinatorFixture({
477
+ contradictionLocalization: {
478
+ anchorEnabled: false,
479
+ anchorCandidates: 0,
480
+ searchCandidates: 0,
481
+ maxCandidates: 0,
482
+ },
483
+ });
484
+ (coordinator as unknown as { searchAcrossNamespaces: unknown }).searchAcrossNamespaces = async (
485
+ options: { maxResults: number },
486
+ ) => {
487
+ requestedLimit = options.maxResults;
488
+ return [qmdResult(candidate.frontmatter.id, 0.95)];
489
+ };
490
+ const result = await coordinator.checkForContradiction(
491
+ "Alice lives in New York",
492
+ "fact",
493
+ "default",
494
+ );
495
+ assert.equal(result?.supersededId, candidate.frontmatter.id);
496
+ assert.equal(requestedLimit, 5);
497
+ });
498
+
499
+ test("disabled localization preserves search-only verification inputs, including string false", async () => {
500
+ const { coordinator, verificationCalls, candidate } = coordinatorFixture({
501
+ contradictionLocalization: {
502
+ anchorEnabled: "false",
503
+ anchorCandidates: 5,
504
+ searchCandidates: 5,
505
+ maxCandidates: 8,
506
+ },
507
+ });
508
+ (coordinator as unknown as { searchAcrossNamespaces: unknown }).searchAcrossNamespaces = async () => [
509
+ qmdResult(candidate.frontmatter.id, 0.95),
510
+ ];
511
+
512
+ const result = await coordinator.checkForContradiction(
513
+ "Alice lives in New York",
514
+ "fact",
515
+ "default",
516
+ { entityRef: "person:alice", attributes: { city: "New York" } },
517
+ );
518
+
519
+ assert.equal(result?.supersededId, candidate.frontmatter.id);
520
+ assert.deepEqual(verificationCalls, [
521
+ {
522
+ incoming: { content: "Alice lives in New York", category: "fact" },
523
+ existing: {
524
+ id: candidate.frontmatter.id,
525
+ content: candidate.content,
526
+ category: "fact",
527
+ created: candidate.frontmatter.created,
528
+ },
529
+ },
530
+ ]);
531
+ });
532
+ test("keeps anchor and search candidates within the requested namespace", async () => {
533
+ const oldDefault = memory("default-old", { entityRef: "person:alice" });
534
+ const oldOther = memory("other-old", { entityRef: "person:alice" });
535
+ const calls: string[] = [];
536
+ const extraction = {
537
+ verifyContradiction: async (_incoming: unknown, existing: { id: string }) => {
538
+ calls.push(existing.id);
539
+ return {
540
+ isContradiction: true,
541
+ confidence: 0.99,
542
+ reasoning: "values conflict",
543
+ whichIsNewer: "second",
544
+ };
545
+ },
546
+ } as unknown as ExtractionEngine;
547
+ const coordinator = new ContradictionLinkingCoordinator({
548
+ getConfig: () =>
549
+ ({
550
+ contradictionSimilarityThreshold: 0.7,
551
+ contradictionMinConfidence: 0.9,
552
+ contradictionAutoResolve: true,
553
+ contradictionLocalization: {
554
+ anchorEnabled: true,
555
+ anchorCandidates: 5,
556
+ searchCandidates: 5,
557
+ maxCandidates: 8,
558
+ },
559
+ }) as unknown as PluginConfig,
560
+ isSearchAvailable: () => true,
561
+ searchAcrossNamespaces: async () => [qmdResult("other-old", 0.99, "other")],
562
+ extractMemoryIdsFromResults: (results) => results.map((result) => result.docid),
563
+ namespaceFromPath: (path) => (path.includes("/other/") ? "other" : "default"),
564
+ storageForNamespace: async (namespace) => storage(namespace === "other" ? [oldOther] : [oldDefault]),
565
+ getExtraction: () => extraction,
566
+ });
567
+
568
+ const result = await coordinator.checkForContradiction(
569
+ "new content",
570
+ "fact",
571
+ "default",
572
+ { entityRef: "person:alice" },
573
+ );
574
+
575
+ assert.equal(result?.supersededId, "default-old");
576
+ assert.deepEqual(calls, ["default-old"]);
577
+ });
578
+ test("deferred resolve propagates invalidation from a cold anchor", async () => {
579
+ const old = memory("cold-old", { content: "old cold claim" });
580
+ old.frontmatter.links = [{ targetId: "dependent", linkType: "supports", strength: 0.9 }];
581
+ old.path = "/synthetic/cold/cold-old.md";
582
+ const dependent = memory("dependent", { content: "dependent claim" });
583
+ dependent.frontmatter.links = [{ targetId: old.frontmatter.id, linkType: "supports", strength: 0.9 }];
584
+ const calls: string[] = [];
585
+ const extraction = {
586
+ revalidateDependents: async (
587
+ _old: unknown,
588
+ _replacement: unknown,
589
+ dependents: Array<{ id: string }>,
590
+ ) => ({
591
+ verdicts: dependents.map((item) => ({
592
+ memoryId: item.id,
593
+ verdict: "invalidated" as const,
594
+ reason: "dependent invalidated",
595
+ })),
596
+ }),
597
+ } as unknown as ExtractionEngine;
598
+ const coldStorage = {
599
+ readAllMemories: async () => [dependent],
600
+ readAllColdMemories: async () => [old],
601
+ getMemoryById: async (id: string) => {
602
+ if (id === old.frontmatter.id) return null;
603
+ if (id === dependent.frontmatter.id) return dependent;
604
+ return memory(id, { content: "replacement claim" });
605
+ },
606
+ supersedeMemory: async (id: string, replacementId: string) => {
607
+ calls.push(`${id}->${replacementId}`);
608
+ return true;
609
+ },
610
+ } as unknown as StorageManager;
611
+ const coordinator = new ContradictionLinkingCoordinator({
612
+ getConfig: () =>
613
+ ({
614
+ contradictionAutoResolve: true,
615
+ dependencyPropagation: {
616
+ enabled: true,
617
+ linkTypes: ["supports"],
618
+ maxDependents: 10,
619
+ timeoutMs: 50,
620
+ dryRun: false,
621
+ },
622
+ }) as unknown as PluginConfig,
623
+ isSearchAvailable: () => false,
624
+ searchAcrossNamespaces: async () => [],
625
+ extractMemoryIdsFromResults: () => [],
626
+ namespaceFromPath: () => "default",
627
+ storageForNamespace: async () => coldStorage,
628
+ getExtraction: () => extraction,
629
+ });
630
+
631
+ await coordinator.applyDeferredContradictionResolve(
632
+ {
633
+ supersededId: old.frontmatter.id,
634
+ reason: "old claim retired",
635
+ supersededPath: old.path,
636
+ supersededCreated: old.frontmatter.created,
637
+ supersededTags: [],
638
+ },
639
+ coldStorage,
640
+ "replacement",
641
+ false,
642
+ );
643
+
644
+ assert.deepEqual(calls, ["cold-old->replacement", "dependent->replacement"]);
645
+ });
646
+ test("scores anchor candidates with missing attributes as zero when the incoming anchor has attributes", async () => {
647
+ const result = await localizeUpdateCandidates(
648
+ {
649
+ storage: storage([
650
+ memory("with-overlap", {
651
+ entityRef: "person:alice",
652
+ attributes: { city: "Austin" },
653
+ created: "2020-01-01T00:00:00.000Z",
654
+ }),
655
+ memory("without-attributes", {
656
+ entityRef: "person:alice",
657
+ created: "2026-08-08T00:00:00.000Z",
658
+ }),
659
+ ]),
660
+ qmdSearch: search(),
661
+ },
662
+ { entityRef: "person:alice", category: "fact", attributes: { city: "New York" } },
663
+ "incoming",
664
+ options,
665
+ );
666
+
667
+ assert.deepEqual(result.map((candidate) => candidate.id), ["with-overlap", "without-attributes"]);
668
+ assert.equal(result[0]?.score, 1);
669
+ assert.equal(result[1]?.score, 0);
670
+ });
671
+ test("excludes search candidates with pending_review status in enabled mode", async () => {
672
+ const candidate = memory("pending", { status: "pending_review" });
673
+ const extraction = {
674
+ verifyContradiction: async () => ({
675
+ isContradiction: true,
676
+ confidence: 0.99,
677
+ reasoning: "values conflict",
678
+ whichIsNewer: "second",
679
+ }),
680
+ } as unknown as ExtractionEngine;
681
+ const coordinator = new ContradictionLinkingCoordinator({
682
+ getConfig: () =>
683
+ ({
684
+ contradictionSimilarityThreshold: 0.7,
685
+ contradictionMinConfidence: 0.9,
686
+ contradictionAutoResolve: true,
687
+ contradictionLocalization: {
688
+ anchorEnabled: true,
689
+ anchorCandidates: 5,
690
+ searchCandidates: 5,
691
+ maxCandidates: 8,
692
+ },
693
+ }) as unknown as PluginConfig,
694
+ isSearchAvailable: () => true,
695
+ searchAcrossNamespaces: async () => [qmdResult("pending", 0.95)],
696
+ extractMemoryIdsFromResults: (results) => results.map((result) => result.docid),
697
+ namespaceFromPath: () => "default",
698
+ storageForNamespace: async () => storage([candidate]),
699
+ getExtraction: () => extraction,
700
+ });
701
+
702
+ const result = await coordinator.checkForContradiction("incoming", "fact", "default");
703
+ assert.equal(result, null);
704
+ });
705
+
706
+ test("forwards the new content and search limit to QMD", async () => {
707
+ const calls: Array<{ query: string; limit: number }> = [];
708
+ const result = await localizeUpdateCandidates(
709
+ {
710
+ storage: storage([]),
711
+ qmdSearch: async (query, limit) => {
712
+ calls.push({ query, limit });
713
+ return [hit("search-hit", 0.9)];
714
+ },
715
+ },
716
+ { category: "fact" },
717
+ "incoming content",
718
+ { anchorCandidates: 0, searchCandidates: 3, maxCandidates: 5 },
719
+ );
720
+
721
+ assert.deepEqual(calls, [{ query: "incoming content", limit: 3 }]);
722
+ assert.deepEqual(result.map((candidate) => candidate.id), ["search-hit"]);
723
+ });
724
+
725
+ test("rejects malformed entity references without reading the memory corpus", async () => {
726
+ let readCount = 0;
727
+ let qmdCount = 0;
728
+ const result = await localizeUpdateCandidates(
729
+ {
730
+ storage: {
731
+ readAllMemories: async () => {
732
+ readCount++;
733
+ return [memory("stored", { entityRef: "person:alice" })];
734
+ },
735
+ },
736
+ qmdSearch: async () => {
737
+ qmdCount++;
738
+ return [];
739
+ },
740
+ },
741
+ { entityRef: { invalid: true } as unknown as string, category: "fact" },
742
+ "incoming content",
743
+ { anchorCandidates: 5, searchCandidates: 0, maxCandidates: 5 },
744
+ );
745
+
746
+ assert.deepEqual(result, []);
747
+ assert.equal(readCount, 0);
748
+ assert.equal(qmdCount, 0);
749
+ });
750
+
751
+ test("normalizes extracted and stored entity references symmetrically", async () => {
752
+ const result = await localizeUpdateCandidates(
753
+ {
754
+ storage: storage([memory("stored", { entityRef: "PERSON-ALICE" })]),
755
+ qmdSearch: search(),
756
+ },
757
+ { entityRef: "person alice", category: "fact" },
758
+ "incoming content",
759
+ { anchorCandidates: 5, searchCandidates: 0, maxCandidates: 5 },
760
+ );
761
+
762
+ assert.deepEqual(result.map((candidate) => candidate.id), ["stored"]);
763
+ });
764
+
765
+ test("runs anchor localization when QMD is unavailable and search is disabled", async () => {
766
+ const { coordinator, candidate } = coordinatorFixture({
767
+ contradictionLocalization: {
768
+ anchorEnabled: true,
769
+ anchorCandidates: 5,
770
+ searchCandidates: 0,
771
+ maxCandidates: 8,
772
+ },
773
+ });
774
+ (coordinator as unknown as { isSearchAvailable: () => boolean }).isSearchAvailable = () => false;
775
+
776
+ const result = await coordinator.checkForContradiction(
777
+ "Alice lives in New York",
778
+ "fact",
779
+ "default",
780
+ { entityRef: "person:alice", attributes: { city: "New York" } },
781
+ );
782
+
783
+ assert.equal(result?.supersededId, candidate.frontmatter.id);
784
+ });