@remnic/core 1.1.12 → 1.1.13

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 (1324) hide show
  1. package/dist/access-cli.d.ts +2 -1
  2. package/dist/access-cli.js +263 -82
  3. package/dist/access-cli.js.map +1 -1
  4. package/dist/access-http.d.ts +26 -60
  5. package/dist/access-http.js +43 -29
  6. package/dist/access-mcp.d.ts +24 -6
  7. package/dist/access-mcp.js +35 -28
  8. package/dist/access-schema.d.ts +9 -6
  9. package/dist/access-schema.js +7 -5
  10. package/dist/access-service-DcCDmNYC.d.ts +1542 -0
  11. package/dist/access-service.d.ts +25 -7
  12. package/dist/access-service.js +33 -26
  13. package/dist/active-memory-bridge.js +2 -2
  14. package/dist/active-recall.js +11 -3
  15. package/dist/active-recall.js.map +1 -1
  16. package/dist/adapters/claude-code.d.ts +24 -0
  17. package/dist/adapters/claude-code.js +9 -0
  18. package/dist/adapters/codex.d.ts +25 -0
  19. package/dist/adapters/codex.js +9 -0
  20. package/dist/adapters/hermes.d.ts +35 -0
  21. package/dist/adapters/hermes.js +9 -0
  22. package/dist/adapters/index.d.ts +6 -0
  23. package/dist/adapters/index.js +26 -0
  24. package/dist/adapters/registry.d.ts +20 -0
  25. package/dist/adapters/registry.js +13 -0
  26. package/dist/adapters/replit.d.ts +28 -0
  27. package/dist/adapters/replit.js +9 -0
  28. package/dist/adapters/types.d.ts +43 -0
  29. package/dist/adapters/types.js +8 -0
  30. package/dist/bootstrap.d.ts +20 -5
  31. package/dist/boxes.d.ts +7 -0
  32. package/dist/boxes.js +1 -1
  33. package/dist/briefing.d.ts +5 -3
  34. package/dist/briefing.js +9 -6
  35. package/dist/buffer-surprise-report.js +1 -1
  36. package/dist/buffer.d.ts +18 -4
  37. package/dist/buffer.js +1 -1
  38. package/dist/calibration.js +4 -4
  39. package/dist/capsule-cli.d.ts +4 -4
  40. package/dist/capsule-cli.js +1 -1
  41. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  42. package/dist/capsule-merge-4MGKE7C5.js +189 -0
  43. package/dist/causal-behavior.d.ts +8 -28
  44. package/dist/causal-behavior.js +6 -3
  45. package/dist/causal-behavior.js.map +1 -1
  46. package/dist/causal-chain.js +3 -2
  47. package/dist/causal-consolidation.d.ts +1 -1
  48. package/dist/causal-consolidation.js +24 -13
  49. package/dist/causal-consolidation.js.map +1 -1
  50. package/dist/causal-retrieval.js +3 -3
  51. package/dist/causal-trajectory.js +1 -1
  52. package/dist/chunk-25MQ7IHJ.js +427 -0
  53. package/dist/chunk-25MQ7IHJ.js.map +1 -0
  54. package/dist/chunk-2F2W355T.js +256 -0
  55. package/dist/chunk-2F2W355T.js.map +1 -0
  56. package/dist/chunk-2KI4QFHU.js +228 -0
  57. package/dist/chunk-2KI4QFHU.js.map +1 -0
  58. package/dist/chunk-2PRQG7PV.js +86 -0
  59. package/dist/chunk-2PRQG7PV.js.map +1 -0
  60. package/dist/chunk-2QR3XXIC.js +2272 -0
  61. package/dist/chunk-2QR3XXIC.js.map +1 -0
  62. package/dist/chunk-2WWLHTZY.js +121 -0
  63. package/dist/chunk-326G7DJK.js +2185 -0
  64. package/dist/chunk-326G7DJK.js.map +1 -0
  65. package/dist/chunk-34DQE4KF.js +174 -0
  66. package/dist/chunk-34DQE4KF.js.map +1 -0
  67. package/dist/chunk-3APJ5EVB.js +601 -0
  68. package/dist/chunk-3APJ5EVB.js.map +1 -0
  69. package/dist/chunk-3HPAPHUK.js +51 -0
  70. package/dist/chunk-3HPAPHUK.js.map +1 -0
  71. package/dist/chunk-3JXBXXM2.js +69 -0
  72. package/dist/chunk-3JXBXXM2.js.map +1 -0
  73. package/dist/chunk-3KW65B36.js +681 -0
  74. package/dist/chunk-3KW65B36.js.map +1 -0
  75. package/dist/chunk-3UXOZBHV.js +20 -0
  76. package/dist/chunk-3UXOZBHV.js.map +1 -0
  77. package/dist/chunk-3VAL7ZL2.js +266 -0
  78. package/dist/chunk-3VAL7ZL2.js.map +1 -0
  79. package/dist/chunk-3Y4P7RXM.js +31 -0
  80. package/dist/chunk-3Y4P7RXM.js.map +1 -0
  81. package/dist/chunk-47VWKCAF.js +273 -0
  82. package/dist/chunk-47VWKCAF.js.map +1 -0
  83. package/dist/chunk-4CRG46BG.js +271 -0
  84. package/dist/chunk-5375UYTQ.js +914 -0
  85. package/dist/chunk-5375UYTQ.js.map +1 -0
  86. package/dist/chunk-56K5QLHX.js +506 -0
  87. package/dist/chunk-56K5QLHX.js.map +1 -0
  88. package/dist/chunk-5RGLBDQF.js +596 -0
  89. package/dist/chunk-5RGLBDQF.js.map +1 -0
  90. package/dist/chunk-5UZXUTVO.js +9 -0
  91. package/dist/chunk-5UZXUTVO.js.map +1 -0
  92. package/dist/chunk-65PG43EQ.js +105 -0
  93. package/dist/chunk-65PG43EQ.js.map +1 -0
  94. package/dist/chunk-66DHUKLO.js +57 -0
  95. package/dist/chunk-66DHUKLO.js.map +1 -0
  96. package/dist/chunk-6FC5EGNV.js +46 -0
  97. package/dist/chunk-6FC5EGNV.js.map +1 -0
  98. package/dist/chunk-6H2TESSP.js +62 -0
  99. package/dist/chunk-6H2TESSP.js.map +1 -0
  100. package/dist/chunk-6LVVDPJ4.js +32 -0
  101. package/dist/chunk-6LVVDPJ4.js.map +1 -0
  102. package/dist/chunk-6RVI47ZR.js +159 -0
  103. package/dist/chunk-6RVI47ZR.js.map +1 -0
  104. package/dist/chunk-7AAT6G4Q.js +5117 -0
  105. package/dist/chunk-7AAT6G4Q.js.map +1 -0
  106. package/dist/chunk-7DTASS5T.js +29 -0
  107. package/dist/chunk-7DTASS5T.js.map +1 -0
  108. package/dist/chunk-7IASACLB.js +596 -0
  109. package/dist/chunk-7MNMYOFP.js +32 -0
  110. package/dist/chunk-7MNMYOFP.js.map +1 -0
  111. package/dist/chunk-7N4KAIGN.js +133 -0
  112. package/dist/chunk-7N4KAIGN.js.map +1 -0
  113. package/dist/chunk-7OZ53EXP.js +101 -0
  114. package/dist/chunk-7OZ53EXP.js.map +1 -0
  115. package/dist/chunk-7XYTQGCC.js +134 -0
  116. package/dist/chunk-7XYTQGCC.js.map +1 -0
  117. package/dist/chunk-A2XUIMJ3.js +341 -0
  118. package/dist/chunk-A2XUIMJ3.js.map +1 -0
  119. package/dist/chunk-AGZQD76C.js +201 -0
  120. package/dist/chunk-AGZQD76C.js.map +1 -0
  121. package/dist/chunk-APO3DCMU.js +361 -0
  122. package/dist/chunk-APO3DCMU.js.map +1 -0
  123. package/dist/chunk-BFBF3XEF.js +283 -0
  124. package/dist/chunk-BFBF3XEF.js.map +1 -0
  125. package/dist/chunk-BJ3KMYTB.js +1974 -0
  126. package/dist/chunk-BJ3KMYTB.js.map +1 -0
  127. package/dist/chunk-CHEL3SKB.js +6758 -0
  128. package/dist/chunk-CHEL3SKB.js.map +1 -0
  129. package/dist/chunk-CQZRLNMV.js +1491 -0
  130. package/dist/chunk-CQZRLNMV.js.map +1 -0
  131. package/dist/chunk-D46YSIYX.js +892 -0
  132. package/dist/chunk-D46YSIYX.js.map +1 -0
  133. package/dist/chunk-DINWEURR.js +648 -0
  134. package/dist/chunk-DINWEURR.js.map +1 -0
  135. package/dist/chunk-DK5LDEQM.js +530 -0
  136. package/dist/chunk-DK5LDEQM.js.map +1 -0
  137. package/dist/chunk-DOM4GKSW.js +34 -0
  138. package/dist/chunk-DOM4GKSW.js.map +1 -0
  139. package/dist/chunk-EDTHC6UD.js +1075 -0
  140. package/dist/chunk-EFJ3MQ4V.js +721 -0
  141. package/dist/chunk-EHRTFRWW.js +89 -0
  142. package/dist/chunk-EHRTFRWW.js.map +1 -0
  143. package/dist/chunk-FAJ7FZYM.js +11 -0
  144. package/dist/chunk-FAJ7FZYM.js.map +1 -0
  145. package/dist/chunk-FBYESMQ2.js +570 -0
  146. package/dist/chunk-FDU6HUUL.js +147 -0
  147. package/dist/chunk-FF4KLI5W.js +99 -0
  148. package/dist/chunk-FF4KLI5W.js.map +1 -0
  149. package/dist/chunk-FIT6DMX6.js +310 -0
  150. package/dist/chunk-FIT6DMX6.js.map +1 -0
  151. package/dist/chunk-FJ43PRLT.js +272 -0
  152. package/dist/chunk-FJ43PRLT.js.map +1 -0
  153. package/dist/chunk-FKFMOY3N.js +32 -0
  154. package/dist/chunk-FKFMOY3N.js.map +1 -0
  155. package/dist/chunk-FLTNHQK6.js +262 -0
  156. package/dist/chunk-FLTNHQK6.js.map +1 -0
  157. package/dist/chunk-GA454ALV.js +12436 -0
  158. package/dist/chunk-GA454ALV.js.map +1 -0
  159. package/dist/chunk-GGKRUQOO.js +228 -0
  160. package/dist/chunk-GIF42EW3.js +63 -0
  161. package/dist/chunk-GIF42EW3.js.map +1 -0
  162. package/dist/chunk-GL6I6MEQ.js +647 -0
  163. package/dist/chunk-H3ME6L6D.js +709 -0
  164. package/dist/chunk-H3ME6L6D.js.map +1 -0
  165. package/dist/chunk-HHLLAQGZ.js +1 -0
  166. package/dist/chunk-HXXBL2KD.js +2040 -0
  167. package/dist/chunk-I5V2VDIW.js +219 -0
  168. package/dist/chunk-I5V2VDIW.js.map +1 -0
  169. package/dist/chunk-I6K5FBRQ.js +35 -0
  170. package/dist/chunk-I6K5FBRQ.js.map +1 -0
  171. package/dist/chunk-ICRIXAP2.js +121 -0
  172. package/dist/chunk-ICRIXAP2.js.map +1 -0
  173. package/dist/chunk-J4EB7DNW.js +11 -0
  174. package/dist/chunk-J4EB7DNW.js.map +1 -0
  175. package/dist/chunk-JLFA7DQG.js +62 -0
  176. package/dist/chunk-JLFA7DQG.js.map +1 -0
  177. package/dist/chunk-KJTKLXTH.js +9 -0
  178. package/dist/chunk-KJTKLXTH.js.map +1 -0
  179. package/dist/chunk-KLAO5DGL.js +917 -0
  180. package/dist/chunk-KLAO5DGL.js.map +1 -0
  181. package/dist/chunk-KNKUID7G.js +183 -0
  182. package/dist/chunk-KOSORCJG.js +624 -0
  183. package/dist/chunk-KOSORCJG.js.map +1 -0
  184. package/dist/chunk-KUJVMMZQ.js +1262 -0
  185. package/dist/chunk-KUJVMMZQ.js.map +1 -0
  186. package/dist/chunk-LCR46JY5.js +123 -0
  187. package/dist/chunk-LCR46JY5.js.map +1 -0
  188. package/dist/chunk-LLQ2LLWF.js +148 -0
  189. package/dist/chunk-LLQ2LLWF.js.map +1 -0
  190. package/dist/chunk-LPMVBPA3.js +236 -0
  191. package/dist/chunk-LT3NLYSI.js +50 -0
  192. package/dist/chunk-LT3NLYSI.js.map +1 -0
  193. package/dist/chunk-LUDTDZLK.js +287 -0
  194. package/dist/chunk-LUDTDZLK.js.map +1 -0
  195. package/dist/chunk-M23FSH32.js +3963 -0
  196. package/dist/chunk-M23FSH32.js.map +1 -0
  197. package/dist/chunk-MC26UJIM.js +118 -0
  198. package/dist/chunk-ME6ESPZU.js +119 -0
  199. package/dist/chunk-ME6ESPZU.js.map +1 -0
  200. package/dist/chunk-MGKYQQYF.js +272 -0
  201. package/dist/chunk-MJFNCJXV.js +66 -0
  202. package/dist/chunk-MJFNCJXV.js.map +1 -0
  203. package/dist/chunk-MSWG7JI6.js +237 -0
  204. package/dist/chunk-MSWG7JI6.js.map +1 -0
  205. package/dist/chunk-MT25YHYH.js +141 -0
  206. package/dist/chunk-MT25YHYH.js.map +1 -0
  207. package/dist/chunk-MT4HVDUZ.js +53 -0
  208. package/dist/chunk-MY6TPVXW.js +219 -0
  209. package/dist/chunk-N2D6GXBM.js +267 -0
  210. package/dist/chunk-N2D6GXBM.js.map +1 -0
  211. package/dist/chunk-NJ3MJQZX.js +46 -0
  212. package/dist/chunk-NJ3MJQZX.js.map +1 -0
  213. package/dist/chunk-NMZY542O.js +335 -0
  214. package/dist/chunk-NMZY542O.js.map +1 -0
  215. package/dist/chunk-NNVTUXEB.js +23 -0
  216. package/dist/chunk-NZL6GGQE.js +375 -0
  217. package/dist/chunk-NZL6GGQE.js.map +1 -0
  218. package/dist/chunk-P4NEIHUT.js +108 -0
  219. package/dist/chunk-P7FMDTKL.js +103 -0
  220. package/dist/chunk-P7FMDTKL.js.map +1 -0
  221. package/dist/chunk-PHK3HARR.js +32 -0
  222. package/dist/chunk-PHK3HARR.js.map +1 -0
  223. package/dist/chunk-PIRJPV5T.js +98 -0
  224. package/dist/chunk-PIRJPV5T.js.map +1 -0
  225. package/dist/chunk-PK7H5L6Y.js +159 -0
  226. package/dist/chunk-PK7H5L6Y.js.map +1 -0
  227. package/dist/chunk-PR5FBTFU.js +233 -0
  228. package/dist/chunk-PR5FBTFU.js.map +1 -0
  229. package/dist/chunk-PU63GXWS.js +174 -0
  230. package/dist/chunk-PU63GXWS.js.map +1 -0
  231. package/dist/chunk-PZIAX57I.js +124 -0
  232. package/dist/chunk-PZIAX57I.js.map +1 -0
  233. package/dist/chunk-Q7P4WJDP.js +26 -0
  234. package/dist/chunk-Q7P4WJDP.js.map +1 -0
  235. package/dist/chunk-QQUAB63I.js +63 -0
  236. package/dist/chunk-QQUAB63I.js.map +1 -0
  237. package/dist/chunk-QRNI5JBH.js +18 -0
  238. package/dist/chunk-RHY3HH7P.js +601 -0
  239. package/dist/chunk-RHY3HH7P.js.map +1 -0
  240. package/dist/chunk-RRF5UOBJ.js +91 -0
  241. package/dist/chunk-RXDLTSWT.js +124 -0
  242. package/dist/chunk-RXDLTSWT.js.map +1 -0
  243. package/dist/chunk-RYED3SPJ.js +42 -0
  244. package/dist/chunk-RYED3SPJ.js.map +1 -0
  245. package/dist/chunk-S7KDBTWT.js +106 -0
  246. package/dist/chunk-S7KDBTWT.js.map +1 -0
  247. package/dist/chunk-SEDEKFYQ.js +1 -0
  248. package/dist/chunk-TECVW3JP.js +36 -0
  249. package/dist/chunk-TECVW3JP.js.map +1 -0
  250. package/dist/chunk-TFO23QT4.js +88 -0
  251. package/dist/chunk-TFO23QT4.js.map +1 -0
  252. package/dist/chunk-TK4UEOSK.js +76 -0
  253. package/dist/chunk-TK4UEOSK.js.map +1 -0
  254. package/dist/chunk-TKWGAOLV.js +122 -0
  255. package/dist/chunk-TKWGAOLV.js.map +1 -0
  256. package/dist/chunk-TMM4S4IJ.js +597 -0
  257. package/dist/chunk-TMM4S4IJ.js.map +1 -0
  258. package/dist/chunk-TMQLARTH.js +188 -0
  259. package/dist/chunk-TMQLARTH.js.map +1 -0
  260. package/dist/chunk-TPDBFYEG.js +130 -0
  261. package/dist/chunk-TPDBFYEG.js.map +1 -0
  262. package/dist/chunk-TPMQ3G6Z.js +145 -0
  263. package/dist/chunk-TPMQ3G6Z.js.map +1 -0
  264. package/dist/chunk-TZOLIGIG.js +61 -0
  265. package/dist/chunk-TZOLIGIG.js.map +1 -0
  266. package/dist/chunk-U3PN77QT.js +113 -0
  267. package/dist/chunk-U3WSW6PZ.js +277 -0
  268. package/dist/chunk-U4SCL7B7.js +640 -0
  269. package/dist/chunk-U4SCL7B7.js.map +1 -0
  270. package/dist/chunk-UWK5OXUJ.js +156 -0
  271. package/dist/chunk-UWK5OXUJ.js.map +1 -0
  272. package/dist/chunk-UWVJF25J.js +74 -0
  273. package/dist/chunk-UXHQAFNA.js +1317 -0
  274. package/dist/chunk-UXHQAFNA.js.map +1 -0
  275. package/dist/chunk-V5OCT34X.js +1 -0
  276. package/dist/chunk-VLXA6PI2.js +304 -0
  277. package/dist/chunk-VLXA6PI2.js.map +1 -0
  278. package/dist/chunk-VNO6ZJ35.js +500 -0
  279. package/dist/chunk-VNO6ZJ35.js.map +1 -0
  280. package/dist/chunk-VW676BEI.js +827 -0
  281. package/dist/chunk-VW676BEI.js.map +1 -0
  282. package/dist/chunk-W3LR522O.js +2296 -0
  283. package/dist/chunk-W4L6CZKA.js +96 -0
  284. package/dist/chunk-W4L6CZKA.js.map +1 -0
  285. package/dist/chunk-W4RVMTHR.js +372 -0
  286. package/dist/chunk-W4RVMTHR.js.map +1 -0
  287. package/dist/chunk-WEHSQBFR.js +188 -0
  288. package/dist/chunk-WEHSQBFR.js.map +1 -0
  289. package/dist/chunk-WELDCG6C.js +380 -0
  290. package/dist/chunk-WELDCG6C.js.map +1 -0
  291. package/dist/chunk-WZYKANL3.js +2800 -0
  292. package/dist/chunk-WZYKANL3.js.map +1 -0
  293. package/dist/chunk-XIG5PDM7.js +48 -0
  294. package/dist/chunk-XJNBEDFE.js +193 -0
  295. package/dist/chunk-XJNBEDFE.js.map +1 -0
  296. package/dist/chunk-XVVIG67A.js +291 -0
  297. package/dist/chunk-XVVIG67A.js.map +1 -0
  298. package/dist/chunk-XVZ7B3HG.js +135 -0
  299. package/dist/chunk-YBPYIAA5.js +73 -0
  300. package/dist/chunk-YBPYIAA5.js.map +1 -0
  301. package/dist/chunk-Z734BLO3.js +21 -0
  302. package/dist/chunk-Z734BLO3.js.map +1 -0
  303. package/dist/chunk-ZKSK55RC.js +269 -0
  304. package/dist/chunk-ZKSK55RC.js.map +1 -0
  305. package/dist/chunk-ZTFCYYEZ.js +69 -0
  306. package/dist/chunk-ZTFCYYEZ.js.map +1 -0
  307. package/dist/chunk-ZY2MNJR6.js +329 -0
  308. package/dist/chunk-ZY2MNJR6.js.map +1 -0
  309. package/dist/cli-D3VpkVwB.d.ts +1136 -0
  310. package/dist/cli.d.ts +39 -10
  311. package/dist/cli.js +108 -49
  312. package/dist/commitment-ledger.js +1 -1
  313. package/dist/compat/checks.d.ts +5 -0
  314. package/dist/compat/checks.js +11 -0
  315. package/dist/compat/checks.js.map +1 -0
  316. package/dist/compat/types.d.ts +30 -0
  317. package/dist/compat/types.js +1 -0
  318. package/dist/compat/types.js.map +1 -0
  319. package/dist/compounding/engine.d.ts +221 -0
  320. package/dist/compounding/engine.js +32 -0
  321. package/dist/compounding/engine.js.map +1 -0
  322. package/dist/compounding/preference-consolidator.d.ts +92 -0
  323. package/dist/compounding/preference-consolidator.js +553 -0
  324. package/dist/compounding/preference-consolidator.js.map +1 -0
  325. package/dist/config.d.ts +4 -2
  326. package/dist/config.js +9 -4
  327. package/dist/conflict-policy-DyJ2wd-h.d.ts +4 -0
  328. package/dist/connectors/codex-materialize-runner.d.ts +64 -0
  329. package/dist/connectors/codex-materialize-runner.js +33 -0
  330. package/dist/connectors/codex-materialize-runner.js.map +1 -0
  331. package/dist/connectors/codex-materialize.d.ts +195 -0
  332. package/dist/connectors/codex-materialize.js +38 -0
  333. package/dist/connectors/codex-materialize.js.map +1 -0
  334. package/dist/connectors/index.d.ts +444 -0
  335. package/dist/connectors/index.js +115 -0
  336. package/dist/connectors/index.js.map +1 -0
  337. package/dist/connectors-cli-CwbyjGR7.d.ts +257 -0
  338. package/dist/connectors-cli.d.ts +1 -1
  339. package/dist/consolidation-provenance-check.d.ts +3 -1
  340. package/dist/consolidation-undo.d.ts +3 -1
  341. package/dist/contradiction/index.d.ts +258 -0
  342. package/dist/contradiction/index.js +43 -0
  343. package/dist/contradiction/index.js.map +1 -0
  344. package/dist/contradiction-review-ATP4S6IC.js +30 -0
  345. package/dist/contradiction-review-ATP4S6IC.js.map +1 -0
  346. package/dist/contradiction-scan-5A4IDZV5.js +13 -0
  347. package/dist/contradiction-scan-5A4IDZV5.js.map +1 -0
  348. package/dist/conversation-index/backend.d.ts +97 -0
  349. package/dist/conversation-index/backend.js +13 -0
  350. package/dist/conversation-index/backend.js.map +1 -0
  351. package/dist/conversation-index/chunker.d.ts +16 -0
  352. package/dist/conversation-index/chunker.js +8 -0
  353. package/dist/conversation-index/chunker.js.map +1 -0
  354. package/dist/conversation-index/cleanup.d.ts +11 -0
  355. package/dist/conversation-index/cleanup.js +9 -0
  356. package/dist/conversation-index/cleanup.js.map +1 -0
  357. package/dist/conversation-index/faiss-adapter.d.ts +6 -0
  358. package/dist/conversation-index/faiss-adapter.js +16 -0
  359. package/dist/conversation-index/faiss-adapter.js.map +1 -0
  360. package/dist/conversation-index/indexer.d.ts +23 -0
  361. package/dist/conversation-index/indexer.js +15 -0
  362. package/dist/conversation-index/indexer.js.map +1 -0
  363. package/dist/conversation-index/search.d.ts +6 -0
  364. package/dist/conversation-index/search.js +11 -0
  365. package/dist/conversation-index/search.js.map +1 -0
  366. package/dist/embedding-fallback.js +2 -2
  367. package/dist/enrichment/index.d.ts +163 -0
  368. package/dist/enrichment/index.js +18 -0
  369. package/dist/enrichment/index.js.map +1 -0
  370. package/dist/entity-retrieval.d.ts +4 -2
  371. package/dist/entity-retrieval.js +8 -5
  372. package/dist/evals.js +1 -1
  373. package/dist/explicit-capture.d.ts +20 -5
  374. package/dist/explicit-capture.js +2 -2
  375. package/dist/extraction-judge-training.js +1 -1
  376. package/dist/extraction.js +8 -8
  377. package/dist/faiss-adapter-CzPghc4C.d.ts +70 -0
  378. package/dist/fallback-llm.d.ts +2 -0
  379. package/dist/fallback-llm.js +4 -4
  380. package/dist/graph-edge-decay-5DI5GUNL.js +207 -0
  381. package/dist/index.d.ts +66 -711
  382. package/dist/index.js +556 -2680
  383. package/dist/index.js.map +1 -1
  384. package/dist/lcm/archive.d.ts +89 -0
  385. package/dist/lcm/archive.js +12 -0
  386. package/dist/lcm/archive.js.map +1 -0
  387. package/dist/lcm/dag.d.ts +48 -0
  388. package/dist/lcm/dag.js +8 -0
  389. package/dist/lcm/dag.js.map +1 -0
  390. package/dist/lcm/engine.d.ts +116 -0
  391. package/dist/lcm/engine.js +20 -0
  392. package/dist/lcm/engine.js.map +1 -0
  393. package/dist/lcm/index.d.ts +12 -0
  394. package/dist/lcm/index.js +44 -0
  395. package/dist/lcm/index.js.map +1 -0
  396. package/dist/lcm/queue.d.ts +62 -0
  397. package/dist/lcm/queue.js +8 -0
  398. package/dist/lcm/queue.js.map +1 -0
  399. package/dist/lcm/recall.d.ts +20 -0
  400. package/dist/lcm/recall.js +8 -0
  401. package/dist/lcm/recall.js.map +1 -0
  402. package/dist/lcm/schema.d.ts +16 -0
  403. package/dist/lcm/schema.js +14 -0
  404. package/dist/lcm/schema.js.map +1 -0
  405. package/dist/lcm/summarizer.d.ts +38 -0
  406. package/dist/lcm/summarizer.js +12 -0
  407. package/dist/lcm/summarizer.js.map +1 -0
  408. package/dist/lcm/tools.d.ts +29 -0
  409. package/dist/lcm/tools.js +8 -0
  410. package/dist/lcm/tools.js.map +1 -0
  411. package/dist/live-connectors-runner.js +5 -5
  412. package/dist/local-llm.js +3 -3
  413. package/dist/maintenance/archive-observations.d.ts +18 -0
  414. package/dist/maintenance/archive-observations.js +8 -0
  415. package/dist/maintenance/archive-observations.js.map +1 -0
  416. package/dist/maintenance/backup-stamp.d.ts +3 -0
  417. package/dist/maintenance/backup-stamp.js +8 -0
  418. package/dist/maintenance/backup-stamp.js.map +1 -0
  419. package/dist/maintenance/memory-governance-cron.d.ts +85 -0
  420. package/dist/maintenance/memory-governance-cron.js +22 -0
  421. package/dist/maintenance/memory-governance-cron.js.map +1 -0
  422. package/dist/maintenance/memory-governance.d.ts +137 -0
  423. package/dist/maintenance/memory-governance.js +40 -0
  424. package/dist/maintenance/memory-governance.js.map +1 -0
  425. package/dist/maintenance/migrate-observations.d.ts +18 -0
  426. package/dist/maintenance/migrate-observations.js +9 -0
  427. package/dist/maintenance/migrate-observations.js.map +1 -0
  428. package/dist/maintenance/observation-ledger-utils.d.ts +10 -0
  429. package/dist/maintenance/observation-ledger-utils.js +10 -0
  430. package/dist/maintenance/observation-ledger-utils.js.map +1 -0
  431. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +15 -0
  432. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +28 -0
  433. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js.map +1 -0
  434. package/dist/maintenance/rebuild-memory-projection.d.ts +77 -0
  435. package/dist/maintenance/rebuild-memory-projection.js +35 -0
  436. package/dist/maintenance/rebuild-memory-projection.js.map +1 -0
  437. package/dist/maintenance/rebuild-observations.d.ts +17 -0
  438. package/dist/maintenance/rebuild-observations.js +9 -0
  439. package/dist/maintenance/rebuild-observations.js.map +1 -0
  440. package/dist/mcp-memory-inspector-app.d.ts +24 -6
  441. package/dist/memory-projection-store.d.ts +108 -3
  442. package/dist/memory-projection-store.js +2 -1
  443. package/dist/memory-worth-outcomes.d.ts +4 -2
  444. package/dist/migrate/from-engram.d.ts +24 -0
  445. package/dist/migrate/from-engram.js +12 -0
  446. package/dist/migrate/from-engram.js.map +1 -0
  447. package/dist/namespaces/migrate.d.ts +50 -0
  448. package/dist/namespaces/migrate.js +50 -0
  449. package/dist/namespaces/migrate.js.map +1 -0
  450. package/dist/namespaces/principal.d.ts +17 -0
  451. package/dist/namespaces/principal.js +16 -0
  452. package/dist/namespaces/principal.js.map +1 -0
  453. package/dist/namespaces/search.d.ts +46 -0
  454. package/dist/namespaces/search.js +28 -0
  455. package/dist/namespaces/search.js.map +1 -0
  456. package/dist/namespaces/storage.d.ts +32 -0
  457. package/dist/namespaces/storage.js +28 -0
  458. package/dist/namespaces/storage.js.map +1 -0
  459. package/dist/network/tailscale.d.ts +41 -0
  460. package/dist/network/tailscale.js +9 -0
  461. package/dist/network/tailscale.js.map +1 -0
  462. package/dist/network/webdav.d.ts +39 -0
  463. package/dist/network/webdav.js +10 -0
  464. package/dist/network/webdav.js.map +1 -0
  465. package/dist/objective-state-writers.js +2 -2
  466. package/dist/operator-toolkit.d.ts +4 -2
  467. package/dist/operator-toolkit.js +32 -14
  468. package/dist/opik-exporter.js +2 -2
  469. package/dist/opik-exporter.js.map +1 -1
  470. package/dist/orchestrator-DuWl9Hwx.d.ts +1244 -0
  471. package/dist/orchestrator.d.ts +22 -7
  472. package/dist/orchestrator.js +79 -44
  473. package/dist/path-MR5JPYOP.js +9 -0
  474. package/dist/path-MR5JPYOP.js.map +1 -0
  475. package/dist/qmd-recall-cache.d.ts +1 -1
  476. package/dist/qmd.d.ts +102 -3
  477. package/dist/qmd.js +23 -5
  478. package/dist/recall-explain-renderer.js +3 -3
  479. package/dist/recall-xray-cli.js +4 -4
  480. package/dist/recall-xray-renderer.js +3 -3
  481. package/dist/recall-xray.js +2 -2
  482. package/dist/replay/normalizers/chatgpt.d.ts +6 -0
  483. package/dist/replay/normalizers/chatgpt.js +11 -0
  484. package/dist/replay/normalizers/chatgpt.js.map +1 -0
  485. package/dist/replay/normalizers/claude.d.ts +6 -0
  486. package/dist/replay/normalizers/claude.js +11 -0
  487. package/dist/replay/normalizers/claude.js.map +1 -0
  488. package/dist/replay/normalizers/openclaw.d.ts +6 -0
  489. package/dist/replay/normalizers/openclaw.js +11 -0
  490. package/dist/replay/normalizers/openclaw.js.map +1 -0
  491. package/dist/replay/normalizers/shared.d.ts +16 -0
  492. package/dist/replay/normalizers/shared.js +14 -0
  493. package/dist/replay/normalizers/shared.js.map +1 -0
  494. package/dist/replay/runner.d.ts +35 -0
  495. package/dist/replay/runner.js +16 -0
  496. package/dist/replay/runner.js.map +1 -0
  497. package/dist/replay/types.d.ts +57 -0
  498. package/dist/replay/types.js +19 -0
  499. package/dist/replay/types.js.map +1 -0
  500. package/dist/resolution-B7FNQSSP.js +12 -0
  501. package/dist/resolution-B7FNQSSP.js.map +1 -0
  502. package/dist/resolve-provider-secret.js +2 -2
  503. package/dist/resume-bundles.js +8 -6
  504. package/dist/retrieval-agents.d.ts +1 -1
  505. package/dist/routing/engine.d.ts +35 -0
  506. package/dist/routing/engine.js +16 -0
  507. package/dist/routing/engine.js.map +1 -0
  508. package/dist/routing/store.d.ts +27 -0
  509. package/dist/routing/store.js +10 -0
  510. package/dist/routing/store.js.map +1 -0
  511. package/dist/runtime/better-sqlite.d.ts +8 -0
  512. package/dist/runtime/better-sqlite.js +10 -0
  513. package/dist/runtime/better-sqlite.js.map +1 -0
  514. package/dist/runtime/child-process.d.ts +32 -0
  515. package/dist/runtime/child-process.js +10 -0
  516. package/dist/runtime/child-process.js.map +1 -0
  517. package/dist/runtime/env.d.ts +5 -0
  518. package/dist/runtime/env.js +12 -0
  519. package/dist/runtime/env.js.map +1 -0
  520. package/dist/schemas.d.ts +22 -22
  521. package/dist/sdk-compat.js +1 -1
  522. package/dist/search/document-scanner.d.ts +22 -0
  523. package/dist/search/document-scanner.js +8 -0
  524. package/dist/search/document-scanner.js.map +1 -0
  525. package/dist/search/embed-helper.d.ts +35 -0
  526. package/dist/search/embed-helper.js +9 -0
  527. package/dist/search/embed-helper.js.map +1 -0
  528. package/dist/search/factory.d.ts +32 -0
  529. package/dist/search/factory.js +29 -0
  530. package/dist/search/factory.js.map +1 -0
  531. package/dist/search/index.d.ts +15 -0
  532. package/dist/search/index.js +50 -0
  533. package/dist/search/index.js.map +1 -0
  534. package/dist/search/lancedb-backend.d.ts +51 -0
  535. package/dist/search/lancedb-backend.js +10 -0
  536. package/dist/search/lancedb-backend.js.map +1 -0
  537. package/dist/search/meilisearch-backend.d.ts +48 -0
  538. package/dist/search/meilisearch-backend.js +10 -0
  539. package/dist/search/meilisearch-backend.js.map +1 -0
  540. package/dist/search/noop-backend.d.ts +26 -0
  541. package/dist/search/noop-backend.js +8 -0
  542. package/dist/search/noop-backend.js.map +1 -0
  543. package/dist/search/orama-backend.d.ts +53 -0
  544. package/dist/search/orama-backend.js +10 -0
  545. package/dist/search/orama-backend.js.map +1 -0
  546. package/dist/search/port.d.ts +61 -0
  547. package/dist/search/port.js +1 -0
  548. package/dist/search/port.js.map +1 -0
  549. package/dist/search/remote-backend.d.ts +39 -0
  550. package/dist/search/remote-backend.js +9 -0
  551. package/dist/search/remote-backend.js.map +1 -0
  552. package/dist/secure-store/index.d.ts +890 -0
  553. package/dist/secure-store/index.js +156 -0
  554. package/dist/secure-store/index.js.map +1 -0
  555. package/dist/semantic-VwGI14Ok.d.ts +69 -0
  556. package/dist/semantic-consolidation-4HkHWgeI.d.ts +180 -0
  557. package/dist/semantic-consolidation.d.ts +2 -2
  558. package/dist/semantic-consolidation.js +13 -6
  559. package/dist/semantic-rule-promotion.js +8 -5
  560. package/dist/semantic-rule-verifier.js +8 -5
  561. package/dist/shared-context/manager.d.ts +131 -0
  562. package/dist/shared-context/manager.js +15 -0
  563. package/dist/shared-context/manager.js.map +1 -0
  564. package/dist/skills-registry.js +13 -1
  565. package/dist/skills-registry.js.map +1 -1
  566. package/dist/state-store-VZU2IA53.js +16 -0
  567. package/dist/state-store-VZU2IA53.js.map +1 -0
  568. package/dist/storage-paths.d.ts +9 -0
  569. package/dist/storage-paths.js +20 -0
  570. package/dist/storage-paths.js.map +1 -0
  571. package/dist/storage.d.ts +3 -1
  572. package/dist/storage.js +7 -4
  573. package/dist/summarizer.d.ts +5 -0
  574. package/dist/summarizer.js +9 -8
  575. package/dist/summary-snapshot.js +2 -1
  576. package/dist/surfaces/dreams.d.ts +16 -0
  577. package/dist/surfaces/dreams.js +282 -0
  578. package/dist/surfaces/dreams.js.map +1 -0
  579. package/dist/surfaces/heartbeat.d.ts +17 -0
  580. package/dist/surfaces/heartbeat.js +265 -0
  581. package/dist/surfaces/heartbeat.js.map +1 -0
  582. package/dist/temporal-supersession.d.ts +3 -1
  583. package/dist/threading.d.ts +5 -0
  584. package/dist/threading.js +2 -1
  585. package/dist/tier-migration.d.ts +4 -2
  586. package/dist/tokens.js +2 -2
  587. package/dist/transcript.d.ts +15 -1
  588. package/dist/transcript.js +2 -1
  589. package/dist/transfer/autodetect.d.ts +4 -0
  590. package/dist/transfer/autodetect.js +15 -0
  591. package/dist/transfer/autodetect.js.map +1 -0
  592. package/dist/transfer/backup.d.ts +21 -0
  593. package/dist/transfer/backup.js +17 -0
  594. package/dist/transfer/backup.js.map +1 -0
  595. package/dist/transfer/capsule-export.d.ts +113 -0
  596. package/dist/transfer/capsule-export.js +19 -0
  597. package/dist/transfer/capsule-export.js.map +1 -0
  598. package/dist/transfer/capsule-import.d.ts +124 -0
  599. package/dist/transfer/capsule-import.js +16 -0
  600. package/dist/transfer/capsule-import.js.map +1 -0
  601. package/dist/transfer/constants.d.ts +13 -0
  602. package/dist/transfer/constants.js +12 -0
  603. package/dist/transfer/constants.js.map +1 -0
  604. package/dist/transfer/export-json.d.ts +11 -0
  605. package/dist/transfer/export-json.js +11 -0
  606. package/dist/transfer/export-json.js.map +1 -0
  607. package/dist/transfer/export-md.d.ts +10 -0
  608. package/dist/transfer/export-md.js +13 -0
  609. package/dist/transfer/export-md.js.map +1 -0
  610. package/dist/transfer/export-sqlite.d.ts +9 -0
  611. package/dist/transfer/export-sqlite.js +12 -0
  612. package/dist/transfer/export-sqlite.js.map +1 -0
  613. package/dist/transfer/fs-utils.d.ts +61 -0
  614. package/dist/transfer/fs-utils.js +40 -0
  615. package/dist/transfer/fs-utils.js.map +1 -0
  616. package/dist/transfer/import-json.d.ts +16 -0
  617. package/dist/transfer/import-json.js +13 -0
  618. package/dist/transfer/import-json.js.map +1 -0
  619. package/dist/transfer/import-md.d.ts +14 -0
  620. package/dist/transfer/import-md.js +11 -0
  621. package/dist/transfer/import-md.js.map +1 -0
  622. package/dist/transfer/import-sqlite.d.ts +14 -0
  623. package/dist/transfer/import-sqlite.js +12 -0
  624. package/dist/transfer/import-sqlite.js.map +1 -0
  625. package/dist/transfer/sqlite-schema.d.ts +4 -0
  626. package/dist/transfer/sqlite-schema.js +10 -0
  627. package/dist/transfer/sqlite-schema.js.map +1 -0
  628. package/dist/transfer/types.d.ts +916 -0
  629. package/dist/transfer/types.js +30 -0
  630. package/dist/transfer/types.js.map +1 -0
  631. package/dist/types.d.ts +28 -1
  632. package/dist/types.js +1 -1
  633. package/dist/verified-recall.js +9 -6
  634. package/dist/work/board.d.ts +43 -0
  635. package/dist/work/board.js +14 -0
  636. package/dist/work/board.js.map +1 -0
  637. package/dist/work/boundary.d.ts +8 -0
  638. package/dist/work/boundary.js +14 -0
  639. package/dist/work/boundary.js.map +1 -0
  640. package/dist/work/storage.d.ts +39 -0
  641. package/dist/work/storage.js +11 -0
  642. package/dist/work/storage.js.map +1 -0
  643. package/dist/work/types.d.ts +75 -0
  644. package/dist/work/types.js +1 -0
  645. package/dist/work/types.js.map +1 -0
  646. package/package.json +2767 -6
  647. package/scripts/faiss_index.py +816 -0
  648. package/scripts/faiss_requirements.txt +3 -0
  649. package/skills/remnic-entities/SKILL.md +51 -0
  650. package/skills/remnic-memory-workflow/SKILL.md +61 -0
  651. package/skills/remnic-recall/SKILL.md +51 -0
  652. package/skills/remnic-remember/SKILL.md +56 -0
  653. package/skills/remnic-search/SKILL.md +51 -0
  654. package/skills/remnic-status/SKILL.md +51 -0
  655. package/src/abort-error.test.ts +49 -0
  656. package/src/abort-error.ts +46 -0
  657. package/src/abstraction-nodes.ts +162 -0
  658. package/src/access-audit.test.ts +178 -0
  659. package/src/access-audit.ts +125 -0
  660. package/src/access-cli.test.ts +439 -0
  661. package/src/access-cli.ts +438 -0
  662. package/src/access-http.test.ts +225 -0
  663. package/src/access-http.ts +1899 -0
  664. package/src/access-idempotency.ts +232 -0
  665. package/src/access-mcp.test.ts +568 -0
  666. package/src/access-mcp.ts +3056 -0
  667. package/src/access-schema-pi.test.ts +60 -0
  668. package/src/access-schema.ts +522 -0
  669. package/src/access-service-namespace.test.ts +123 -0
  670. package/src/access-service.ts +5629 -0
  671. package/src/action-confidence.test.ts +206 -0
  672. package/src/action-confidence.ts +466 -0
  673. package/src/active-memory-bridge.test.ts +285 -0
  674. package/src/active-memory-bridge.ts +217 -0
  675. package/src/active-recall.test.ts +484 -0
  676. package/src/active-recall.ts +459 -0
  677. package/src/adapters/claude-code.ts +56 -0
  678. package/src/adapters/codex.ts +57 -0
  679. package/src/adapters/hermes.ts +64 -0
  680. package/src/adapters/index.ts +6 -0
  681. package/src/adapters/registry.ts +41 -0
  682. package/src/adapters/replit.ts +55 -0
  683. package/src/adapters/types.ts +51 -0
  684. package/src/behavior-learner.ts +144 -0
  685. package/src/behavior-signals.ts +73 -0
  686. package/src/binary-lifecycle/backend.ts +117 -0
  687. package/src/binary-lifecycle/index.ts +35 -0
  688. package/src/binary-lifecycle/manifest.ts +79 -0
  689. package/src/binary-lifecycle/pipeline.ts +352 -0
  690. package/src/binary-lifecycle/scanner.ts +89 -0
  691. package/src/binary-lifecycle/types.ts +89 -0
  692. package/src/bootstrap.ts +178 -0
  693. package/src/boxes.ts +521 -0
  694. package/src/briefing.test.ts +1535 -0
  695. package/src/briefing.ts +1382 -0
  696. package/src/buffer-session.test.ts +443 -0
  697. package/src/buffer-surprise-report.ts +176 -0
  698. package/src/buffer-surprise-telemetry.test.ts +606 -0
  699. package/src/buffer-surprise-trigger.test.ts +766 -0
  700. package/src/buffer-surprise.test.ts +339 -0
  701. package/src/buffer-surprise.ts +203 -0
  702. package/src/buffer.ts +900 -0
  703. package/src/bulk-import/cli-command.test.ts +204 -0
  704. package/src/bulk-import/index.ts +34 -0
  705. package/src/bulk-import/pipeline.test.ts +445 -0
  706. package/src/bulk-import/pipeline.ts +178 -0
  707. package/src/bulk-import/registry.test.ts +151 -0
  708. package/src/bulk-import/registry.ts +72 -0
  709. package/src/bulk-import/types.test.ts +272 -0
  710. package/src/bulk-import/types.ts +145 -0
  711. package/src/calibration.ts +394 -0
  712. package/src/capsule-cli.test.ts +398 -0
  713. package/src/capsule-cli.ts +565 -0
  714. package/src/causal-behavior.ts +308 -0
  715. package/src/causal-chain.ts +419 -0
  716. package/src/causal-consolidation.ts +370 -0
  717. package/src/causal-retrieval.ts +286 -0
  718. package/src/causal-trajectory-graph.ts +60 -0
  719. package/src/causal-trajectory.ts +303 -0
  720. package/src/chunking.ts +220 -0
  721. package/src/citations.ts +232 -0
  722. package/src/cli.ts +9403 -0
  723. package/src/codex-cli-fallback.ts +162 -0
  724. package/src/codex-thread-key.ts +1 -0
  725. package/src/coding/access-coding-context.test.ts +197 -0
  726. package/src/coding/coding-branch-scope.test.ts +281 -0
  727. package/src/coding/coding-namespace.test.ts +360 -0
  728. package/src/coding/coding-namespace.ts +412 -0
  729. package/src/coding/coding-orchestrator.test.ts +249 -0
  730. package/src/coding/git-context.test.ts +507 -0
  731. package/src/coding/git-context.ts +336 -0
  732. package/src/coding/mcp-set-coding-context.test.ts +174 -0
  733. package/src/coding/review-context.test.ts +316 -0
  734. package/src/coding/review-context.ts +349 -0
  735. package/src/coding/wire-coding-context.test.ts +468 -0
  736. package/src/commitment-ledger.test.ts +78 -0
  737. package/src/commitment-ledger.ts +337 -0
  738. package/src/compat/checks.test.ts +206 -0
  739. package/src/compat/checks.ts +716 -0
  740. package/src/compat/types.ts +33 -0
  741. package/src/compounding/engine.ts +1686 -0
  742. package/src/compounding/preference-consolidator.ts +778 -0
  743. package/src/compression-optimizer.ts +312 -0
  744. package/src/config.test.ts +930 -0
  745. package/src/config.ts +3807 -0
  746. package/src/connectors/codex/instructions.md +160 -0
  747. package/src/connectors/codex/resources/namespace-cheatsheet.md +48 -0
  748. package/src/connectors/codex-marketplace.ts +500 -0
  749. package/src/connectors/codex-materialize-runner.ts +212 -0
  750. package/src/connectors/codex-materialize.ts +983 -0
  751. package/src/connectors/coerce.ts +62 -0
  752. package/src/connectors/index.test.ts +1570 -0
  753. package/src/connectors/index.ts +3222 -0
  754. package/src/connectors/live/framework.ts +164 -0
  755. package/src/connectors/live/github.test.ts +1218 -0
  756. package/src/connectors/live/github.ts +1068 -0
  757. package/src/connectors/live/gmail.test.ts +1706 -0
  758. package/src/connectors/live/gmail.ts +1293 -0
  759. package/src/connectors/live/google-drive.test.ts +696 -0
  760. package/src/connectors/live/google-drive.ts +724 -0
  761. package/src/connectors/live/index.ts +101 -0
  762. package/src/connectors/live/live-connectors.test.ts +689 -0
  763. package/src/connectors/live/notion.test.ts +1109 -0
  764. package/src/connectors/live/notion.ts +978 -0
  765. package/src/connectors/live/registry.ts +103 -0
  766. package/src/connectors/live/state-store.ts +399 -0
  767. package/src/connectors/live/transient-errors.ts +150 -0
  768. package/src/connectors/weclone-installer.test.ts +850 -0
  769. package/src/connectors-cli.ts +513 -0
  770. package/src/console/state.test.ts +224 -0
  771. package/src/console/state.ts +514 -0
  772. package/src/console/trace.test.ts +813 -0
  773. package/src/console/trace.ts +603 -0
  774. package/src/console/tui.test.ts +582 -0
  775. package/src/console/tui.ts +508 -0
  776. package/src/consolidation-operator.ts +182 -0
  777. package/src/consolidation-provenance-check.ts +551 -0
  778. package/src/consolidation-undo.ts +718 -0
  779. package/src/contradiction/contradiction-judge.test.ts +189 -0
  780. package/src/contradiction/contradiction-judge.ts +333 -0
  781. package/src/contradiction/contradiction-review.ts +574 -0
  782. package/src/contradiction/contradiction-scan.ts +504 -0
  783. package/src/contradiction/contradiction.test.ts +2230 -0
  784. package/src/contradiction/index.ts +37 -0
  785. package/src/contradiction/resolution.ts +383 -0
  786. package/src/conversation-index/backend.ts +323 -0
  787. package/src/conversation-index/chunker.ts +47 -0
  788. package/src/conversation-index/cleanup.ts +53 -0
  789. package/src/conversation-index/faiss-adapter.ts +384 -0
  790. package/src/conversation-index/indexer.test.ts +164 -0
  791. package/src/conversation-index/indexer.ts +192 -0
  792. package/src/conversation-index/search.ts +37 -0
  793. package/src/cross-namespace-budget.test.ts +275 -0
  794. package/src/cross-namespace-budget.ts +365 -0
  795. package/src/cue-anchors.ts +163 -0
  796. package/src/curation/index.ts +544 -0
  797. package/src/dashboard-runtime.ts +337 -0
  798. package/src/day-summary.ts +122 -0
  799. package/src/dedup/index.ts +330 -0
  800. package/src/dedup/semantic.test.ts +1577 -0
  801. package/src/dedup/semantic.ts +148 -0
  802. package/src/delinearize.ts +193 -0
  803. package/src/direct-answer-wiring.test.ts +473 -0
  804. package/src/direct-answer-wiring.ts +180 -0
  805. package/src/direct-answer.test.ts +484 -0
  806. package/src/direct-answer.ts +273 -0
  807. package/src/embedding-fallback.ts +565 -0
  808. package/src/enrichment/audit.ts +89 -0
  809. package/src/enrichment/index.ts +27 -0
  810. package/src/enrichment/pipeline.ts +197 -0
  811. package/src/enrichment/provider-registry.ts +85 -0
  812. package/src/enrichment/types.ts +100 -0
  813. package/src/enrichment/web-search-provider.ts +63 -0
  814. package/src/entity-retrieval.ts +774 -0
  815. package/src/entity-schema.ts +239 -0
  816. package/src/evals.ts +1312 -0
  817. package/src/event-order-recall.test.ts +4164 -0
  818. package/src/event-order-recall.ts +2802 -0
  819. package/src/evidence-pack.test.ts +89 -0
  820. package/src/evidence-pack.ts +388 -0
  821. package/src/explicit-capture.ts +530 -0
  822. package/src/explicit-cue-recall.test.ts +3019 -0
  823. package/src/explicit-cue-recall.ts +5545 -0
  824. package/src/extraction-judge-telemetry.ts +234 -0
  825. package/src/extraction-judge-training.ts +221 -0
  826. package/src/extraction-judge.ts +846 -0
  827. package/src/extraction-timeout.test.ts +265 -0
  828. package/src/extraction.ts +2719 -0
  829. package/src/fallback-llm.test.ts +1060 -0
  830. package/src/fallback-llm.ts +918 -0
  831. package/src/focused-list-recall.test.ts +734 -0
  832. package/src/focused-list-recall.ts +1160 -0
  833. package/src/graph-dashboard-diff.ts +35 -0
  834. package/src/graph-dashboard-key.ts +5 -0
  835. package/src/graph-dashboard-parser.ts +104 -0
  836. package/src/graph-edge-reinforcement.ts +192 -0
  837. package/src/graph-events.ts +151 -0
  838. package/src/graph-recall.test.ts +164 -0
  839. package/src/graph-recall.ts +189 -0
  840. package/src/graph-retrieval.test.ts +809 -0
  841. package/src/graph-retrieval.ts +823 -0
  842. package/src/graph-snapshot.ts +329 -0
  843. package/src/graph.ts +813 -0
  844. package/src/harmonic-retrieval.ts +223 -0
  845. package/src/himem.ts +154 -0
  846. package/src/hygiene.ts +87 -0
  847. package/src/identity-continuity.ts +333 -0
  848. package/src/importance.ts +328 -0
  849. package/src/importers/base.test.ts +294 -0
  850. package/src/importers/base.ts +436 -0
  851. package/src/importers/index.ts +21 -0
  852. package/src/index.ts +1204 -0
  853. package/src/intent.ts +154 -0
  854. package/src/json-extract.ts +85 -0
  855. package/src/json-store.ts +42 -0
  856. package/src/lcm/archive.ts +617 -0
  857. package/src/lcm/dag.ts +199 -0
  858. package/src/lcm/engine.ts +645 -0
  859. package/src/lcm/index.ts +7 -0
  860. package/src/lcm/queue.test.ts +178 -0
  861. package/src/lcm/queue.ts +200 -0
  862. package/src/lcm/recall.ts +117 -0
  863. package/src/lcm/schema.ts +154 -0
  864. package/src/lcm/summarizer.ts +235 -0
  865. package/src/lcm/tools.ts +191 -0
  866. package/src/lcm-engine.test.ts +660 -0
  867. package/src/legacy-hook-compat.test.ts +20 -0
  868. package/src/legacy-hook-compat.ts +45 -0
  869. package/src/lifecycle.ts +289 -0
  870. package/src/live-connectors-runner.ts +385 -0
  871. package/src/local-llm-qos.test.ts +303 -0
  872. package/src/local-llm-thinking.test.ts +292 -0
  873. package/src/local-llm.ts +1464 -0
  874. package/src/logger.ts +49 -0
  875. package/src/maintenance/archive-observations.ts +147 -0
  876. package/src/maintenance/backup-stamp.ts +3 -0
  877. package/src/maintenance/dreams-ledger.ts +516 -0
  878. package/src/maintenance/first-start-migration.ts +362 -0
  879. package/src/maintenance/forget.test.ts +206 -0
  880. package/src/maintenance/forget.ts +126 -0
  881. package/src/maintenance/graph-edge-decay.test.ts +409 -0
  882. package/src/maintenance/graph-edge-decay.ts +394 -0
  883. package/src/maintenance/memory-governance-cron.ts +447 -0
  884. package/src/maintenance/memory-governance.ts +1039 -0
  885. package/src/maintenance/migrate-observations.ts +216 -0
  886. package/src/maintenance/observation-ledger-utils.ts +54 -0
  887. package/src/maintenance/pattern-reinforcement.test.ts +875 -0
  888. package/src/maintenance/pattern-reinforcement.ts +369 -0
  889. package/src/maintenance/purge.ts +334 -0
  890. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +78 -0
  891. package/src/maintenance/rebuild-memory-projection.ts +1234 -0
  892. package/src/maintenance/rebuild-observations.ts +178 -0
  893. package/src/maintenance/tier-stats.test.ts +378 -0
  894. package/src/maintenance/tier-stats.ts +222 -0
  895. package/src/mcp-memory-inspector-app.ts +421 -0
  896. package/src/memory-action-policy.ts +80 -0
  897. package/src/memory-cache.ts +208 -0
  898. package/src/memory-extension/claude-code-publisher.ts +51 -0
  899. package/src/memory-extension/codex-publisher.ts +149 -0
  900. package/src/memory-extension/hermes-publisher.ts +51 -0
  901. package/src/memory-extension/index.ts +100 -0
  902. package/src/memory-extension/shared-instructions.ts +133 -0
  903. package/src/memory-extension/types.ts +86 -0
  904. package/src/memory-extension-host/host-discovery.ts +276 -0
  905. package/src/memory-extension-host/index.ts +14 -0
  906. package/src/memory-extension-host/render-extensions-block.ts +73 -0
  907. package/src/memory-extension-host/types.ts +21 -0
  908. package/src/memory-lifecycle-ledger-utils.ts +116 -0
  909. package/src/memory-projection-format.ts +11 -0
  910. package/src/memory-projection-store.ts +951 -0
  911. package/src/memory-provenance.test.ts +196 -0
  912. package/src/memory-provenance.ts +484 -0
  913. package/src/memory-worth-bench.test.ts +71 -0
  914. package/src/memory-worth-bench.ts +265 -0
  915. package/src/memory-worth-filter.test.ts +209 -0
  916. package/src/memory-worth-filter.ts +204 -0
  917. package/src/memory-worth-frontmatter.test.ts +311 -0
  918. package/src/memory-worth-outcomes.test.ts +316 -0
  919. package/src/memory-worth-outcomes.ts +286 -0
  920. package/src/memory-worth.test.ts +317 -0
  921. package/src/memory-worth.ts +215 -0
  922. package/src/message-parts/index.ts +806 -0
  923. package/src/message-parts/message-parts.test.ts +421 -0
  924. package/src/migrate/from-engram.ts +789 -0
  925. package/src/model-registry.ts +313 -0
  926. package/src/models-json.ts +76 -0
  927. package/src/namespaces/migrate.ts +187 -0
  928. package/src/namespaces/path.ts +25 -0
  929. package/src/namespaces/principal.test.ts +195 -0
  930. package/src/namespaces/principal.ts +86 -0
  931. package/src/namespaces/search.test.ts +105 -0
  932. package/src/namespaces/search.ts +233 -0
  933. package/src/namespaces/storage.ts +74 -0
  934. package/src/native-knowledge.ts +1823 -0
  935. package/src/negative.ts +72 -0
  936. package/src/network/tailscale.ts +179 -0
  937. package/src/network/webdav.ts +385 -0
  938. package/src/objective-state-writers.ts +951 -0
  939. package/src/objective-state.ts +320 -0
  940. package/src/onboarding/index.ts +529 -0
  941. package/src/openai-chat-compat.ts +56 -0
  942. package/src/operator-toolkit.ts +2132 -0
  943. package/src/opik-exporter.test.ts +72 -0
  944. package/src/opik-exporter.ts +587 -0
  945. package/src/orchestrator-extraction-queue.test.ts +197 -0
  946. package/src/orchestrator-flush.test.ts +1171 -0
  947. package/src/orchestrator-pattern-reinforcement.test.ts +128 -0
  948. package/src/orchestrator-source-attribution.test.ts +701 -0
  949. package/src/orchestrator.ts +16368 -0
  950. package/src/page-versioning.ts +450 -0
  951. package/src/patterns-cli.ts +574 -0
  952. package/src/peers/index.ts +54 -0
  953. package/src/peers/migrate-from-identity-anchor.test.ts +291 -0
  954. package/src/peers/migrate-from-identity-anchor.ts +350 -0
  955. package/src/peers/peers.test.ts +419 -0
  956. package/src/peers/profile-reasoner.ts +694 -0
  957. package/src/peers/storage.ts +1350 -0
  958. package/src/peers/types.ts +138 -0
  959. package/src/plugin-id.ts +84 -0
  960. package/src/policy-runtime.ts +209 -0
  961. package/src/procedural/procedure-miner.ts +150 -0
  962. package/src/procedural/procedure-recall.ts +93 -0
  963. package/src/procedural/procedure-stats.ts +213 -0
  964. package/src/procedural/procedure-types.ts +132 -0
  965. package/src/procedural/reinforcement-core.test.ts +132 -0
  966. package/src/procedural/reinforcement-core.ts +73 -0
  967. package/src/profiling.test.ts +263 -0
  968. package/src/profiling.ts +435 -0
  969. package/src/projection/index.ts +398 -0
  970. package/src/qmd-recall-cache.test.ts +138 -0
  971. package/src/qmd-recall-cache.ts +111 -0
  972. package/src/qmd.test.ts +257 -0
  973. package/src/qmd.ts +2614 -0
  974. package/src/reasoning-trace-recall.ts +201 -0
  975. package/src/reasoning-trace-types.ts +235 -0
  976. package/src/recall-audit-anomaly.test.ts +246 -0
  977. package/src/recall-audit-anomaly.ts +297 -0
  978. package/src/recall-audit.test.ts +51 -0
  979. package/src/recall-audit.ts +72 -0
  980. package/src/recall-budget-config.test.ts +87 -0
  981. package/src/recall-disclosure-escalation.test.ts +196 -0
  982. package/src/recall-disclosure-escalation.ts +158 -0
  983. package/src/recall-disclosure-shaping.test.ts +146 -0
  984. package/src/recall-disclosure.test.ts +214 -0
  985. package/src/recall-explain-renderer.test.ts +140 -0
  986. package/src/recall-explain-renderer.ts +356 -0
  987. package/src/recall-mmr.test.ts +808 -0
  988. package/src/recall-mmr.ts +607 -0
  989. package/src/recall-qos.test.ts +85 -0
  990. package/src/recall-qos.ts +82 -0
  991. package/src/recall-query-policy.ts +221 -0
  992. package/src/recall-state.test.ts +233 -0
  993. package/src/recall-state.ts +456 -0
  994. package/src/recall-tag-filter.ts +143 -0
  995. package/src/recall-tokenization.ts +35 -0
  996. package/src/recall-xray-cli.test.ts +118 -0
  997. package/src/recall-xray-cli.ts +100 -0
  998. package/src/recall-xray-disclosure-telemetry.test.ts +183 -0
  999. package/src/recall-xray-renderer.test.ts +539 -0
  1000. package/src/recall-xray-renderer.ts +487 -0
  1001. package/src/recall-xray.test.ts +503 -0
  1002. package/src/recall-xray.ts +621 -0
  1003. package/src/reconstruct.ts +41 -0
  1004. package/src/release-changelog.ts +35 -0
  1005. package/src/relevance.ts +67 -0
  1006. package/src/replay/normalizers/chatgpt.ts +133 -0
  1007. package/src/replay/normalizers/claude.ts +102 -0
  1008. package/src/replay/normalizers/openclaw.ts +119 -0
  1009. package/src/replay/normalizers/shared.ts +69 -0
  1010. package/src/replay/runner.ts +197 -0
  1011. package/src/replay/types.ts +143 -0
  1012. package/src/rerank.test.ts +48 -0
  1013. package/src/rerank.ts +176 -0
  1014. package/src/resolve-auth-token.test.ts +226 -0
  1015. package/src/resolve-auth-token.ts +151 -0
  1016. package/src/resolve-provider-secret.test.ts +187 -0
  1017. package/src/resolve-provider-secret.ts +410 -0
  1018. package/src/response-guidance-recall.test.ts +3952 -0
  1019. package/src/response-guidance-recall.ts +4431 -0
  1020. package/src/resume-bundles.ts +415 -0
  1021. package/src/retrieval-agents.ts +623 -0
  1022. package/src/retrieval-tiers.ts +25 -0
  1023. package/src/retrieval.ts +104 -0
  1024. package/src/review/index.test.ts +201 -0
  1025. package/src/review/index.ts +536 -0
  1026. package/src/routing/engine.ts +162 -0
  1027. package/src/routing/store.ts +321 -0
  1028. package/src/runtime/better-sqlite.test.ts +32 -0
  1029. package/src/runtime/better-sqlite.ts +76 -0
  1030. package/src/runtime/child-process.ts +67 -0
  1031. package/src/runtime/env.ts +48 -0
  1032. package/src/sanitize.ts +58 -0
  1033. package/src/schemas.ts +449 -0
  1034. package/src/sdk-compat.ts +87 -0
  1035. package/src/search/document-scanner.ts +96 -0
  1036. package/src/search/embed-helper.ts +142 -0
  1037. package/src/search/factory.ts +189 -0
  1038. package/src/search/index.ts +10 -0
  1039. package/src/search/lancedb-backend.ts +342 -0
  1040. package/src/search/meilisearch-backend.ts +232 -0
  1041. package/src/search/noop-backend.ts +57 -0
  1042. package/src/search/orama-backend.ts +358 -0
  1043. package/src/search/port.ts +86 -0
  1044. package/src/search/remote-backend.ts +124 -0
  1045. package/src/secure-store/cipher.ts +271 -0
  1046. package/src/secure-store/cli-handlers.ts +355 -0
  1047. package/src/secure-store/cli-renderer.ts +131 -0
  1048. package/src/secure-store/header.ts +373 -0
  1049. package/src/secure-store/index.ts +137 -0
  1050. package/src/secure-store/kdf.ts +263 -0
  1051. package/src/secure-store/keyring.ts +106 -0
  1052. package/src/secure-store/metadata.ts +394 -0
  1053. package/src/secure-store/passphrase-reader.ts +252 -0
  1054. package/src/secure-store/secure-fs.ts +571 -0
  1055. package/src/secure-store/secure-store.test.ts +755 -0
  1056. package/src/semantic-chunking.ts +545 -0
  1057. package/src/semantic-consolidation.test.ts +182 -0
  1058. package/src/semantic-consolidation.ts +432 -0
  1059. package/src/semantic-rule-promotion.ts +183 -0
  1060. package/src/semantic-rule-verifier.ts +160 -0
  1061. package/src/session-integrity.ts +569 -0
  1062. package/src/session-observer-bands.ts +11 -0
  1063. package/src/session-observer-state.ts +346 -0
  1064. package/src/session-toggles.test.ts +96 -0
  1065. package/src/session-toggles.ts +159 -0
  1066. package/src/shared-context/manager.ts +810 -0
  1067. package/src/signal.ts +84 -0
  1068. package/src/skills-registry.test.ts +277 -0
  1069. package/src/skills-registry.ts +120 -0
  1070. package/src/source-attribution-roundtrip.test.ts +215 -0
  1071. package/src/source-attribution.test.ts +1425 -0
  1072. package/src/source-attribution.ts +639 -0
  1073. package/src/spaces/index.ts +627 -0
  1074. package/src/storage-paths.ts +117 -0
  1075. package/src/storage.ts +6657 -0
  1076. package/src/store-contract.ts +55 -0
  1077. package/src/summarizer.ts +844 -0
  1078. package/src/summary-snapshot.test.ts +681 -0
  1079. package/src/summary-snapshot.ts +238 -0
  1080. package/src/surfaces/dreams.test.ts +394 -0
  1081. package/src/surfaces/dreams.ts +346 -0
  1082. package/src/surfaces/heartbeat.test.ts +415 -0
  1083. package/src/surfaces/heartbeat.ts +325 -0
  1084. package/src/sync/index.ts +308 -0
  1085. package/src/targeted-fact-recall.test.ts +1694 -0
  1086. package/src/targeted-fact-recall.ts +2905 -0
  1087. package/src/taxonomy/default-taxonomy.ts +87 -0
  1088. package/src/taxonomy/index.ts +26 -0
  1089. package/src/taxonomy/resolver-doc-generator.ts +57 -0
  1090. package/src/taxonomy/resolver.ts +184 -0
  1091. package/src/taxonomy/taxonomy-loader.ts +186 -0
  1092. package/src/taxonomy/types.ts +48 -0
  1093. package/src/telemetry-transcript.ts +70 -0
  1094. package/src/temporal-index.ts +890 -0
  1095. package/src/temporal-supersession.test.ts +2703 -0
  1096. package/src/temporal-supersession.ts +493 -0
  1097. package/src/temporal-validity.test.ts +448 -0
  1098. package/src/temporal-validity.ts +123 -0
  1099. package/src/threading.ts +395 -0
  1100. package/src/tier-migration.ts +124 -0
  1101. package/src/tier-routing.ts +102 -0
  1102. package/src/tmt.ts +462 -0
  1103. package/src/tokens.test.ts +178 -0
  1104. package/src/tokens.ts +279 -0
  1105. package/src/topics.ts +147 -0
  1106. package/src/training-export/cli-date-validation.test.ts +258 -0
  1107. package/src/training-export/converter.test.ts +452 -0
  1108. package/src/training-export/converter.ts +319 -0
  1109. package/src/training-export/date-parse.ts +117 -0
  1110. package/src/training-export/index.ts +26 -0
  1111. package/src/training-export/registry.test.ts +85 -0
  1112. package/src/training-export/registry.ts +57 -0
  1113. package/src/training-export/types.ts +31 -0
  1114. package/src/transcript.ts +1179 -0
  1115. package/src/transfer/autodetect.ts +30 -0
  1116. package/src/transfer/backup.ts +138 -0
  1117. package/src/transfer/capsule-crypto.ts +485 -0
  1118. package/src/transfer/capsule-encrypt.test.ts +690 -0
  1119. package/src/transfer/capsule-export.ts +543 -0
  1120. package/src/transfer/capsule-fork.ts +375 -0
  1121. package/src/transfer/capsule-import.ts +564 -0
  1122. package/src/transfer/capsule-merge.ts +433 -0
  1123. package/src/transfer/conflict-policy.ts +16 -0
  1124. package/src/transfer/constants.ts +13 -0
  1125. package/src/transfer/exclusions.ts +37 -0
  1126. package/src/transfer/export-json.ts +65 -0
  1127. package/src/transfer/export-md.ts +59 -0
  1128. package/src/transfer/export-sqlite.ts +52 -0
  1129. package/src/transfer/fs-utils.ts +269 -0
  1130. package/src/transfer/import-json.ts +108 -0
  1131. package/src/transfer/import-md.ts +84 -0
  1132. package/src/transfer/import-sqlite.ts +100 -0
  1133. package/src/transfer/integrity.ts +71 -0
  1134. package/src/transfer/sqlite-schema.ts +16 -0
  1135. package/src/transfer/types.ts +297 -0
  1136. package/src/trust-zones.ts +1186 -0
  1137. package/src/types.ts +3074 -0
  1138. package/src/user-model.test.ts +124 -0
  1139. package/src/user-model.ts +162 -0
  1140. package/src/utility-learner.ts +353 -0
  1141. package/src/utility-runtime.ts +88 -0
  1142. package/src/utility-telemetry.ts +215 -0
  1143. package/src/utils/category-dir.ts +44 -0
  1144. package/src/utils/errno.ts +6 -0
  1145. package/src/utils/iso-timestamp.test.ts +37 -0
  1146. package/src/utils/iso-timestamp.ts +164 -0
  1147. package/src/utils/path.ts +26 -0
  1148. package/src/verified-recall.ts +138 -0
  1149. package/src/version-utils.test.ts +10 -0
  1150. package/src/version-utils.ts +9 -0
  1151. package/src/whitespace.ts +10 -0
  1152. package/src/work/board.ts +359 -0
  1153. package/src/work/boundary.ts +107 -0
  1154. package/src/work/storage.ts +436 -0
  1155. package/src/work/types.ts +82 -0
  1156. package/src/work-product-ledger.ts +265 -0
  1157. package/dist/access-service-DDjzFALq.d.ts +0 -2088
  1158. package/dist/capsule-crypto-SJS5VVAP.js +0 -18
  1159. package/dist/capsule-export-7QNCBZOQ.js +0 -17
  1160. package/dist/capsule-import-EPBHD2EN.js +0 -16
  1161. package/dist/capsule-merge-DI7PNQ2H.js +0 -189
  1162. package/dist/chunk-23ZZK64Y.js +0 -26
  1163. package/dist/chunk-23ZZK64Y.js.map +0 -1
  1164. package/dist/chunk-242S3I2A.js +0 -647
  1165. package/dist/chunk-2LGMW3DJ.js +0 -111
  1166. package/dist/chunk-3B6KIRBH.js +0 -5213
  1167. package/dist/chunk-3B6KIRBH.js.map +0 -1
  1168. package/dist/chunk-457A4P3L.js +0 -119
  1169. package/dist/chunk-457A4P3L.js.map +0 -1
  1170. package/dist/chunk-4IS4SXIQ.js +0 -2040
  1171. package/dist/chunk-4YM32CRU.js +0 -721
  1172. package/dist/chunk-6TBWYBJ3.js +0 -236
  1173. package/dist/chunk-74EMIVE4.js +0 -329
  1174. package/dist/chunk-74EMIVE4.js.map +0 -1
  1175. package/dist/chunk-767ODGE6.js +0 -183
  1176. package/dist/chunk-7V22HTMD.js +0 -623
  1177. package/dist/chunk-7V22HTMD.js.map +0 -1
  1178. package/dist/chunk-7ZM3BFKK.js +0 -9705
  1179. package/dist/chunk-7ZM3BFKK.js.map +0 -1
  1180. package/dist/chunk-AQJNPMOA.js +0 -643
  1181. package/dist/chunk-AQJNPMOA.js.map +0 -1
  1182. package/dist/chunk-ASAITVLA.js +0 -64
  1183. package/dist/chunk-ASAITVLA.js.map +0 -1
  1184. package/dist/chunk-BBE34QBJ.js +0 -275
  1185. package/dist/chunk-BBE34QBJ.js.map +0 -1
  1186. package/dist/chunk-BZSQEPRW.js +0 -14710
  1187. package/dist/chunk-BZSQEPRW.js.map +0 -1
  1188. package/dist/chunk-CPKTBRS2.js +0 -891
  1189. package/dist/chunk-CPKTBRS2.js.map +0 -1
  1190. package/dist/chunk-D4GAOFF6.js +0 -562
  1191. package/dist/chunk-D4GAOFF6.js.map +0 -1
  1192. package/dist/chunk-D54LZC5L.js +0 -147
  1193. package/dist/chunk-DF3RVK3X.js +0 -119
  1194. package/dist/chunk-DF3RVK3X.js.map +0 -1
  1195. package/dist/chunk-DZZPC36E.js +0 -1451
  1196. package/dist/chunk-DZZPC36E.js.map +0 -1
  1197. package/dist/chunk-E2UCDP5S.js +0 -570
  1198. package/dist/chunk-E6K4NIEU.js +0 -747
  1199. package/dist/chunk-E6K4NIEU.js.map +0 -1
  1200. package/dist/chunk-EEQLFRUM.js +0 -89
  1201. package/dist/chunk-ETOW6ACV.js +0 -158
  1202. package/dist/chunk-ETOW6ACV.js.map +0 -1
  1203. package/dist/chunk-FMEBPEAO.js +0 -347
  1204. package/dist/chunk-FMEBPEAO.js.map +0 -1
  1205. package/dist/chunk-FQDPCE3I.js +0 -1837
  1206. package/dist/chunk-FQDPCE3I.js.map +0 -1
  1207. package/dist/chunk-FYIYMQ5N.js +0 -221
  1208. package/dist/chunk-FYIYMQ5N.js.map +0 -1
  1209. package/dist/chunk-G2WADRQ3.js +0 -219
  1210. package/dist/chunk-G4SK7DSQ.js +0 -121
  1211. package/dist/chunk-GVPWB7EY.js +0 -390
  1212. package/dist/chunk-GVPWB7EY.js.map +0 -1
  1213. package/dist/chunk-HELQZFZO.js +0 -1075
  1214. package/dist/chunk-HL5LRPNA.js +0 -1914
  1215. package/dist/chunk-HL5LRPNA.js.map +0 -1
  1216. package/dist/chunk-HQZVVSVB.js +0 -147
  1217. package/dist/chunk-HQZVVSVB.js.map +0 -1
  1218. package/dist/chunk-HY3L4WKC.js +0 -2195
  1219. package/dist/chunk-HY3L4WKC.js.map +0 -1
  1220. package/dist/chunk-IB3BFHGN.js +0 -228
  1221. package/dist/chunk-IXEJRKCZ.js +0 -18
  1222. package/dist/chunk-JBMSGZEQ.js +0 -441
  1223. package/dist/chunk-JBMSGZEQ.js.map +0 -1
  1224. package/dist/chunk-JESOB2HO.js +0 -108
  1225. package/dist/chunk-JKDVIE52.js +0 -272
  1226. package/dist/chunk-JRNQ3RNA.js +0 -284
  1227. package/dist/chunk-JRNQ3RNA.js.map +0 -1
  1228. package/dist/chunk-K6WK37A6.js +0 -865
  1229. package/dist/chunk-K6WK37A6.js.map +0 -1
  1230. package/dist/chunk-MARWOCVP.js +0 -48
  1231. package/dist/chunk-MNU6ZBWT.js +0 -4454
  1232. package/dist/chunk-MNU6ZBWT.js.map +0 -1
  1233. package/dist/chunk-N5AKDXAI.js +0 -74
  1234. package/dist/chunk-OA3L7BFR.js +0 -183
  1235. package/dist/chunk-OA3L7BFR.js.map +0 -1
  1236. package/dist/chunk-OR64ZGRZ.js +0 -23
  1237. package/dist/chunk-P77UEOU2.js +0 -1521
  1238. package/dist/chunk-P77UEOU2.js.map +0 -1
  1239. package/dist/chunk-PH4C2U43.js +0 -239
  1240. package/dist/chunk-PH4C2U43.js.map +0 -1
  1241. package/dist/chunk-RVPLBATS.js +0 -1586
  1242. package/dist/chunk-RVPLBATS.js.map +0 -1
  1243. package/dist/chunk-U5JMRGKX.js +0 -340
  1244. package/dist/chunk-U5JMRGKX.js.map +0 -1
  1245. package/dist/chunk-URB2WSKZ.js +0 -350
  1246. package/dist/chunk-URB2WSKZ.js.map +0 -1
  1247. package/dist/chunk-UVMUAWVT.js +0 -596
  1248. package/dist/chunk-WEJG4TB5.js +0 -118
  1249. package/dist/chunk-X7HPGUVG.js +0 -271
  1250. package/dist/chunk-XAMBKFQS.js +0 -2777
  1251. package/dist/chunk-XAMBKFQS.js.map +0 -1
  1252. package/dist/chunk-XJKFSSDW.js +0 -726
  1253. package/dist/chunk-XJKFSSDW.js.map +0 -1
  1254. package/dist/chunk-XMHBH5H6.js +0 -283
  1255. package/dist/chunk-XMHBH5H6.js.map +0 -1
  1256. package/dist/chunk-XMVFHBHT.js +0 -277
  1257. package/dist/chunk-Y3VMVTYX.js +0 -53
  1258. package/dist/chunk-YNB73F22.js +0 -137
  1259. package/dist/chunk-YNB73F22.js.map +0 -1
  1260. package/dist/chunk-Z2E7VW55.js +0 -335
  1261. package/dist/chunk-Z2E7VW55.js.map +0 -1
  1262. package/dist/chunk-ZG7PTKBK.js +0 -2296
  1263. package/dist/chunk-ZNQN6ZTA.js +0 -135
  1264. package/dist/chunk-ZVTKDVVM.js +0 -827
  1265. package/dist/chunk-ZVTKDVVM.js.map +0 -1
  1266. package/dist/cli-BR8KpIU0.d.ts +0 -1259
  1267. package/dist/codex-materialize-CQlLTzke.d.ts +0 -139
  1268. package/dist/connectors-cli-DFGtY2DB.d.ts +0 -257
  1269. package/dist/contradiction-review-5LTTVDQV.js +0 -22
  1270. package/dist/contradiction-scan-QTXAMBUA.js +0 -414
  1271. package/dist/contradiction-scan-QTXAMBUA.js.map +0 -1
  1272. package/dist/engine-35M5BKQ7.js +0 -28
  1273. package/dist/fs-utils-IRVUFB6G.js +0 -30
  1274. package/dist/graph-edge-decay-PWB63GRE.js +0 -207
  1275. package/dist/memory-governance-IMPQZXFC.js +0 -37
  1276. package/dist/memory-projection-store-CY8TU40w.d.ts +0 -222
  1277. package/dist/orchestrator-DDMPqU6R.d.ts +0 -1792
  1278. package/dist/path-RMTY5Y5A.js +0 -9
  1279. package/dist/port-B6VEDIkC.d.ts +0 -53
  1280. package/dist/resolution-YGIBORXI.js +0 -101
  1281. package/dist/resolution-YGIBORXI.js.map +0 -1
  1282. package/dist/secure-store-4R2GSO7S.js +0 -156
  1283. package/dist/semantic-consolidation-ByBXb-sf.d.ts +0 -180
  1284. package/dist/state-store-3EH7HYIN.js +0 -16
  1285. package/dist/types-V3FJ26TF.js +0 -30
  1286. /package/dist/{capsule-crypto-SJS5VVAP.js.map → adapters/claude-code.js.map} +0 -0
  1287. /package/dist/{capsule-export-7QNCBZOQ.js.map → adapters/codex.js.map} +0 -0
  1288. /package/dist/{capsule-import-EPBHD2EN.js.map → adapters/hermes.js.map} +0 -0
  1289. /package/dist/{contradiction-review-5LTTVDQV.js.map → adapters/index.js.map} +0 -0
  1290. /package/dist/{engine-35M5BKQ7.js.map → adapters/registry.js.map} +0 -0
  1291. /package/dist/{fs-utils-IRVUFB6G.js.map → adapters/replit.js.map} +0 -0
  1292. /package/dist/{memory-governance-IMPQZXFC.js.map → adapters/types.js.map} +0 -0
  1293. /package/dist/{path-RMTY5Y5A.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  1294. /package/dist/{capsule-merge-DI7PNQ2H.js.map → capsule-merge-4MGKE7C5.js.map} +0 -0
  1295. /package/dist/{chunk-G4SK7DSQ.js.map → chunk-2WWLHTZY.js.map} +0 -0
  1296. /package/dist/{chunk-X7HPGUVG.js.map → chunk-4CRG46BG.js.map} +0 -0
  1297. /package/dist/{chunk-UVMUAWVT.js.map → chunk-7IASACLB.js.map} +0 -0
  1298. /package/dist/{chunk-HELQZFZO.js.map → chunk-EDTHC6UD.js.map} +0 -0
  1299. /package/dist/{chunk-4YM32CRU.js.map → chunk-EFJ3MQ4V.js.map} +0 -0
  1300. /package/dist/{chunk-E2UCDP5S.js.map → chunk-FBYESMQ2.js.map} +0 -0
  1301. /package/dist/{chunk-D54LZC5L.js.map → chunk-FDU6HUUL.js.map} +0 -0
  1302. /package/dist/{chunk-IB3BFHGN.js.map → chunk-GGKRUQOO.js.map} +0 -0
  1303. /package/dist/{chunk-242S3I2A.js.map → chunk-GL6I6MEQ.js.map} +0 -0
  1304. /package/dist/{secure-store-4R2GSO7S.js.map → chunk-HHLLAQGZ.js.map} +0 -0
  1305. /package/dist/{chunk-4IS4SXIQ.js.map → chunk-HXXBL2KD.js.map} +0 -0
  1306. /package/dist/{chunk-767ODGE6.js.map → chunk-KNKUID7G.js.map} +0 -0
  1307. /package/dist/{chunk-6TBWYBJ3.js.map → chunk-LPMVBPA3.js.map} +0 -0
  1308. /package/dist/{chunk-WEJG4TB5.js.map → chunk-MC26UJIM.js.map} +0 -0
  1309. /package/dist/{chunk-JKDVIE52.js.map → chunk-MGKYQQYF.js.map} +0 -0
  1310. /package/dist/{chunk-Y3VMVTYX.js.map → chunk-MT4HVDUZ.js.map} +0 -0
  1311. /package/dist/{chunk-G2WADRQ3.js.map → chunk-MY6TPVXW.js.map} +0 -0
  1312. /package/dist/{chunk-OR64ZGRZ.js.map → chunk-NNVTUXEB.js.map} +0 -0
  1313. /package/dist/{chunk-JESOB2HO.js.map → chunk-P4NEIHUT.js.map} +0 -0
  1314. /package/dist/{chunk-IXEJRKCZ.js.map → chunk-QRNI5JBH.js.map} +0 -0
  1315. /package/dist/{chunk-EEQLFRUM.js.map → chunk-RRF5UOBJ.js.map} +0 -0
  1316. /package/dist/{state-store-3EH7HYIN.js.map → chunk-SEDEKFYQ.js.map} +0 -0
  1317. /package/dist/{chunk-2LGMW3DJ.js.map → chunk-U3PN77QT.js.map} +0 -0
  1318. /package/dist/{chunk-XMVFHBHT.js.map → chunk-U3WSW6PZ.js.map} +0 -0
  1319. /package/dist/{chunk-N5AKDXAI.js.map → chunk-UWVJF25J.js.map} +0 -0
  1320. /package/dist/{types-V3FJ26TF.js.map → chunk-V5OCT34X.js.map} +0 -0
  1321. /package/dist/{chunk-ZG7PTKBK.js.map → chunk-W3LR522O.js.map} +0 -0
  1322. /package/dist/{chunk-MARWOCVP.js.map → chunk-XIG5PDM7.js.map} +0 -0
  1323. /package/dist/{chunk-ZNQN6ZTA.js.map → chunk-XVZ7B3HG.js.map} +0 -0
  1324. /package/dist/{graph-edge-decay-PWB63GRE.js.map → graph-edge-decay-5DI5GUNL.js.map} +0 -0
@@ -0,0 +1,2230 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs";
3
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import test from "node:test";
7
+
8
+ import {
9
+ computePairId,
10
+ writePair,
11
+ writePairs,
12
+ readPair,
13
+ listPairs,
14
+ isCoolingDown,
15
+ memoryHashesChanged,
16
+ computeMemoryContentHash,
17
+ resolvePair,
18
+ deferPair,
19
+ migrateUnscopedPairsToNamespace,
20
+ type ContradictionPair,
21
+ } from "./contradiction-review.js";
22
+ import { _pairKey, _contentHash } from "./contradiction-judge.js";
23
+ import { executeResolution, isValidResolutionVerb } from "./resolution.js";
24
+ import { ACTIVE_STATUSES, runContradictionScan } from "./contradiction-scan.js";
25
+ import { parseConfig } from "../config.js";
26
+ import type { StorageManager } from "../storage.js";
27
+ import type { MemoryCategory, MemoryFile, MemoryFrontmatter } from "../types.js";
28
+
29
+ type FrontmatterLifecycleOptions = Parameters<StorageManager["writeMemoryFrontmatter"]>[2];
30
+
31
+ // ── Helpers ────────────────────────────────────────────────────────────────────
32
+
33
+ async function makeTempDir(prefix = "contradiction-test-"): Promise<{
34
+ dir: string;
35
+ cleanup: () => Promise<void>;
36
+ }> {
37
+ const dir = await mkdtemp(path.join(os.tmpdir(), prefix));
38
+ return { dir, cleanup: () => rm(dir, { recursive: true, force: true }) };
39
+ }
40
+
41
+ function makePair(overrides?: Partial<ContradictionPair>): Omit<ContradictionPair, "pairId"> & { memoryIds: [string, string] } {
42
+ return {
43
+ memoryIds: ["mem-a-001", "mem-b-002"],
44
+ verdict: "contradicts",
45
+ rationale: "Test rationale",
46
+ confidence: 0.9,
47
+ detectedAt: new Date().toISOString(),
48
+ ...overrides,
49
+ };
50
+ }
51
+
52
+ async function writeStoredPair(dir: string, pair: ContradictionPair): Promise<void> {
53
+ const reviewDir = path.join(dir, ".review", "contradictions");
54
+ await mkdir(reviewDir, { recursive: true });
55
+ await writeFile(path.join(reviewDir, `${pair.pairId}.json`), JSON.stringify(pair, null, 2), "utf-8");
56
+ }
57
+
58
+ function makeMemory(id: string, category: MemoryCategory = "fact"): MemoryFile {
59
+ const now = "2026-05-17T00:00:00.000Z";
60
+ return {
61
+ path: `/tmp/${id}.md`,
62
+ content: `content for ${id}`,
63
+ frontmatter: {
64
+ id,
65
+ category,
66
+ created: now,
67
+ updated: now,
68
+ source: "test",
69
+ confidence: 0.9,
70
+ confidenceTier: "explicit",
71
+ tags: [],
72
+ },
73
+ };
74
+ }
75
+
76
+ function cloneMemory(memory: MemoryFile): MemoryFile {
77
+ return {
78
+ path: memory.path,
79
+ content: memory.content,
80
+ frontmatter: {
81
+ ...memory.frontmatter,
82
+ tags: [...(memory.frontmatter.tags ?? [])],
83
+ lineage: memory.frontmatter.lineage ? [...memory.frontmatter.lineage] : undefined,
84
+ derived_from: memory.frontmatter.derived_from ? [...memory.frontmatter.derived_from] : undefined,
85
+ },
86
+ };
87
+ }
88
+
89
+ function makeResolutionStorage(options: {
90
+ failSupersedeFor?: string;
91
+ failRollbackFor?: string;
92
+ partialSupersedeBeforeFailureFor?: string;
93
+ } = {}) {
94
+ const memories = new Map<string, MemoryFile>([
95
+ ["mem-a-001", makeMemory("mem-a-001")],
96
+ ["mem-b-002", makeMemory("mem-b-002")],
97
+ ["mem-merged-003", makeMemory("mem-merged-003")],
98
+ ]);
99
+ const supersedeCalls: Array<{ oldId: string; newId: string; reason: string }> = [];
100
+ const frontmatterWrites: Array<{
101
+ memoryId: string;
102
+ beforeStatus: MemoryFrontmatter["status"];
103
+ patch: Partial<MemoryFrontmatter>;
104
+ lifecycle?: FrontmatterLifecycleOptions;
105
+ }> = [];
106
+ const removedFactHashIds: string[] = [];
107
+
108
+ const storage = {
109
+ memories,
110
+ supersedeCalls,
111
+ frontmatterWrites,
112
+ removedFactHashIds,
113
+ async getMemoryById(id: string) {
114
+ const memory = memories.get(id);
115
+ return memory ? cloneMemory(memory) : null;
116
+ },
117
+ async writeMemory(category: MemoryCategory, content: string, writeOptions: {
118
+ lineage?: string[];
119
+ derivedFrom?: string[];
120
+ derivedVia?: string;
121
+ tags?: string[];
122
+ }) {
123
+ const id = `merged-created-${memories.size}`;
124
+ const memory = makeMemory(id, category);
125
+ memory.content = content;
126
+ memory.frontmatter.tags = writeOptions.tags ?? [];
127
+ memory.frontmatter.lineage = writeOptions.lineage;
128
+ memory.frontmatter.derived_from = writeOptions.derivedFrom;
129
+ memory.frontmatter.derived_via = writeOptions.derivedVia as MemoryFrontmatter["derived_via"];
130
+ memories.set(id, memory);
131
+ return id;
132
+ },
133
+ async supersedeMemory(oldId: string, newId: string, reason: string) {
134
+ supersedeCalls.push({ oldId, newId, reason });
135
+ if (oldId === options.failSupersedeFor) return false;
136
+ const memory = memories.get(oldId);
137
+ if (!memory) return false;
138
+ const supersededMemory: MemoryFile = {
139
+ ...memory,
140
+ frontmatter: {
141
+ ...memory.frontmatter,
142
+ status: "superseded",
143
+ supersededBy: newId,
144
+ supersededAt: "2026-05-17T00:01:00.000Z",
145
+ },
146
+ };
147
+ memories.set(oldId, supersededMemory);
148
+ if (oldId === options.partialSupersedeBeforeFailureFor) return false;
149
+ return true;
150
+ },
151
+ async writeMemoryFrontmatter(
152
+ memory: MemoryFile,
153
+ patch: Partial<MemoryFrontmatter>,
154
+ lifecycle?: FrontmatterLifecycleOptions,
155
+ ) {
156
+ const existing = memories.get(memory.frontmatter.id);
157
+ if (!existing) return false;
158
+ frontmatterWrites.push({
159
+ memoryId: memory.frontmatter.id,
160
+ beforeStatus: memory.frontmatter.status,
161
+ patch,
162
+ lifecycle,
163
+ });
164
+ if (memory.frontmatter.id === options.failRollbackFor) return false;
165
+ memories.set(memory.frontmatter.id, {
166
+ ...memory,
167
+ frontmatter: { ...memory.frontmatter, ...patch },
168
+ });
169
+ return true;
170
+ },
171
+ async invalidateMemory(id: string) {
172
+ return memories.delete(id);
173
+ },
174
+ async removeFactContentHashesForMemories(hashMemories: MemoryFile[]) {
175
+ removedFactHashIds.push(...hashMemories.map((memory) => memory.frontmatter.id));
176
+ },
177
+ };
178
+
179
+ return storage as typeof storage & StorageManager;
180
+ }
181
+
182
+ function makeScanStorage(memories: MemoryFile[]) {
183
+ let readCount = 0;
184
+ const storage = {
185
+ get readCount() {
186
+ return readCount;
187
+ },
188
+ async readAllMemories() {
189
+ readCount += 1;
190
+ return memories.map(cloneMemory);
191
+ },
192
+ };
193
+ return storage as typeof storage & StorageManager;
194
+ }
195
+
196
+ // ── Pair ID determinism ────────────────────────────────────────────────────────
197
+
198
+ test("computePairId is deterministic and order-independent", () => {
199
+ const ab = computePairId("a", "b");
200
+ const ba = computePairId("b", "a");
201
+ assert.equal(ab, ba, "Pair ID should be the same regardless of argument order");
202
+ });
203
+
204
+ test("computePairId produces different IDs for different pairs", () => {
205
+ const ab = computePairId("a", "b");
206
+ const ac = computePairId("a", "c");
207
+ assert.notEqual(ab, ac);
208
+ });
209
+
210
+ test("computePairId includes namespace scope when present", () => {
211
+ const unscoped = computePairId("a", "b");
212
+ const ns1 = computePairId("a", "b", "ns1");
213
+ const ns1Reversed = computePairId("b", "a", "ns1");
214
+ const ns2 = computePairId("a", "b", "ns2");
215
+
216
+ assert.notEqual(ns1, unscoped);
217
+ assert.equal(ns1, ns1Reversed);
218
+ assert.notEqual(ns1, ns2);
219
+ assert.equal(computePairId("a", "b", " "), unscoped);
220
+ });
221
+
222
+ // ── Review queue write/read ────────────────────────────────────────────────────
223
+
224
+ test("writePair and readPair round-trip", async () => {
225
+ const { dir, cleanup } = await makeTempDir();
226
+ try {
227
+ const pair = makePair();
228
+ const written = writePair(dir, pair);
229
+ assert.ok(written.pairId, "Written pair should have a pairId");
230
+ assert.deepEqual(written.memoryIds, pair.memoryIds);
231
+
232
+ const read = readPair(dir, written.pairId);
233
+ assert.ok(read, "Should read back the pair");
234
+ assert.equal(read!.pairId, written.pairId);
235
+ assert.equal(read!.verdict, "contradicts");
236
+ } finally {
237
+ await cleanup();
238
+ }
239
+ });
240
+
241
+ test("writePair is idempotent", async () => {
242
+ const { dir, cleanup } = await makeTempDir();
243
+ try {
244
+ const pair = makePair();
245
+ const first = writePair(dir, pair);
246
+ const second = writePair(dir, pair);
247
+ assert.equal(first.pairId, second.pairId);
248
+ } finally {
249
+ await cleanup();
250
+ }
251
+ });
252
+
253
+ test("writePair stores identical memory id pairs separately per namespace", async () => {
254
+ const { dir, cleanup } = await makeTempDir();
255
+ try {
256
+ const ns1 = writePair(dir, makePair({ namespace: "ns1" }));
257
+ const ns2 = writePair(dir, makePair({ namespace: "ns2" }));
258
+
259
+ assert.notEqual(ns1.pairId, ns2.pairId);
260
+ assert.equal(listPairs(dir, { namespace: "ns1" }).pairs[0]?.pairId, ns1.pairId);
261
+ assert.equal(listPairs(dir, { namespace: "ns2" }).pairs[0]?.pairId, ns2.pairId);
262
+ } finally {
263
+ await cleanup();
264
+ }
265
+ });
266
+
267
+ test("review queue writes use unique temporary paths", async () => {
268
+ const { dir, cleanup } = await makeTempDir();
269
+ const tempPaths: string[] = [];
270
+ const originalWriteFileSync = fs.writeFileSync;
271
+
272
+ (fs as any).writeFileSync = (file: unknown, ...args: unknown[]) => {
273
+ const filePath = String(file);
274
+ if (filePath.includes(`${path.sep}.review${path.sep}contradictions${path.sep}`)) {
275
+ tempPaths.push(filePath);
276
+ }
277
+ return (originalWriteFileSync as any).call(fs, file, ...args);
278
+ };
279
+
280
+ try {
281
+ const first = writePair(dir, makePair({ memoryIds: ["mem-a-001", "mem-b-002"] }));
282
+ const second = writePair(dir, makePair({ memoryIds: ["mem-a-003", "mem-b-004"] }));
283
+ resolvePair(dir, first.pairId, "both-valid");
284
+ deferPair(dir, second.pairId);
285
+
286
+ assert.equal(tempPaths.length, 4);
287
+ assert.equal(new Set(tempPaths).size, tempPaths.length);
288
+ for (const tempPath of tempPaths) {
289
+ assert.match(tempPath, /\.json\.\d+\.\d+\.[0-9a-f-]+\.tmp$/);
290
+ assert.equal(tempPath.endsWith(".json.tmp"), false);
291
+ }
292
+ } finally {
293
+ fs.writeFileSync = originalWriteFileSync;
294
+ await cleanup();
295
+ }
296
+ });
297
+
298
+ test("review queue write failures clean up unique temporary files", async () => {
299
+ const { dir, cleanup } = await makeTempDir();
300
+ const originalRenameSync = fs.renameSync;
301
+ let attemptedTempPath: string | null = null;
302
+
303
+ (fs as any).renameSync = (oldPath: unknown, newPath: unknown) => {
304
+ if (String(newPath).includes(`${path.sep}.review${path.sep}contradictions${path.sep}`)) {
305
+ attemptedTempPath = String(oldPath);
306
+ throw new Error("simulated rename failure");
307
+ }
308
+ return (originalRenameSync as any).call(fs, oldPath, newPath);
309
+ };
310
+
311
+ try {
312
+ assert.throws(
313
+ () => writePair(dir, makePair()),
314
+ /simulated rename failure/,
315
+ );
316
+ assert.ok(attemptedTempPath);
317
+ assert.equal(fs.existsSync(attemptedTempPath), false);
318
+ } finally {
319
+ fs.renameSync = originalRenameSync;
320
+ await cleanup();
321
+ }
322
+ });
323
+
324
+ test("writePair preserves user resolution", async () => {
325
+ const { dir, cleanup } = await makeTempDir();
326
+ try {
327
+ const pair = makePair();
328
+ const written = writePair(dir, pair);
329
+ resolvePair(dir, written.pairId, "keep-a");
330
+
331
+ const updated = writePair(dir, makePair({ memoryIds: ["mem-a-001", "mem-b-002"], confidence: 0.95 }));
332
+ assert.equal(updated.resolution, "keep-a", "Should preserve existing resolution");
333
+ } finally {
334
+ await cleanup();
335
+ }
336
+ });
337
+
338
+ test("writePair preserves both-valid resolutions without scan cooldown context", async () => {
339
+ const { dir, cleanup } = await makeTempDir();
340
+ try {
341
+ const written = writePair(dir, makePair({ confidence: 0.5 }));
342
+ resolvePair(dir, written.pairId, "both-valid");
343
+
344
+ const updated = writePair(dir, makePair({ confidence: 0.95 }));
345
+ assert.equal(updated.resolution, "both-valid");
346
+ assert.equal(updated.confidence, 0.5);
347
+ } finally {
348
+ await cleanup();
349
+ }
350
+ });
351
+
352
+ test("writePair preserves dormant independent verdicts during cooldown", async () => {
353
+ const { dir, cleanup } = await makeTempDir();
354
+ try {
355
+ const now = new Date().toISOString();
356
+ const dormant = writePair(dir, makePair({
357
+ verdict: "independent",
358
+ confidence: 0.95,
359
+ lastReviewedAt: now,
360
+ }));
361
+
362
+ const refreshed = writePair(dir, makePair({
363
+ verdict: "contradicts",
364
+ confidence: 1,
365
+ rationale: "Fresh actionable judge result during cooldown",
366
+ }), { cooldownDays: 14 });
367
+
368
+ assert.equal(refreshed.pairId, dormant.pairId);
369
+ assert.equal(refreshed.verdict, "independent");
370
+ assert.equal(refreshed.confidence, 0.95);
371
+ assert.equal(refreshed.lastReviewedAt, now);
372
+ } finally {
373
+ await cleanup();
374
+ }
375
+ });
376
+
377
+ test("writePair refreshes dormant independent verdicts during cooldown when memory content changed", async () => {
378
+ const { dir, cleanup } = await makeTempDir();
379
+ try {
380
+ const now = new Date().toISOString();
381
+ const staleAHash = computeMemoryContentHash("old content for mem-a-001", "fact");
382
+ const currentAHash = computeMemoryContentHash("new content for mem-a-001", "fact");
383
+ const bHash = computeMemoryContentHash("content for mem-b-002", "fact");
384
+ const dormant = writePair(dir, makePair({
385
+ verdict: "independent",
386
+ confidence: 0.95,
387
+ lastReviewedAt: now,
388
+ memoryContentHashes: {
389
+ "mem-a-001": staleAHash,
390
+ "mem-b-002": bHash,
391
+ },
392
+ }));
393
+
394
+ const refreshed = writePair(dir, makePair({
395
+ verdict: "contradicts",
396
+ confidence: 0.5,
397
+ rationale: "Changed source memories now conflict",
398
+ memoryContentHashes: {
399
+ "mem-a-001": currentAHash,
400
+ "mem-b-002": bHash,
401
+ },
402
+ }), { cooldownDays: 14 });
403
+
404
+ assert.equal(refreshed.pairId, dormant.pairId);
405
+ assert.equal(refreshed.verdict, "contradicts");
406
+ assert.equal(refreshed.confidence, 0.5);
407
+ assert.equal(refreshed.resolution, undefined);
408
+ assert.equal(refreshed.lastReviewedAt, undefined);
409
+ assert.deepEqual(refreshed.memoryContentHashes, {
410
+ "mem-a-001": currentAHash,
411
+ "mem-b-002": bHash,
412
+ });
413
+ } finally {
414
+ await cleanup();
415
+ }
416
+ });
417
+
418
+ test("memoryHashesChanged compares stored pair hashes with current memory hashes", async () => {
419
+ const previousHash = computeMemoryContentHash("old content", "fact");
420
+ const unchangedHash = computeMemoryContentHash("same content", "fact");
421
+ const currentHash = computeMemoryContentHash("new content", "fact");
422
+ const pair = makePair({
423
+ memoryContentHashes: {
424
+ "mem-a-001": previousHash,
425
+ "mem-b-002": unchangedHash,
426
+ },
427
+ });
428
+
429
+ assert.equal(
430
+ memoryHashesChanged("", { ...pair, pairId: computePairId("mem-a-001", "mem-b-002") }, (memoryId) => {
431
+ if (memoryId === "mem-a-001") return currentHash;
432
+ if (memoryId === "mem-b-002") return unchangedHash;
433
+ return null;
434
+ }),
435
+ true,
436
+ );
437
+ assert.equal(
438
+ memoryHashesChanged("", { ...pair, pairId: computePairId("mem-a-001", "mem-b-002") }, (memoryId) => {
439
+ if (memoryId === "mem-a-001") return previousHash;
440
+ if (memoryId === "mem-b-002") return unchangedHash;
441
+ return null;
442
+ }),
443
+ false,
444
+ );
445
+ });
446
+
447
+ test("writePair refreshes expired independent verdicts with actionable lower-confidence results", async () => {
448
+ const { dir, cleanup } = await makeTempDir();
449
+ try {
450
+ const expiredAt = new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString();
451
+ const dormant = writePair(dir, makePair({
452
+ verdict: "independent",
453
+ confidence: 0.95,
454
+ detectedAt: expiredAt,
455
+ lastReviewedAt: expiredAt,
456
+ }));
457
+
458
+ const refreshed = writePair(dir, makePair({
459
+ verdict: "contradicts",
460
+ confidence: 0.5,
461
+ rationale: "Fresh actionable judge result after cooldown",
462
+ }), { cooldownDays: 14 });
463
+
464
+ assert.equal(refreshed.pairId, dormant.pairId);
465
+ assert.equal(refreshed.verdict, "contradicts");
466
+ assert.equal(refreshed.confidence, 0.5);
467
+ assert.equal(refreshed.resolution, undefined);
468
+ assert.equal(refreshed.lastReviewedAt, undefined);
469
+ assert.equal(readPair(dir, dormant.pairId)?.verdict, "contradicts");
470
+
471
+ const unresolved = listPairs(dir, { filter: "unresolved" });
472
+ assert.equal(unresolved.total, 1);
473
+ assert.equal(unresolved.pairs[0]?.pairId, dormant.pairId);
474
+ assert.equal(unresolved.pairs[0]?.verdict, "contradicts");
475
+ } finally {
476
+ await cleanup();
477
+ }
478
+ });
479
+
480
+ test("writePair refreshes expired both-valid resolutions with actionable results", async () => {
481
+ const { dir, cleanup } = await makeTempDir();
482
+ try {
483
+ const expiredAt = new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString();
484
+ const written = writePair(dir, makePair({ confidence: 0.95 }));
485
+ const resolved = resolvePair(dir, written.pairId, "both-valid");
486
+ assert.ok(resolved);
487
+ await writeStoredPair(dir, {
488
+ ...resolved,
489
+ lastReviewedAt: expiredAt,
490
+ });
491
+
492
+ const refreshed = writePair(dir, makePair({
493
+ verdict: "contradicts",
494
+ confidence: 0.5,
495
+ rationale: "Fresh actionable judge result after both-valid cooldown",
496
+ }), { cooldownDays: 14 });
497
+
498
+ assert.equal(refreshed.pairId, written.pairId);
499
+ assert.equal(refreshed.verdict, "contradicts");
500
+ assert.equal(refreshed.confidence, 0.5);
501
+ assert.equal(refreshed.resolution, undefined);
502
+ assert.equal(refreshed.lastReviewedAt, undefined);
503
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
504
+ } finally {
505
+ await cleanup();
506
+ }
507
+ });
508
+
509
+ // ── Batch dedup (rule 49) ──────────────────────────────────────────────────────
510
+
511
+ test("writePairs deduplicates batch inputs", async () => {
512
+ const { dir, cleanup } = await makeTempDir();
513
+ try {
514
+ const pair = makePair();
515
+ // Same pair submitted 3 times
516
+ const results = writePairs(dir, [pair, pair, pair]);
517
+ assert.equal(results.length, 1, "Should deduplicate identical pairs in batch");
518
+ } finally {
519
+ await cleanup();
520
+ }
521
+ });
522
+
523
+ // ── List and filter ────────────────────────────────────────────────────────────
524
+
525
+ test("listPairs filters by verdict", async () => {
526
+ const { dir, cleanup } = await makeTempDir();
527
+ try {
528
+ writePair(dir, makePair({ verdict: "contradicts", memoryIds: ["a1", "b1"] }));
529
+ writePair(dir, makePair({ verdict: "independent", memoryIds: ["a2", "b2"] }));
530
+ writePair(dir, makePair({ verdict: "duplicates", memoryIds: ["a3", "b3"] }));
531
+
532
+ const contradicts = listPairs(dir, { filter: "contradicts" });
533
+ assert.equal(contradicts.pairs.length, 1);
534
+ assert.equal(contradicts.pairs[0].verdict, "contradicts");
535
+
536
+ const all = listPairs(dir, { filter: "all" });
537
+ assert.equal(all.pairs.length, 3);
538
+ } finally {
539
+ await cleanup();
540
+ }
541
+ });
542
+
543
+ test("listPairs respects limit", async () => {
544
+ const { dir, cleanup } = await makeTempDir();
545
+ try {
546
+ for (let i = 0; i < 5; i++) {
547
+ writePair(dir, makePair({ memoryIds: [`a-${i}`, `b-${i}`] }));
548
+ }
549
+ const result = listPairs(dir, { filter: "all", limit: 2 });
550
+ assert.equal(result.pairs.length, 2);
551
+ assert.equal(result.total, 5, "total should reflect all matching pairs, not just returned");
552
+ } finally {
553
+ await cleanup();
554
+ }
555
+ });
556
+
557
+ test("listPairs filters by namespace", async () => {
558
+ const { dir, cleanup } = await makeTempDir();
559
+ try {
560
+ writePair(dir, makePair({ namespace: "ns1", memoryIds: ["a1", "b1"] }));
561
+ writePair(dir, makePair({ namespace: "ns2", memoryIds: ["a2", "b2"] }));
562
+
563
+ const ns1 = listPairs(dir, { namespace: "ns1" });
564
+ assert.equal(ns1.pairs.length, 1);
565
+ assert.equal(ns1.pairs[0].namespace, "ns1");
566
+ } finally {
567
+ await cleanup();
568
+ }
569
+ });
570
+
571
+ test("listPairs can include legacy unscoped pairs for a namespace filter", async () => {
572
+ const { dir, cleanup } = await makeTempDir();
573
+ try {
574
+ const legacy = writePair(dir, makePair({ memoryIds: ["legacy-a", "legacy-b"] }));
575
+ writePair(dir, makePair({ namespace: "other", memoryIds: ["other-a", "other-b"] }));
576
+
577
+ const result = listPairs(dir, { namespace: "default", includeUnscopedForNamespace: true });
578
+
579
+ assert.equal(result.total, 1);
580
+ assert.equal(result.pairs[0]?.pairId, legacy.pairId);
581
+ assert.equal(result.pairs[0]?.namespace, undefined);
582
+ } finally {
583
+ await cleanup();
584
+ }
585
+ });
586
+
587
+ test("migrateUnscopedPairsToNamespace adopts legacy unscoped review pairs", async () => {
588
+ const { dir, cleanup } = await makeTempDir();
589
+ try {
590
+ const legacy = writePair(dir, makePair({ memoryIds: ["legacy-a", "legacy-b"] }));
591
+ writePair(dir, makePair({ namespace: "other", memoryIds: ["other-a", "other-b"] }));
592
+
593
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
594
+
595
+ const migrated = listPairs(dir, { filter: "all", namespace: "default" }).pairs;
596
+ assert.equal(migrated.length, 1);
597
+ assert.equal(migrated[0]!.namespace, "default");
598
+ assert.equal(migrated[0]!.pairId, computePairId("legacy-a", "legacy-b", "default"));
599
+ assert.equal(readPair(dir, legacy.pairId), null);
600
+
601
+ const other = listPairs(dir, { filter: "all", namespace: "other" }).pairs;
602
+ assert.equal(other.length, 1);
603
+ } finally {
604
+ await cleanup();
605
+ }
606
+ });
607
+
608
+ test("migrateUnscopedPairsToNamespace skips review directory scan after completion marker", async () => {
609
+ const { dir, cleanup } = await makeTempDir();
610
+ try {
611
+ writePair(dir, makePair({ memoryIds: ["legacy-a", "legacy-b"] }));
612
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
613
+
614
+ const reviewPath = path.join(dir, ".review", "contradictions");
615
+ const originalReaddirSync = fs.readdirSync;
616
+ const callOriginalReaddirSync = originalReaddirSync as unknown as (...args: unknown[]) => unknown;
617
+ const fsMutable = fs as unknown as { readdirSync: typeof fs.readdirSync };
618
+ let reviewDirScans = 0;
619
+ try {
620
+ fsMutable.readdirSync = ((...args: unknown[]) => {
621
+ if (String(args[0]) === reviewPath) reviewDirScans += 1;
622
+ return callOriginalReaddirSync(...args);
623
+ }) as typeof fs.readdirSync;
624
+
625
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 0);
626
+ assert.equal(reviewDirScans, 0);
627
+ } finally {
628
+ fsMutable.readdirSync = originalReaddirSync;
629
+ }
630
+
631
+ const lateLegacy = writePair(dir, makePair({ memoryIds: ["late-a", "late-b"] }));
632
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
633
+ assert.equal(readPair(dir, lateLegacy.pairId), null);
634
+ assert.equal(readPair(dir, computePairId("late-a", "late-b", "default"))?.namespace, "default");
635
+ } finally {
636
+ await cleanup();
637
+ }
638
+ });
639
+
640
+ test("migrateUnscopedPairsToNamespace retries after partial migration failure", async () => {
641
+ const { dir, cleanup } = await makeTempDir();
642
+ try {
643
+ const failingLegacy = writePair(dir, makePair({ memoryIds: ["fail-a", "fail-b"] }));
644
+ writePair(dir, makePair({ memoryIds: ["ok-a", "ok-b"] }));
645
+
646
+ const reviewPath = path.join(dir, ".review", "contradictions");
647
+ const failingPath = path.join(reviewPath, `${failingLegacy.pairId}.json`);
648
+ const originalRmSync = fs.rmSync;
649
+ const fsMutable = fs as unknown as { rmSync: typeof fs.rmSync };
650
+ let failedOnce = false;
651
+
652
+ try {
653
+ fsMutable.rmSync = ((target: fs.PathLike, options?: fs.RmOptions) => {
654
+ if (!failedOnce && String(target) === failingPath) {
655
+ failedOnce = true;
656
+ throw new Error("simulated legacy cleanup failure");
657
+ }
658
+ return originalRmSync(target, options);
659
+ }) as typeof fs.rmSync;
660
+
661
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
662
+ } finally {
663
+ fsMutable.rmSync = originalRmSync;
664
+ }
665
+
666
+ const markerEntriesAfterFailure = fs
667
+ .readdirSync(reviewPath)
668
+ .filter((entry) => entry.startsWith(".unscoped-migrated-"));
669
+ assert.deepEqual(
670
+ markerEntriesAfterFailure,
671
+ [],
672
+ "partial migration failure must not write the completion marker",
673
+ );
674
+ assert.ok(readPair(dir, failingLegacy.pairId), "failed legacy pair remains retryable");
675
+
676
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
677
+ assert.equal(readPair(dir, failingLegacy.pairId), null);
678
+ assert.equal(readPair(dir, computePairId("fail-a", "fail-b", "default"))?.namespace, "default");
679
+
680
+ const markerEntriesAfterRetry = fs
681
+ .readdirSync(reviewPath)
682
+ .filter((entry) => entry.startsWith(".unscoped-migrated-"));
683
+ assert.equal(markerEntriesAfterRetry.length, 1);
684
+ } finally {
685
+ await cleanup();
686
+ }
687
+ });
688
+
689
+ test("migrateUnscopedPairsToNamespace still completes when malformed files are skipped", async () => {
690
+ const { dir, cleanup } = await makeTempDir();
691
+ try {
692
+ const legacy = writePair(dir, makePair({ memoryIds: ["legacy-a", "legacy-b"] }));
693
+ const reviewPath = path.join(dir, ".review", "contradictions");
694
+ await writeFile(path.join(reviewPath, "malformed.json"), "{not-json", "utf-8");
695
+
696
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
697
+ assert.equal(readPair(dir, legacy.pairId), null);
698
+ assert.equal(readPair(dir, computePairId("legacy-a", "legacy-b", "default"))?.namespace, "default");
699
+
700
+ const markerEntries = fs
701
+ .readdirSync(reviewPath)
702
+ .filter((entry) => entry.startsWith(".unscoped-migrated-"));
703
+ assert.equal(markerEntries.length, 1);
704
+ } finally {
705
+ await cleanup();
706
+ }
707
+ });
708
+
709
+ test("migrateUnscopedPairsToNamespace preserves legacy both-valid state on scoped collisions", async () => {
710
+ const { dir, cleanup } = await makeTempDir();
711
+ try {
712
+ const scoped = writePair(dir, makePair({
713
+ namespace: "default",
714
+ memoryIds: ["shared-a", "shared-b"],
715
+ verdict: "contradicts",
716
+ confidence: 0.95,
717
+ detectedAt: "2026-01-01T00:00:00.000Z",
718
+ }));
719
+ const legacy: ContradictionPair = {
720
+ ...makePair({
721
+ memoryIds: ["shared-a", "shared-b"],
722
+ verdict: "independent",
723
+ resolution: "both-valid",
724
+ lastReviewedAt: "2026-02-01T00:00:00.000Z",
725
+ detectedAt: "2026-01-15T00:00:00.000Z",
726
+ }),
727
+ pairId: computePairId("shared-a", "shared-b"),
728
+ };
729
+ await writeStoredPair(dir, legacy);
730
+
731
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
732
+
733
+ const migrated = readPair(dir, scoped.pairId);
734
+ assert.ok(migrated);
735
+ assert.equal(migrated.namespace, "default");
736
+ assert.equal(migrated.resolution, "both-valid");
737
+ assert.equal(migrated.verdict, "independent");
738
+ assert.equal(migrated.lastReviewedAt, "2026-02-01T00:00:00.000Z");
739
+ assert.equal(readPair(dir, legacy.pairId), null);
740
+ } finally {
741
+ await cleanup();
742
+ }
743
+ });
744
+
745
+ test("migrateUnscopedPairsToNamespace preserves legacy cooldown state on scoped collisions", async () => {
746
+ const { dir, cleanup } = await makeTempDir();
747
+ try {
748
+ const scoped = writePair(dir, makePair({
749
+ namespace: "default",
750
+ memoryIds: ["shared-a", "shared-b"],
751
+ verdict: "contradicts",
752
+ confidence: 0.95,
753
+ detectedAt: "2026-01-01T00:00:00.000Z",
754
+ }));
755
+ const legacy: ContradictionPair = {
756
+ ...makePair({
757
+ memoryIds: ["shared-a", "shared-b"],
758
+ verdict: "independent",
759
+ lastReviewedAt: "2026-02-01T00:00:00.000Z",
760
+ detectedAt: "2026-01-15T00:00:00.000Z",
761
+ }),
762
+ pairId: computePairId("shared-a", "shared-b"),
763
+ };
764
+ await writeStoredPair(dir, legacy);
765
+
766
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
767
+
768
+ const migrated = readPair(dir, scoped.pairId);
769
+ assert.ok(migrated);
770
+ assert.equal(migrated.namespace, "default");
771
+ assert.equal(migrated.verdict, "independent");
772
+ assert.equal(migrated.lastReviewedAt, "2026-02-01T00:00:00.000Z");
773
+ assert.equal(readPair(dir, legacy.pairId), null);
774
+ } finally {
775
+ await cleanup();
776
+ }
777
+ });
778
+
779
+ test("migrateUnscopedPairsToNamespace preserves scoped conflicts over expired legacy cooldowns", async () => {
780
+ const { dir, cleanup } = await makeTempDir();
781
+ try {
782
+ const scoped = writePair(dir, makePair({
783
+ namespace: "default",
784
+ memoryIds: ["shared-a", "shared-b"],
785
+ verdict: "contradicts",
786
+ confidence: 0.95,
787
+ detectedAt: "2026-04-01T00:00:00.000Z",
788
+ }));
789
+ const legacy: ContradictionPair = {
790
+ ...makePair({
791
+ memoryIds: ["shared-a", "shared-b"],
792
+ verdict: "independent",
793
+ lastReviewedAt: "2020-01-01T00:00:00.000Z",
794
+ detectedAt: "2020-01-01T00:00:00.000Z",
795
+ }),
796
+ pairId: computePairId("shared-a", "shared-b"),
797
+ };
798
+ await writeStoredPair(dir, legacy);
799
+
800
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default", { cooldownDays: 14 }), 1);
801
+
802
+ const migrated = readPair(dir, scoped.pairId);
803
+ assert.ok(migrated);
804
+ assert.equal(migrated.namespace, "default");
805
+ assert.equal(migrated.verdict, "contradicts");
806
+ assert.equal(migrated.resolution, undefined);
807
+ assert.equal(readPair(dir, legacy.pairId), null);
808
+ } finally {
809
+ await cleanup();
810
+ }
811
+ });
812
+
813
+ test("migrateUnscopedPairsToNamespace preserves existing terminal scoped state on collisions", async () => {
814
+ const { dir, cleanup } = await makeTempDir();
815
+ try {
816
+ const scoped: ContradictionPair = {
817
+ ...makePair({
818
+ namespace: "default",
819
+ memoryIds: ["shared-a", "shared-b"],
820
+ verdict: "contradicts",
821
+ resolution: "keep-a",
822
+ lastReviewedAt: "2026-01-01T00:00:00.000Z",
823
+ }),
824
+ pairId: computePairId("shared-a", "shared-b", "default"),
825
+ };
826
+ await writeStoredPair(dir, scoped);
827
+ const legacy: ContradictionPair = {
828
+ ...makePair({
829
+ memoryIds: ["shared-a", "shared-b"],
830
+ verdict: "independent",
831
+ resolution: "both-valid",
832
+ lastReviewedAt: "2026-02-01T00:00:00.000Z",
833
+ }),
834
+ pairId: computePairId("shared-a", "shared-b"),
835
+ };
836
+ await writeStoredPair(dir, legacy);
837
+
838
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
839
+
840
+ const migrated = readPair(dir, scoped.pairId);
841
+ assert.ok(migrated);
842
+ assert.equal(migrated.namespace, "default");
843
+ assert.equal(migrated.resolution, "keep-a");
844
+ assert.equal(migrated.verdict, "contradicts");
845
+ assert.equal(readPair(dir, legacy.pairId), null);
846
+ } finally {
847
+ await cleanup();
848
+ }
849
+ });
850
+
851
+ test("migrateUnscopedPairsToNamespace keeps selected memory order on scoped collisions", async () => {
852
+ const { dir, cleanup } = await makeTempDir();
853
+ try {
854
+ const scoped: ContradictionPair = {
855
+ ...makePair({
856
+ namespace: "default",
857
+ memoryIds: ["shared-b", "shared-a"],
858
+ verdict: "contradicts",
859
+ resolution: "keep-a",
860
+ lastReviewedAt: "2026-01-01T00:00:00.000Z",
861
+ }),
862
+ pairId: computePairId("shared-a", "shared-b", "default"),
863
+ };
864
+ await writeStoredPair(dir, scoped);
865
+ const legacy: ContradictionPair = {
866
+ ...makePair({
867
+ memoryIds: ["shared-a", "shared-b"],
868
+ verdict: "independent",
869
+ resolution: "both-valid",
870
+ lastReviewedAt: "2026-02-01T00:00:00.000Z",
871
+ }),
872
+ pairId: computePairId("shared-a", "shared-b"),
873
+ };
874
+ await writeStoredPair(dir, legacy);
875
+
876
+ assert.equal(migrateUnscopedPairsToNamespace(dir, "default"), 1);
877
+
878
+ const migrated = readPair(dir, scoped.pairId);
879
+ assert.ok(migrated);
880
+ assert.equal(migrated.resolution, "keep-a");
881
+ assert.deepEqual(migrated.memoryIds, ["shared-b", "shared-a"]);
882
+ assert.equal(readPair(dir, legacy.pairId), null);
883
+ } finally {
884
+ await cleanup();
885
+ }
886
+ });
887
+
888
+ test("runContradictionScan loads memories from namespace-scoped storage", async () => {
889
+ const { dir, cleanup } = await makeTempDir();
890
+ try {
891
+ const ns1A = makeMemory("ns1-a");
892
+ ns1A.frontmatter.entityRef = "entity:shared";
893
+ const ns1B = makeMemory("ns1-b");
894
+ ns1B.frontmatter.entityRef = "entity:shared";
895
+ const ns2A = makeMemory("ns2-a");
896
+ ns2A.frontmatter.entityRef = "entity:shared";
897
+
898
+ const rootStorage = makeScanStorage([ns1A, ns1B, ns2A]);
899
+ const ns1Storage = makeScanStorage([ns1A, ns1B]);
900
+ const config = parseConfig({
901
+ memoryDir: dir,
902
+ namespacesEnabled: true,
903
+ defaultNamespace: "default",
904
+ contradictionScan: {
905
+ enabled: true,
906
+ maxPairsPerRun: 10,
907
+ topicOverlapFloor: 0,
908
+ similarityFloor: 0,
909
+ },
910
+ });
911
+
912
+ const result = await runContradictionScan({
913
+ storage: rootStorage,
914
+ storageForNamespace(namespace) {
915
+ assert.equal(namespace, "ns1");
916
+ return ns1Storage;
917
+ },
918
+ config,
919
+ memoryDir: dir,
920
+ localLlm: null,
921
+ fallbackLlm: null,
922
+ namespace: "ns1",
923
+ });
924
+
925
+ assert.equal(rootStorage.readCount, 0);
926
+ assert.equal(ns1Storage.readCount, 1);
927
+ assert.equal(result.scanned, 2);
928
+ assert.equal(result.judged, 1);
929
+ assert.equal(result.queued, 1);
930
+
931
+ const queued = listPairs(dir, { filter: "all", namespace: "ns1" }).pairs;
932
+ assert.equal(queued.length, 1);
933
+ assert.deepEqual([...queued[0]!.memoryIds].sort(), ["ns1-a", "ns1-b"]);
934
+ } finally {
935
+ await cleanup();
936
+ }
937
+ });
938
+
939
+ test("runContradictionScan caps candidates during generation and preserves strategy priority", async () => {
940
+ const { dir, cleanup } = await makeTempDir();
941
+ try {
942
+ const entityA = makeMemory("entity-a");
943
+ entityA.frontmatter.entityRef = "entity:shared";
944
+ const entityB = makeMemory("entity-b");
945
+ entityB.frontmatter.entityRef = "entity:shared";
946
+
947
+ const topicA = makeMemory("topic-a");
948
+ topicA.frontmatter.tags = ["shared-topic"];
949
+ const topicB = makeMemory("topic-b");
950
+ topicB.frontmatter.tags = ["shared-topic"];
951
+
952
+ const embedA = makeMemory("embed-0-a");
953
+ embedA.frontmatter.tags = ["embed-a"];
954
+ const embedB = makeMemory("embed-0-b");
955
+ embedB.frontmatter.tags = ["embed-b"];
956
+
957
+ const storage = makeScanStorage([embedB, topicB, entityB, embedA, topicA, entityA]);
958
+ const config = parseConfig({
959
+ memoryDir: dir,
960
+ contradictionScan: {
961
+ enabled: true,
962
+ maxPairsPerRun: 2,
963
+ topicOverlapFloor: 0.5,
964
+ similarityFloor: 0.8,
965
+ },
966
+ });
967
+ let embeddingCalls = 0;
968
+
969
+ const result = await runContradictionScan({
970
+ storage,
971
+ config,
972
+ memoryDir: dir,
973
+ embeddingLookup: async (content) => {
974
+ embeddingCalls += 1;
975
+ return content === embedA.content ? [{ id: "embed-0-b", score: 0.99 }] : [];
976
+ },
977
+ localLlm: null,
978
+ fallbackLlm: null,
979
+ });
980
+
981
+ assert.equal(result.candidates, 2);
982
+ assert.equal(result.judged, 2);
983
+ assert.equal(result.queued, 2);
984
+ assert.equal(embeddingCalls, 0);
985
+
986
+ const queuedPairs = listPairs(dir, { filter: "all" }).pairs
987
+ .map((pair) => [...pair.memoryIds].sort().join(":"))
988
+ .sort();
989
+ assert.deepEqual(queuedPairs, ["entity-a:entity-b", "topic-a:topic-b"]);
990
+ } finally {
991
+ await cleanup();
992
+ }
993
+ });
994
+
995
+ test("runContradictionScan resolves default namespace scans through namespace storage resolver", async () => {
996
+ const { dir, cleanup } = await makeTempDir();
997
+ try {
998
+ const defaultA = makeMemory("default-a");
999
+ defaultA.frontmatter.entityRef = "entity:shared";
1000
+ const defaultB = makeMemory("default-b");
1001
+ defaultB.frontmatter.entityRef = "entity:shared";
1002
+ const rootOnly = makeMemory("root-only");
1003
+ rootOnly.frontmatter.entityRef = "entity:shared";
1004
+
1005
+ const rootStorage = makeScanStorage([rootOnly]);
1006
+ const defaultStorage = makeScanStorage([defaultA, defaultB]);
1007
+ const config = parseConfig({
1008
+ memoryDir: dir,
1009
+ namespacesEnabled: true,
1010
+ defaultNamespace: "configured-default",
1011
+ contradictionScan: {
1012
+ enabled: true,
1013
+ maxPairsPerRun: 10,
1014
+ topicOverlapFloor: 0,
1015
+ similarityFloor: 0,
1016
+ },
1017
+ });
1018
+
1019
+ const result = await runContradictionScan({
1020
+ storage: rootStorage,
1021
+ storageForNamespace(namespace) {
1022
+ assert.equal(namespace, undefined);
1023
+ return { storage: defaultStorage, namespace: "resolved-default" };
1024
+ },
1025
+ config,
1026
+ memoryDir: dir,
1027
+ localLlm: null,
1028
+ fallbackLlm: null,
1029
+ });
1030
+
1031
+ assert.equal(rootStorage.readCount, 0);
1032
+ assert.equal(defaultStorage.readCount, 1);
1033
+ assert.equal(result.scanned, 2);
1034
+
1035
+ const queued = listPairs(dir, { filter: "all", namespace: "resolved-default" }).pairs;
1036
+ assert.equal(queued.length, 1);
1037
+ assert.equal(queued[0]!.namespace, "resolved-default");
1038
+ assert.deepEqual([...queued[0]!.memoryIds].sort(), ["default-a", "default-b"]);
1039
+ } finally {
1040
+ await cleanup();
1041
+ }
1042
+ });
1043
+
1044
+ test("runContradictionScan treats StorageManager with storage property as raw storage", async () => {
1045
+ const { dir, cleanup } = await makeTempDir();
1046
+ try {
1047
+ const defaultA = makeMemory("default-a");
1048
+ defaultA.frontmatter.entityRef = "entity:shared";
1049
+ const defaultB = makeMemory("default-b");
1050
+ defaultB.frontmatter.entityRef = "entity:shared";
1051
+ const nestedOnly = makeMemory("nested-only");
1052
+ nestedOnly.frontmatter.entityRef = "entity:shared";
1053
+
1054
+ const rawStorage = makeScanStorage([defaultA, defaultB]) as ReturnType<typeof makeScanStorage> & {
1055
+ storage: ReturnType<typeof makeScanStorage>;
1056
+ };
1057
+ rawStorage.storage = makeScanStorage([nestedOnly]);
1058
+ const config = parseConfig({
1059
+ memoryDir: dir,
1060
+ namespacesEnabled: true,
1061
+ defaultNamespace: "configured-default",
1062
+ contradictionScan: {
1063
+ enabled: true,
1064
+ maxPairsPerRun: 10,
1065
+ topicOverlapFloor: 0,
1066
+ similarityFloor: 0,
1067
+ },
1068
+ });
1069
+
1070
+ const result = await runContradictionScan({
1071
+ storage: makeScanStorage([]),
1072
+ storageForNamespace() {
1073
+ return rawStorage;
1074
+ },
1075
+ config,
1076
+ memoryDir: dir,
1077
+ localLlm: null,
1078
+ fallbackLlm: null,
1079
+ });
1080
+
1081
+ assert.equal(rawStorage.readCount, 1);
1082
+ assert.equal(rawStorage.storage.readCount, 0);
1083
+ assert.equal(result.scanned, 2);
1084
+
1085
+ const queued = listPairs(dir, { filter: "all", namespace: "configured-default" }).pairs;
1086
+ assert.equal(queued.length, 1);
1087
+ assert.deepEqual([...queued[0]!.memoryIds].sort(), ["default-a", "default-b"]);
1088
+ } finally {
1089
+ await cleanup();
1090
+ }
1091
+ });
1092
+
1093
+ test("runContradictionScan migrates legacy unscoped cooldown pairs for default namespace scans", async () => {
1094
+ const { dir, cleanup } = await makeTempDir();
1095
+ try {
1096
+ const defaultA = makeMemory("default-a");
1097
+ defaultA.frontmatter.entityRef = "entity:shared";
1098
+ const defaultB = makeMemory("default-b");
1099
+ defaultB.frontmatter.entityRef = "entity:shared";
1100
+ writePair(dir, makePair({
1101
+ memoryIds: ["default-a", "default-b"],
1102
+ verdict: "independent",
1103
+ lastReviewedAt: new Date().toISOString(),
1104
+ }));
1105
+
1106
+ const defaultStorage = makeScanStorage([defaultA, defaultB]);
1107
+ const config = parseConfig({
1108
+ memoryDir: dir,
1109
+ namespacesEnabled: true,
1110
+ defaultNamespace: "configured-default",
1111
+ contradictionScan: {
1112
+ enabled: true,
1113
+ cooldownDays: 14,
1114
+ maxPairsPerRun: 10,
1115
+ topicOverlapFloor: 0,
1116
+ similarityFloor: 0,
1117
+ },
1118
+ });
1119
+
1120
+ const result = await runContradictionScan({
1121
+ storage: makeScanStorage([]),
1122
+ storageForNamespace(namespace) {
1123
+ assert.equal(namespace, undefined);
1124
+ return { storage: defaultStorage, namespace: "resolved-default" };
1125
+ },
1126
+ config,
1127
+ memoryDir: dir,
1128
+ localLlm: null,
1129
+ fallbackLlm: null,
1130
+ });
1131
+
1132
+ assert.equal(result.cooledDown, 1);
1133
+ assert.equal(result.judged, 0);
1134
+ assert.equal(result.queued, 0);
1135
+
1136
+ const queued = listPairs(dir, { filter: "all", namespace: "resolved-default" }).pairs;
1137
+ assert.equal(queued.length, 1);
1138
+ assert.equal(queued[0]!.namespace, "resolved-default");
1139
+ } finally {
1140
+ await cleanup();
1141
+ }
1142
+ });
1143
+
1144
+ test("runContradictionScan migrates legacy unscoped cooldown pairs for explicit default namespace scans", async () => {
1145
+ const { dir, cleanup } = await makeTempDir();
1146
+ try {
1147
+ const defaultA = makeMemory("default-a");
1148
+ defaultA.frontmatter.entityRef = "entity:shared";
1149
+ const defaultB = makeMemory("default-b");
1150
+ defaultB.frontmatter.entityRef = "entity:shared";
1151
+ writePair(dir, makePair({
1152
+ memoryIds: ["default-a", "default-b"],
1153
+ verdict: "independent",
1154
+ lastReviewedAt: new Date().toISOString(),
1155
+ }));
1156
+
1157
+ const defaultStorage = makeScanStorage([defaultA, defaultB]);
1158
+ const config = parseConfig({
1159
+ memoryDir: dir,
1160
+ namespacesEnabled: true,
1161
+ defaultNamespace: "configured-default",
1162
+ contradictionScan: {
1163
+ enabled: true,
1164
+ cooldownDays: 14,
1165
+ maxPairsPerRun: 10,
1166
+ topicOverlapFloor: 0,
1167
+ similarityFloor: 0,
1168
+ },
1169
+ });
1170
+
1171
+ const result = await runContradictionScan({
1172
+ storage: makeScanStorage([]),
1173
+ storageForNamespace(namespace) {
1174
+ assert.equal(namespace, "configured-default");
1175
+ return { storage: defaultStorage, namespace: "configured-default" };
1176
+ },
1177
+ config,
1178
+ memoryDir: dir,
1179
+ localLlm: null,
1180
+ fallbackLlm: null,
1181
+ namespace: "configured-default",
1182
+ });
1183
+
1184
+ assert.equal(result.cooledDown, 1);
1185
+ assert.equal(result.judged, 0);
1186
+ assert.equal(result.queued, 0);
1187
+
1188
+ const queued = listPairs(dir, { filter: "all", namespace: "configured-default" }).pairs;
1189
+ assert.equal(queued.length, 1);
1190
+ assert.equal(queued[0]!.namespace, "configured-default");
1191
+ } finally {
1192
+ await cleanup();
1193
+ }
1194
+ });
1195
+
1196
+ test("runContradictionScan rejudges cooling pairs when referenced memory content changed", async () => {
1197
+ const { dir, cleanup } = await makeTempDir();
1198
+ try {
1199
+ const defaultA = makeMemory("default-a");
1200
+ defaultA.frontmatter.entityRef = "entity:shared";
1201
+ defaultA.content = "Joshua uses pnpm for Remnic";
1202
+ const defaultB = makeMemory("default-b");
1203
+ defaultB.frontmatter.entityRef = "entity:shared";
1204
+ defaultB.content = "Joshua uses npm for Remnic";
1205
+ const currentAHash = computeMemoryContentHash(defaultA.content, "fact");
1206
+ const currentBHash = computeMemoryContentHash(defaultB.content, "fact");
1207
+
1208
+ writePair(dir, makePair({
1209
+ memoryIds: ["default-a", "default-b"],
1210
+ verdict: "independent",
1211
+ lastReviewedAt: new Date().toISOString(),
1212
+ memoryContentHashes: {
1213
+ "default-a": computeMemoryContentHash("Joshua uses yarn for Remnic", "fact"),
1214
+ "default-b": currentBHash,
1215
+ },
1216
+ }));
1217
+
1218
+ const storage = makeScanStorage([defaultA, defaultB]);
1219
+ const config = parseConfig({
1220
+ memoryDir: dir,
1221
+ contradictionScan: {
1222
+ enabled: true,
1223
+ cooldownDays: 14,
1224
+ maxPairsPerRun: 10,
1225
+ topicOverlapFloor: 0,
1226
+ similarityFloor: 0,
1227
+ },
1228
+ });
1229
+
1230
+ const result = await runContradictionScan({
1231
+ storage,
1232
+ config,
1233
+ memoryDir: dir,
1234
+ localLlm: null,
1235
+ fallbackLlm: {
1236
+ async complete() {
1237
+ return {
1238
+ content: JSON.stringify([{
1239
+ pairKey: "default-a:default-b",
1240
+ verdict: "independent",
1241
+ rationale: "Still no contradiction after changed content",
1242
+ confidence: 0.4,
1243
+ }]),
1244
+ };
1245
+ },
1246
+ } as any,
1247
+ });
1248
+
1249
+ assert.equal(result.cooledDown, 0);
1250
+ assert.equal(result.candidates, 1);
1251
+ assert.equal(result.judged, 1);
1252
+ assert.equal(result.queued, 1);
1253
+
1254
+ const queued = listPairs(dir, { filter: "all" }).pairs;
1255
+ assert.equal(queued.length, 1);
1256
+ assert.deepEqual(queued[0]!.memoryContentHashes, {
1257
+ "default-a": currentAHash,
1258
+ "default-b": currentBHash,
1259
+ });
1260
+ } finally {
1261
+ await cleanup();
1262
+ }
1263
+ });
1264
+
1265
+ test("runContradictionScan rejects namespace scans without an access-checked storage resolver", async () => {
1266
+ const { dir, cleanup } = await makeTempDir();
1267
+ try {
1268
+ const rootStorage = makeScanStorage([makeMemory("root-a"), makeMemory("root-b")]);
1269
+ const config = parseConfig({
1270
+ memoryDir: dir,
1271
+ namespacesEnabled: true,
1272
+ defaultNamespace: "default",
1273
+ contradictionScan: {
1274
+ enabled: true,
1275
+ maxPairsPerRun: 10,
1276
+ },
1277
+ });
1278
+
1279
+ await assert.rejects(
1280
+ runContradictionScan({
1281
+ storage: rootStorage,
1282
+ config,
1283
+ memoryDir: dir,
1284
+ localLlm: null,
1285
+ fallbackLlm: null,
1286
+ namespace: "ns1",
1287
+ }),
1288
+ /storageForNamespace/,
1289
+ );
1290
+
1291
+ assert.equal(rootStorage.readCount, 0);
1292
+ } finally {
1293
+ await cleanup();
1294
+ }
1295
+ });
1296
+
1297
+ test("runContradictionScan rejects default scans without an access-checked storage resolver when namespaces are enabled", async () => {
1298
+ const { dir, cleanup } = await makeTempDir();
1299
+ try {
1300
+ const rootStorage = makeScanStorage([makeMemory("root-a"), makeMemory("root-b")]);
1301
+ const config = parseConfig({
1302
+ memoryDir: dir,
1303
+ namespacesEnabled: true,
1304
+ defaultNamespace: "default",
1305
+ contradictionScan: {
1306
+ enabled: true,
1307
+ maxPairsPerRun: 10,
1308
+ },
1309
+ });
1310
+
1311
+ await assert.rejects(
1312
+ runContradictionScan({
1313
+ storage: rootStorage,
1314
+ config,
1315
+ memoryDir: dir,
1316
+ localLlm: null,
1317
+ fallbackLlm: null,
1318
+ }),
1319
+ /storageForNamespace/,
1320
+ );
1321
+
1322
+ assert.equal(rootStorage.readCount, 0);
1323
+ } finally {
1324
+ await cleanup();
1325
+ }
1326
+ });
1327
+
1328
+ test("runContradictionScan rejects unsupported explicit namespaces when namespaces are disabled", async () => {
1329
+ const { dir, cleanup } = await makeTempDir();
1330
+ try {
1331
+ const rootStorage = makeScanStorage([makeMemory("root-a"), makeMemory("root-b")]);
1332
+ let resolverCalls = 0;
1333
+ const config = parseConfig({
1334
+ memoryDir: dir,
1335
+ namespacesEnabled: false,
1336
+ defaultNamespace: "default",
1337
+ contradictionScan: {
1338
+ enabled: true,
1339
+ maxPairsPerRun: 10,
1340
+ },
1341
+ });
1342
+
1343
+ await assert.rejects(
1344
+ runContradictionScan({
1345
+ storage: rootStorage,
1346
+ storageForNamespace() {
1347
+ resolverCalls += 1;
1348
+ return makeScanStorage([]);
1349
+ },
1350
+ config,
1351
+ memoryDir: dir,
1352
+ localLlm: null,
1353
+ fallbackLlm: null,
1354
+ namespace: "typo",
1355
+ }),
1356
+ /unsupported namespace: typo/,
1357
+ );
1358
+
1359
+ assert.equal(resolverCalls, 0);
1360
+ assert.equal(rootStorage.readCount, 0);
1361
+ } finally {
1362
+ await cleanup();
1363
+ }
1364
+ });
1365
+
1366
+ test("runContradictionScan ignores explicit default namespace when namespaces are disabled", async () => {
1367
+ const { dir, cleanup } = await makeTempDir();
1368
+ try {
1369
+ const rootA = makeMemory("root-a");
1370
+ rootA.frontmatter.entityRef = "entity:shared";
1371
+ const rootB = makeMemory("root-b");
1372
+ rootB.frontmatter.entityRef = "entity:shared";
1373
+ const rootStorage = makeScanStorage([rootA, rootB]);
1374
+ let resolverCalls = 0;
1375
+ const config = parseConfig({
1376
+ memoryDir: dir,
1377
+ namespacesEnabled: false,
1378
+ defaultNamespace: "default",
1379
+ contradictionScan: {
1380
+ enabled: true,
1381
+ maxPairsPerRun: 10,
1382
+ topicOverlapFloor: 0,
1383
+ similarityFloor: 0,
1384
+ },
1385
+ });
1386
+
1387
+ const result = await runContradictionScan({
1388
+ storage: rootStorage,
1389
+ storageForNamespace() {
1390
+ resolverCalls += 1;
1391
+ return makeScanStorage([]);
1392
+ },
1393
+ config,
1394
+ memoryDir: dir,
1395
+ localLlm: null,
1396
+ fallbackLlm: null,
1397
+ namespace: "default",
1398
+ });
1399
+
1400
+ assert.equal(resolverCalls, 0);
1401
+ assert.equal(rootStorage.readCount, 1);
1402
+ assert.equal(result.scanned, 2);
1403
+ assert.equal(result.queued, 1);
1404
+ assert.equal(listPairs(dir, { filter: "all", namespace: "default" }).pairs.length, 0);
1405
+ assert.equal(listPairs(dir, { filter: "all" }).pairs.length, 1);
1406
+ } finally {
1407
+ await cleanup();
1408
+ }
1409
+ });
1410
+
1411
+ test("listPairs returns empty when dir does not exist", async () => {
1412
+ const { dir, cleanup } = await makeTempDir();
1413
+ try {
1414
+ const result = listPairs(path.join(dir, "nonexistent"));
1415
+ assert.equal(result.pairs.length, 0);
1416
+ assert.equal(result.total, 0);
1417
+ } finally {
1418
+ await cleanup();
1419
+ }
1420
+ });
1421
+
1422
+ // ── Cooldown ───────────────────────────────────────────────────────────────────
1423
+
1424
+ test("isCoolingDown returns false when no lastReviewedAt", () => {
1425
+ const pair: ContradictionPair = {
1426
+ pairId: "test",
1427
+ memoryIds: ["a", "b"],
1428
+ verdict: "independent",
1429
+ rationale: "",
1430
+ confidence: 0.8,
1431
+ detectedAt: new Date().toISOString(),
1432
+ };
1433
+ assert.equal(isCoolingDown(pair, 14), false);
1434
+ });
1435
+
1436
+ test("isCoolingDown returns true within cooldown window", () => {
1437
+ const pair: ContradictionPair = {
1438
+ pairId: "test",
1439
+ memoryIds: ["a", "b"],
1440
+ verdict: "independent",
1441
+ rationale: "",
1442
+ confidence: 0.8,
1443
+ detectedAt: new Date().toISOString(),
1444
+ lastReviewedAt: new Date().toISOString(),
1445
+ };
1446
+ assert.equal(isCoolingDown(pair, 14), true);
1447
+ });
1448
+
1449
+ test("isCoolingDown returns false after cooldown expires", () => {
1450
+ const past = new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString();
1451
+ const pair: ContradictionPair = {
1452
+ pairId: "test",
1453
+ memoryIds: ["a", "b"],
1454
+ verdict: "independent",
1455
+ rationale: "",
1456
+ confidence: 0.8,
1457
+ detectedAt: past,
1458
+ lastReviewedAt: past,
1459
+ };
1460
+ assert.equal(isCoolingDown(pair, 14), false);
1461
+ });
1462
+
1463
+ test("isCoolingDown returns false when cooldownDays is 0 (rule 27)", () => {
1464
+ const pair: ContradictionPair = {
1465
+ pairId: "test",
1466
+ memoryIds: ["a", "b"],
1467
+ verdict: "independent",
1468
+ rationale: "",
1469
+ confidence: 0.8,
1470
+ detectedAt: new Date().toISOString(),
1471
+ lastReviewedAt: new Date().toISOString(),
1472
+ };
1473
+ assert.equal(isCoolingDown(pair, 0), false, "0 cooldownDays should disable cooldown");
1474
+ assert.equal(
1475
+ isCoolingDown({ ...pair, pairId: "deferred", deferredUntil: new Date(Date.now() + 60_000).toISOString() }, 0),
1476
+ false,
1477
+ "0 cooldownDays should disable explicit deferral cooldown",
1478
+ );
1479
+ assert.equal(
1480
+ isCoolingDown({ ...pair, pairId: "legacy-deferred", resolution: "needs-more-context" }, 0),
1481
+ false,
1482
+ "0 cooldownDays should disable legacy deferral cooldown",
1483
+ );
1484
+ });
1485
+
1486
+ test("isCoolingDown uses deferredUntil instead of generic cooldown for deferrals", () => {
1487
+ const now = Date.now();
1488
+ const active: ContradictionPair = {
1489
+ pairId: "active-deferral",
1490
+ memoryIds: ["a", "b"],
1491
+ verdict: "contradicts",
1492
+ rationale: "",
1493
+ confidence: 0.8,
1494
+ detectedAt: new Date(now).toISOString(),
1495
+ lastReviewedAt: new Date(now).toISOString(),
1496
+ deferredUntil: new Date(now + 60_000).toISOString(),
1497
+ };
1498
+ const expired: ContradictionPair = {
1499
+ ...active,
1500
+ pairId: "expired-deferral",
1501
+ deferredUntil: new Date(now - 60_000).toISOString(),
1502
+ };
1503
+
1504
+ assert.equal(isCoolingDown(active, 14), true);
1505
+ assert.equal(isCoolingDown(expired, 14), false);
1506
+ });
1507
+
1508
+ // ── Resolution verbs ───────────────────────────────────────────────────────────
1509
+
1510
+ test("isValidResolutionVerb accepts valid verbs", () => {
1511
+ assert.equal(isValidResolutionVerb("keep-a"), true);
1512
+ assert.equal(isValidResolutionVerb("keep-b"), true);
1513
+ assert.equal(isValidResolutionVerb("merge"), true);
1514
+ assert.equal(isValidResolutionVerb("both-valid"), true);
1515
+ assert.equal(isValidResolutionVerb("needs-more-context"), true);
1516
+ });
1517
+
1518
+ test("isValidResolutionVerb rejects invalid verbs", () => {
1519
+ assert.equal(isValidResolutionVerb("delete"), false);
1520
+ assert.equal(isValidResolutionVerb(""), false);
1521
+ assert.equal(isValidResolutionVerb("unknown"), false);
1522
+ });
1523
+
1524
+ test("executeResolution rejects invalid runtime verbs without poisoning the pair", async () => {
1525
+ const { dir, cleanup } = await makeTempDir();
1526
+ try {
1527
+ const written = writePair(dir, makePair());
1528
+ const storage = makeResolutionStorage();
1529
+
1530
+ await assert.rejects(
1531
+ () => executeResolution(dir, storage, written.pairId, "delete" as never),
1532
+ /Invalid contradiction resolution verb: delete/,
1533
+ );
1534
+
1535
+ assert.deepEqual(storage.supersedeCalls, []);
1536
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1537
+
1538
+ const valid = await executeResolution(dir, storage, written.pairId, "keep-a");
1539
+
1540
+ assert.deepEqual(valid.affectedIds, ["mem-b-002"]);
1541
+ assert.equal(readPair(dir, written.pairId)?.resolution, "keep-a");
1542
+ } finally {
1543
+ await cleanup();
1544
+ }
1545
+ });
1546
+
1547
+ test("resolvePair rejects invalid runtime verbs without mutating the pair", async () => {
1548
+ const { dir, cleanup } = await makeTempDir();
1549
+ try {
1550
+ const written = writePair(dir, makePair());
1551
+
1552
+ assert.throws(
1553
+ () => resolvePair(dir, written.pairId, "delete" as never),
1554
+ /Invalid contradiction resolution verb: delete/,
1555
+ );
1556
+
1557
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1558
+ assert.equal(resolvePair(dir, written.pairId, "both-valid")?.resolution, "both-valid");
1559
+ } finally {
1560
+ await cleanup();
1561
+ }
1562
+ });
1563
+
1564
+ test("executeResolution merge requires a real merged memory", async () => {
1565
+ const { dir, cleanup } = await makeTempDir();
1566
+ try {
1567
+ const written = writePair(dir, makePair());
1568
+ const storage = makeResolutionStorage();
1569
+
1570
+ const result = await executeResolution(dir, storage, written.pairId, "merge");
1571
+
1572
+ assert.deepEqual(storage.supersedeCalls, []);
1573
+ assert.match(result.message, /requires mergedMemoryId or mergedContent/);
1574
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1575
+ } finally {
1576
+ await cleanup();
1577
+ }
1578
+ });
1579
+
1580
+ test("executeResolution merge rejects missing replacement before superseding sources", async () => {
1581
+ const { dir, cleanup } = await makeTempDir();
1582
+ try {
1583
+ const written = writePair(dir, makePair());
1584
+ const storage = makeResolutionStorage();
1585
+
1586
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1587
+ mergedMemoryId: "missing-merged-memory",
1588
+ });
1589
+
1590
+ assert.deepEqual(storage.supersedeCalls, []);
1591
+ assert.match(result.message, /Merged memory missing-merged-memory not found/);
1592
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1593
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1594
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1595
+ } finally {
1596
+ await cleanup();
1597
+ }
1598
+ });
1599
+
1600
+ test("executeResolution merge supersedes both sources to a verified merged memory", async () => {
1601
+ const { dir, cleanup } = await makeTempDir();
1602
+ try {
1603
+ const written = writePair(dir, makePair());
1604
+ const storage = makeResolutionStorage();
1605
+
1606
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1607
+ mergedMemoryId: "mem-merged-003",
1608
+ });
1609
+
1610
+ assert.deepEqual(
1611
+ storage.supersedeCalls.map(({ oldId, newId }) => ({ oldId, newId })),
1612
+ [
1613
+ { oldId: "mem-a-001", newId: "mem-merged-003" },
1614
+ { oldId: "mem-b-002", newId: "mem-merged-003" },
1615
+ ],
1616
+ );
1617
+ assert.deepEqual(result.affectedIds, ["mem-a-001", "mem-b-002"]);
1618
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, "superseded");
1619
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.supersededBy, "mem-merged-003");
1620
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, "superseded");
1621
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.supersededBy, "mem-merged-003");
1622
+ assert.equal(readPair(dir, written.pairId)?.resolution, "merge");
1623
+ } finally {
1624
+ await cleanup();
1625
+ }
1626
+ });
1627
+
1628
+ test("executeResolution merge can create and verify a merged memory from content", async () => {
1629
+ const { dir, cleanup } = await makeTempDir();
1630
+ try {
1631
+ const written = writePair(dir, makePair());
1632
+ const storage = makeResolutionStorage();
1633
+
1634
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1635
+ mergedContent: "merged canonical fact",
1636
+ });
1637
+
1638
+ const mergedId = storage.supersedeCalls[0]?.newId;
1639
+ assert.ok(mergedId);
1640
+ assert.deepEqual(result.affectedIds, ["mem-a-001", "mem-b-002"]);
1641
+ assert.equal(storage.memories.get(mergedId)?.content, "merged canonical fact");
1642
+ assert.deepEqual(storage.memories.get(mergedId)?.frontmatter.derived_from, ["mem-a-001", "mem-b-002"]);
1643
+ assert.equal(storage.memories.get(mergedId)?.frontmatter.derived_via, "merge");
1644
+ assert.equal(readPair(dir, written.pairId)?.resolution, "merge");
1645
+ } finally {
1646
+ await cleanup();
1647
+ }
1648
+ });
1649
+
1650
+ test("executeResolution merge rolls back the first supersession when the second fails", async () => {
1651
+ const { dir, cleanup } = await makeTempDir();
1652
+ try {
1653
+ const written = writePair(dir, makePair());
1654
+ const storage = makeResolutionStorage({ failSupersedeFor: "mem-b-002" });
1655
+
1656
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1657
+ mergedMemoryId: "mem-merged-003",
1658
+ });
1659
+
1660
+ assert.deepEqual(
1661
+ storage.supersedeCalls.map(({ oldId, newId }) => ({ oldId, newId })),
1662
+ [
1663
+ { oldId: "mem-a-001", newId: "mem-merged-003" },
1664
+ { oldId: "mem-b-002", newId: "mem-merged-003" },
1665
+ ],
1666
+ );
1667
+ assert.match(result.message, /restored mem-a-001 and mem-b-002/);
1668
+ assert.deepEqual(result.affectedIds, []);
1669
+ assert.deepEqual(
1670
+ storage.frontmatterWrites.map(({ memoryId, lifecycle }) => ({
1671
+ memoryId,
1672
+ actor: lifecycle?.actor,
1673
+ reasonCode: lifecycle?.reasonCode,
1674
+ })),
1675
+ [
1676
+ {
1677
+ memoryId: "mem-a-001",
1678
+ actor: "contradiction-resolution",
1679
+ reasonCode: "contradiction-resolution:merge-rollback",
1680
+ },
1681
+ {
1682
+ memoryId: "mem-b-002",
1683
+ actor: "contradiction-resolution",
1684
+ reasonCode: "contradiction-resolution:merge-rollback",
1685
+ },
1686
+ ],
1687
+ );
1688
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1689
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.supersededBy, undefined);
1690
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1691
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1692
+ } finally {
1693
+ await cleanup();
1694
+ }
1695
+ });
1696
+
1697
+ test("executeResolution merge restores the second source after partial supersede failure", async () => {
1698
+ const { dir, cleanup } = await makeTempDir();
1699
+ try {
1700
+ const written = writePair(dir, makePair());
1701
+ const storage = makeResolutionStorage({ partialSupersedeBeforeFailureFor: "mem-b-002" });
1702
+
1703
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1704
+ mergedContent: "merged canonical fact",
1705
+ });
1706
+
1707
+ const mergedId = storage.supersedeCalls[0]?.newId;
1708
+ assert.ok(mergedId);
1709
+ assert.match(result.message, /restored mem-a-001 and mem-b-002/);
1710
+ assert.deepEqual(result.affectedIds, []);
1711
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1712
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1713
+ assert.equal(storage.memories.has(mergedId), false);
1714
+ assert.deepEqual(
1715
+ storage.frontmatterWrites.map(({ memoryId, beforeStatus }) => ({ memoryId, beforeStatus })),
1716
+ [
1717
+ { memoryId: "mem-a-001", beforeStatus: "superseded" },
1718
+ { memoryId: "mem-b-002", beforeStatus: "superseded" },
1719
+ ],
1720
+ );
1721
+ assert.deepEqual(storage.removedFactHashIds, [mergedId]);
1722
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1723
+ } finally {
1724
+ await cleanup();
1725
+ }
1726
+ });
1727
+
1728
+ test("executeResolution merge restores the first source after partial supersede failure", async () => {
1729
+ const { dir, cleanup } = await makeTempDir();
1730
+ try {
1731
+ const written = writePair(dir, makePair());
1732
+ const storage = makeResolutionStorage({ partialSupersedeBeforeFailureFor: "mem-a-001" });
1733
+
1734
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1735
+ mergedContent: "merged canonical fact",
1736
+ });
1737
+
1738
+ const mergedId = storage.supersedeCalls[0]?.newId;
1739
+ assert.ok(mergedId);
1740
+ assert.match(result.message, /restored mem-a-001/);
1741
+ assert.deepEqual(result.affectedIds, []);
1742
+ assert.deepEqual(
1743
+ storage.frontmatterWrites.map(({ memoryId, lifecycle }) => ({
1744
+ memoryId,
1745
+ actor: lifecycle?.actor,
1746
+ reasonCode: lifecycle?.reasonCode,
1747
+ })),
1748
+ [
1749
+ {
1750
+ memoryId: "mem-a-001",
1751
+ actor: "contradiction-resolution",
1752
+ reasonCode: "contradiction-resolution:merge-rollback",
1753
+ },
1754
+ ],
1755
+ );
1756
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1757
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.supersededBy, undefined);
1758
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1759
+ assert.equal(storage.memories.has(mergedId), false);
1760
+ assert.deepEqual(
1761
+ storage.frontmatterWrites.map(({ memoryId, beforeStatus }) => ({ memoryId, beforeStatus })),
1762
+ [{ memoryId: "mem-a-001", beforeStatus: "superseded" }],
1763
+ );
1764
+ assert.deepEqual(storage.removedFactHashIds, [mergedId]);
1765
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1766
+ } finally {
1767
+ await cleanup();
1768
+ }
1769
+ });
1770
+
1771
+ test("executeResolution merge keeps created replacement when rollback fails", async () => {
1772
+ const { dir, cleanup } = await makeTempDir();
1773
+ try {
1774
+ const written = writePair(dir, makePair());
1775
+ const storage = makeResolutionStorage({
1776
+ failSupersedeFor: "mem-b-002",
1777
+ failRollbackFor: "mem-a-001",
1778
+ });
1779
+
1780
+ const result = await executeResolution(dir, storage, written.pairId, "merge", {
1781
+ mergedContent: "merged canonical fact",
1782
+ });
1783
+
1784
+ const mergedId = storage.supersedeCalls[0]?.newId;
1785
+ assert.ok(mergedId);
1786
+ assert.match(result.message, /rollback incomplete for mem-a-001/);
1787
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, "superseded");
1788
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.supersededBy, mergedId);
1789
+ assert.equal(storage.memories.get(mergedId)?.content, "merged canonical fact");
1790
+ assert.deepEqual(storage.removedFactHashIds, []);
1791
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1792
+ } finally {
1793
+ await cleanup();
1794
+ }
1795
+ });
1796
+
1797
+ test("executeResolution keep-a does not supersede when the kept memory is missing", async () => {
1798
+ const { dir, cleanup } = await makeTempDir();
1799
+ try {
1800
+ const written = writePair(dir, makePair());
1801
+ const storage = makeResolutionStorage();
1802
+ storage.memories.delete("mem-a-001");
1803
+
1804
+ const result = await executeResolution(dir, storage, written.pairId, "keep-a");
1805
+
1806
+ assert.match(result.message, /Kept memory mem-a-001 not found/);
1807
+ assert.deepEqual(result.affectedIds, []);
1808
+ assert.deepEqual(storage.supersedeCalls, []);
1809
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1810
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1811
+ } finally {
1812
+ await cleanup();
1813
+ }
1814
+ });
1815
+
1816
+ test("executeResolution resolves namespaced pairs against namespace storage", async () => {
1817
+ const { dir, cleanup } = await makeTempDir();
1818
+ try {
1819
+ const rootStorage = makeResolutionStorage();
1820
+ rootStorage.memories.clear();
1821
+ const nsStorage = makeResolutionStorage();
1822
+ const written = writePair(dir, makePair({ namespace: "ns1" }));
1823
+
1824
+ const result = await executeResolution(dir, rootStorage, written.pairId, "keep-a", {
1825
+ storageForNamespace(namespace) {
1826
+ assert.equal(namespace, "ns1");
1827
+ return nsStorage;
1828
+ },
1829
+ });
1830
+
1831
+ assert.deepEqual(result.affectedIds, ["mem-b-002"]);
1832
+ assert.equal(rootStorage.supersedeCalls.length, 0);
1833
+ assert.deepEqual(nsStorage.supersedeCalls, [{
1834
+ oldId: "mem-b-002",
1835
+ newId: "mem-a-001",
1836
+ reason: "contradiction-resolution:keep-a",
1837
+ }]);
1838
+ assert.equal(readPair(dir, written.pairId)?.resolution, "keep-a");
1839
+ } finally {
1840
+ await cleanup();
1841
+ }
1842
+ });
1843
+
1844
+ test("executeResolution rejects namespaced pairs without a storage resolver", async () => {
1845
+ const { dir, cleanup } = await makeTempDir();
1846
+ try {
1847
+ const rootStorage = makeResolutionStorage();
1848
+ const written = writePair(dir, makePair({ namespace: "ns1" }));
1849
+
1850
+ await assert.rejects(
1851
+ () => executeResolution(dir, rootStorage, written.pairId, "keep-a"),
1852
+ /storageForNamespace/,
1853
+ );
1854
+ assert.equal(rootStorage.supersedeCalls.length, 0);
1855
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1856
+ } finally {
1857
+ await cleanup();
1858
+ }
1859
+ });
1860
+
1861
+ test("executeResolution checks namespace resolver before reporting already resolved pairs", async () => {
1862
+ const { dir, cleanup } = await makeTempDir();
1863
+ try {
1864
+ const pair: ContradictionPair = {
1865
+ ...makePair({
1866
+ namespace: "team",
1867
+ resolution: "both-valid",
1868
+ lastReviewedAt: "2026-01-01T00:00:00.000Z",
1869
+ }),
1870
+ pairId: computePairId("mem-a-001", "mem-b-002", "team"),
1871
+ };
1872
+ await writeStoredPair(dir, pair);
1873
+ const storage = makeResolutionStorage();
1874
+ let resolverCalls = 0;
1875
+
1876
+ await assert.rejects(
1877
+ () => executeResolution(dir, storage, pair.pairId, "keep-a", {
1878
+ storageForNamespace(namespace) {
1879
+ resolverCalls += 1;
1880
+ assert.equal(namespace, "team");
1881
+ throw new Error("namespace denied");
1882
+ },
1883
+ }),
1884
+ /namespace denied/,
1885
+ );
1886
+
1887
+ assert.equal(resolverCalls, 1);
1888
+ assert.equal(storage.supersedeCalls.length, 0);
1889
+ } finally {
1890
+ await cleanup();
1891
+ }
1892
+ });
1893
+
1894
+ test("executeResolution resolves legacy unscoped pairs through default namespace storage", async () => {
1895
+ const { dir, cleanup } = await makeTempDir();
1896
+ try {
1897
+ const rootStorage = makeResolutionStorage();
1898
+ rootStorage.memories.clear();
1899
+ const defaultStorage = makeResolutionStorage();
1900
+ const written = writePair(dir, makePair());
1901
+
1902
+ const result = await executeResolution(dir, rootStorage, written.pairId, "keep-a", {
1903
+ storageForNamespace(namespace) {
1904
+ assert.equal(namespace, undefined);
1905
+ return defaultStorage;
1906
+ },
1907
+ });
1908
+
1909
+ assert.deepEqual(result.affectedIds, ["mem-b-002"]);
1910
+ assert.equal(rootStorage.supersedeCalls.length, 0);
1911
+ assert.deepEqual(defaultStorage.supersedeCalls, [{
1912
+ oldId: "mem-b-002",
1913
+ newId: "mem-a-001",
1914
+ reason: "contradiction-resolution:keep-a",
1915
+ }]);
1916
+ assert.equal(readPair(dir, written.pairId)?.resolution, "keep-a");
1917
+ } finally {
1918
+ await cleanup();
1919
+ }
1920
+ });
1921
+
1922
+ test("executeResolution keep-b does not supersede when the kept memory is inactive", async () => {
1923
+ const { dir, cleanup } = await makeTempDir();
1924
+ try {
1925
+ const written = writePair(dir, makePair());
1926
+ const storage = makeResolutionStorage();
1927
+ const keepB = storage.memories.get("mem-b-002");
1928
+ assert.ok(keepB);
1929
+ storage.memories.set("mem-b-002", {
1930
+ ...keepB,
1931
+ frontmatter: {
1932
+ ...keepB.frontmatter,
1933
+ status: "superseded",
1934
+ supersededBy: "replacement",
1935
+ },
1936
+ });
1937
+
1938
+ const result = await executeResolution(dir, storage, written.pairId, "keep-b");
1939
+
1940
+ assert.match(result.message, /Kept memory mem-b-002 is superseded/);
1941
+ assert.deepEqual(result.affectedIds, []);
1942
+ assert.deepEqual(storage.supersedeCalls, []);
1943
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1944
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1945
+ } finally {
1946
+ await cleanup();
1947
+ }
1948
+ });
1949
+
1950
+ test("executeResolution keep-a restores source after partial supersede failure", async () => {
1951
+ const { dir, cleanup } = await makeTempDir();
1952
+ try {
1953
+ const written = writePair(dir, makePair());
1954
+ const storage = makeResolutionStorage({ partialSupersedeBeforeFailureFor: "mem-b-002" });
1955
+
1956
+ const result = await executeResolution(dir, storage, written.pairId, "keep-a");
1957
+
1958
+ assert.match(result.message, /restored mem-b-002/);
1959
+ assert.deepEqual(result.affectedIds, []);
1960
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.status, undefined);
1961
+ assert.equal(storage.memories.get("mem-b-002")?.frontmatter.supersededBy, undefined);
1962
+ assert.deepEqual(
1963
+ storage.frontmatterWrites.map(({ memoryId, beforeStatus, lifecycle }) => ({
1964
+ memoryId,
1965
+ beforeStatus,
1966
+ actor: lifecycle?.actor,
1967
+ reasonCode: lifecycle?.reasonCode,
1968
+ })),
1969
+ [
1970
+ {
1971
+ memoryId: "mem-b-002",
1972
+ beforeStatus: "superseded",
1973
+ actor: "contradiction-resolution",
1974
+ reasonCode: "contradiction-resolution:keep-a-rollback",
1975
+ },
1976
+ ],
1977
+ );
1978
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
1979
+ } finally {
1980
+ await cleanup();
1981
+ }
1982
+ });
1983
+
1984
+ test("executeResolution keep-b restores source after partial supersede failure", async () => {
1985
+ const { dir, cleanup } = await makeTempDir();
1986
+ try {
1987
+ const written = writePair(dir, makePair());
1988
+ const storage = makeResolutionStorage({ partialSupersedeBeforeFailureFor: "mem-a-001" });
1989
+
1990
+ const result = await executeResolution(dir, storage, written.pairId, "keep-b");
1991
+
1992
+ assert.match(result.message, /restored mem-a-001/);
1993
+ assert.deepEqual(result.affectedIds, []);
1994
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.status, undefined);
1995
+ assert.equal(storage.memories.get("mem-a-001")?.frontmatter.supersededBy, undefined);
1996
+ assert.deepEqual(
1997
+ storage.frontmatterWrites.map(({ memoryId, beforeStatus, lifecycle }) => ({
1998
+ memoryId,
1999
+ beforeStatus,
2000
+ actor: lifecycle?.actor,
2001
+ reasonCode: lifecycle?.reasonCode,
2002
+ })),
2003
+ [
2004
+ {
2005
+ memoryId: "mem-a-001",
2006
+ beforeStatus: "superseded",
2007
+ actor: "contradiction-resolution",
2008
+ reasonCode: "contradiction-resolution:keep-b-rollback",
2009
+ },
2010
+ ],
2011
+ );
2012
+ assert.equal(readPair(dir, written.pairId)?.resolution, undefined);
2013
+ } finally {
2014
+ await cleanup();
2015
+ }
2016
+ });
2017
+
2018
+ test("executeResolution needs-more-context defers without terminal resolution", async () => {
2019
+ const { dir, cleanup } = await makeTempDir();
2020
+ try {
2021
+ const written = writePair(dir, makePair());
2022
+ const storage = makeResolutionStorage();
2023
+
2024
+ const result = await executeResolution(dir, storage, written.pairId, "needs-more-context");
2025
+ const deferred = readPair(dir, written.pairId);
2026
+
2027
+ assert.deepEqual(result.affectedIds, []);
2028
+ assert.match(result.message, /Deferred/);
2029
+ assert.ok(deferred?.lastReviewedAt);
2030
+ assert.ok(deferred?.deferredUntil);
2031
+ assert.equal(deferred?.resolution, undefined);
2032
+ assert.equal(listPairs(dir, { filter: "unresolved" }).total, 0);
2033
+ assert.equal(listPairs(dir, { filter: "all" }).total, 1);
2034
+ } finally {
2035
+ await cleanup();
2036
+ }
2037
+ });
2038
+
2039
+ test("expired needs-more-context deferral returns to unresolved and can be refreshed", async () => {
2040
+ const { dir, cleanup } = await makeTempDir();
2041
+ try {
2042
+ const written = writePair(dir, makePair({ confidence: 0.95 }));
2043
+ const deferred = resolvePair(dir, written.pairId, "needs-more-context");
2044
+ assert.ok(deferred);
2045
+
2046
+ const expiredAt = new Date(Date.now() - 60_000).toISOString();
2047
+ await writeStoredPair(dir, {
2048
+ ...deferred!,
2049
+ lastReviewedAt: expiredAt,
2050
+ deferredUntil: expiredAt,
2051
+ });
2052
+
2053
+ assert.equal(listPairs(dir, { filter: "unresolved" }).total, 1);
2054
+
2055
+ const refreshed = writePair(dir, makePair({
2056
+ confidence: 0.5,
2057
+ verdict: "duplicates",
2058
+ rationale: "Fresh judge result after deferral expiry",
2059
+ }));
2060
+
2061
+ assert.equal(refreshed.confidence, 0.5);
2062
+ assert.equal(refreshed.verdict, "duplicates");
2063
+ assert.equal(refreshed.resolution, undefined);
2064
+ assert.equal(refreshed.deferredUntil, undefined);
2065
+ assert.equal(readPair(dir, written.pairId)?.deferredUntil, undefined);
2066
+ } finally {
2067
+ await cleanup();
2068
+ }
2069
+ });
2070
+
2071
+ test("legacy needs-more-context resolutions honor cooldown before returning to unresolved", async () => {
2072
+ const { dir, cleanup } = await makeTempDir();
2073
+ try {
2074
+ const written = writePair(dir, makePair());
2075
+
2076
+ await writeStoredPair(dir, {
2077
+ ...written,
2078
+ lastReviewedAt: new Date().toISOString(),
2079
+ resolution: "needs-more-context",
2080
+ });
2081
+ assert.equal(listPairs(dir, { filter: "unresolved" }).total, 0);
2082
+
2083
+ await writeStoredPair(dir, {
2084
+ ...written,
2085
+ lastReviewedAt: new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString(),
2086
+ resolution: "needs-more-context",
2087
+ });
2088
+ assert.equal(listPairs(dir, { filter: "unresolved" }).total, 1);
2089
+ } finally {
2090
+ await cleanup();
2091
+ }
2092
+ });
2093
+
2094
+ // ── resolvePair ────────────────────────────────────────────────────────────────
2095
+
2096
+ test("resolvePair sets resolution and lastReviewedAt", async () => {
2097
+ const { dir, cleanup } = await makeTempDir();
2098
+ try {
2099
+ const written = writePair(dir, makePair());
2100
+ const resolved = resolvePair(dir, written.pairId, "both-valid");
2101
+ assert.ok(resolved);
2102
+ assert.equal(resolved!.resolution, "both-valid");
2103
+ assert.ok(resolved!.lastReviewedAt);
2104
+ } finally {
2105
+ await cleanup();
2106
+ }
2107
+ });
2108
+
2109
+ test("needs-more-context deferral does not clear terminal resolutions", async () => {
2110
+ const { dir, cleanup } = await makeTempDir();
2111
+ try {
2112
+ const keepPair = writePair(dir, makePair());
2113
+ const keepResolved = resolvePair(dir, keepPair.pairId, "keep-a");
2114
+ assert.equal(keepResolved?.resolution, "keep-a");
2115
+
2116
+ const deferredKeepViaResolve = resolvePair(dir, keepPair.pairId, "needs-more-context");
2117
+ assert.equal(deferredKeepViaResolve?.resolution, "keep-a");
2118
+ assert.equal(deferredKeepViaResolve?.deferredUntil, undefined);
2119
+
2120
+ const deferredKeepDirectly = deferPair(dir, keepPair.pairId);
2121
+ assert.equal(deferredKeepDirectly?.resolution, "keep-a");
2122
+ assert.equal(deferredKeepDirectly?.deferredUntil, undefined);
2123
+
2124
+ const bothValidPair = writePair(dir, makePair({ memoryIds: ["mem-a-003", "mem-b-004"] }));
2125
+ const bothValidResolved = resolvePair(dir, bothValidPair.pairId, "both-valid");
2126
+ assert.equal(bothValidResolved?.resolution, "both-valid");
2127
+
2128
+ const deferredBothValidViaResolve = resolvePair(dir, bothValidPair.pairId, "needs-more-context");
2129
+ assert.equal(deferredBothValidViaResolve?.resolution, "both-valid");
2130
+ assert.equal(deferredBothValidViaResolve?.deferredUntil, undefined);
2131
+
2132
+ const deferredBothValidDirectly = deferPair(dir, bothValidPair.pairId);
2133
+ assert.equal(deferredBothValidDirectly?.resolution, "both-valid");
2134
+ assert.equal(deferredBothValidDirectly?.deferredUntil, undefined);
2135
+ assert.equal(listPairs(dir, { filter: "unresolved" }).total, 0);
2136
+ } finally {
2137
+ await cleanup();
2138
+ }
2139
+ });
2140
+
2141
+ test("resolvePair does not overwrite terminal resolutions", async () => {
2142
+ const { dir, cleanup } = await makeTempDir();
2143
+ try {
2144
+ const written = writePair(dir, makePair());
2145
+ const first = resolvePair(dir, written.pairId, "keep-a");
2146
+ assert.equal(first?.resolution, "keep-a");
2147
+ assert.ok(first?.lastReviewedAt);
2148
+
2149
+ const second = resolvePair(dir, written.pairId, "keep-b");
2150
+ assert.equal(second?.resolution, "keep-a");
2151
+ assert.equal(second?.lastReviewedAt, first?.lastReviewedAt);
2152
+
2153
+ const third = resolvePair(dir, written.pairId, "merge");
2154
+ assert.equal(third?.resolution, "keep-a");
2155
+ assert.equal(third?.lastReviewedAt, first?.lastReviewedAt);
2156
+
2157
+ const stored = readPair(dir, written.pairId);
2158
+ assert.equal(stored?.resolution, "keep-a");
2159
+ assert.equal(stored?.lastReviewedAt, first?.lastReviewedAt);
2160
+ } finally {
2161
+ await cleanup();
2162
+ }
2163
+ });
2164
+
2165
+ test("resolvePair returns null for nonexistent pair", async () => {
2166
+ const { dir, cleanup } = await makeTempDir();
2167
+ try {
2168
+ const result = resolvePair(dir, "nonexistent", "both-valid");
2169
+ assert.equal(result, null);
2170
+ } finally {
2171
+ await cleanup();
2172
+ }
2173
+ });
2174
+
2175
+ // ── ACTIVE_STATUSES (rule 53) ──────────────────────────────────────────────────
2176
+
2177
+ test("ACTIVE_STATUSES contains only active", () => {
2178
+ assert.ok(ACTIVE_STATUSES.has("active"));
2179
+ assert.equal(ACTIVE_STATUSES.has("superseded"), false);
2180
+ assert.equal(ACTIVE_STATUSES.has("archived"), false);
2181
+ assert.equal(ACTIVE_STATUSES.has("quarantined"), false);
2182
+ assert.equal(ACTIVE_STATUSES.has("rejected"), false);
2183
+ assert.equal(ACTIVE_STATUSES.has("pending_review"), false);
2184
+ });
2185
+
2186
+ // ── Judge helper: pairKey ──────────────────────────────────────────────────────
2187
+
2188
+ test("pairKey is order-independent", () => {
2189
+ assert.equal(_pairKey("a", "b"), _pairKey("b", "a"));
2190
+ });
2191
+
2192
+ // ── Judge helper: contentHash ──────────────────────────────────────────────────
2193
+
2194
+ test("contentHash is deterministic", () => {
2195
+ const a = { memoryIdA: "1", memoryIdB: "2", textA: "hello", textB: "world" };
2196
+ const b = { memoryIdA: "1", memoryIdB: "2", textA: "hello", textB: "world" };
2197
+ assert.equal(_contentHash(a), _contentHash(b));
2198
+ });
2199
+
2200
+ test("contentHash differs for different content", () => {
2201
+ const a = { memoryIdA: "1", memoryIdB: "2", textA: "hello", textB: "world" };
2202
+ const b = { memoryIdA: "1", memoryIdB: "2", textA: "goodbye", textB: "world" };
2203
+ assert.notEqual(_contentHash(a), _contentHash(b));
2204
+ });
2205
+
2206
+ // ── JSON parse safety (rule 18) ────────────────────────────────────────────────
2207
+
2208
+ test("readPair returns null for invalid JSON", async () => {
2209
+ const { dir, cleanup } = await makeTempDir();
2210
+ try {
2211
+ const reviewDir = path.join(dir, ".review", "contradictions");
2212
+ await mkdir(reviewDir, { recursive: true });
2213
+ await writeFile(path.join(reviewDir, "test-id.json"), "null");
2214
+ assert.equal(readPair(dir, "test-id"), null, "JSON.parse('null') should not be a valid pair");
2215
+ } finally {
2216
+ await cleanup();
2217
+ }
2218
+ });
2219
+
2220
+ test("readPair returns null for non-object JSON", async () => {
2221
+ const { dir, cleanup } = await makeTempDir();
2222
+ try {
2223
+ const reviewDir = path.join(dir, ".review", "contradictions");
2224
+ await mkdir(reviewDir, { recursive: true });
2225
+ await writeFile(path.join(reviewDir, "test-id.json"), '"a string"');
2226
+ assert.equal(readPair(dir, "test-id"), null);
2227
+ } finally {
2228
+ await cleanup();
2229
+ }
2230
+ });