@remnic/core 9.69.22 → 9.69.24

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 (772) hide show
  1. package/dist/abstraction-nodes.js +3 -2
  2. package/dist/access-admin-ops-surface.d.ts +14 -12
  3. package/dist/access-admin-ops-surface.js +94 -91
  4. package/dist/access-authorization-probe.d.ts +14 -12
  5. package/dist/access-authorization-probe.js +95 -92
  6. package/dist/access-boundary.d.ts +14 -12
  7. package/dist/access-boundary.js +94 -91
  8. package/dist/access-citation-namespace.js +3 -3
  9. package/dist/access-cli.js +200 -195
  10. package/dist/access-cli.js.map +1 -1
  11. package/dist/access-coding-context-resolution.d.ts +2 -1
  12. package/dist/access-extraction-force-flush.d.ts +14 -12
  13. package/dist/access-extraction-force-flush.js +94 -91
  14. package/dist/access-health-types.d.ts +2 -1
  15. package/dist/access-http-briefing.d.ts +156 -0
  16. package/dist/access-http-briefing.js +233 -0
  17. package/dist/access-http-lcm-compaction.d.ts +14 -12
  18. package/dist/access-http-lifecycle-flush.d.ts +14 -12
  19. package/dist/access-http-offline-stream.d.ts +14 -12
  20. package/dist/access-http-query.d.ts +3 -2
  21. package/dist/access-http-query.js +96 -93
  22. package/dist/access-http.d.ts +15 -13
  23. package/dist/access-http.js +119 -114
  24. package/dist/access-identity-continuity-surface.d.ts +12 -10
  25. package/dist/access-identity-continuity-surface.js +94 -91
  26. package/dist/access-lcm-surface.d.ts +14 -12
  27. package/dist/access-lcm-surface.js +94 -91
  28. package/dist/access-mcp.d.ts +14 -12
  29. package/dist/access-mcp.js +105 -101
  30. package/dist/access-memory-search-fanout.d.ts +3 -2
  31. package/dist/{access-namespace-preflight-BMHhxoL9.d.ts → access-namespace-preflight-BsvmyENS.d.ts} +1 -1
  32. package/dist/access-namespace-preflight.d.ts +4 -3
  33. package/dist/access-namespace-preflight.js +94 -91
  34. package/dist/access-observe-transcript.d.ts +12 -10
  35. package/dist/access-observe-write-surface.d.ts +14 -12
  36. package/dist/access-observe-write-surface.js +94 -91
  37. package/dist/access-offline-manifest.d.ts +12 -10
  38. package/dist/access-offline-manifest.js +15 -15
  39. package/dist/access-operations-batch.js +99 -95
  40. package/dist/access-operations.d.ts +14 -12
  41. package/dist/access-operations.js +104 -100
  42. package/dist/access-recall-concurrency.d.ts +14 -12
  43. package/dist/access-recall-concurrency.js +94 -91
  44. package/dist/access-recall-response.d.ts +14 -12
  45. package/dist/access-recall-response.js +94 -91
  46. package/dist/access-recall-surface.d.ts +14 -12
  47. package/dist/access-recall-surface.js +94 -91
  48. package/dist/access-schema.js +8 -7
  49. package/dist/{access-service-BlsNXFwx.d.ts → access-service-DWdY9Mlk.d.ts} +7 -7
  50. package/dist/access-service-helpers.d.ts +14 -12
  51. package/dist/access-service.d.ts +14 -12
  52. package/dist/access-service.js +94 -91
  53. package/dist/access-surface-catalog.d.ts +14 -12
  54. package/dist/access-surface-catalog.js +97 -93
  55. package/dist/access-surface-catalog.js.map +1 -1
  56. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  57. package/dist/action-confidence.d.ts +2 -1
  58. package/dist/active-memory-bridge.d.ts +2 -1
  59. package/dist/active-recall.d.ts +2 -1
  60. package/dist/active-recall.js +16 -13
  61. package/dist/active-recall.js.map +1 -1
  62. package/dist/adapters/index.js +7 -7
  63. package/dist/adapters/registry.js +3 -3
  64. package/dist/ambient-provenance.d.ts +2 -1
  65. package/dist/artifact-search.d.ts +2 -1
  66. package/dist/{auto-sync-GRUJFD2F.js → auto-sync-WNGG2GC2.js} +9 -9
  67. package/dist/behavior-learner.d.ts +2 -1
  68. package/dist/behavior-signals.d.ts +2 -1
  69. package/dist/bootstrap.d.ts +12 -10
  70. package/dist/briefing-window.d.ts +3 -2
  71. package/dist/briefing.d.ts +3 -2
  72. package/dist/briefing.js +36 -36
  73. package/dist/buffer-surprise-report.d.ts +2 -1
  74. package/dist/buffer-turn-helpers.d.ts +2 -1
  75. package/dist/buffer.d.ts +3 -2
  76. package/dist/buffer.js +13 -13
  77. package/dist/bulk-import/index.d.ts +4 -3
  78. package/dist/calibration.d.ts +2 -1
  79. package/dist/calibration.js +2 -1
  80. package/dist/calibration.js.map +1 -1
  81. package/dist/capabilities.d.ts +2 -1
  82. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  83. package/dist/{capsule-merge-SEHERWWP.js → capsule-merge-IPG4IOFP.js} +5 -5
  84. package/dist/{catalog-C1qHsGew.d.ts → catalog-CDZLyiXL.d.ts} +1 -1
  85. package/dist/causal-behavior.d.ts +2 -1
  86. package/dist/causal-behavior.js +4 -3
  87. package/dist/causal-behavior.js.map +1 -1
  88. package/dist/causal-chain.js +4 -3
  89. package/dist/causal-consolidation.d.ts +2 -1
  90. package/dist/causal-consolidation.js +42 -42
  91. package/dist/causal-retrieval.js +4 -3
  92. package/dist/causal-retrieval.js.map +1 -1
  93. package/dist/causal-trajectory-graph.d.ts +5 -2
  94. package/dist/causal-trajectory-graph.js +6 -2
  95. package/dist/causal-trajectory-graph.js.map +1 -1
  96. package/dist/causal-trajectory.js +3 -2
  97. package/dist/{chunk-KTVSPFCQ.js → chunk-22FVR2KE.js} +2 -2
  98. package/dist/{chunk-7Y5V3LAP.js → chunk-27QVNSQ3.js} +2 -2
  99. package/dist/{chunk-R7LY4YKF.js → chunk-2EKJDQZB.js} +2 -2
  100. package/dist/{chunk-FCATYKQA.js → chunk-2IOHTUP3.js} +263 -13
  101. package/dist/chunk-2IOHTUP3.js.map +1 -0
  102. package/dist/{chunk-HOUST5UX.js → chunk-2ITE4C2Z.js} +2 -2
  103. package/dist/{chunk-JOYC4RYC.js → chunk-2JVJ7UHC.js} +2 -2
  104. package/dist/{chunk-X2NFFBTO.js → chunk-2L5FSNPC.js} +7 -7
  105. package/dist/{chunk-DUAJKRR2.js → chunk-2SGLMP2E.js} +2 -2
  106. package/dist/{chunk-6FUMA6AA.js → chunk-2Z4GS5E6.js} +2 -2
  107. package/dist/{chunk-G6MXN2G5.js → chunk-37KUQPX4.js} +6 -6
  108. package/dist/{chunk-DDQQY2E3.js → chunk-3BTFBQLO.js} +7 -7
  109. package/dist/chunk-3BTFBQLO.js.map +1 -0
  110. package/dist/{chunk-UR6PBX2J.js → chunk-3K7V3HE6.js} +35 -60
  111. package/dist/chunk-3K7V3HE6.js.map +1 -0
  112. package/dist/{chunk-WKAXBXVA.js → chunk-3QQTXYZ6.js} +2 -2
  113. package/dist/{chunk-DJUKBGAD.js → chunk-46EST7JO.js} +5 -5
  114. package/dist/chunk-46EST7JO.js.map +1 -0
  115. package/dist/{chunk-4ZWCQJNM.js → chunk-46WM6JX2.js} +5 -5
  116. package/dist/{chunk-CASWJ2HM.js → chunk-46ZPIGWI.js} +3 -3
  117. package/dist/{chunk-HTIIXNJQ.js → chunk-4FIH6MPS.js} +6 -3
  118. package/dist/chunk-4FIH6MPS.js.map +1 -0
  119. package/dist/{chunk-MCA2X4WH.js → chunk-4IHBN6WU.js} +2 -2
  120. package/dist/{chunk-W7IGLX4G.js → chunk-4O6WRBGE.js} +7 -7
  121. package/dist/chunk-4O6WRBGE.js.map +1 -0
  122. package/dist/{chunk-FB7LAJQM.js → chunk-4TKJGOCJ.js} +2 -2
  123. package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
  124. package/dist/{chunk-N4Y5T6VD.js → chunk-54WHLA65.js} +4 -4
  125. package/dist/chunk-56Y6EKZN.js +24 -0
  126. package/dist/chunk-56Y6EKZN.js.map +1 -0
  127. package/dist/{chunk-YVLENSNS.js → chunk-5ATKSPEQ.js} +2 -2
  128. package/dist/{chunk-OLT3YTDH.js → chunk-5FAGCOZD.js} +37 -24
  129. package/dist/chunk-5FAGCOZD.js.map +1 -0
  130. package/dist/{chunk-ZVZHG7AI.js → chunk-5UBH37SL.js} +3 -3
  131. package/dist/{chunk-N3WZU76A.js → chunk-66OJSCI6.js} +2 -2
  132. package/dist/{chunk-D35XLYQ7.js → chunk-6CVNSDCZ.js} +11 -11
  133. package/dist/{chunk-KA2HZCMG.js → chunk-6NXSYYGP.js} +2 -2
  134. package/dist/{chunk-2HIJHXB3.js → chunk-6WHJ2EAB.js} +2 -2
  135. package/dist/{chunk-ZZM476NV.js → chunk-6XL73HQ4.js} +4 -4
  136. package/dist/{chunk-EJ5RKUXW.js → chunk-AQ7SYDVO.js} +2 -2
  137. package/dist/{chunk-2Z3DG5CQ.js → chunk-B3O3IRZN.js} +2 -2
  138. package/dist/{chunk-P77QX3ID.js → chunk-B6O2YLUR.js} +21 -20
  139. package/dist/chunk-B6O2YLUR.js.map +1 -0
  140. package/dist/{chunk-RACZB5HT.js → chunk-BD7JTBYP.js} +4 -4
  141. package/dist/{chunk-I762GW7V.js → chunk-BLJWYCNO.js} +5 -5
  142. package/dist/{chunk-ACPCA4NO.js → chunk-BMWN7B3Y.js} +6 -6
  143. package/dist/chunk-BMWN7B3Y.js.map +1 -0
  144. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  145. package/dist/{chunk-KK66P5GQ.js → chunk-C553ZTLF.js} +46 -48
  146. package/dist/chunk-C553ZTLF.js.map +1 -0
  147. package/dist/{chunk-GCASGYIO.js → chunk-C7HJ3NEI.js} +2 -2
  148. package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
  149. package/dist/{chunk-WVGXCBOC.js → chunk-D5F7TKMH.js} +2 -2
  150. package/dist/chunk-DGS34QSY.js +141 -0
  151. package/dist/chunk-DGS34QSY.js.map +1 -0
  152. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  153. package/dist/{chunk-2OXIPF3A.js → chunk-DZD3WGCD.js} +4 -4
  154. package/dist/{chunk-UMEOXLIZ.js → chunk-E2P7TZTF.js} +5 -5
  155. package/dist/{chunk-6FC3IZ26.js → chunk-EBA5DA77.js} +2 -2
  156. package/dist/{chunk-N7JK2RKG.js → chunk-EOQ6FSQP.js} +2 -2
  157. package/dist/chunk-EUT2WCWS.js +54 -0
  158. package/dist/chunk-EUT2WCWS.js.map +1 -0
  159. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  160. package/dist/{chunk-XDMI5VKE.js → chunk-FVOP3NT7.js} +2 -2
  161. package/dist/{chunk-NRLELHAY.js → chunk-G7NYVKD6.js} +2 -2
  162. package/dist/{chunk-B3W7GWQB.js → chunk-GHTSNGBZ.js} +2 -2
  163. package/dist/chunk-GKCXTSFF.js +17 -0
  164. package/dist/chunk-GKCXTSFF.js.map +1 -0
  165. package/dist/{chunk-LUDBXTBJ.js → chunk-H272ZPQ3.js} +5 -5
  166. package/dist/{chunk-SN4JXNLL.js → chunk-H3TKENU4.js} +2 -2
  167. package/dist/{chunk-4HYNMLT6.js → chunk-H4SEGIZY.js} +2 -2
  168. package/dist/{chunk-ACZN5ZXD.js → chunk-H54VWRPS.js} +13 -13
  169. package/dist/{chunk-HTP6XRUI.js → chunk-HM7RHKS4.js} +2 -2
  170. package/dist/{chunk-Z3SQEEB6.js → chunk-HWLIMQE2.js} +2 -2
  171. package/dist/{chunk-NQFCLAYT.js → chunk-ICKJ52PE.js} +99 -322
  172. package/dist/chunk-ICKJ52PE.js.map +1 -0
  173. package/dist/{chunk-2QSZNTDO.js → chunk-JBPKEARU.js} +7 -7
  174. package/dist/{chunk-DK6GMO6D.js → chunk-JEC4DVM3.js} +16 -16
  175. package/dist/chunk-JEC4DVM3.js.map +1 -0
  176. package/dist/{chunk-ET2CNMLD.js → chunk-JN72EPOE.js} +2 -2
  177. package/dist/{chunk-U62OK7BB.js → chunk-JPKK466T.js} +188 -21
  178. package/dist/chunk-JPKK466T.js.map +1 -0
  179. package/dist/{chunk-JCCWJHOP.js → chunk-JYZSRNR7.js} +2 -2
  180. package/dist/{chunk-7D6HXODY.js → chunk-K7724CH2.js} +2 -2
  181. package/dist/{chunk-X33MJFD2.js → chunk-KAXCYM66.js} +3 -3
  182. package/dist/{chunk-7RRUHJPG.js → chunk-KB2G2I6Q.js} +3 -3
  183. package/dist/{chunk-ZXBTTMGZ.js → chunk-KEF46KL2.js} +5 -5
  184. package/dist/{chunk-5UZXUTVO.js → chunk-KNA3BXXL.js} +6 -2
  185. package/dist/chunk-KNA3BXXL.js.map +1 -0
  186. package/dist/{chunk-UWTDARPF.js → chunk-KTWG7CNY.js} +6 -6
  187. package/dist/{chunk-XQYTSZW3.js → chunk-L7Z57SID.js} +6 -6
  188. package/dist/{chunk-JMAG7WZ7.js → chunk-LO4UKPKX.js} +3 -3
  189. package/dist/{chunk-LDWIPYJ6.js → chunk-LS2FHUML.js} +3 -3
  190. package/dist/{chunk-GDB4J2H3.js → chunk-MPC7TYTZ.js} +2 -2
  191. package/dist/{chunk-2GF27PGH.js → chunk-MRPOZBJC.js} +3 -3
  192. package/dist/{chunk-BR3OOQZQ.js → chunk-MWN6QEI2.js} +2 -2
  193. package/dist/{chunk-NZGO2GKL.js → chunk-MY5EDR46.js} +4 -4
  194. package/dist/{chunk-LCMUZDBZ.js → chunk-N3ZOP7KC.js} +3 -3
  195. package/dist/{chunk-TVW4C7PV.js → chunk-NB3LRY4T.js} +6 -6
  196. package/dist/{chunk-QJCWK2A7.js → chunk-ND6IQGSZ.js} +2 -2
  197. package/dist/{chunk-NOB2T2FC.js → chunk-NHLLKEKK.js} +2 -2
  198. package/dist/{chunk-7GSSHAXC.js → chunk-NLYVH66G.js} +6 -6
  199. package/dist/chunk-NLYVH66G.js.map +1 -0
  200. package/dist/{chunk-EJIWBTVM.js → chunk-O6ZNNVSP.js} +2 -2
  201. package/dist/{chunk-AG46P24C.js → chunk-OB3XMWX5.js} +4 -4
  202. package/dist/{chunk-NYRB7BKY.js → chunk-OEYZXDQI.js} +6 -6
  203. package/dist/chunk-OEYZXDQI.js.map +1 -0
  204. package/dist/{chunk-46QMN7I7.js → chunk-PAZY2ZKP.js} +6 -6
  205. package/dist/{chunk-EF4JUM55.js → chunk-PX4UMA5Z.js} +2 -2
  206. package/dist/chunk-QLK3SL7Q.js +242 -0
  207. package/dist/chunk-QLK3SL7Q.js.map +1 -0
  208. package/dist/{chunk-GGYDJJBO.js → chunk-QOOBICJF.js} +5 -5
  209. package/dist/chunk-QOOBICJF.js.map +1 -0
  210. package/dist/{chunk-NNZFPYYX.js → chunk-R7QY5ZVB.js} +2 -2
  211. package/dist/{chunk-RO2X2EYM.js → chunk-R7RTXEYG.js} +2 -2
  212. package/dist/{chunk-3LJPSRAN.js → chunk-RBCQVOVJ.js} +3 -3
  213. package/dist/{chunk-N4F7ZSSG.js → chunk-RC5DXXWC.js} +2 -2
  214. package/dist/{chunk-VLAQV4HT.js → chunk-RJYJ7KR7.js} +1636 -611
  215. package/dist/chunk-RJYJ7KR7.js.map +1 -0
  216. package/dist/{chunk-5CF2R4NS.js → chunk-RKBLRTNT.js} +2 -2
  217. package/dist/{chunk-5QZR2RA3.js → chunk-ROBHL3GL.js} +2 -2
  218. package/dist/{chunk-D5ZNOKR7.js → chunk-S7T2TY65.js} +3 -3
  219. package/dist/{chunk-C2JCVZWX.js → chunk-SCXURCVT.js} +25 -13
  220. package/dist/chunk-SCXURCVT.js.map +1 -0
  221. package/dist/{chunk-3LADWWMA.js → chunk-SJDQ5RSN.js} +3 -3
  222. package/dist/{chunk-45XVII3J.js → chunk-SMWTZLHE.js} +99 -89
  223. package/dist/{chunk-45XVII3J.js.map → chunk-SMWTZLHE.js.map} +1 -1
  224. package/dist/{chunk-XOQGUGJL.js → chunk-SO7SV523.js} +1 -1
  225. package/dist/{chunk-XOQGUGJL.js.map → chunk-SO7SV523.js.map} +1 -1
  226. package/dist/{chunk-CHWUICVY.js → chunk-SV4Z2S67.js} +4 -4
  227. package/dist/{chunk-JHP45LO5.js → chunk-SVXJLDDC.js} +9 -7
  228. package/dist/{chunk-JHP45LO5.js.map → chunk-SVXJLDDC.js.map} +1 -1
  229. package/dist/{chunk-SEF4IOFE.js → chunk-SWIKABKI.js} +2 -2
  230. package/dist/{chunk-JRRQ747T.js → chunk-TBXAY2SS.js} +13 -13
  231. package/dist/{chunk-J6A3CX5N.js → chunk-TG3FAM2S.js} +33 -8
  232. package/dist/{chunk-J6A3CX5N.js.map → chunk-TG3FAM2S.js.map} +1 -1
  233. package/dist/{chunk-XZBXINXZ.js → chunk-TNSCIPBQ.js} +4 -4
  234. package/dist/{chunk-S37NN23M.js → chunk-TVEONGBU.js} +2 -2
  235. package/dist/{chunk-5RPMTFB6.js → chunk-TWF35IC6.js} +3 -3
  236. package/dist/{chunk-BZTJEILZ.js → chunk-U6N5IBVY.js} +2 -2
  237. package/dist/{chunk-7TUB6JWA.js → chunk-UCKYTA2T.js} +3 -3
  238. package/dist/{chunk-PPOT6SPR.js → chunk-UNNPNBR2.js} +11 -11
  239. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  240. package/dist/{chunk-J2R275FN.js → chunk-VVX5PZFS.js} +4 -4
  241. package/dist/{chunk-ME35HVDJ.js → chunk-VYCOJKSX.js} +2 -2
  242. package/dist/{chunk-F5UWQ4LX.js → chunk-W24T5YMW.js} +2 -2
  243. package/dist/{chunk-HDQUQBPW.js → chunk-W3K3HITK.js} +2 -2
  244. package/dist/{chunk-GDASG7NC.js → chunk-W4F3C7N7.js} +2 -2
  245. package/dist/{chunk-LFK623SF.js → chunk-WJHGDE7X.js} +5 -5
  246. package/dist/{chunk-DP4EBV7C.js → chunk-WMLEPWMO.js} +16 -16
  247. package/dist/chunk-WMLEPWMO.js.map +1 -0
  248. package/dist/{chunk-3Q6RD76J.js → chunk-WQZZDN5M.js} +5 -5
  249. package/dist/{chunk-ZJWDWPX6.js → chunk-X5K5TAQZ.js} +4 -4
  250. package/dist/{chunk-ZL3XX5LW.js → chunk-XM24CDZX.js} +3 -3
  251. package/dist/{chunk-JTWZKNUH.js → chunk-XOVKXJEP.js} +3 -3
  252. package/dist/{chunk-OGTKQ5MJ.js → chunk-XSGUMQQQ.js} +62 -50
  253. package/dist/chunk-XSGUMQQQ.js.map +1 -0
  254. package/dist/{chunk-X5YYSAZX.js → chunk-XUE46UYW.js} +3 -3
  255. package/dist/{chunk-DJORULH3.js → chunk-YRLHEEQT.js} +2 -2
  256. package/dist/{chunk-TA7UZZMW.js → chunk-Z3O53WZR.js} +2 -2
  257. package/dist/{chunk-4LG4CPOC.js → chunk-Z6COGHHN.js} +2 -2
  258. package/dist/{chunk-RE3H6Y2X.js → chunk-ZIW5JVRM.js} +2 -2
  259. package/dist/{cli-BNtvR-nU.d.ts → cli-DD0P-lu8.d.ts} +6 -6
  260. package/dist/cli.d.ts +16 -14
  261. package/dist/cli.js +154 -149
  262. package/dist/coding/export-okf-codegraph.d.ts +2 -1
  263. package/dist/coding/export-okf-codegraph.js +37 -37
  264. package/dist/coding/pre-action-gate.d.ts +2 -1
  265. package/dist/coding/pre-action-gate.js +4 -3
  266. package/dist/commitment-ledger.js +3 -2
  267. package/dist/compounding/engine.d.ts +3 -2
  268. package/dist/compounding/engine.js +37 -37
  269. package/dist/compounding/preference-consolidator.d.ts +2 -1
  270. package/dist/compression-optimizer.d.ts +2 -1
  271. package/dist/config.d.ts +2 -1
  272. package/dist/config.js +16 -13
  273. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  274. package/dist/connectors/codex-materialize-runner.js +38 -38
  275. package/dist/connectors/codex-materialize.d.ts +2 -1
  276. package/dist/connectors/codex-materialize.js +4 -4
  277. package/dist/connectors/index.d.ts +2 -1
  278. package/dist/connectors/index.js +38 -38
  279. package/dist/consolidation-provenance-check.d.ts +3 -2
  280. package/dist/consolidation-provenance-check.js +4 -4
  281. package/dist/consolidation-undo.d.ts +3 -2
  282. package/dist/consolidation-undo.js +3 -3
  283. package/dist/contradiction/index.d.ts +4 -3
  284. package/dist/contradiction/index.js +9 -9
  285. package/dist/converge-config.d.ts +2 -1
  286. package/dist/convergence-refresh.d.ts +3 -2
  287. package/dist/convergence-refresh.js +38 -38
  288. package/dist/conversation-index/backend.d.ts +2 -1
  289. package/dist/conversation-index/chunker.d.ts +2 -1
  290. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  291. package/dist/conversation-index/indexer.d.ts +2 -1
  292. package/dist/conversation-index/search.d.ts +2 -1
  293. package/dist/corpus-watermark.d.ts +2 -1
  294. package/dist/corpus-watermark.js +38 -38
  295. package/dist/cross-lingual-recall.d.ts +2 -1
  296. package/dist/cue-anchors.js +4 -3
  297. package/dist/dashboard-runtime.js +2 -2
  298. package/dist/day-summary.d.ts +2 -1
  299. package/dist/deep-recall-http-glue.d.ts +14 -12
  300. package/dist/deep-recall-http-glue.js +9 -8
  301. package/dist/deep-recall-mcp-tools.d.ts +14 -12
  302. package/dist/deep-recall-policy-llm.d.ts +2 -1
  303. package/dist/deep-recall-seeds.d.ts +2 -1
  304. package/dist/deep-recall.js +2 -2
  305. package/dist/delinearize.d.ts +2 -1
  306. package/dist/dependency-propagation-config.d.ts +2 -1
  307. package/dist/{dependency-propagation-delivery-DjpUlhLi.d.ts → dependency-propagation-delivery-CQPCu0o5.d.ts} +1 -1
  308. package/dist/direct-answer-wiring.d.ts +2 -1
  309. package/dist/direct-answer.d.ts +2 -1
  310. package/dist/embedding-fallback.d.ts +2 -1
  311. package/dist/enrichment/index.d.ts +2 -1
  312. package/dist/entity-origin-fields.d.ts +2 -1
  313. package/dist/entity-retrieval.d.ts +3 -2
  314. package/dist/entity-retrieval.js +36 -36
  315. package/dist/entity-schema.d.ts +2 -1
  316. package/dist/episodic-context.d.ts +2 -1
  317. package/dist/eval-trajectory-contracts.d.ts +2 -1
  318. package/dist/eval-trajectory-store.d.ts +2 -1
  319. package/dist/eval-trajectory-store.js +4 -3
  320. package/dist/eval-trajectory.d.ts +2 -1
  321. package/dist/eval-trajectory.js +4 -3
  322. package/dist/evals.js +3 -2
  323. package/dist/event-order-recall.js +2 -2
  324. package/dist/explicit-capture.d.ts +12 -10
  325. package/dist/explicit-capture.js +10 -10
  326. package/dist/external-wiki-access.d.ts +14 -12
  327. package/dist/external-wiki-access.js +95 -92
  328. package/dist/external-wiki-collection-registration.d.ts +2 -1
  329. package/dist/external-wiki-collection.d.ts +2 -1
  330. package/dist/external-wiki-mcp-tools.d.ts +14 -12
  331. package/dist/extraction-error-classification.d.ts +2 -1
  332. package/dist/extraction-faithfulness.d.ts +2 -1
  333. package/dist/extraction-judge-telemetry.d.ts +2 -1
  334. package/dist/extraction-judge-training.d.ts +2 -1
  335. package/dist/extraction-judge.d.ts +2 -1
  336. package/dist/extraction-liveness.d.ts +2 -1
  337. package/dist/extraction-normalization.d.ts +2 -1
  338. package/dist/extraction-prompt.d.ts +2 -1
  339. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  340. package/dist/extraction-source-grounding.d.ts +2 -1
  341. package/dist/extraction.d.ts +2 -1
  342. package/dist/extraction.js +43 -43
  343. package/dist/fallback-llm.d.ts +2 -1
  344. package/dist/{first-start-migration-KHIMCBIC.js → first-start-migration-RC345GPL.js} +6 -5
  345. package/dist/{first-start-migration-KHIMCBIC.js.map → first-start-migration-RC345GPL.js.map} +1 -1
  346. package/dist/{forget-2AE4MDK3.js → forget-SZ2BXDGF.js} +3 -3
  347. package/dist/{graph-444E-DrF.d.ts → graph-DRkl22KE.d.ts} +10 -12
  348. package/dist/graph-append-error.d.ts +40 -0
  349. package/dist/graph-append-error.js +8 -0
  350. package/dist/graph-dashboard-diff.d.ts +5 -2
  351. package/dist/graph-dashboard-key.d.ts +5 -2
  352. package/dist/graph-dashboard-parser.d.ts +5 -2
  353. package/dist/{graph-edge-decay-DGTBFALQ.js → graph-edge-decay-MKIRZ762.js} +10 -4
  354. package/dist/graph-edge-decay-MKIRZ762.js.map +1 -0
  355. package/dist/graph-edge-reinforcement.d.ts +5 -2
  356. package/dist/graph-jsonl.d.ts +82 -0
  357. package/dist/graph-jsonl.js +23 -0
  358. package/dist/graph-jsonl.js.map +1 -0
  359. package/dist/graph-path-reconstruction.d.ts +5 -2
  360. package/dist/graph-path-scoring.d.ts +5 -2
  361. package/dist/graph-snapshot.d.ts +5 -2
  362. package/dist/graph-snapshot.js +7 -3
  363. package/dist/graph-write-lock.d.ts +84 -0
  364. package/dist/graph-write-lock.js +15 -0
  365. package/dist/graph-write-lock.js.map +1 -0
  366. package/dist/graph.d.ts +5 -2
  367. package/dist/graph.js +10 -3
  368. package/dist/harmonic-construction.js +5 -4
  369. package/dist/harmonic-retrieval.js +5 -4
  370. package/dist/importance.d.ts +2 -1
  371. package/dist/importers/index.d.ts +2 -1
  372. package/dist/in-flight-reads.d.ts +2 -1
  373. package/dist/{index-CsUrdMyL.d.ts → index-C9VXenR8.d.ts} +2 -2
  374. package/dist/index.d.ts +39 -25
  375. package/dist/index.js +291 -284
  376. package/dist/intent.d.ts +2 -1
  377. package/dist/json-store.js +2 -1
  378. package/dist/lcm/engine.d.ts +2 -1
  379. package/dist/lcm/engine.js +3 -3
  380. package/dist/lcm/index.d.ts +2 -1
  381. package/dist/lcm/index.js +6 -6
  382. package/dist/lcm/tools.d.ts +2 -1
  383. package/dist/lifecycle.d.ts +2 -1
  384. package/dist/live-connectors-runner.d.ts +2 -1
  385. package/dist/live-connectors-runner.js +3 -2
  386. package/dist/local-llm.d.ts +2 -1
  387. package/dist/local-model-endpoint.d.ts +2 -1
  388. package/dist/location/index.d.ts +4 -3
  389. package/dist/location/index.js +39 -39
  390. package/dist/maintenance/memory-governance.d.ts +2 -1
  391. package/dist/maintenance/memory-governance.js +36 -36
  392. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  393. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +36 -36
  394. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  395. package/dist/maintenance/rebuild-memory-projection.js +37 -37
  396. package/dist/{maintenance-D1GRGLTE.d.ts → maintenance-C14sorKa.d.ts} +3 -3
  397. package/dist/mcp-memory-inspector-app.d.ts +14 -12
  398. package/dist/memory-action-policy.d.ts +2 -1
  399. package/dist/memory-cache.d.ts +2 -1
  400. package/dist/memory-controller.d.ts +2 -1
  401. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  402. package/dist/memory-projection-mutations.js +3 -3
  403. package/dist/memory-projection-store.d.ts +2 -1
  404. package/dist/memory-provenance.d.ts +2 -1
  405. package/dist/memory-snapshot.d.ts +2 -1
  406. package/dist/memory-subject-cli.d.ts +14 -12
  407. package/dist/memory-subject.d.ts +14 -12
  408. package/dist/memory-subject.js +5 -5
  409. package/dist/memory-worth-outcomes.d.ts +3 -2
  410. package/dist/models-json.d.ts +2 -1
  411. package/dist/namespaces/migrate.d.ts +4 -3
  412. package/dist/namespaces/migrate.js +37 -37
  413. package/dist/namespaces/principal.d.ts +2 -1
  414. package/dist/namespaces/search.d.ts +2 -1
  415. package/dist/namespaces/search.js +11 -11
  416. package/dist/namespaces/storage.d.ts +4 -3
  417. package/dist/namespaces/storage.js +36 -36
  418. package/dist/native-knowledge.d.ts +2 -1
  419. package/dist/objective-state-writers.js +4 -3
  420. package/dist/objective-state.js +3 -2
  421. package/dist/offline-sync-file-io.js +4 -3
  422. package/dist/offline-sync-impression-drain.d.ts +2 -1
  423. package/dist/offline-sync-impression-drain.js +7 -7
  424. package/dist/offline-sync.js +5 -4
  425. package/dist/operator-doctor-corpus.d.ts +2 -1
  426. package/dist/operator-doctor-corpus.js +39 -39
  427. package/dist/operator-doctor-replica.d.ts +2 -1
  428. package/dist/operator-toolkit.d.ts +6 -4
  429. package/dist/operator-toolkit.js +61 -58
  430. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  431. package/dist/orchestration/maintenance.d.ts +5 -4
  432. package/dist/orchestration/maintenance.js +46 -46
  433. package/dist/{orchestrator-DeqaPGT5.d.ts → orchestrator-DgyvFfPR.d.ts} +9 -9
  434. package/dist/orchestrator.d.ts +12 -10
  435. package/dist/orchestrator.js +201 -196
  436. package/dist/page-versioning.d.ts +73 -4
  437. package/dist/page-versioning.js +11 -3
  438. package/dist/patterns-cli.d.ts +2 -1
  439. package/dist/{pipeline-umUzU0D1.d.ts → pipeline-DRUwHb1X.d.ts} +1 -1
  440. package/dist/policy-runtime.d.ts +2 -1
  441. package/dist/proactive-contention.d.ts +2 -1
  442. package/dist/provenance.d.ts +2 -1
  443. package/dist/{public-http-Bevrjll9.d.ts → public-http-C4i8Opxc.d.ts} +1 -1
  444. package/dist/{purge-OP6BEDFY.js → purge-TZKRE6ZQ.js} +5 -5
  445. package/dist/purge-TZKRE6ZQ.js.map +1 -0
  446. package/dist/{qmd-BasT78PP.d.ts → qmd-BVWlg1YS.d.ts} +1 -1
  447. package/dist/qmd-preflight.d.ts +3 -2
  448. package/dist/qmd-recall-cache.d.ts +2 -1
  449. package/dist/qmd.d.ts +3 -2
  450. package/dist/qmd.js +4 -4
  451. package/dist/recall-concurrency-config.d.ts +2 -1
  452. package/dist/recall-disclosure-escalation.d.ts +2 -1
  453. package/dist/recall-explain-renderer.d.ts +2 -1
  454. package/dist/recall-explain-renderer.js +3 -3
  455. package/dist/recall-memory-map.d.ts +2 -1
  456. package/dist/recall-navigate-access.d.ts +2 -1
  457. package/dist/recall-navigate-access.js +2 -2
  458. package/dist/recall-navigate-disclosure.d.ts +2 -1
  459. package/dist/recall-navigate-disclosure.js +1 -1
  460. package/dist/recall-navigate.d.ts +2 -1
  461. package/dist/recall-navigate.js +2 -2
  462. package/dist/recall-planner-llm.d.ts +2 -1
  463. package/dist/recall-state.d.ts +2 -1
  464. package/dist/recall-state.js +3 -3
  465. package/dist/recall-tag-filter.d.ts +2 -1
  466. package/dist/recall-timings.d.ts +2 -1
  467. package/dist/recall-xray-cli.d.ts +2 -1
  468. package/dist/recall-xray-cli.js +4 -4
  469. package/dist/recall-xray-renderer.d.ts +2 -1
  470. package/dist/recall-xray-renderer.js +3 -3
  471. package/dist/recall-xray.d.ts +2 -1
  472. package/dist/recall-xray.js +2 -2
  473. package/dist/reconcile/cursor.d.ts +2 -1
  474. package/dist/reconcile/manifest.d.ts +2 -1
  475. package/dist/reconcile/manifest.js +7 -7
  476. package/dist/reconcile/plan.d.ts +2 -1
  477. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  478. package/dist/replay/normalizers/claude.d.ts +2 -1
  479. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  480. package/dist/replay/normalizers/shared.d.ts +2 -1
  481. package/dist/replay/runner.d.ts +2 -1
  482. package/dist/replay/types.d.ts +2 -1
  483. package/dist/replica-divergence.d.ts +2 -1
  484. package/dist/replica-peers-config.d.ts +2 -1
  485. package/dist/{resolution-4DLI3IOR.js → resolution-VKATP2HT.js} +10 -10
  486. package/dist/resolution-VKATP2HT.js.map +1 -0
  487. package/dist/resolve-auth-token.d.ts +2 -1
  488. package/dist/resume-bundles.js +21 -18
  489. package/dist/retrieval-agents.d.ts +3 -2
  490. package/dist/retrieval-tiers.d.ts +2 -1
  491. package/dist/routing/engine.d.ts +2 -1
  492. package/dist/routing/store.d.ts +2 -1
  493. package/dist/salvage-envelope.d.ts +2 -1
  494. package/dist/salvage-envelope.js +7 -7
  495. package/dist/{scope-profiles-DXYzyOXW.d.ts → scope-profiles-Vl00B1KU.d.ts} +1 -1
  496. package/dist/search/document-scanner.js +3 -3
  497. package/dist/search/embed-helper.d.ts +2 -1
  498. package/dist/search/factory.d.ts +2 -1
  499. package/dist/search/factory.js +10 -10
  500. package/dist/search/index.d.ts +2 -1
  501. package/dist/search/index.js +16 -16
  502. package/dist/search/lancedb-backend.d.ts +2 -1
  503. package/dist/search/lancedb-backend.js +4 -4
  504. package/dist/search/meilisearch-backend.d.ts +2 -1
  505. package/dist/search/meilisearch-backend.js +4 -4
  506. package/dist/search/noop-backend.d.ts +2 -1
  507. package/dist/search/orama-backend.d.ts +2 -1
  508. package/dist/search/orama-backend.js +4 -4
  509. package/dist/search/port.d.ts +2 -1
  510. package/dist/search/remote-backend.d.ts +2 -1
  511. package/dist/secure-store/index.js +3 -3
  512. package/dist/{semantic-consolidation-CqDeaY0U.d.ts → semantic-consolidation-BC9-GFuT.d.ts} +1 -1
  513. package/dist/semantic-consolidation.d.ts +3 -2
  514. package/dist/semantic-consolidation.js +39 -39
  515. package/dist/semantic-merge-config.d.ts +17 -0
  516. package/dist/semantic-merge-config.js +1 -0
  517. package/dist/semantic-merge-config.js.map +1 -0
  518. package/dist/semantic-rule-promotion.js +36 -36
  519. package/dist/semantic-rule-verifier.d.ts +2 -1
  520. package/dist/semantic-rule-verifier.js +36 -36
  521. package/dist/{service-BKD-DVYZ.d.ts → service-BOy6dHfc.d.ts} +2 -2
  522. package/dist/session-observer-bands.d.ts +2 -1
  523. package/dist/session-observer-state.d.ts +2 -1
  524. package/dist/shared-context/manager.d.ts +2 -1
  525. package/dist/signal.d.ts +2 -1
  526. package/dist/source-agent-qualifier.d.ts +2 -1
  527. package/dist/source-agent-qualifier.js +42 -42
  528. package/dist/source-attribution.d.ts +18 -6
  529. package/dist/source-attribution.js +3 -1
  530. package/dist/standup/build.js +36 -36
  531. package/dist/{storage-BcFd1lN_.d.ts → storage-BLJRnFi6.d.ts} +15 -8
  532. package/dist/storage.d.ts +3 -2
  533. package/dist/storage.js +35 -35
  534. package/dist/subject-config.d.ts +2 -1
  535. package/dist/subject-config.js +6 -6
  536. package/dist/summarizer.d.ts +2 -1
  537. package/dist/summary-snapshot.d.ts +2 -1
  538. package/dist/support-passport/index.d.ts +17 -15
  539. package/dist/support-passport/index.js +97 -94
  540. package/dist/temporal-supersession.d.ts +3 -2
  541. package/dist/temporal-timeline-recall.d.ts +2 -1
  542. package/dist/temporal-validity.d.ts +2 -1
  543. package/dist/threading.d.ts +2 -1
  544. package/dist/tier-migration.d.ts +3 -2
  545. package/dist/tier-routing.d.ts +2 -1
  546. package/dist/{tier-stats-2TOW3QNL.js → tier-stats-KA6OZX2C.js} +6 -5
  547. package/dist/{tier-stats-2TOW3QNL.js.map → tier-stats-KA6OZX2C.js.map} +1 -1
  548. package/dist/topics.d.ts +2 -1
  549. package/dist/transcript.d.ts +2 -1
  550. package/dist/transfer/backup.js +2 -2
  551. package/dist/transfer/capsule-export.js +2 -2
  552. package/dist/transfer/capsule-import.js +6 -6
  553. package/dist/transfer/export-okf.d.ts +2 -1
  554. package/dist/transfer/export-okf.js +37 -37
  555. package/dist/trust-score-stage.d.ts +2 -1
  556. package/dist/trust-score.d.ts +2 -1
  557. package/dist/trust-zones.js +3 -2
  558. package/dist/{types-BRg3tMyp.d.ts → types-YY-eKKU7.d.ts} +3 -0
  559. package/dist/types.d.ts +2 -1
  560. package/dist/types.js +1 -1
  561. package/dist/utility-learner.js +4 -3
  562. package/dist/utility-runtime.d.ts +2 -1
  563. package/dist/utility-runtime.js +5 -4
  564. package/dist/utility-telemetry.js +3 -2
  565. package/dist/verified-recall.js +36 -36
  566. package/dist/who-knows-cli.d.ts +14 -12
  567. package/dist/who-knows-cli.js +37 -37
  568. package/dist/who-knows.d.ts +14 -12
  569. package/dist/who-knows.js +36 -36
  570. package/dist/work/board.js +3 -3
  571. package/dist/work/storage.js +2 -2
  572. package/dist/work-product-ledger.js +3 -2
  573. package/dist/write-envelope.d.ts +2 -1
  574. package/dist/write-envelope.js +6 -6
  575. package/package.json +2 -2
  576. package/src/abstraction-nodes.ts +1 -4
  577. package/src/access-http-briefing.ts +35 -0
  578. package/src/access-http.test.ts +76 -0
  579. package/src/access-http.ts +20 -23
  580. package/src/access-surface-catalog.test.ts +9 -0
  581. package/src/access-surface-catalog.ts +1 -0
  582. package/src/binary-lifecycle/backend.ts +2 -1
  583. package/src/config.ts +2 -0
  584. package/src/connectors/live/github.ts +10 -17
  585. package/src/connectors/live/gmail.ts +8 -19
  586. package/src/connectors/live/google-drive.ts +6 -13
  587. package/src/connectors/live/notion.ts +11 -21
  588. package/src/cue-anchors.ts +1 -6
  589. package/src/dedup/connector-scope.ts +39 -0
  590. package/src/dedup/merge-content.test.ts +21 -0
  591. package/src/dedup/merge-content.ts +21 -7
  592. package/src/dedup/merge-judge.ts +146 -0
  593. package/src/dedup/merge.test.ts +3542 -0
  594. package/src/dedup/merge.ts +384 -0
  595. package/src/dedup/novelty-gate.ts +12 -10
  596. package/src/dedup/semantic.ts +7 -9
  597. package/src/graph-append-error.ts +28 -0
  598. package/src/graph-jsonl.ts +267 -0
  599. package/src/graph-write-lock.test.ts +228 -0
  600. package/src/graph-write-lock.ts +132 -0
  601. package/src/graph.ts +49 -45
  602. package/src/harmonic-construction.test.ts +329 -0
  603. package/src/json-store.ts +17 -20
  604. package/src/live-connectors-runner.ts +2 -1
  605. package/src/location/store.ts +1 -4
  606. package/src/maintenance/graph-edge-decay.ts +24 -13
  607. package/src/maintenance/purge.ts +2 -5
  608. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +3 -6
  609. package/src/maintenance/rebuild-memory-projection.ts +2 -5
  610. package/src/namespaces/catalog.ts +1 -9
  611. package/src/offline-sync-file-io.test.ts +39 -0
  612. package/src/offline-sync-file-io.ts +3 -7
  613. package/src/orchestration/contradiction-localization.integration.test.ts +35 -0
  614. package/src/orchestration/extraction-anchor-snapshot.ts +6 -1
  615. package/src/orchestration/extraction-persist-deps.ts +2 -1
  616. package/src/orchestration/extraction-persist-profile-promotion.test.ts +456 -0
  617. package/src/orchestration/extraction-persist-promotion.test.ts +534 -0
  618. package/src/orchestration/extraction-persist-promotion.ts +387 -1
  619. package/src/orchestration/extraction-persist.ts +95 -94
  620. package/src/orchestration/harmonic-construction-persist.test.ts +69 -0
  621. package/src/orchestration/harmonic-construction-persist.ts +55 -0
  622. package/src/orchestration/persistence-index.ts +35 -7
  623. package/src/orchestration/semantic-merge-commit-effects.ts +354 -0
  624. package/src/orchestration/semantic-merge-persist.ts +1095 -0
  625. package/src/orchestration/semantic-merge-promotion-payload.ts +161 -0
  626. package/src/orchestrator.ts +2 -2
  627. package/src/page-versioning.ts +396 -22
  628. package/src/procedural/procedure-miner.ts +1 -9
  629. package/src/search/document-scanner.ts +3 -6
  630. package/src/semantic-merge-config.ts +16 -0
  631. package/src/semantic-rule-promotion.ts +1 -4
  632. package/src/source-attribution-roundtrip.test.ts +21 -0
  633. package/src/source-attribution.ts +57 -17
  634. package/src/storage-contract/versioning.test.ts +500 -1
  635. package/src/storage.ts +30 -30
  636. package/src/testing/subjects/graph-edge-decay.test.ts +163 -0
  637. package/src/testing/subjects/semantic-merge-lifecycle.test.ts +1175 -0
  638. package/src/types.ts +2 -0
  639. package/src/utils/errno.test.ts +31 -0
  640. package/src/utils/errno.ts +5 -0
  641. package/src/wearables/index.ts +1 -0
  642. package/src/wearables/registry.ts +23 -0
  643. package/dist/chunk-5UZXUTVO.js.map +0 -1
  644. package/dist/chunk-7GSSHAXC.js.map +0 -1
  645. package/dist/chunk-ACPCA4NO.js.map +0 -1
  646. package/dist/chunk-C2JCVZWX.js.map +0 -1
  647. package/dist/chunk-DDQQY2E3.js.map +0 -1
  648. package/dist/chunk-DJUKBGAD.js.map +0 -1
  649. package/dist/chunk-DK6GMO6D.js.map +0 -1
  650. package/dist/chunk-DP4EBV7C.js.map +0 -1
  651. package/dist/chunk-FCATYKQA.js.map +0 -1
  652. package/dist/chunk-GGYDJJBO.js.map +0 -1
  653. package/dist/chunk-HTIIXNJQ.js.map +0 -1
  654. package/dist/chunk-KK66P5GQ.js.map +0 -1
  655. package/dist/chunk-NQFCLAYT.js.map +0 -1
  656. package/dist/chunk-NYRB7BKY.js.map +0 -1
  657. package/dist/chunk-OGTKQ5MJ.js.map +0 -1
  658. package/dist/chunk-OLT3YTDH.js.map +0 -1
  659. package/dist/chunk-P77QX3ID.js.map +0 -1
  660. package/dist/chunk-U62OK7BB.js.map +0 -1
  661. package/dist/chunk-UR6PBX2J.js.map +0 -1
  662. package/dist/chunk-VLAQV4HT.js.map +0 -1
  663. package/dist/chunk-W7IGLX4G.js.map +0 -1
  664. package/dist/purge-OP6BEDFY.js.map +0 -1
  665. /package/dist/{capsule-crypto-7FJQINUR.js.map → access-http-briefing.js.map} +0 -0
  666. /package/dist/{auto-sync-GRUJFD2F.js.map → auto-sync-WNGG2GC2.js.map} +0 -0
  667. /package/dist/{graph-edge-decay-DGTBFALQ.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  668. /package/dist/{capsule-merge-SEHERWWP.js.map → capsule-merge-IPG4IOFP.js.map} +0 -0
  669. /package/dist/{chunk-KTVSPFCQ.js.map → chunk-22FVR2KE.js.map} +0 -0
  670. /package/dist/{chunk-7Y5V3LAP.js.map → chunk-27QVNSQ3.js.map} +0 -0
  671. /package/dist/{chunk-R7LY4YKF.js.map → chunk-2EKJDQZB.js.map} +0 -0
  672. /package/dist/{chunk-HOUST5UX.js.map → chunk-2ITE4C2Z.js.map} +0 -0
  673. /package/dist/{chunk-JOYC4RYC.js.map → chunk-2JVJ7UHC.js.map} +0 -0
  674. /package/dist/{chunk-X2NFFBTO.js.map → chunk-2L5FSNPC.js.map} +0 -0
  675. /package/dist/{chunk-DUAJKRR2.js.map → chunk-2SGLMP2E.js.map} +0 -0
  676. /package/dist/{chunk-6FUMA6AA.js.map → chunk-2Z4GS5E6.js.map} +0 -0
  677. /package/dist/{chunk-G6MXN2G5.js.map → chunk-37KUQPX4.js.map} +0 -0
  678. /package/dist/{chunk-WKAXBXVA.js.map → chunk-3QQTXYZ6.js.map} +0 -0
  679. /package/dist/{chunk-4ZWCQJNM.js.map → chunk-46WM6JX2.js.map} +0 -0
  680. /package/dist/{chunk-CASWJ2HM.js.map → chunk-46ZPIGWI.js.map} +0 -0
  681. /package/dist/{chunk-MCA2X4WH.js.map → chunk-4IHBN6WU.js.map} +0 -0
  682. /package/dist/{chunk-FB7LAJQM.js.map → chunk-4TKJGOCJ.js.map} +0 -0
  683. /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
  684. /package/dist/{chunk-N4Y5T6VD.js.map → chunk-54WHLA65.js.map} +0 -0
  685. /package/dist/{chunk-YVLENSNS.js.map → chunk-5ATKSPEQ.js.map} +0 -0
  686. /package/dist/{chunk-ZVZHG7AI.js.map → chunk-5UBH37SL.js.map} +0 -0
  687. /package/dist/{chunk-N3WZU76A.js.map → chunk-66OJSCI6.js.map} +0 -0
  688. /package/dist/{chunk-D35XLYQ7.js.map → chunk-6CVNSDCZ.js.map} +0 -0
  689. /package/dist/{chunk-KA2HZCMG.js.map → chunk-6NXSYYGP.js.map} +0 -0
  690. /package/dist/{chunk-2HIJHXB3.js.map → chunk-6WHJ2EAB.js.map} +0 -0
  691. /package/dist/{chunk-ZZM476NV.js.map → chunk-6XL73HQ4.js.map} +0 -0
  692. /package/dist/{chunk-EJ5RKUXW.js.map → chunk-AQ7SYDVO.js.map} +0 -0
  693. /package/dist/{chunk-2Z3DG5CQ.js.map → chunk-B3O3IRZN.js.map} +0 -0
  694. /package/dist/{chunk-RACZB5HT.js.map → chunk-BD7JTBYP.js.map} +0 -0
  695. /package/dist/{chunk-I762GW7V.js.map → chunk-BLJWYCNO.js.map} +0 -0
  696. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  697. /package/dist/{chunk-GCASGYIO.js.map → chunk-C7HJ3NEI.js.map} +0 -0
  698. /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
  699. /package/dist/{chunk-WVGXCBOC.js.map → chunk-D5F7TKMH.js.map} +0 -0
  700. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  701. /package/dist/{chunk-2OXIPF3A.js.map → chunk-DZD3WGCD.js.map} +0 -0
  702. /package/dist/{chunk-UMEOXLIZ.js.map → chunk-E2P7TZTF.js.map} +0 -0
  703. /package/dist/{chunk-6FC3IZ26.js.map → chunk-EBA5DA77.js.map} +0 -0
  704. /package/dist/{chunk-N7JK2RKG.js.map → chunk-EOQ6FSQP.js.map} +0 -0
  705. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  706. /package/dist/{chunk-XDMI5VKE.js.map → chunk-FVOP3NT7.js.map} +0 -0
  707. /package/dist/{chunk-NRLELHAY.js.map → chunk-G7NYVKD6.js.map} +0 -0
  708. /package/dist/{chunk-B3W7GWQB.js.map → chunk-GHTSNGBZ.js.map} +0 -0
  709. /package/dist/{chunk-LUDBXTBJ.js.map → chunk-H272ZPQ3.js.map} +0 -0
  710. /package/dist/{chunk-SN4JXNLL.js.map → chunk-H3TKENU4.js.map} +0 -0
  711. /package/dist/{chunk-4HYNMLT6.js.map → chunk-H4SEGIZY.js.map} +0 -0
  712. /package/dist/{chunk-ACZN5ZXD.js.map → chunk-H54VWRPS.js.map} +0 -0
  713. /package/dist/{chunk-HTP6XRUI.js.map → chunk-HM7RHKS4.js.map} +0 -0
  714. /package/dist/{chunk-Z3SQEEB6.js.map → chunk-HWLIMQE2.js.map} +0 -0
  715. /package/dist/{chunk-2QSZNTDO.js.map → chunk-JBPKEARU.js.map} +0 -0
  716. /package/dist/{chunk-ET2CNMLD.js.map → chunk-JN72EPOE.js.map} +0 -0
  717. /package/dist/{chunk-JCCWJHOP.js.map → chunk-JYZSRNR7.js.map} +0 -0
  718. /package/dist/{chunk-7D6HXODY.js.map → chunk-K7724CH2.js.map} +0 -0
  719. /package/dist/{chunk-X33MJFD2.js.map → chunk-KAXCYM66.js.map} +0 -0
  720. /package/dist/{chunk-7RRUHJPG.js.map → chunk-KB2G2I6Q.js.map} +0 -0
  721. /package/dist/{chunk-ZXBTTMGZ.js.map → chunk-KEF46KL2.js.map} +0 -0
  722. /package/dist/{chunk-UWTDARPF.js.map → chunk-KTWG7CNY.js.map} +0 -0
  723. /package/dist/{chunk-XQYTSZW3.js.map → chunk-L7Z57SID.js.map} +0 -0
  724. /package/dist/{chunk-JMAG7WZ7.js.map → chunk-LO4UKPKX.js.map} +0 -0
  725. /package/dist/{chunk-LDWIPYJ6.js.map → chunk-LS2FHUML.js.map} +0 -0
  726. /package/dist/{chunk-GDB4J2H3.js.map → chunk-MPC7TYTZ.js.map} +0 -0
  727. /package/dist/{chunk-2GF27PGH.js.map → chunk-MRPOZBJC.js.map} +0 -0
  728. /package/dist/{chunk-BR3OOQZQ.js.map → chunk-MWN6QEI2.js.map} +0 -0
  729. /package/dist/{chunk-NZGO2GKL.js.map → chunk-MY5EDR46.js.map} +0 -0
  730. /package/dist/{chunk-LCMUZDBZ.js.map → chunk-N3ZOP7KC.js.map} +0 -0
  731. /package/dist/{chunk-TVW4C7PV.js.map → chunk-NB3LRY4T.js.map} +0 -0
  732. /package/dist/{chunk-QJCWK2A7.js.map → chunk-ND6IQGSZ.js.map} +0 -0
  733. /package/dist/{chunk-NOB2T2FC.js.map → chunk-NHLLKEKK.js.map} +0 -0
  734. /package/dist/{chunk-EJIWBTVM.js.map → chunk-O6ZNNVSP.js.map} +0 -0
  735. /package/dist/{chunk-AG46P24C.js.map → chunk-OB3XMWX5.js.map} +0 -0
  736. /package/dist/{chunk-46QMN7I7.js.map → chunk-PAZY2ZKP.js.map} +0 -0
  737. /package/dist/{chunk-EF4JUM55.js.map → chunk-PX4UMA5Z.js.map} +0 -0
  738. /package/dist/{chunk-NNZFPYYX.js.map → chunk-R7QY5ZVB.js.map} +0 -0
  739. /package/dist/{chunk-RO2X2EYM.js.map → chunk-R7RTXEYG.js.map} +0 -0
  740. /package/dist/{chunk-3LJPSRAN.js.map → chunk-RBCQVOVJ.js.map} +0 -0
  741. /package/dist/{chunk-N4F7ZSSG.js.map → chunk-RC5DXXWC.js.map} +0 -0
  742. /package/dist/{chunk-5CF2R4NS.js.map → chunk-RKBLRTNT.js.map} +0 -0
  743. /package/dist/{chunk-5QZR2RA3.js.map → chunk-ROBHL3GL.js.map} +0 -0
  744. /package/dist/{chunk-D5ZNOKR7.js.map → chunk-S7T2TY65.js.map} +0 -0
  745. /package/dist/{chunk-3LADWWMA.js.map → chunk-SJDQ5RSN.js.map} +0 -0
  746. /package/dist/{chunk-CHWUICVY.js.map → chunk-SV4Z2S67.js.map} +0 -0
  747. /package/dist/{chunk-SEF4IOFE.js.map → chunk-SWIKABKI.js.map} +0 -0
  748. /package/dist/{chunk-JRRQ747T.js.map → chunk-TBXAY2SS.js.map} +0 -0
  749. /package/dist/{chunk-XZBXINXZ.js.map → chunk-TNSCIPBQ.js.map} +0 -0
  750. /package/dist/{chunk-S37NN23M.js.map → chunk-TVEONGBU.js.map} +0 -0
  751. /package/dist/{chunk-5RPMTFB6.js.map → chunk-TWF35IC6.js.map} +0 -0
  752. /package/dist/{chunk-BZTJEILZ.js.map → chunk-U6N5IBVY.js.map} +0 -0
  753. /package/dist/{chunk-7TUB6JWA.js.map → chunk-UCKYTA2T.js.map} +0 -0
  754. /package/dist/{chunk-PPOT6SPR.js.map → chunk-UNNPNBR2.js.map} +0 -0
  755. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  756. /package/dist/{chunk-J2R275FN.js.map → chunk-VVX5PZFS.js.map} +0 -0
  757. /package/dist/{chunk-ME35HVDJ.js.map → chunk-VYCOJKSX.js.map} +0 -0
  758. /package/dist/{chunk-F5UWQ4LX.js.map → chunk-W24T5YMW.js.map} +0 -0
  759. /package/dist/{chunk-HDQUQBPW.js.map → chunk-W3K3HITK.js.map} +0 -0
  760. /package/dist/{chunk-GDASG7NC.js.map → chunk-W4F3C7N7.js.map} +0 -0
  761. /package/dist/{chunk-LFK623SF.js.map → chunk-WJHGDE7X.js.map} +0 -0
  762. /package/dist/{chunk-3Q6RD76J.js.map → chunk-WQZZDN5M.js.map} +0 -0
  763. /package/dist/{chunk-ZJWDWPX6.js.map → chunk-X5K5TAQZ.js.map} +0 -0
  764. /package/dist/{chunk-ZL3XX5LW.js.map → chunk-XM24CDZX.js.map} +0 -0
  765. /package/dist/{chunk-JTWZKNUH.js.map → chunk-XOVKXJEP.js.map} +0 -0
  766. /package/dist/{chunk-X5YYSAZX.js.map → chunk-XUE46UYW.js.map} +0 -0
  767. /package/dist/{chunk-DJORULH3.js.map → chunk-YRLHEEQT.js.map} +0 -0
  768. /package/dist/{chunk-TA7UZZMW.js.map → chunk-Z3O53WZR.js.map} +0 -0
  769. /package/dist/{chunk-4LG4CPOC.js.map → chunk-Z6COGHHN.js.map} +0 -0
  770. /package/dist/{chunk-RE3H6Y2X.js.map → chunk-ZIW5JVRM.js.map} +0 -0
  771. /package/dist/{forget-2AE4MDK3.js.map → forget-SZ2BXDGF.js.map} +0 -0
  772. /package/dist/{resolution-4DLI3IOR.js.map → graph-append-error.js.map} +0 -0
@@ -0,0 +1,1175 @@
1
+ /**
2
+ * Semantic merge-on-write lifecycle subject for the scenario-matrix harness
3
+ * (PR #2771 review finding B, issue #2330).
4
+ *
5
+ * The lifecycle-matrix gate previously accepted changes to
6
+ * `orchestration/semantic-merge-persist.ts` through the `extraction-lifecycle`
7
+ * subject, which builds every configuration with `semanticMerge` disabled —
8
+ * the required gate passed without ever exercising the merge path it claimed
9
+ * to cover. This subject runs the REAL orchestrator + storage persist path
10
+ * (turn ingestion → buffer → flush → `ExtractionPersistCoordinator` →
11
+ * `applySemanticMergeAtPersist` → `StorageManager` compare-and-swap) with
12
+ * `semanticMerge` ENABLED for all nine canonical rows, and asserts the merge
13
+ * outcome survives each lifecycle transition.
14
+ *
15
+ * Deterministic sensors use the established field-level seams (never
16
+ * production hooks): the extraction client (`stubExtraction`), the embedding
17
+ * neighbor index (`embeddingFallback`), and the local-llm judge client
18
+ * (`localLlm`, answering only the merge-judge system prompt). Storage,
19
+ * versioning, the merge decision, the CAS writes, the rollback data, and the
20
+ * index repair are all production code.
21
+ */
22
+
23
+ import assert from "node:assert/strict";
24
+ import { test } from "node:test";
25
+ import crypto from "node:crypto";
26
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
27
+ import path from "node:path";
28
+ import { Orchestrator } from "../../orchestrator.js";
29
+ import { resolveNamespaceStorageRoot } from "../../namespaces/storage.js";
30
+ import type { BufferTurn, PluginConfig } from "../../types.js";
31
+ import {
32
+ type LifecycleSubject,
33
+ type MatrixRow,
34
+ runLifecycleMatrix,
35
+ } from "../lifecycle-matrix.js";
36
+ import {
37
+ cleanupDir,
38
+ makeLifecycleConfig,
39
+ markdownFilesUnder,
40
+ mkTempMemoryDir,
41
+ pastIso,
42
+ singleFactResult,
43
+ sleep,
44
+ stubExtraction,
45
+ } from "../orchestrator-lite.js";
46
+ import { queryTemporalTimelineAsync } from "../../temporal-index.js";
47
+
48
+ // ── Fixtures (synthetic; no real paths, hosts, or memory content) ─────────────
49
+
50
+ const SEED_A = "The billing service deploys on a Tuesday cadence.";
51
+ const INCOMING_A = "The billing service deploys at 09:00 UTC sharp.";
52
+ const INCOMING_B = "The billing service deploy includes the payments module.";
53
+ const SEED_B = "The audit service tracks quarterly access reviews.";
54
+ const INCOMING_BOB = "The audit service also covers vendor onboarding.";
55
+
56
+ /**
57
+ * Capture-cued turn contents. The smart trigger auto-fires on the explicit
58
+ * "Please remember" cue (the same pattern every auto-extraction row in the
59
+ * reference subject uses); flush-driven rows use the same turns for uniformity,
60
+ * and the fact body carries the cue verbatim.
61
+ */
62
+ const TURN_A = `Please remember: ${INCOMING_A}`;
63
+ const TURN_B = `Please remember: ${INCOMING_B}`;
64
+ const TURN_BOB = `Please remember: ${INCOMING_BOB}`;
65
+ const GRAPH_SEED = "The billing service deploys on a Tuesday cadence.";
66
+ const GRAPH_INCOMING = "The billing service deploys at 09:00 UTC because payments reconciliation gates the window.";
67
+ const GRAPH_SIBLING = "The billing service pages the on-call engineer after failed deploys.";
68
+ const PREF_SEED = "Commit messages favor terse commit subject lines.";
69
+ const PREF_INCOMING = "Commit messages favor imperative mood subjects.";
70
+
71
+ const NEEDLE_SEED_A = "Tuesday cadence";
72
+ const NEEDLE_A = "09:00 UTC sharp";
73
+ const NEEDLE_B = "payments module";
74
+ const NEEDLE_SEED_B = "quarterly access reviews";
75
+ const NEEDLE_BOB = "vendor onboarding";
76
+
77
+ /** A sparse, opaque session id remembered (bound) to alice from a PRIOR session. */
78
+ const REMEMBERED_SESSION = "restored-session-9f2a";
79
+ /** A sparse, opaque session id with NO remembered binding. */
80
+ const UNBOUND_SESSION = "unbound-session-0000";
81
+
82
+ /** Merge band neighbor score: inside [minSimilarity=0.8, dedupThreshold=0.92). */
83
+ const BAND_SCORE = 0.85;
84
+
85
+ interface SemanticMergeLifecycleState {
86
+ memoryDir: string;
87
+ cfg: PluginConfig;
88
+ orchestrators: Orchestrator[];
89
+ calls: BufferTurn[][];
90
+ restartCalls?: BufferTurn[][];
91
+ /** Judge verdicts answered across ALL orchestrator instances. */
92
+ judge: { calls: number };
93
+ aliceRoot?: string;
94
+ bobRoot?: string;
95
+ aliceFile?: string;
96
+ bobFile?: string;
97
+ targetFile?: string;
98
+ callsBeforeForceFlush?: number;
99
+ }
100
+
101
+ // ── Configs ───────────────────────────────────────────────────────────────────
102
+
103
+ /** Merge-on-write lifecycle config: semanticMerge ON, embedding + versioning ON. */
104
+ function mergeLifecycleConfig(memoryDir: string, overrides: Record<string, unknown> = {}): PluginConfig {
105
+ return makeLifecycleConfig(memoryDir, {
106
+ semanticMerge: { enabled: true },
107
+ embeddingFallbackEnabled: true,
108
+ versioningEnabled: true,
109
+ // Round N+12 (CI-0): the commit-effects sibling (snapshot staging, prune
110
+ // finalization, durable thread-episode persist) runs on this subject's
111
+ // merge path — threading ON gives the thread-episode helper a real
112
+ // thread id so every exported function of that module executes here.
113
+ threadingEnabled: true,
114
+ ...overrides,
115
+ });
116
+ }
117
+
118
+ /** Namespaces-on config with alice/bob principal prefix routing (identity rows). */
119
+ function namespacedConfig(memoryDir: string): PluginConfig {
120
+ return mergeLifecycleConfig(memoryDir, {
121
+ namespacesEnabled: true,
122
+ defaultNamespace: "default",
123
+ sharedNamespace: "shared",
124
+ defaultRecallNamespaces: ["self"],
125
+ principalFromSessionKeyMode: "prefix",
126
+ principalFromSessionKeyRules: [
127
+ { match: "alice:", principal: "alice" },
128
+ { match: "bob:", principal: "bob" },
129
+ ],
130
+ namespacePolicies: [
131
+ { name: "alice", readPrincipals: ["alice"], writePrincipals: ["alice"] },
132
+ { name: "bob", readPrincipals: ["bob"], writePrincipals: ["bob"] },
133
+ ],
134
+ });
135
+ }
136
+
137
+ /** Map-mode config where {@link REMEMBERED_SESSION} is bound to alice. */
138
+ function rememberedBindingConfig(memoryDir: string): PluginConfig {
139
+ return mergeLifecycleConfig(memoryDir, {
140
+ namespacesEnabled: true,
141
+ defaultNamespace: "default",
142
+ sharedNamespace: "shared",
143
+ defaultRecallNamespaces: ["self"],
144
+ principalFromSessionKeyMode: "map",
145
+ principalFromSessionKeyRules: [{ match: REMEMBERED_SESSION, principal: "alice" }],
146
+ namespacePolicies: [{ name: "alice", readPrincipals: ["alice"], writePrincipals: ["alice"] }],
147
+ });
148
+ }
149
+
150
+ // ── Deterministic sensors (field-level seams) ─────────────────────────────────
151
+
152
+ /** The embedding-fallback field seam replaced by {@link installNeighbors}. */
153
+ interface EmbeddingFallbackSeam {
154
+ embeddingFallback: {
155
+ isAvailable: () => Promise<boolean>;
156
+ search: (
157
+ query: string,
158
+ limit: number,
159
+ options?: unknown,
160
+ ) => Promise<Array<{ id: string; score: number; path: string }>>;
161
+ indexFile: (id: string, content: string, path: string) => Promise<void>;
162
+ removeFromIndex: (id: string) => Promise<void>;
163
+ };
164
+ }
165
+
166
+ /**
167
+ * Serve in-band nearest neighbors for EXACT incoming fact contents only.
168
+ * Recall queries and any other content get an empty index, so the stub can
169
+ * never fabricate a recall hit.
170
+ */
171
+ function installNeighbors(
172
+ orchestrator: Orchestrator,
173
+ neighborsFor: (query: string) => Array<{ id: string; score: number }>,
174
+ ): void {
175
+ (orchestrator as unknown as EmbeddingFallbackSeam).embeddingFallback = {
176
+ isAvailable: async () => true,
177
+ search: async (query: string) =>
178
+ neighborsFor(query).map((n) => ({ id: n.id, score: n.score, path: "" })),
179
+ indexFile: async () => {},
180
+ removeFromIndex: async () => {},
181
+ };
182
+ }
183
+
184
+ /** The local-llm field seam replaced by {@link installJudge}. */
185
+ interface LocalLlmSeam {
186
+ localLlm: {
187
+ chatCompletion: (
188
+ messages: Array<{ role: string; content: string }>,
189
+ options?: unknown,
190
+ ) => Promise<{ content: string } | null>;
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Answer ONLY the merge-judge prompt (the production callMergeJudge routing
196
+ * reaches this field through the late-binding `getLocalLlm` dep). Every other
197
+ * caller gets `null` — the same "no backend answered" they already handle.
198
+ * The verdict merges the top candidate's CURRENT body with the incoming text,
199
+ * so replays merge into the already-merged target.
200
+ */
201
+ function installJudge(orchestrator: Orchestrator, judge: { calls: number }): void {
202
+ (orchestrator as unknown as LocalLlmSeam).localLlm = {
203
+ chatCompletion: async (messages) => {
204
+ if (messages[0]?.role !== "system" || !messages[0].content.startsWith("You maintain a long-term memory store")) {
205
+ return null;
206
+ }
207
+ judge.calls++;
208
+ const input = JSON.parse(messages[1]?.content ?? "{}") as {
209
+ new?: { content?: string };
210
+ existing?: Array<{ id?: string; content?: string }>;
211
+ };
212
+ const target = input.existing?.[0];
213
+ if (!target?.id || typeof target.content !== "string" || typeof input.new?.content !== "string") {
214
+ return { content: JSON.stringify({ decision: "create", targetId: null, mergedContent: null, reason: "no candidate" }) };
215
+ }
216
+ return {
217
+ content: JSON.stringify({
218
+ decision: "merge",
219
+ targetId: target.id,
220
+ mergedContent: `${target.content} ${input.new.content}`.trim(),
221
+ reason: "deterministic lifecycle subject judge",
222
+ }),
223
+ };
224
+ },
225
+ };
226
+ }
227
+
228
+ // ── Seeding ───────────────────────────────────────────────────────────────────
229
+
230
+ /**
231
+ * Seed a merge TARGET directly on disk with PAST timestamps and a high
232
+ * importance score, so an incoming fact's own importance never bypasses the
233
+ * merge as unpreservable metadata. Returns the file path.
234
+ */
235
+ async function seedMergeTarget(
236
+ root: string,
237
+ id: string,
238
+ content: string,
239
+ options: {
240
+ /** Category (and its directory) for the target; default `fact`/`facts`. */
241
+ category?: "fact" | "preference";
242
+ /** Storage tier: `cold` seeds under `<root>/cold/...` (demoted target). */
243
+ tier?: "hot" | "cold";
244
+ /** Extra frontmatter lines stamped between `status` and `importanceScore`. */
245
+ extraFrontmatter?: string[];
246
+ } = {},
247
+ ): Promise<string> {
248
+ const category = options.category ?? "fact";
249
+ const created = pastIso();
250
+ const dir = path.join(
251
+ root,
252
+ options.tier === "cold" ? "cold" : ".",
253
+ category === "preference" ? "preferences" : "facts",
254
+ created.slice(0, 10),
255
+ );
256
+ await mkdir(dir, { recursive: true });
257
+ const file = path.join(dir, `${id}.md`);
258
+ await writeFile(
259
+ file,
260
+ [
261
+ "---",
262
+ `id: ${id}`,
263
+ `category: ${category}`,
264
+ `created: ${created}`,
265
+ `updated: ${created}`,
266
+ "source: extraction",
267
+ "confidence: 0.9",
268
+ "confidenceTier: explicit",
269
+ "status: active",
270
+ ...(options.extraFrontmatter ?? []),
271
+ "importanceScore: 0.9",
272
+ "importanceLevel: high",
273
+ "---",
274
+ "",
275
+ content,
276
+ "",
277
+ ].join("\n"),
278
+ "utf8",
279
+ );
280
+ return file;
281
+ }
282
+
283
+ async function assertMerged(file: string, needles: string[], reinforcementCount: number): Promise<void> {
284
+ const raw = await readFile(file, "utf8");
285
+ for (const needle of needles) {
286
+ assert.ok(raw.includes(needle), `merged target must contain "${needle}"`);
287
+ }
288
+ assert.ok(raw.includes("derived_via: merge"), "merged target must carry merge provenance");
289
+ assert.ok(
290
+ raw.includes(`reinforcement_count: ${reinforcementCount}`),
291
+ `merged target must record reinforcement_count: ${reinforcementCount}`,
292
+ );
293
+ }
294
+
295
+ /** Read one graph JSONL edge file (entity/time/causal) as parsed rows. */
296
+ async function readGraphEdges(
297
+ memoryDir: string,
298
+ type: "entity" | "time" | "causal",
299
+ ): Promise<Array<{ from: string; to: string; label: string }>> {
300
+ const file = path.join(memoryDir, "state", "graphs", `${type}.jsonl`);
301
+ try {
302
+ const raw = await readFile(file, "utf8");
303
+ return raw
304
+ .split("\n")
305
+ .map((line) => line.trim())
306
+ .filter((line) => line.length > 0)
307
+ .map((line) => JSON.parse(line) as { from: string; to: string; label: string });
308
+ } catch (err) {
309
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") return [];
310
+ throw err;
311
+ }
312
+ }
313
+
314
+ test("a judge-accepted merge builds the create path's graph edges for the target (round N+5 A)", async () => {
315
+ const memoryDir = await mkTempMemoryDir("semantic-merge-graph");
316
+ let orch: Orchestrator | undefined;
317
+ try {
318
+ const cfg = mergeLifecycleConfig(memoryDir, {
319
+ multiGraphMemoryEnabled: true,
320
+ threadingEnabled: true,
321
+ });
322
+ orch = new Orchestrator(cfg);
323
+ const judge = { calls: 0 };
324
+ installJudge(orch, judge);
325
+ // Fact 1 has no merge candidate (created; becomes the batch's causal and
326
+ // time predecessor). Fact 2 merges into the seeded target.
327
+ const FIRST = "The audit service tracks quarterly access reviews.";
328
+ stubExtraction(orch, () => ({
329
+ facts: [
330
+ { category: "fact", content: FIRST, confidence: 0.9, tags: [] },
331
+ { category: "fact", content: GRAPH_INCOMING, confidence: 0.9, tags: [] },
332
+ ],
333
+ entities: [],
334
+ relationships: [],
335
+ questions: [],
336
+ profileUpdates: [],
337
+ }));
338
+ installNeighbors(orch, (query) =>
339
+ query === GRAPH_INCOMING ? [{ id: "merge-target-graph", score: BAND_SCORE }] : [],
340
+ );
341
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-graph", GRAPH_SEED, {
342
+ extraFrontmatter: ["entityRef: entity-billing-service"],
343
+ });
344
+ await seedMergeTarget(memoryDir, "merge-sibling-graph", GRAPH_SIBLING, {
345
+ extraFrontmatter: ["entityRef: entity-billing-service"],
346
+ });
347
+ await orch.processTurn("user", `Please remember: ${GRAPH_INCOMING}`, "session-graph");
348
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
349
+
350
+ assert.equal(judge.calls, 1, "the mergeable fact must reach the judge exactly once");
351
+ await assertMerged(targetFile, ["Tuesday cadence", "09:00 UTC"], 1);
352
+
353
+ const entityEdges = await readGraphEdges(memoryDir, "entity");
354
+ assert.equal(
355
+ entityEdges.filter((e) => e.from.endsWith("merge-target-graph.md")).length,
356
+ 1,
357
+ "the merged target must carry an entity edge to its seeded sibling",
358
+ );
359
+ assert.ok(
360
+ entityEdges.some(
361
+ (e) =>
362
+ e.from.endsWith("merge-target-graph.md") &&
363
+ e.to.endsWith("merge-sibling-graph.md") &&
364
+ e.label === "entity-billing-service",
365
+ ),
366
+ );
367
+ const timeEdges = await readGraphEdges(memoryDir, "time");
368
+ assert.equal(
369
+ timeEdges.filter((e) => e.to.endsWith("merge-target-graph.md")).length,
370
+ 1,
371
+ "the merged target must carry a time edge from the same extraction's created fact",
372
+ );
373
+ assert.ok(
374
+ timeEdges.every((e) => typeof e.label === "string" && e.label.length > 0),
375
+ "time edges carry the thread id as their label",
376
+ );
377
+ const causalEdges = await readGraphEdges(memoryDir, "causal");
378
+ assert.equal(
379
+ causalEdges.filter((e) => e.to.endsWith("merge-target-graph.md")).length,
380
+ 1,
381
+ "the merged body's causal phrase must link the created fact to the merged target",
382
+ );
383
+ } finally {
384
+ await orch?.destroy().catch(() => undefined);
385
+ await cleanupDir(memoryDir);
386
+ }
387
+ });
388
+
389
+ test("a preference accepted through semantic merge reaches the behavior-signal ledger (round N+5 B)", async () => {
390
+ const memoryDir = await mkTempMemoryDir("semantic-merge-pref");
391
+ let orch: Orchestrator | undefined;
392
+ try {
393
+ const cfg = mergeLifecycleConfig(memoryDir);
394
+ orch = new Orchestrator(cfg);
395
+ const judge = { calls: 0 };
396
+ installJudge(orch, judge);
397
+ stubExtraction(orch, () => ({
398
+ facts: [
399
+ { category: "preference", content: PREF_INCOMING, confidence: 0.9, tags: [] },
400
+ ],
401
+ entities: [],
402
+ relationships: [],
403
+ questions: [],
404
+ profileUpdates: [],
405
+ }));
406
+ installNeighbors(orch, (query) =>
407
+ query === PREF_INCOMING ? [{ id: "merge-target-pref", score: BAND_SCORE }] : [],
408
+ );
409
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-pref", PREF_SEED, {
410
+ category: "preference",
411
+ });
412
+ await orch.processTurn("user", `Please remember: ${PREF_INCOMING}`, "session-pref");
413
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
414
+
415
+ assert.equal(judge.calls, 1, "the preference must reach the judge exactly once");
416
+ await assertMerged(targetFile, ["terse commit subject lines", "imperative mood"], 1);
417
+
418
+ const ledgerPath = path.join(memoryDir, "state", "behavior-signals.jsonl");
419
+ const rows = (await readFile(ledgerPath, "utf8"))
420
+ .split("\n")
421
+ .map((line) => line.trim())
422
+ .filter((line) => line.length > 0)
423
+ .map((line) => JSON.parse(line) as Record<string, string>);
424
+ const affinity = rows.filter(
425
+ (row) => row.memoryId === "merge-target-pref" && row.signalType === "preference_affinity",
426
+ );
427
+ assert.equal(
428
+ affinity.length,
429
+ 1,
430
+ "the merged preference target must record exactly one preference_affinity event",
431
+ );
432
+ assert.equal(affinity[0]?.direction, "positive");
433
+ assert.equal(affinity[0]?.category, "preference");
434
+ assert.equal(affinity[0]?.source, "extraction");
435
+ } finally {
436
+ await orch?.destroy().catch(() => undefined);
437
+ await cleanupDir(memoryDir);
438
+ }
439
+ });
440
+
441
+ test("a merge into a cold-tier target records graph edges at the committed cold path (round N+6 A)", async () => {
442
+ const memoryDir = await mkTempMemoryDir("semantic-merge-cold-graph");
443
+ let orch: Orchestrator | undefined;
444
+ try {
445
+ const cfg = mergeLifecycleConfig(memoryDir, {
446
+ multiGraphMemoryEnabled: true,
447
+ threadingEnabled: true,
448
+ });
449
+ orch = new Orchestrator(cfg);
450
+ const judge = { calls: 0 };
451
+ installJudge(orch, judge);
452
+ stubExtraction(orch, () => ({
453
+ facts: [
454
+ { category: "fact", content: INCOMING_A, confidence: 0.9, tags: [] },
455
+ ],
456
+ entities: [],
457
+ relationships: [],
458
+ questions: [],
459
+ profileUpdates: [],
460
+ }));
461
+ installNeighbors(orch, (query) =>
462
+ query === INCOMING_A ? [{ id: "merge-target-cold", score: BAND_SCORE }] : [],
463
+ );
464
+ // The sibling stays hot so the entity-edge neighbor scan can see it; the
465
+ // TARGET is demoted to cold/, invisible to the hot-only graph context.
466
+ await seedMergeTarget(memoryDir, "merge-sibling-cold", GRAPH_SIBLING, {
467
+ extraFrontmatter: ["entityRef: entity-billing-service"],
468
+ });
469
+ const coldFile = await seedMergeTarget(memoryDir, "merge-target-cold", GRAPH_SEED, {
470
+ tier: "cold",
471
+ extraFrontmatter: ["entityRef: entity-billing-service"],
472
+ });
473
+ await orch.processTurn("user", `Please remember: ${INCOMING_A}`, "session-cold");
474
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
475
+
476
+ assert.equal(judge.calls, 1, "the cold-tier target must still reach the judge");
477
+ await assertMerged(coldFile, ["Tuesday cadence", "09:00 UTC sharp"], 1);
478
+
479
+ const entityEdges = await readGraphEdges(memoryDir, "entity");
480
+ const targetEdges = entityEdges.filter((e) => e.from.endsWith("merge-target-cold.md"));
481
+ assert.equal(targetEdges.length, 1, "the cold target must carry its entity edge");
482
+ assert.ok(
483
+ targetEdges[0]?.from.startsWith(`cold${path.sep}`),
484
+ `entity edge must reference the committed cold path, got ${targetEdges[0]?.from}`,
485
+ );
486
+ // The pre-fix hot-only fallback fabricated facts/<day>/merge-target-cold.md.
487
+ const day = path.basename(path.dirname(coldFile));
488
+ const fabricated = path.join("facts", day, "merge-target-cold.md");
489
+ for (const type of ["entity", "time", "causal"] as const) {
490
+ const edges = await readGraphEdges(memoryDir, type);
491
+ assert.ok(
492
+ edges.every((e) => e.from !== fabricated && e.to !== fabricated),
493
+ `no ${type} edge may reference the fabricated hot path ${fabricated}`,
494
+ );
495
+ }
496
+ } finally {
497
+ await orch?.destroy().catch(() => undefined);
498
+ await cleanupDir(memoryDir);
499
+ }
500
+ });
501
+
502
+ test("repeated merges of one target replace, not re-append, its entity edges (round N+6 B)", async () => {
503
+ const memoryDir = await mkTempMemoryDir("semantic-merge-dup-edges");
504
+ let orch: Orchestrator | undefined;
505
+ try {
506
+ const cfg = mergeLifecycleConfig(memoryDir, { multiGraphMemoryEnabled: true });
507
+ orch = new Orchestrator(cfg);
508
+ const judge = { calls: 0 };
509
+ installJudge(orch, judge);
510
+ // Turn 1 merges INCOMING_A into the target; turn 2 merges INCOMING_B into
511
+ // the SAME (already-merged) target — the replay pattern the judge stub
512
+ // exists for.
513
+ let extractionCall = 0;
514
+ stubExtraction(orch, () => {
515
+ extractionCall++;
516
+ return {
517
+ facts: [
518
+ {
519
+ category: "fact",
520
+ content: extractionCall === 1 ? INCOMING_A : INCOMING_B,
521
+ confidence: 0.9,
522
+ tags: [],
523
+ },
524
+ ],
525
+ entities: [],
526
+ relationships: [],
527
+ questions: [],
528
+ profileUpdates: [],
529
+ };
530
+ });
531
+ installNeighbors(orch, (query) =>
532
+ query === INCOMING_A || query === INCOMING_B
533
+ ? [{ id: "merge-target-dup", score: BAND_SCORE }]
534
+ : [],
535
+ );
536
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-dup", GRAPH_SEED, {
537
+ extraFrontmatter: ["entityRef: entity-billing-service"],
538
+ });
539
+ await seedMergeTarget(memoryDir, "merge-sibling-dup", GRAPH_SIBLING, {
540
+ extraFrontmatter: ["entityRef: entity-billing-service"],
541
+ });
542
+ await orch.processTurn("user", `Please remember: ${INCOMING_A}`, "session-dup-1");
543
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
544
+ await orch.processTurn("user", `Please remember: ${INCOMING_B}`, "session-dup-2");
545
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
546
+
547
+ assert.equal(judge.calls, 2, "both turns must reach the judge");
548
+ await assertMerged(targetFile, ["Tuesday cadence", "09:00 UTC sharp", "payments module"], 2);
549
+
550
+ const entityEdges = await readGraphEdges(memoryDir, "entity");
551
+ const fromTarget = entityEdges.filter((e) => e.from.endsWith("merge-target-dup.md"));
552
+ assert.equal(
553
+ fromTarget.length,
554
+ 1,
555
+ `re-merging must replace the target's entity edges, got ${JSON.stringify(fromTarget)}`,
556
+ );
557
+ assert.equal(
558
+ fromTarget.filter((e) => e.to.endsWith("merge-sibling-dup.md")).length,
559
+ 1,
560
+ "exactly one edge per (target, neighbor) pair after both merges",
561
+ );
562
+ } finally {
563
+ await orch?.destroy().catch(() => undefined);
564
+ await cleanupDir(memoryDir);
565
+ }
566
+ });
567
+
568
+ test("the fact after a merge chains time/causal adjacency through the merged target (round N+6 C)", async () => {
569
+ const memoryDir = await mkTempMemoryDir("semantic-merge-thread-chain");
570
+ let orch: Orchestrator | undefined;
571
+ try {
572
+ const cfg = mergeLifecycleConfig(memoryDir, {
573
+ multiGraphMemoryEnabled: true,
574
+ threadingEnabled: true,
575
+ });
576
+ orch = new Orchestrator(cfg);
577
+ const judge = { calls: 0 };
578
+ installJudge(orch, judge);
579
+ // One batch: FIRST is created (becomes the thread's first episode),
580
+ // INCOMING_A merges into the target, then SUCCESSOR is created and must
581
+ // chain through the merged target — its "because" phrase drives the
582
+ // causal edge. No other content carries a causal phrase.
583
+ const FIRST = "The audit service tracks quarterly access reviews.";
584
+ const SUCCESSOR =
585
+ "The billing service deploy queue drains slowly because reconciliation locks the ledger.";
586
+ stubExtraction(orch, () => ({
587
+ facts: [
588
+ { category: "fact", content: FIRST, confidence: 0.9, tags: [] },
589
+ { category: "fact", content: INCOMING_A, confidence: 0.9, tags: [] },
590
+ { category: "fact", content: SUCCESSOR, confidence: 0.9, tags: [] },
591
+ ],
592
+ entities: [],
593
+ relationships: [],
594
+ questions: [],
595
+ profileUpdates: [],
596
+ }));
597
+ installNeighbors(orch, (query) =>
598
+ query === INCOMING_A ? [{ id: "merge-target-thread", score: BAND_SCORE }] : [],
599
+ );
600
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-thread", GRAPH_SEED, {});
601
+ await orch.processTurn("user", `Please remember: ${INCOMING_A}`, "session-chain");
602
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
603
+
604
+ assert.equal(judge.calls, 1, "only the mergeable fact reaches the judge");
605
+ await assertMerged(targetFile, ["Tuesday cadence", "09:00 UTC sharp"], 1);
606
+
607
+ const timeEdges = await readGraphEdges(memoryDir, "time");
608
+ const intoTarget = timeEdges.find((e) => e.to.endsWith("merge-target-thread.md"));
609
+ const outOfTarget = timeEdges.find((e) => e.from.endsWith("merge-target-thread.md"));
610
+ assert.ok(intoTarget, "the merged target keeps its own incoming time edge");
611
+ assert.ok(
612
+ outOfTarget,
613
+ "the fact following the merge must chain its time edge through the merged target",
614
+ );
615
+ assert.equal(
616
+ outOfTarget?.from,
617
+ intoTarget?.to,
618
+ "the successor edge starts at the merged target's committed path",
619
+ );
620
+ const causalEdges = await readGraphEdges(memoryDir, "causal");
621
+ assert.equal(
622
+ causalEdges.filter((e) => e.from.endsWith("merge-target-thread.md")).length,
623
+ 1,
624
+ "the successor fact's causal phrase must link through the merged target",
625
+ );
626
+ } finally {
627
+ await orch?.destroy().catch(() => undefined);
628
+ await cleanupDir(memoryDir);
629
+ }
630
+ });
631
+
632
+ // ── Subject ───────────────────────────────────────────────────────────────────
633
+
634
+ const subject: LifecycleSubject<SemanticMergeLifecycleState> = {
635
+ async setup(row: MatrixRow): Promise<SemanticMergeLifecycleState> {
636
+ const memoryDir = await mkTempMemoryDir(`semantic-merge-${row.id}`);
637
+ let primary: Orchestrator | undefined;
638
+ try {
639
+ const cfg =
640
+ row.id === "sparse-metadata-with-binding" || row.id === "sparse-metadata-without-binding"
641
+ ? rememberedBindingConfig(memoryDir)
642
+ : row.id === "explicit-provider-identity" || row.id === "provider-rebinding"
643
+ ? namespacedConfig(memoryDir)
644
+ : row.id === "dedupe-replay"
645
+ ? mergeLifecycleConfig(memoryDir, {
646
+ extractionDedupeEnabled: true,
647
+ extractionDedupeWindowMs: 60_000,
648
+ })
649
+ : mergeLifecycleConfig(memoryDir);
650
+ primary = new Orchestrator(cfg);
651
+ const judge = { calls: 0 };
652
+ const state: SemanticMergeLifecycleState = {
653
+ memoryDir,
654
+ cfg,
655
+ orchestrators: [primary],
656
+ calls: [],
657
+ judge,
658
+ };
659
+ state.calls = stubExtraction(primary, (turns) =>
660
+ singleFactResult(
661
+ // Identical buffered turns (the replay row keeps its in-window
662
+ // duplicate buffered) collapse to one fact body so the neighbor
663
+ // index sees the same content on the force-flushed re-extraction.
664
+ [...new Set(turns.filter((turn) => turn.role === "user").map((turn) => turn.content))].join(" "),
665
+ ),
666
+ );
667
+ installJudge(primary, judge);
668
+
669
+ // In-band neighbors for the row's OWN target ids: candidate resolution
670
+ // runs against the write's storage, so a foreign row's id resolves to
671
+ // nothing and the merge correctly falls back to create.
672
+ const namespacedRow =
673
+ row.id === "explicit-provider-identity" ||
674
+ row.id === "provider-rebinding" ||
675
+ row.id === "sparse-metadata-with-binding" ||
676
+ row.id === "sparse-metadata-without-binding";
677
+ const neighbors = (query: string): Array<{ id: string; score: number }> => {
678
+ if (query === TURN_A || query === INCOMING_A) {
679
+ return [{ id: namespacedRow ? "merge-target-alice" : "merge-target-main", score: BAND_SCORE }];
680
+ }
681
+ if (query === TURN_BOB) return [{ id: "merge-target-bob", score: BAND_SCORE }];
682
+ if (query === TURN_B) return [{ id: "merge-target-main", score: BAND_SCORE }];
683
+ return [];
684
+ };
685
+ installNeighbors(primary, neighbors);
686
+
687
+ // Seed the merge targets AFTER construction (cold caches) so the
688
+ // orchestrator's own storage instances discover them on first read.
689
+ if (row.id === "explicit-provider-identity" || row.id === "provider-rebinding") {
690
+ state.aliceRoot = await resolveNamespaceStorageRoot(cfg, "alice");
691
+ state.aliceFile = await seedMergeTarget(state.aliceRoot, "merge-target-alice", SEED_A);
692
+ }
693
+ if (row.id === "sparse-metadata-with-binding" || row.id === "sparse-metadata-without-binding") {
694
+ state.aliceRoot = await resolveNamespaceStorageRoot(cfg, "alice");
695
+ state.aliceFile = await seedMergeTarget(state.aliceRoot, "merge-target-alice", SEED_A);
696
+ }
697
+ if (row.id === "provider-rebinding") {
698
+ state.bobRoot = await resolveNamespaceStorageRoot(cfg, "bob");
699
+ state.bobFile = await seedMergeTarget(state.bobRoot, "merge-target-bob", SEED_B);
700
+ }
701
+ if (
702
+ row.id === "restart-reload-recovery" ||
703
+ row.id === "compaction-flush" ||
704
+ row.id === "before-reset" ||
705
+ row.id === "session-end" ||
706
+ row.id === "dedupe-replay"
707
+ ) {
708
+ state.targetFile = await seedMergeTarget(memoryDir, "merge-target-main", SEED_A);
709
+ }
710
+ return state;
711
+ } catch (err) {
712
+ // Transactional setup: a partial build must not leak the orchestrator or temp dir.
713
+ await primary?.destroy().catch(() => undefined);
714
+ await cleanupDir(memoryDir);
715
+ throw err;
716
+ }
717
+ },
718
+
719
+ async exercise(state: SemanticMergeLifecycleState, row: MatrixRow): Promise<void> {
720
+ const primary = state.orchestrators[0];
721
+ switch (row.id) {
722
+ case "explicit-provider-identity": {
723
+ await primary.processTurn("user", TURN_A, "alice:chat");
724
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
725
+ return;
726
+ }
727
+ case "sparse-metadata-with-binding": {
728
+ await primary.processTurn("user", INCOMING_A, REMEMBERED_SESSION);
729
+ await primary.flushSession(REMEMBERED_SESSION, { reason: "before_reset" });
730
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
731
+ return;
732
+ }
733
+ case "sparse-metadata-without-binding": {
734
+ await primary.processTurn("user", INCOMING_A, UNBOUND_SESSION);
735
+ await primary.flushSession(UNBOUND_SESSION, { reason: "before_reset" });
736
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
737
+ return;
738
+ }
739
+ case "provider-rebinding": {
740
+ await primary.processTurn("user", TURN_A, "alice:chat");
741
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
742
+ await primary.processTurn("user", TURN_BOB, "bob:chat");
743
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
744
+ return;
745
+ }
746
+ case "restart-reload-recovery": {
747
+ await primary.processTurn("user", TURN_A, "session-merge");
748
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
749
+ await primary.destroy();
750
+ state.orchestrators.length = 0;
751
+ const second = new Orchestrator(mergeLifecycleConfig(state.memoryDir));
752
+ state.orchestrators.push(second);
753
+ state.restartCalls = stubExtraction(second, (turns) =>
754
+ singleFactResult(
755
+ turns
756
+ .filter((turn) => turn.role === "user")
757
+ .map((turn) => turn.content)
758
+ .join(" "),
759
+ ),
760
+ );
761
+ installJudge(second, state.judge);
762
+ installNeighbors(second, (query) =>
763
+ query === TURN_B ? [{ id: "merge-target-main", score: BAND_SCORE }] : [],
764
+ );
765
+ await second.processTurn("user", TURN_B, "session-merge");
766
+ assert.equal(await second.waitForExtractionIdle(15_000), true);
767
+ return;
768
+ }
769
+ case "compaction-flush": {
770
+ await primary.processTurn("user", INCOMING_A, "session-compact");
771
+ await primary.processTurn("assistant", "Noted the Tuesday deploy detail.", "session-compact");
772
+ await primary.flushSession("session-compact", { reason: "compaction" });
773
+ return;
774
+ }
775
+ case "before-reset": {
776
+ await primary.processTurn("user", INCOMING_A, "session-reset");
777
+ await primary.flushSession("session-reset", { reason: "before_reset" });
778
+ return;
779
+ }
780
+ case "session-end": {
781
+ await primary.processTurn("user", INCOMING_A, "session-end");
782
+ await primary.flushSession("session-end", { reason: "session_end" });
783
+ return;
784
+ }
785
+ case "dedupe-replay": {
786
+ await primary.processTurn("user", TURN_A, "session-dedupe");
787
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
788
+ await primary.processTurn("user", TURN_A, "session-dedupe");
789
+ assert.equal(await primary.waitForExtractionIdle(15_000), true);
790
+ state.callsBeforeForceFlush = state.calls.length;
791
+ await primary.flushSession("session-dedupe", { reason: "before_reset" });
792
+ return;
793
+ }
794
+ default: {
795
+ const exhaustive: never = row.id;
796
+ throw new Error(`unhandled row ${String(exhaustive)}`);
797
+ }
798
+ }
799
+ },
800
+
801
+ async invariants(state: SemanticMergeLifecycleState, row: MatrixRow): Promise<void> {
802
+ const primary = state.orchestrators[0];
803
+ assert.equal(state.cfg.semanticMerge.enabled, true, "every lifecycle row enables semantic merge-on-write");
804
+ switch (row.id) {
805
+ case "explicit-provider-identity": {
806
+ assert.equal(state.judge.calls, 1, "the turn extracts and merges exactly once");
807
+ assert.ok(state.aliceFile);
808
+ await assertMerged(state.aliceFile, [NEEDLE_SEED_A, NEEDLE_A], 1);
809
+ assert.equal(
810
+ (await markdownFilesUnder(path.join(state.aliceRoot ?? "", "facts"))).length,
811
+ 1,
812
+ "a merge updates in place — no second fragment",
813
+ );
814
+ assert.equal(
815
+ (await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length,
816
+ 0,
817
+ "an identity-routed merge must not land in the default root",
818
+ );
819
+ return;
820
+ }
821
+ case "sparse-metadata-with-binding": {
822
+ assert.equal(state.judge.calls, 1);
823
+ assert.ok(state.aliceFile);
824
+ await assertMerged(state.aliceFile, [NEEDLE_SEED_A, NEEDLE_A], 1);
825
+ assert.equal((await markdownFilesUnder(path.join(state.aliceRoot ?? "", "facts"))).length, 1);
826
+ return;
827
+ }
828
+ case "sparse-metadata-without-binding": {
829
+ // The unbound session must NOT merge into alice's target: candidate
830
+ // resolution runs against the WRITE's storage, where her id is unknown.
831
+ assert.equal(state.judge.calls, 0, "no candidate resolves for an unbound session — the judge is never asked");
832
+ assert.ok(state.aliceFile);
833
+ const raw = await readFile(state.aliceFile, "utf8");
834
+ assert.ok(raw.includes(NEEDLE_SEED_A), "alice's target keeps its original body");
835
+ assert.ok(!raw.includes(NEEDLE_A), "an unbound session must not merge into alice's target");
836
+ assert.ok(!raw.includes("derived_via"), "alice's target carries no merge provenance");
837
+ assert.equal(
838
+ (await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length,
839
+ 1,
840
+ "the fact is CREATED in the default root instead of merging cross-tenant",
841
+ );
842
+ return;
843
+ }
844
+ case "provider-rebinding": {
845
+ assert.equal(state.judge.calls, 2, "each identity's turn merges exactly once");
846
+ assert.ok(state.aliceFile && state.bobFile);
847
+ const aliceRaw = await readFile(state.aliceFile, "utf8");
848
+ const bobRaw = await readFile(state.bobFile, "utf8");
849
+ assert.ok(aliceRaw.includes(NEEDLE_A) && aliceRaw.includes(NEEDLE_SEED_A));
850
+ assert.ok(bobRaw.includes(NEEDLE_BOB) && bobRaw.includes(NEEDLE_SEED_B));
851
+ assert.ok(!aliceRaw.includes(NEEDLE_BOB), "bob's fact must not merge into alice's target");
852
+ assert.ok(!bobRaw.includes(NEEDLE_A), "alice's fact must not merge into bob's target");
853
+ assert.ok(aliceRaw.includes("derived_via: merge") && bobRaw.includes("derived_via: merge"));
854
+ return;
855
+ }
856
+ case "restart-reload-recovery": {
857
+ const second = state.orchestrators[0];
858
+ assert.ok(state.targetFile);
859
+ assert.equal(state.judge.calls, 2, "one merge before the restart, one through the restarted instance");
860
+ await assertMerged(state.targetFile, [NEEDLE_SEED_A, NEEDLE_A, NEEDLE_B], 2);
861
+ assert.equal(
862
+ (await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length,
863
+ 1,
864
+ "both merges update the SAME target — restart must not fork a fragment",
865
+ );
866
+ const context = await second.recall("What does the billing service deploy include?", "reader");
867
+ assert.match(context, /payments module/i, "the post-restart merge is recallable");
868
+ return;
869
+ }
870
+ case "compaction-flush": {
871
+ assert.equal(state.calls.length, 1, "the flush compacts the buffered turns into one extraction");
872
+ assert.deepEqual(
873
+ state.calls[0]?.map((turn) => turn.content),
874
+ [INCOMING_A, "Noted the Tuesday deploy detail."],
875
+ );
876
+ assert.equal(state.judge.calls, 1);
877
+ assert.ok(state.targetFile);
878
+ await assertMerged(state.targetFile, [NEEDLE_SEED_A, NEEDLE_A], 1);
879
+ assert.equal((await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length, 1);
880
+ return;
881
+ }
882
+ case "before-reset": {
883
+ assert.equal(state.judge.calls, 1);
884
+ assert.ok(state.targetFile);
885
+ await assertMerged(state.targetFile, [NEEDLE_SEED_A, NEEDLE_A], 1);
886
+ const merged = await readFile(state.targetFile, "utf8");
887
+ await primary.flushSession("session-reset", { reason: "before_reset" });
888
+ assert.equal(state.judge.calls, 1, "an empty-buffer re-flush must not merge again");
889
+ assert.equal(
890
+ await readFile(state.targetFile, "utf8").then((raw) => raw === merged),
891
+ true,
892
+ "the drained re-flush leaves the merged target byte-identical",
893
+ );
894
+ assert.equal((await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length, 1);
895
+ return;
896
+ }
897
+ case "session-end": {
898
+ assert.equal(state.calls.length, 1, "session_end drains the buffer like before_reset");
899
+ assert.equal(state.judge.calls, 1);
900
+ assert.ok(state.targetFile);
901
+ await assertMerged(state.targetFile, [NEEDLE_SEED_A, NEEDLE_A], 1);
902
+ assert.equal((await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length, 1);
903
+ return;
904
+ }
905
+ case "dedupe-replay": {
906
+ assert.equal(
907
+ state.callsBeforeForceFlush,
908
+ 1,
909
+ "the in-window duplicate must be suppressed — one extraction before the force flush",
910
+ );
911
+ assert.equal(state.calls.length, 2, "the force flush bypasses the dedupe fingerprint and re-extracts");
912
+ assert.equal(state.judge.calls, 2, "the replayed duplicate MERGES AGAIN into the same target");
913
+ assert.ok(state.targetFile);
914
+ await assertMerged(state.targetFile, [NEEDLE_SEED_A, NEEDLE_A], 2);
915
+ assert.equal(
916
+ (await markdownFilesUnder(path.join(state.memoryDir, "facts"))).length,
917
+ 1,
918
+ "replaying the duplicate must not fork a second fragment",
919
+ );
920
+ return;
921
+ }
922
+ default: {
923
+ const exhaustive: never = row.id;
924
+ throw new Error(`unhandled row ${String(exhaustive)}`);
925
+ }
926
+ }
927
+ },
928
+
929
+ async teardown(state: SemanticMergeLifecycleState): Promise<void> {
930
+ for (const orchestrator of state.orchestrators) {
931
+ await orchestrator.destroy().catch(() => undefined);
932
+ }
933
+ await cleanupDir(state.memoryDir);
934
+ },
935
+ };
936
+
937
+ test("a merged target's new claims reach the temporal timeline index (round N+7 D)", async () => {
938
+ const memoryDir = await mkTempMemoryDir("semantic-merge-temporal");
939
+ let orch: Orchestrator | undefined;
940
+ try {
941
+ const cfg = mergeLifecycleConfig(memoryDir, { queryAwareIndexingEnabled: true });
942
+ orch = new Orchestrator(cfg);
943
+ const judge = { calls: 0 };
944
+ installJudge(orch, judge);
945
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-temporal", SEED_A);
946
+ // Turn 1: an unrelated created fact bootstraps the temporal index, so the
947
+ // seeded target is indexed with its PRE-merge text (which has no
948
+ // "sharp") and turn 2 runs the INCREMENTAL, id-filtered update.
949
+ const FIRST = "The audit service tracks quarterly access reviews.";
950
+ stubExtraction(orch, () => ({
951
+ facts: [{ category: "fact", content: FIRST, confidence: 0.9, tags: [] }],
952
+ entities: [],
953
+ relationships: [],
954
+ questions: [],
955
+ profileUpdates: [],
956
+ }));
957
+ installNeighbors(orch, () => []);
958
+ await orch.processTurn("user", `Please remember: ${FIRST}`, "session-temporal-1");
959
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
960
+ // Turn 1's temporal-index bootstrap is fire-and-forget: wait until it
961
+ // has COMPLETED (the created fact's row is served) so turn 2 runs the
962
+ // INCREMENTAL id-filtered update instead of re-bootstrapping the whole
963
+ // corpus — a re-bootstrap would index the already-merged target even
964
+ // without the fix, masking the defect.
965
+ let bootstrapped = false;
966
+ for (let attempt = 0; attempt < 40 && !bootstrapped; attempt++) {
967
+ const events =
968
+ (await queryTemporalTimelineAsync(memoryDir, { query: "quarterly", limit: 10 })) ?? [];
969
+ bootstrapped = events.length > 0;
970
+ if (!bootstrapped) await sleep(250);
971
+ }
972
+ assert.ok(bootstrapped, "turn 1's temporal index bootstrap must complete");
973
+ // Turn 2: the merge commits "09:00 UTC sharp" into the target.
974
+ stubExtraction(orch, () => ({
975
+ facts: [{ category: "fact", content: INCOMING_A, confidence: 0.9, tags: [] }],
976
+ entities: [],
977
+ relationships: [],
978
+ questions: [],
979
+ profileUpdates: [],
980
+ }));
981
+ installNeighbors(orch, (query) =>
982
+ query === INCOMING_A ? [{ id: "merge-target-temporal", score: BAND_SCORE }] : [],
983
+ );
984
+ await orch.processTurn("user", `Please remember: ${INCOMING_A}`, "session-temporal-2");
985
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
986
+ assert.equal(judge.calls, 1);
987
+ await assertMerged(targetFile, ["Tuesday cadence", "09:00 UTC sharp"], 1);
988
+ // Membership in the returned rows is not evidence on its own: with few
989
+ // rows the query returns the chronology unfiltered (and the no-match
990
+ // fallback returns both edges). Assert the merged token's HASH is on the
991
+ // target's own row — the exact contract queryTemporalTimelineAsync
992
+ // scores against.
993
+ const sharpToken = crypto.createHash("sha256").update("sharp").digest("hex");
994
+ let served = false;
995
+ for (let attempt = 0; attempt < 40 && !served; attempt++) {
996
+ const events =
997
+ (await queryTemporalTimelineAsync(memoryDir, { query: "sharp", limit: 10 })) ?? [];
998
+ served = events.some(
999
+ (event) =>
1000
+ event.path.endsWith("merge-target-temporal.md") &&
1001
+ (event.searchTokenHashes ?? []).includes(sharpToken),
1002
+ );
1003
+ if (!served) await sleep(250);
1004
+ }
1005
+ assert.ok(
1006
+ served,
1007
+ "event-order queries must find the merged target's new tokens without a full rebuild",
1008
+ );
1009
+ } finally {
1010
+ await orch?.destroy().catch(() => undefined);
1011
+ await cleanupDir(memoryDir);
1012
+ }
1013
+ });
1014
+
1015
+ test("a cold-tier merged target's new claims reach the temporal timeline index (round N+9 B)", async () => {
1016
+ const memoryDir = await mkTempMemoryDir("semantic-merge-temporal-cold");
1017
+ let orch: Orchestrator | undefined;
1018
+ try {
1019
+ const cfg = mergeLifecycleConfig(memoryDir, { queryAwareIndexingEnabled: true });
1020
+ orch = new Orchestrator(cfg);
1021
+ const judge = { calls: 0 };
1022
+ installJudge(orch, judge);
1023
+ // The target lives under cold/ — invisible to the hot-only
1024
+ // readAllMemories() scan that builds the incremental temporal-index
1025
+ // pool, so only a cold-aware id lookup can refresh its row.
1026
+ const coldFile = await seedMergeTarget(memoryDir, "merge-target-cold-temporal", SEED_A, {
1027
+ tier: "cold",
1028
+ });
1029
+ // Turn 1 bootstraps the index from a hot fact so turn 2 runs the
1030
+ // INCREMENTAL id-filtered update (a re-bootstrap would index the cold
1031
+ // target even without the fix, masking the defect).
1032
+ const FIRST = "The audit service tracks quarterly access reviews.";
1033
+ stubExtraction(orch, () => ({
1034
+ facts: [{ category: "fact", content: FIRST, confidence: 0.9, tags: [] }],
1035
+ entities: [],
1036
+ relationships: [],
1037
+ questions: [],
1038
+ profileUpdates: [],
1039
+ }));
1040
+ installNeighbors(orch, () => []);
1041
+ await orch.processTurn("user", `Please remember: ${FIRST}`, "session-temporal-cold-1");
1042
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
1043
+ let bootstrapped = false;
1044
+ for (let attempt = 0; attempt < 40 && !bootstrapped; attempt++) {
1045
+ const events =
1046
+ (await queryTemporalTimelineAsync(memoryDir, { query: "quarterly", limit: 10 })) ?? [];
1047
+ bootstrapped = events.length > 0;
1048
+ if (!bootstrapped) await sleep(250);
1049
+ }
1050
+ assert.ok(bootstrapped, "turn 1's temporal index bootstrap must complete");
1051
+ // Turn 2: the merge commits "09:00 UTC sharp" into the COLD target.
1052
+ stubExtraction(orch, () => ({
1053
+ facts: [{ category: "fact", content: INCOMING_A, confidence: 0.9, tags: [] }],
1054
+ entities: [],
1055
+ relationships: [],
1056
+ questions: [],
1057
+ profileUpdates: [],
1058
+ }));
1059
+ installNeighbors(orch, (query) =>
1060
+ query === INCOMING_A ? [{ id: "merge-target-cold-temporal", score: BAND_SCORE }] : [],
1061
+ );
1062
+ await orch.processTurn("user", `Please remember: ${INCOMING_A}`, "session-temporal-cold-2");
1063
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
1064
+ assert.equal(judge.calls, 1);
1065
+ await assertMerged(coldFile, ["Tuesday cadence", "09:00 UTC sharp"], 1);
1066
+ // Same token-hash contract as the hot-tier test above: the merged
1067
+ // token's HASH must sit on the cold target's own row.
1068
+ const sharpToken = crypto.createHash("sha256").update("sharp").digest("hex");
1069
+ let served = false;
1070
+ for (let attempt = 0; attempt < 40 && !served; attempt++) {
1071
+ const events =
1072
+ (await queryTemporalTimelineAsync(memoryDir, { query: "sharp", limit: 10 })) ?? [];
1073
+ served = events.some(
1074
+ (event) =>
1075
+ event.path.endsWith("merge-target-cold-temporal.md") &&
1076
+ (event.searchTokenHashes ?? []).includes(sharpToken),
1077
+ );
1078
+ if (!served) await sleep(250);
1079
+ }
1080
+ assert.ok(
1081
+ served,
1082
+ "event-order queries must find the cold-tier merged target's new tokens",
1083
+ );
1084
+ } finally {
1085
+ await orch?.destroy().catch(() => undefined);
1086
+ await cleanupDir(memoryDir);
1087
+ }
1088
+ });
1089
+
1090
+ test("repeated merges leave exactly one generated edge per graph type for the target (round N+7 G)", async () => {
1091
+ const memoryDir = await mkTempMemoryDir("semantic-merge-graph-parity");
1092
+ let orch: Orchestrator | undefined;
1093
+ try {
1094
+ const cfg = mergeLifecycleConfig(memoryDir, {
1095
+ multiGraphMemoryEnabled: true,
1096
+ threadingEnabled: true,
1097
+ });
1098
+ orch = new Orchestrator(cfg);
1099
+ const judge = { calls: 0 };
1100
+ installJudge(orch, judge);
1101
+ // Two turns; each creates its own thread-local fact (becomes that
1102
+ // thread's first episode) and merges a because-sentence into the SAME
1103
+ // target. Each merge appends time+causal edges INTO the target from that
1104
+ // turn's created fact — without per-type replacement the second merge
1105
+ // duplicates them.
1106
+ const GRAPH_INCOMING_2 =
1107
+ "The billing service deploy window opens early because the EU handoff needs overlap.";
1108
+ let extractionCall = 0;
1109
+ stubExtraction(orch, () => {
1110
+ extractionCall++;
1111
+ return {
1112
+ facts: [
1113
+ {
1114
+ category: "fact",
1115
+ content: extractionCall === 1 ? "The audit service tracks quarterly access reviews." : "The audit service also archives vendor onboarding evidence.",
1116
+ confidence: 0.9,
1117
+ tags: [],
1118
+ },
1119
+ {
1120
+ category: "fact",
1121
+ content: extractionCall === 1 ? GRAPH_INCOMING : GRAPH_INCOMING_2,
1122
+ confidence: 0.9,
1123
+ tags: [],
1124
+ },
1125
+ ],
1126
+ entities: [],
1127
+ relationships: [],
1128
+ questions: [],
1129
+ profileUpdates: [],
1130
+ };
1131
+ });
1132
+ installNeighbors(orch, (query) =>
1133
+ query === GRAPH_INCOMING || query === GRAPH_INCOMING_2
1134
+ ? [{ id: "merge-target-parity", score: BAND_SCORE }]
1135
+ : [],
1136
+ );
1137
+ const targetFile = await seedMergeTarget(memoryDir, "merge-target-parity", GRAPH_SEED, {
1138
+ extraFrontmatter: ["entityRef: entity-billing-service"],
1139
+ });
1140
+ await seedMergeTarget(memoryDir, "merge-sibling-parity", GRAPH_SIBLING, {
1141
+ extraFrontmatter: ["entityRef: entity-billing-service"],
1142
+ });
1143
+ await orch.processTurn("user", `Please remember: ${GRAPH_INCOMING}`, "session-parity-1");
1144
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
1145
+ await orch.processTurn("user", `Please remember: ${GRAPH_INCOMING_2}`, "session-parity-2");
1146
+ assert.equal(await orch.waitForExtractionIdle(15_000), true);
1147
+
1148
+ assert.equal(judge.calls, 2, "both turns must reach the judge");
1149
+ await assertMerged(targetFile, ["Tuesday cadence", "09:00 UTC"], 2);
1150
+
1151
+ const entityEdges = await readGraphEdges(memoryDir, "entity");
1152
+ assert.equal(
1153
+ entityEdges.filter((e) => e.from.endsWith("merge-target-parity.md")).length,
1154
+ 1,
1155
+ "entity: the target's from-side edges are replaced, not accumulated",
1156
+ );
1157
+ const timeEdges = await readGraphEdges(memoryDir, "time");
1158
+ assert.equal(
1159
+ timeEdges.filter((e) => e.to.endsWith("merge-target-parity.md")).length,
1160
+ 1,
1161
+ `time: one inbound edge for the target, got ${JSON.stringify(timeEdges)}`,
1162
+ );
1163
+ const causalEdges = await readGraphEdges(memoryDir, "causal");
1164
+ assert.equal(
1165
+ causalEdges.filter((e) => e.to.endsWith("merge-target-parity.md")).length,
1166
+ 1,
1167
+ `causal: one inbound edge for the target, got ${JSON.stringify(causalEdges)}`,
1168
+ );
1169
+ } finally {
1170
+ await orch?.destroy().catch(() => undefined);
1171
+ await cleanupDir(memoryDir);
1172
+ }
1173
+ });
1174
+
1175
+ runLifecycleMatrix("semantic-merge-lifecycle", subject);