@remnic/core 9.45.3 → 9.45.4

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 (747) hide show
  1. package/dist/abort-error.d.ts +2 -1
  2. package/dist/abort-error.js +3 -1
  3. package/dist/access-admin-ops-surface.d.ts +14 -10
  4. package/dist/access-admin-ops-surface.js +84 -76
  5. package/dist/access-audit.js +2 -2
  6. package/dist/access-authorization-probe.d.ts +14 -10
  7. package/dist/access-authorization-probe.js +85 -77
  8. package/dist/access-boundary.d.ts +15 -11
  9. package/dist/access-boundary.js +84 -76
  10. package/dist/access-citation-namespace.js +2 -2
  11. package/dist/access-cli.js +193 -181
  12. package/dist/access-cli.js.map +1 -1
  13. package/dist/access-coding-context-resolution.d.ts +16 -0
  14. package/dist/access-coding-context-resolution.js +13 -0
  15. package/dist/access-coding-context-resolution.js.map +1 -0
  16. package/dist/access-extraction-force-flush.d.ts +14 -10
  17. package/dist/access-extraction-force-flush.js +84 -76
  18. package/dist/access-health-types.d.ts +2 -1
  19. package/dist/access-http-lcm-compaction.d.ts +16 -12
  20. package/dist/access-http-lcm-compaction.js +3 -3
  21. package/dist/access-http-lifecycle-flush.d.ts +14 -10
  22. package/dist/access-http-lifecycle-flush.js +2 -2
  23. package/dist/access-http-offline-stream.d.ts +123 -0
  24. package/dist/access-http-offline-stream.js +10 -0
  25. package/dist/access-http-offline-stream.js.map +1 -0
  26. package/dist/access-http-query.js +84 -76
  27. package/dist/access-http.d.ts +15 -10
  28. package/dist/access-http.js +105 -92
  29. package/dist/access-identity-continuity-surface.d.ts +9 -8
  30. package/dist/access-identity-continuity-surface.js +84 -76
  31. package/dist/access-lcm-surface.d.ts +14 -10
  32. package/dist/access-lcm-surface.js +84 -76
  33. package/dist/access-mcp-output-schemas.js +1 -1
  34. package/dist/access-mcp.d.ts +14 -10
  35. package/dist/access-mcp.js +95 -83
  36. package/dist/access-memory-search-fanout.d.ts +3 -2
  37. package/dist/{access-namespace-preflight-5yZ4g6F8.d.ts → access-namespace-preflight-CWUDwB4M.d.ts} +1 -1
  38. package/dist/access-namespace-preflight.d.ts +4 -3
  39. package/dist/access-namespace-preflight.js +84 -76
  40. package/dist/access-observe-helpers.d.ts +1 -0
  41. package/dist/access-observe-helpers.js +1 -1
  42. package/dist/access-observe-write-surface.d.ts +16 -10
  43. package/dist/access-observe-write-surface.js +84 -76
  44. package/dist/access-offline-manifest.d.ts +104 -0
  45. package/dist/access-offline-manifest.js +45 -0
  46. package/dist/access-offline-manifest.js.map +1 -0
  47. package/dist/access-operations-batch.js +86 -78
  48. package/dist/access-operations.d.ts +15 -11
  49. package/dist/access-operations.js +91 -80
  50. package/dist/access-recall-concurrency.d.ts +16 -26
  51. package/dist/access-recall-concurrency.js +86 -77
  52. package/dist/access-recall-response.d.ts +18 -14
  53. package/dist/access-recall-response.js +84 -76
  54. package/dist/access-recall-surface.d.ts +29 -24
  55. package/dist/access-recall-surface.js +84 -76
  56. package/dist/access-schema.js +3 -3
  57. package/dist/{access-service-CiJRsgAB.d.ts → access-service-CsU-ljFD.d.ts} +25 -16
  58. package/dist/access-service-helpers.d.ts +14 -10
  59. package/dist/access-service.d.ts +14 -10
  60. package/dist/access-service.js +84 -76
  61. package/dist/access-surface-catalog.d.ts +14 -10
  62. package/dist/access-surface-catalog.js +4 -0
  63. package/dist/access-surface-catalog.js.map +1 -1
  64. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  65. package/dist/action-confidence.d.ts +2 -1
  66. package/dist/active-memory-bridge.d.ts +2 -1
  67. package/dist/active-recall.d.ts +2 -1
  68. package/dist/active-recall.js +10 -8
  69. package/dist/active-recall.js.map +1 -1
  70. package/dist/adapters/index.js +7 -7
  71. package/dist/adapters/registry.js +3 -3
  72. package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +6 -6
  73. package/dist/behavior-learner.d.ts +2 -1
  74. package/dist/behavior-learner.js +1 -1
  75. package/dist/behavior-signals.d.ts +2 -1
  76. package/dist/bootstrap.d.ts +9 -8
  77. package/dist/briefing.d.ts +3 -2
  78. package/dist/briefing.js +23 -22
  79. package/dist/buffer-surprise-report.d.ts +2 -1
  80. package/dist/buffer-turn-helpers.d.ts +2 -1
  81. package/dist/buffer.d.ts +3 -2
  82. package/dist/buffer.js +12 -11
  83. package/dist/bulk-import/index.d.ts +4 -3
  84. package/dist/calibration.d.ts +2 -1
  85. package/dist/capabilities.d.ts +2 -1
  86. package/dist/{capsule-merge-IDWJPCWK.js → capsule-merge-Q6AR3XL7.js} +67 -54
  87. package/dist/capsule-merge-Q6AR3XL7.js.map +1 -0
  88. package/dist/{catalog-scBmy0sO.d.ts → catalog-bctMURhN.d.ts} +1 -1
  89. package/dist/causal-behavior.d.ts +2 -1
  90. package/dist/causal-behavior.js +2 -2
  91. package/dist/causal-chain.js +2 -2
  92. package/dist/causal-consolidation.d.ts +2 -1
  93. package/dist/causal-consolidation.js +27 -26
  94. package/dist/causal-consolidation.js.map +1 -1
  95. package/dist/causal-retrieval.js +2 -2
  96. package/dist/causal-trajectory-graph.d.ts +2 -1
  97. package/dist/causal-trajectory.js +1 -1
  98. package/dist/{chunk-VUPTKTDV.js → chunk-2MRHJNWL.js} +3 -3
  99. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  100. package/dist/{chunk-5IVLTFOV.js → chunk-44N6ESJ4.js} +2 -2
  101. package/dist/{chunk-WOCNN776.js → chunk-4POAMKV6.js} +100 -41
  102. package/dist/chunk-4POAMKV6.js.map +1 -0
  103. package/dist/{chunk-HO3QBJEY.js → chunk-5546W5SI.js} +2 -2
  104. package/dist/{chunk-U7GW7NE7.js → chunk-5CEECY6P.js} +10 -10
  105. package/dist/{chunk-4UH4BTGK.js → chunk-5SNZSWWR.js} +82 -82
  106. package/dist/{chunk-6CZPDBJS.js → chunk-5U7ID3EZ.js} +3 -3
  107. package/dist/{chunk-GF22HWS2.js → chunk-6NNNURLK.js} +7 -7
  108. package/dist/chunk-773TRRGT.js +36 -0
  109. package/dist/chunk-773TRRGT.js.map +1 -0
  110. package/dist/chunk-7CITSYSH.js +242 -0
  111. package/dist/chunk-7CITSYSH.js.map +1 -0
  112. package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
  113. package/dist/{chunk-E5UK4VPE.js → chunk-7SHJHPTY.js} +5 -5
  114. package/dist/{chunk-UVIKWC7M.js → chunk-7YERSTN7.js} +17 -17
  115. package/dist/{chunk-DLVPUX7U.js → chunk-7YKVM5H3.js} +8 -6
  116. package/dist/chunk-7YKVM5H3.js.map +1 -0
  117. package/dist/{chunk-3CE77VAP.js → chunk-A4JMGKCD.js} +87 -74
  118. package/dist/chunk-A4JMGKCD.js.map +1 -0
  119. package/dist/chunk-A5KNZSNA.js +26 -0
  120. package/dist/chunk-A5KNZSNA.js.map +1 -0
  121. package/dist/{chunk-S2NCTZGJ.js → chunk-AJQ57VV3.js} +15 -15
  122. package/dist/chunk-AJQ57VV3.js.map +1 -0
  123. package/dist/{chunk-CUM2BBPN.js → chunk-AUMWZSE7.js} +19 -10
  124. package/dist/chunk-AUMWZSE7.js.map +1 -0
  125. package/dist/{chunk-XYTOI63Z.js → chunk-BGHFOD5A.js} +19 -11
  126. package/dist/chunk-BGHFOD5A.js.map +1 -0
  127. package/dist/{chunk-BUE5E2HL.js → chunk-BGLY7EEM.js} +5 -314
  128. package/dist/chunk-BGLY7EEM.js.map +1 -0
  129. package/dist/chunk-BIPBQQFI.js +44 -0
  130. package/dist/chunk-BIPBQQFI.js.map +1 -0
  131. package/dist/{chunk-S5SLVSVY.js → chunk-BQIFZ2MP.js} +5 -5
  132. package/dist/chunk-BTTPKDIL.js +34 -0
  133. package/dist/{chunk-PVGDJXVK.js.map → chunk-BTTPKDIL.js.map} +1 -1
  134. package/dist/{chunk-E53DSZEN.js → chunk-C26TE27X.js} +3 -3
  135. package/dist/{chunk-LZ4LDKHZ.js → chunk-CLB32OHM.js} +6 -6
  136. package/dist/{chunk-Q6IP2ARR.js → chunk-CSOYVTRX.js} +2 -2
  137. package/dist/{chunk-XOQSEF7X.js → chunk-CVILPI77.js} +6 -6
  138. package/dist/chunk-D3I2MCN7.js +29 -0
  139. package/dist/chunk-D3I2MCN7.js.map +1 -0
  140. package/dist/{chunk-A5OJCXZL.js → chunk-DSUAAZZX.js} +15 -4
  141. package/dist/chunk-DSUAAZZX.js.map +1 -0
  142. package/dist/{chunk-HREE4JHI.js → chunk-DYVMXPCF.js} +486 -287
  143. package/dist/chunk-DYVMXPCF.js.map +1 -0
  144. package/dist/{chunk-J7VGGECD.js → chunk-DZPFMQZ7.js} +1 -1
  145. package/dist/chunk-DZPFMQZ7.js.map +1 -0
  146. package/dist/{chunk-PDLBLTOK.js → chunk-EITZHSX6.js} +9 -9
  147. package/dist/{chunk-D3J5SLQK.js → chunk-EJHEWCGQ.js} +81 -20
  148. package/dist/chunk-EJHEWCGQ.js.map +1 -0
  149. package/dist/{chunk-WUNIWKY4.js → chunk-ELIL2A37.js} +6 -6
  150. package/dist/{chunk-E6PNLPGJ.js → chunk-FZP32336.js} +806 -470
  151. package/dist/chunk-FZP32336.js.map +1 -0
  152. package/dist/{chunk-HZFHQ4AQ.js → chunk-G7A5HLUS.js} +23 -17
  153. package/dist/chunk-G7A5HLUS.js.map +1 -0
  154. package/dist/{chunk-CINZGPSJ.js → chunk-GUMZC2BO.js} +2 -2
  155. package/dist/{chunk-H24WNPA2.js → chunk-GWFSVJ4P.js} +3 -3
  156. package/dist/{chunk-7XC2HX75.js → chunk-GYPQL6XN.js} +157 -16
  157. package/dist/chunk-GYPQL6XN.js.map +1 -0
  158. package/dist/{chunk-TSH56VPU.js → chunk-HAYSYUAB.js} +2 -2
  159. package/dist/{chunk-TDHTVMPG.js → chunk-HFPASSFV.js} +7 -2
  160. package/dist/chunk-HFPASSFV.js.map +1 -0
  161. package/dist/chunk-J2WC5LF4.js +395 -0
  162. package/dist/chunk-J2WC5LF4.js.map +1 -0
  163. package/dist/{chunk-PKNLM44P.js → chunk-JH6BPLOP.js} +9 -9
  164. package/dist/{chunk-KXB4VXHY.js → chunk-JIYDRBVZ.js} +2 -2
  165. package/dist/chunk-JV3C2MNQ.js +74 -0
  166. package/dist/chunk-JV3C2MNQ.js.map +1 -0
  167. package/dist/{chunk-AV5ZEH4M.js → chunk-KVJRXN2E.js} +2 -2
  168. package/dist/{chunk-JVLCVFQ4.js → chunk-KXEFRMCF.js} +3 -3
  169. package/dist/{chunk-WFTIGIIS.js → chunk-L6CQ7WIW.js} +5 -5
  170. package/dist/{chunk-EJUEXZHX.js → chunk-LLJMAULE.js} +2 -2
  171. package/dist/{chunk-N5Z4EVOR.js → chunk-LNEWDF2A.js} +36 -11
  172. package/dist/chunk-LNEWDF2A.js.map +1 -0
  173. package/dist/{chunk-AS7YMSL6.js → chunk-M23RF3LJ.js} +4 -4
  174. package/dist/{chunk-UYLMNVY6.js → chunk-MDISBSYA.js} +16 -9
  175. package/dist/chunk-MDISBSYA.js.map +1 -0
  176. package/dist/{chunk-3F2LKUMU.js → chunk-NIS256NW.js} +2 -2
  177. package/dist/{chunk-YIAA2X3D.js → chunk-NK5RGJ65.js} +3 -3
  178. package/dist/chunk-NLDVVWCL.js +84 -0
  179. package/dist/chunk-NLDVVWCL.js.map +1 -0
  180. package/dist/{chunk-OQ5PRDDS.js → chunk-NTOIP2E6.js} +6 -6
  181. package/dist/{chunk-HLPD7B7P.js → chunk-NUEQKLNB.js} +2 -2
  182. package/dist/{chunk-4J7G5SY4.js → chunk-NZBZ7IS2.js} +72 -24
  183. package/dist/chunk-NZBZ7IS2.js.map +1 -0
  184. package/dist/{chunk-3TBLDMJA.js → chunk-O4KMGRXE.js} +5 -2
  185. package/dist/chunk-O4KMGRXE.js.map +1 -0
  186. package/dist/{chunk-33PLLLL7.js → chunk-P7NGM24P.js} +6 -6
  187. package/dist/{chunk-7TWUCYER.js → chunk-PNRA7FAD.js} +7 -7
  188. package/dist/{chunk-5I4M26Q7.js → chunk-QBSFOKY6.js} +4 -4
  189. package/dist/{chunk-QJAQNXWI.js → chunk-QCECHYZL.js} +76 -79
  190. package/dist/chunk-QCECHYZL.js.map +1 -0
  191. package/dist/{chunk-P4DRWEYC.js → chunk-QVSBTCVP.js} +2 -2
  192. package/dist/{chunk-AAIUERNB.js → chunk-R5RFK3CB.js} +6 -6
  193. package/dist/{chunk-WDISJRMG.js → chunk-RMMVQQA6.js} +2 -2
  194. package/dist/{chunk-KWMXR7XS.js → chunk-S2V7RUCL.js} +8 -1
  195. package/dist/{chunk-KWMXR7XS.js.map → chunk-S2V7RUCL.js.map} +1 -1
  196. package/dist/{chunk-5SM35XZR.js → chunk-S5NZBKKQ.js} +2 -2
  197. package/dist/{chunk-VNA7W7QF.js → chunk-SVH57F5Z.js} +12 -4
  198. package/dist/chunk-SVH57F5Z.js.map +1 -0
  199. package/dist/{chunk-WIPEXG6R.js → chunk-SXIMQLGV.js} +2 -2
  200. package/dist/{chunk-RVLJEII5.js → chunk-SYUBB3WM.js} +256 -187
  201. package/dist/chunk-SYUBB3WM.js.map +1 -0
  202. package/dist/{chunk-OAEQLRCY.js → chunk-TN76AKO3.js} +5 -5
  203. package/dist/{chunk-QN25OCUF.js → chunk-TQ4GD737.js} +5 -5
  204. package/dist/{chunk-VCD4PSK2.js → chunk-TQZ4DVBC.js} +7 -4
  205. package/dist/chunk-TQZ4DVBC.js.map +1 -0
  206. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  207. package/dist/{chunk-DNWXFTLD.js → chunk-TYISDI6B.js} +2 -2
  208. package/dist/{chunk-4LMA77JH.js → chunk-U2VLVBBH.js} +3 -3
  209. package/dist/{chunk-5ZE7QHTK.js → chunk-ULVR5KG7.js} +5 -5
  210. package/dist/{chunk-NVRYW264.js → chunk-UQWIKLQK.js} +18 -15
  211. package/dist/chunk-UQWIKLQK.js.map +1 -0
  212. package/dist/{chunk-YV32N67O.js → chunk-URS5GSM7.js} +1 -1
  213. package/dist/chunk-URS5GSM7.js.map +1 -0
  214. package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
  215. package/dist/{chunk-S2BBISHU.js → chunk-VANZKHTN.js} +3 -3
  216. package/dist/chunk-VHFXP27N.js +250 -0
  217. package/dist/chunk-VHFXP27N.js.map +1 -0
  218. package/dist/{chunk-3Y224NYC.js → chunk-VYISFWVX.js} +2 -2
  219. package/dist/{chunk-TIHMZFIV.js → chunk-W3IC7QOY.js} +3 -3
  220. package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
  221. package/dist/{chunk-P2BM76KT.js → chunk-WAS4HV46.js} +174 -43
  222. package/dist/chunk-WAS4HV46.js.map +1 -0
  223. package/dist/{chunk-57QKLRBV.js → chunk-WB7JSQCP.js} +2 -1
  224. package/dist/chunk-WB7JSQCP.js.map +1 -0
  225. package/dist/chunk-WGP57SR3.js +68 -0
  226. package/dist/chunk-WGP57SR3.js.map +1 -0
  227. package/dist/{chunk-ECK75GDJ.js → chunk-WQIHRA5F.js} +43 -24
  228. package/dist/chunk-WQIHRA5F.js.map +1 -0
  229. package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
  230. package/dist/{chunk-T2TTP3KU.js → chunk-X4IDNPOS.js} +2 -2
  231. package/dist/{chunk-BLAKS3CP.js → chunk-XL3TATMJ.js} +3 -3
  232. package/dist/{chunk-W4XJFLAL.js → chunk-XPRJSHNI.js} +2 -2
  233. package/dist/{chunk-5TFP4CUL.js → chunk-XQ3HXAQH.js} +14 -11
  234. package/dist/chunk-XQ3HXAQH.js.map +1 -0
  235. package/dist/{chunk-VWAXN2BN.js → chunk-XSFHWBQO.js} +93 -31
  236. package/dist/chunk-XSFHWBQO.js.map +1 -0
  237. package/dist/{chunk-DL7ZD3JH.js → chunk-XTAUXTDO.js} +14 -9
  238. package/dist/chunk-XTAUXTDO.js.map +1 -0
  239. package/dist/{chunk-JE7EK33X.js → chunk-Y7HRYCNW.js} +2 -2
  240. package/dist/{chunk-E6EE5B67.js → chunk-YK6BDDHP.js} +4 -4
  241. package/dist/{chunk-ES36HTSC.js → chunk-YLHM5BQQ.js} +3 -3
  242. package/dist/{chunk-RN7DY3FC.js → chunk-YMAQDHQM.js} +31 -12
  243. package/dist/chunk-YMAQDHQM.js.map +1 -0
  244. package/dist/{chunk-ULARSG5Z.js → chunk-YN6ASZUG.js} +10 -8
  245. package/dist/{chunk-ULARSG5Z.js.map → chunk-YN6ASZUG.js.map} +1 -1
  246. package/dist/{chunk-IKKWIPYN.js → chunk-YYQAKIDJ.js} +37 -1
  247. package/dist/chunk-YYQAKIDJ.js.map +1 -0
  248. package/dist/{chunk-BJKPPZ6Z.js → chunk-ZFGZ6PZ2.js} +2 -2
  249. package/dist/{chunk-CJ2ZR7UA.js → chunk-ZI32MKDW.js} +267 -214
  250. package/dist/chunk-ZI32MKDW.js.map +1 -0
  251. package/dist/{chunk-64UDOIMI.js → chunk-ZLQ37WJX.js} +2 -2
  252. package/dist/chunk-ZMAYKGPN.js +351 -0
  253. package/dist/chunk-ZMAYKGPN.js.map +1 -0
  254. package/dist/{cli-BUGN3d6_.d.ts → cli-BBHDtG36.d.ts} +5 -5
  255. package/dist/cli.d.ts +16 -12
  256. package/dist/cli.js +138 -124
  257. package/dist/compounding/engine.d.ts +3 -2
  258. package/dist/compounding/engine.js +24 -23
  259. package/dist/compounding/preference-consolidator.d.ts +2 -1
  260. package/dist/compression-optimizer.d.ts +2 -1
  261. package/dist/config.d.ts +2 -1
  262. package/dist/config.js +10 -8
  263. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  264. package/dist/connectors/codex-materialize-runner.js +23 -22
  265. package/dist/connectors/codex-materialize.d.ts +2 -1
  266. package/dist/connectors/index.d.ts +2 -1
  267. package/dist/connectors/index.js +26 -25
  268. package/dist/consolidation-provenance-check.d.ts +3 -2
  269. package/dist/consolidation-provenance-check.js +4 -4
  270. package/dist/consolidation-undo.d.ts +3 -2
  271. package/dist/consolidation-undo.js +10 -7
  272. package/dist/consolidation-undo.js.map +1 -1
  273. package/dist/contradiction/index.d.ts +3 -2
  274. package/dist/converge-config.d.ts +2 -1
  275. package/dist/convergence-refresh.d.ts +4 -3
  276. package/dist/convergence-refresh.js +27 -26
  277. package/dist/conversation-index/backend.d.ts +2 -1
  278. package/dist/conversation-index/backend.js +2 -2
  279. package/dist/conversation-index/chunker.d.ts +2 -1
  280. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  281. package/dist/conversation-index/indexer.d.ts +2 -1
  282. package/dist/conversation-index/search.d.ts +2 -1
  283. package/dist/corpus-watermark.d.ts +2 -1
  284. package/dist/corpus-watermark.js +42 -41
  285. package/dist/day-summary.d.ts +2 -1
  286. package/dist/delinearize.d.ts +2 -1
  287. package/dist/direct-answer-wiring.d.ts +2 -1
  288. package/dist/direct-answer-wiring.js +2 -2
  289. package/dist/direct-answer.d.ts +2 -1
  290. package/dist/embedding-fallback.d.ts +2 -1
  291. package/dist/embedding-fallback.js +2 -2
  292. package/dist/enrichment/index.d.ts +2 -1
  293. package/dist/entity-retrieval-boundaries.js +1 -1
  294. package/dist/entity-retrieval.d.ts +3 -2
  295. package/dist/entity-retrieval.js +24 -23
  296. package/dist/entity-schema.d.ts +2 -1
  297. package/dist/explicit-capture.d.ts +9 -8
  298. package/dist/explicit-capture.js +11 -9
  299. package/dist/external-wiki-access.d.ts +127 -0
  300. package/dist/external-wiki-access.js +186 -0
  301. package/dist/external-wiki-access.js.map +1 -0
  302. package/dist/external-wiki-cli.d.ts +13 -0
  303. package/dist/external-wiki-cli.js +96 -0
  304. package/dist/external-wiki-cli.js.map +1 -0
  305. package/dist/external-wiki-collection-registration.d.ts +39 -0
  306. package/dist/external-wiki-collection-registration.js +79 -0
  307. package/dist/external-wiki-collection-registration.js.map +1 -0
  308. package/dist/external-wiki-collection.d.ts +50 -0
  309. package/dist/external-wiki-collection.js +387 -0
  310. package/dist/external-wiki-collection.js.map +1 -0
  311. package/dist/external-wiki-config.d.ts +13 -0
  312. package/dist/external-wiki-config.js +13 -0
  313. package/dist/external-wiki-config.js.map +1 -0
  314. package/dist/external-wiki-guard.d.ts +11 -0
  315. package/dist/external-wiki-guard.js +18 -0
  316. package/dist/external-wiki-guard.js.map +1 -0
  317. package/dist/external-wiki-mcp-tools.d.ts +123 -0
  318. package/dist/external-wiki-mcp-tools.js +8 -0
  319. package/dist/external-wiki-mcp-tools.js.map +1 -0
  320. package/dist/external-wiki-search.d.ts +42 -0
  321. package/dist/external-wiki-search.js +11 -0
  322. package/dist/external-wiki-search.js.map +1 -0
  323. package/dist/external-wiki.d.ts +43 -0
  324. package/dist/external-wiki.js +16 -0
  325. package/dist/external-wiki.js.map +1 -0
  326. package/dist/extraction-error-classification.d.ts +2 -1
  327. package/dist/extraction-faithfulness.d.ts +2 -1
  328. package/dist/extraction-judge-telemetry.d.ts +2 -1
  329. package/dist/extraction-judge-training.d.ts +2 -1
  330. package/dist/extraction-judge.d.ts +2 -1
  331. package/dist/extraction-liveness.d.ts +2 -1
  332. package/dist/extraction-source-grounding-helpers.d.ts +5 -3
  333. package/dist/extraction-source-grounding-helpers.js +1 -1
  334. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  335. package/dist/extraction-source-grounding-rules.js +2 -2
  336. package/dist/extraction-source-grounding.d.ts +2 -1
  337. package/dist/extraction-source-grounding.js +5 -5
  338. package/dist/extraction.d.ts +2 -1
  339. package/dist/extraction.js +45 -43
  340. package/dist/fallback-llm.d.ts +2 -1
  341. package/dist/graph-dashboard-diff.d.ts +2 -1
  342. package/dist/graph-dashboard-key.d.ts +2 -1
  343. package/dist/graph-dashboard-parser.d.ts +2 -1
  344. package/dist/graph-edge-reinforcement.d.ts +2 -1
  345. package/dist/graph-snapshot.d.ts +2 -1
  346. package/dist/graph.d.ts +2 -1
  347. package/dist/harmonic-retrieval.js +2 -2
  348. package/dist/importance.d.ts +2 -1
  349. package/dist/importers/index.d.ts +2 -1
  350. package/dist/in-flight-reads.d.ts +2 -1
  351. package/dist/index.d.ts +362 -350
  352. package/dist/index.js +291 -259
  353. package/dist/intent.d.ts +2 -1
  354. package/dist/lcm/engine.d.ts +2 -1
  355. package/dist/lcm/engine.js +3 -3
  356. package/dist/lcm/index.d.ts +2 -1
  357. package/dist/lcm/index.js +8 -8
  358. package/dist/lcm/tools.d.ts +2 -1
  359. package/dist/lifecycle.d.ts +2 -1
  360. package/dist/live-connectors-runner.d.ts +2 -1
  361. package/dist/local-llm.d.ts +2 -1
  362. package/dist/local-llm.js +2 -2
  363. package/dist/local-model-endpoint.d.ts +2 -1
  364. package/dist/maintenance/memory-governance.d.ts +2 -1
  365. package/dist/maintenance/memory-governance.js +24 -23
  366. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  367. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +24 -23
  368. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  369. package/dist/maintenance/rebuild-memory-projection.js +26 -25
  370. package/dist/{maintenance-LbuS2rUA.d.ts → maintenance-D2mveyCd.d.ts} +3 -3
  371. package/dist/mcp-memory-inspector-app.d.ts +14 -10
  372. package/dist/mcp-read-only-tools.js +1 -1
  373. package/dist/memory-action-policy.d.ts +2 -1
  374. package/dist/memory-cache.d.ts +2 -1
  375. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  376. package/dist/memory-projection-store.d.ts +2 -1
  377. package/dist/memory-provenance.d.ts +2 -1
  378. package/dist/memory-worth-outcomes.d.ts +3 -2
  379. package/dist/models-json.d.ts +2 -1
  380. package/dist/namespaces/migrate.d.ts +4 -3
  381. package/dist/namespaces/migrate.js +40 -39
  382. package/dist/namespaces/principal.d.ts +2 -1
  383. package/dist/namespaces/search.d.ts +2 -1
  384. package/dist/namespaces/search.js +18 -18
  385. package/dist/namespaces/storage.d.ts +4 -3
  386. package/dist/namespaces/storage.js +23 -22
  387. package/dist/native-knowledge.d.ts +2 -1
  388. package/dist/offline-sync-impression-drain.d.ts +2 -1
  389. package/dist/offline-sync-impression-drain.js +11 -9
  390. package/dist/offline-sync.d.ts +29 -3
  391. package/dist/offline-sync.js +6 -2
  392. package/dist/operator-doctor-corpus.d.ts +2 -1
  393. package/dist/operator-doctor-corpus.js +45 -44
  394. package/dist/operator-doctor-replica.d.ts +2 -1
  395. package/dist/operator-doctor-replica.js +3 -3
  396. package/dist/operator-toolkit.d.ts +4 -3
  397. package/dist/operator-toolkit.js +59 -55
  398. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  399. package/dist/orchestration/maintenance.d.ts +5 -4
  400. package/dist/orchestration/maintenance.js +36 -33
  401. package/dist/{orchestrator-rHiWt32X.d.ts → orchestrator-DJYlwiUv.d.ts} +14 -7
  402. package/dist/orchestrator.d.ts +9 -8
  403. package/dist/orchestrator.js +201 -189
  404. package/dist/page-versioning.js +3 -3
  405. package/dist/patterns-cli.d.ts +2 -1
  406. package/dist/{pipeline-W_97O8BV.d.ts → pipeline-CNjY4wk3.d.ts} +1 -1
  407. package/dist/policy-runtime.d.ts +2 -1
  408. package/dist/policy-runtime.js +1 -1
  409. package/dist/proactive-contention.d.ts +2 -1
  410. package/dist/provenance.d.ts +2 -1
  411. package/dist/provenance.js +2 -2
  412. package/dist/{qmd-LWtMofAf.d.ts → qmd-C0UDZidt.d.ts} +9 -7
  413. package/dist/qmd-preflight.d.ts +5 -4
  414. package/dist/qmd-preflight.js +2 -2
  415. package/dist/qmd-recall-cache.d.ts +2 -1
  416. package/dist/qmd.d.ts +4 -3
  417. package/dist/qmd.js +5 -5
  418. package/dist/recall-concurrency-config.d.ts +2 -1
  419. package/dist/recall-disclosure-escalation.d.ts +2 -1
  420. package/dist/recall-explain-renderer.d.ts +2 -1
  421. package/dist/recall-explain-renderer.js +3 -3
  422. package/dist/recall-memory-map.d.ts +2 -1
  423. package/dist/recall-planner-llm.d.ts +2 -1
  424. package/dist/recall-state.d.ts +2 -1
  425. package/dist/recall-tag-filter.d.ts +2 -1
  426. package/dist/recall-timings.d.ts +2 -1
  427. package/dist/recall-xray-cli.d.ts +2 -1
  428. package/dist/recall-xray-cli.js +4 -4
  429. package/dist/recall-xray-renderer.d.ts +2 -1
  430. package/dist/recall-xray-renderer.js +3 -3
  431. package/dist/recall-xray.d.ts +8 -1
  432. package/dist/recall-xray.js +2 -2
  433. package/dist/reconcile/cursor.d.ts +12 -2
  434. package/dist/reconcile/cursor.js +46 -7
  435. package/dist/reconcile/cursor.js.map +1 -1
  436. package/dist/reconcile/manifest.d.ts +9 -2
  437. package/dist/reconcile/manifest.js +15 -268
  438. package/dist/reconcile/manifest.js.map +1 -1
  439. package/dist/reconcile/plan.d.ts +4 -1
  440. package/dist/reconcile/plan.js +4 -4
  441. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  442. package/dist/replay/normalizers/claude.d.ts +2 -1
  443. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  444. package/dist/replay/normalizers/shared.d.ts +2 -1
  445. package/dist/replay/runner.d.ts +2 -1
  446. package/dist/replay/types.d.ts +2 -1
  447. package/dist/replica-divergence.d.ts +2 -1
  448. package/dist/replica-divergence.js +2 -2
  449. package/dist/replica-peers-config.d.ts +2 -1
  450. package/dist/resolve-auth-token.d.ts +2 -1
  451. package/dist/resume-bundles.js +12 -10
  452. package/dist/retrieval-agents.d.ts +4 -3
  453. package/dist/retrieval-agents.js +2 -2
  454. package/dist/retrieval-tiers.d.ts +2 -1
  455. package/dist/routing/engine.d.ts +2 -1
  456. package/dist/routing/store.d.ts +2 -1
  457. package/dist/salvage-envelope.d.ts +2 -1
  458. package/dist/schemas.d.ts +32 -32
  459. package/dist/{scope-profiles-BiQKOE-p.d.ts → scope-profiles-BJzp2F5A.d.ts} +1 -1
  460. package/dist/search/embed-helper.d.ts +2 -1
  461. package/dist/search/embed-helper.js +3 -3
  462. package/dist/search/factory.d.ts +4 -2
  463. package/dist/search/factory.js +20 -18
  464. package/dist/search/index.d.ts +2 -1
  465. package/dist/search/index.js +22 -22
  466. package/dist/search/lancedb-backend.d.ts +2 -1
  467. package/dist/search/lancedb-backend.js +4 -4
  468. package/dist/search/meilisearch-backend.d.ts +2 -1
  469. package/dist/search/meilisearch-backend.js +4 -4
  470. package/dist/search/noop-backend.d.ts +2 -1
  471. package/dist/search/orama-backend.d.ts +2 -1
  472. package/dist/search/orama-backend.js +4 -4
  473. package/dist/search/port.d.ts +18 -1
  474. package/dist/search/port.js +1 -1
  475. package/dist/search/remote-backend.d.ts +2 -1
  476. package/dist/search/remote-backend.js +2 -2
  477. package/dist/secure-store/index.js +2 -2
  478. package/dist/{semantic-consolidation-dHYCyqgh.d.ts → semantic-consolidation-D4KAZO2G.d.ts} +1 -1
  479. package/dist/semantic-consolidation.d.ts +3 -2
  480. package/dist/semantic-consolidation.js +25 -24
  481. package/dist/semantic-rule-promotion.js +23 -22
  482. package/dist/semantic-rule-verifier.d.ts +2 -1
  483. package/dist/semantic-rule-verifier.js +24 -23
  484. package/dist/{service-DJG3KCQ4.d.ts → service-BeDxSqE-.d.ts} +2 -2
  485. package/dist/session-observer-bands.d.ts +2 -1
  486. package/dist/session-observer-state.d.ts +2 -1
  487. package/dist/shared-context/manager.d.ts +2 -1
  488. package/dist/shared-context/manager.js +2 -2
  489. package/dist/signal.d.ts +2 -1
  490. package/dist/source-agent-qualifier.d.ts +2 -1
  491. package/dist/source-agent-qualifier.js +42 -40
  492. package/dist/{storage-F9FVh-w9.d.ts → storage-DfjxusTE.d.ts} +24 -12
  493. package/dist/storage.d.ts +3 -2
  494. package/dist/storage.js +25 -24
  495. package/dist/summarizer.d.ts +2 -1
  496. package/dist/summarizer.js +5 -5
  497. package/dist/summary-snapshot.d.ts +2 -1
  498. package/dist/temporal-supersession.d.ts +3 -2
  499. package/dist/temporal-timeline-recall.d.ts +2 -1
  500. package/dist/temporal-validity.d.ts +2 -1
  501. package/dist/threading.d.ts +2 -1
  502. package/dist/tier-migration.d.ts +3 -2
  503. package/dist/tier-routing.d.ts +2 -1
  504. package/dist/tool-scoped-memory.d.ts +5 -1
  505. package/dist/tool-scoped-memory.js +3 -1
  506. package/dist/topics.d.ts +2 -1
  507. package/dist/transcript.d.ts +2 -1
  508. package/dist/transfer/capsule-import.js +4 -4
  509. package/dist/transfer/types.d.ts +12 -12
  510. package/dist/trust-score-stage.d.ts +2 -1
  511. package/dist/trust-score.d.ts +2 -1
  512. package/dist/{types-rEwubvim.d.ts → types-yX_FwERf.d.ts} +8 -1
  513. package/dist/types.d.ts +2 -1
  514. package/dist/types.js +1 -1
  515. package/dist/utility-runtime.d.ts +2 -1
  516. package/dist/verified-recall.js +24 -23
  517. package/dist/write-envelope.d.ts +2 -1
  518. package/package.json +2 -2
  519. package/src/abort-error.ts +17 -0
  520. package/src/access-admin-ops-surface.ts +1 -0
  521. package/src/access-boundary.ts +1 -0
  522. package/src/access-coding-context-resolution.ts +42 -0
  523. package/src/access-extraction-force-flush.ts +38 -2
  524. package/src/access-http-lcm-compaction.ts +5 -2
  525. package/src/access-http-offline-stream.ts +79 -0
  526. package/src/access-http.test.ts +310 -3
  527. package/src/access-http.ts +85 -21
  528. package/src/access-mcp-output-schemas.ts +36 -0
  529. package/src/access-mcp.test.ts +95 -1
  530. package/src/access-mcp.ts +7 -9
  531. package/src/access-observe-helpers.ts +64 -22
  532. package/src/access-observe-write-surface.ts +8 -0
  533. package/src/access-offline-manifest.ts +54 -0
  534. package/src/access-operations-batch.ts +3 -3
  535. package/src/access-operations.ts +13 -7
  536. package/src/access-recall-concurrency.ts +3 -27
  537. package/src/access-recall-surface.ts +3 -0
  538. package/src/access-service-health.test.ts +32 -7
  539. package/src/access-service-namespace.test.ts +55 -0
  540. package/src/access-service-observe-idempotency.test.ts +34 -2
  541. package/src/access-service-observe-lcm-parity.test.ts +138 -3
  542. package/src/access-service-observe-scope.test.ts +160 -1
  543. package/src/access-service-offline-file-content.test.ts +345 -1
  544. package/src/access-service.ts +86 -59
  545. package/src/access-surface-catalog.ts +4 -0
  546. package/src/admin/admin-surfaces.ts +2 -0
  547. package/src/binary-lifecycle/pipeline.test.ts +106 -1
  548. package/src/binary-lifecycle/pipeline.ts +3 -0
  549. package/src/coding/git-context.test.ts +47 -0
  550. package/src/coding/git-context.ts +129 -27
  551. package/src/config.test.ts +24 -0
  552. package/src/config.ts +9 -12
  553. package/src/connector-provenance.test.ts +101 -0
  554. package/src/consolidation-undo.ts +3 -0
  555. package/src/convergence-refresh.ts +14 -2
  556. package/src/correction/correction-access-wiring.ts +9 -7
  557. package/src/correction/correction-executor.test.ts +206 -2
  558. package/src/correction/correction-executor.ts +29 -20
  559. package/src/correction/correction-planner.test.ts +36 -0
  560. package/src/correction/correction-planner.ts +9 -15
  561. package/src/correction/correction-service.ts +3 -1
  562. package/src/correction/correction-storage-integration.test.ts +77 -0
  563. package/src/correction/correction-surfaces.test.ts +41 -28
  564. package/src/correction/passive-capture.test.ts +59 -0
  565. package/src/correction/passive-capture.ts +4 -1
  566. package/src/entity-retrieval-boundaries.ts +17 -4
  567. package/src/entity-retrieval.ts +27 -6
  568. package/src/external-wiki-access.test.ts +65 -0
  569. package/src/external-wiki-access.ts +31 -0
  570. package/src/external-wiki-cli.ts +92 -0
  571. package/src/external-wiki-collection-registration.test.ts +163 -0
  572. package/src/external-wiki-collection-registration.ts +101 -0
  573. package/src/external-wiki-collection.test.ts +502 -0
  574. package/src/external-wiki-collection.ts +503 -0
  575. package/src/external-wiki-config.test.ts +135 -0
  576. package/src/external-wiki-config.ts +100 -0
  577. package/src/external-wiki-guard.ts +83 -0
  578. package/src/external-wiki-mcp-tools.ts +23 -0
  579. package/src/external-wiki-search.test.ts +301 -0
  580. package/src/external-wiki-search.ts +362 -0
  581. package/src/external-wiki.test.ts +240 -0
  582. package/src/external-wiki.ts +453 -0
  583. package/src/extraction-scope-source-agent.test.ts +21 -0
  584. package/src/extraction-source-grounding-helpers.ts +243 -53
  585. package/src/extraction-source-grounding-rules.ts +133 -39
  586. package/src/extraction-source-grounding.test.ts +363 -33
  587. package/src/extraction-timeout.test.ts +1 -0
  588. package/src/extraction-watermark.test.ts +150 -7
  589. package/src/extraction.ts +8 -1
  590. package/src/index.ts +8 -0
  591. package/src/mcp-read-only-tools.ts +1 -0
  592. package/src/offline-sync.test.ts +194 -0
  593. package/src/offline-sync.ts +217 -13
  594. package/src/orchestration/external-wiki-recall-guard.test.ts +94 -0
  595. package/src/orchestration/extraction-persist.ts +19 -2
  596. package/src/orchestration/extraction-run-helpers.ts +37 -19
  597. package/src/orchestration/extraction-run.test.ts +171 -2
  598. package/src/orchestration/extraction-run.ts +11 -13
  599. package/src/orchestration/extraction-watermark.ts +106 -17
  600. package/src/orchestration/generic-recall-paths.ts +14 -0
  601. package/src/orchestration/orchestrator-helpers.ts +2 -0
  602. package/src/orchestration/orchestrator-init.ts +9 -0
  603. package/src/orchestration/recall-internal-deps.ts +6 -0
  604. package/src/orchestration/recall-internal.ts +154 -33
  605. package/src/orchestration/recall-rerank-coordinator.ts +60 -25
  606. package/src/orchestration/recall-search-pipeline.test.ts +75 -1
  607. package/src/orchestration/recall-search-pipeline.ts +50 -10
  608. package/src/orchestrator-convergence-refresh.test.ts +36 -2
  609. package/src/orchestrator.ts +13 -3
  610. package/src/page-versioning.ts +5 -19
  611. package/src/procedural/procedure-recall.ts +5 -1
  612. package/src/provenance-surfaces.test.ts +3 -0
  613. package/src/qmd-client.test.ts +78 -17
  614. package/src/qmd.test.ts +24 -0
  615. package/src/qmd.ts +224 -315
  616. package/src/recall-explain-renderer.ts +3 -0
  617. package/src/recall-rerank-coordinator.test.ts +61 -0
  618. package/src/recall-xray-renderer.test.ts +6 -0
  619. package/src/recall-xray.test.ts +88 -1
  620. package/src/recall-xray.ts +15 -0
  621. package/src/reconcile/cursor.test.ts +48 -0
  622. package/src/reconcile/cursor.ts +58 -11
  623. package/src/reconcile/manifest.test.ts +4 -0
  624. package/src/reconcile/manifest.ts +41 -51
  625. package/src/reconcile/plan.test.ts +4 -0
  626. package/src/reconcile/plan.ts +28 -16
  627. package/src/search/factory.ts +6 -6
  628. package/src/search/port.ts +25 -9
  629. package/src/secure-store/secure-fs.ts +20 -12
  630. package/src/secure-store/secure-store.test.ts +41 -2
  631. package/src/spaces/index.test.ts +61 -2
  632. package/src/spaces/index.ts +44 -18
  633. package/src/storage/entity-alias-config.ts +97 -0
  634. package/src/storage/entity-canonical-id-lock.ts +53 -23
  635. package/src/storage/entity-canonical-id-migration.ts +53 -22
  636. package/src/storage/entity-canonical-id-references.ts +3 -0
  637. package/src/storage/entity-id-safety.ts +7 -0
  638. package/src/storage/entity-store.ts +6 -2
  639. package/src/storage/memory-frontmatter-metadata.ts +4 -9
  640. package/src/storage/memory-migration-serialization.ts +10 -15
  641. package/src/storage/tombstone-blocked-capture-mutation.ts +52 -64
  642. package/src/storage/tombstone-blocked-capture-sync.ts +244 -199
  643. package/src/storage-deletion-revisions.test.ts +91 -0
  644. package/src/storage-fact-hash-index-defer.test.ts +446 -163
  645. package/src/storage.ts +534 -245
  646. package/src/tool-scoped-memory.ts +10 -0
  647. package/src/transfer/capsule-import.ts +13 -0
  648. package/src/transfer/capsule-merge.ts +13 -0
  649. package/src/trust-score-recall-paths.test.ts +75 -1
  650. package/src/types.ts +7 -3
  651. package/dist/capsule-merge-IDWJPCWK.js.map +0 -1
  652. package/dist/chunk-3CE77VAP.js.map +0 -1
  653. package/dist/chunk-3TBLDMJA.js.map +0 -1
  654. package/dist/chunk-4J7G5SY4.js.map +0 -1
  655. package/dist/chunk-57QKLRBV.js.map +0 -1
  656. package/dist/chunk-5TFP4CUL.js.map +0 -1
  657. package/dist/chunk-7XC2HX75.js.map +0 -1
  658. package/dist/chunk-A5OJCXZL.js.map +0 -1
  659. package/dist/chunk-BUE5E2HL.js.map +0 -1
  660. package/dist/chunk-CJ2ZR7UA.js.map +0 -1
  661. package/dist/chunk-CUM2BBPN.js.map +0 -1
  662. package/dist/chunk-D3J5SLQK.js.map +0 -1
  663. package/dist/chunk-DL7ZD3JH.js.map +0 -1
  664. package/dist/chunk-DLVPUX7U.js.map +0 -1
  665. package/dist/chunk-E6PNLPGJ.js.map +0 -1
  666. package/dist/chunk-ECK75GDJ.js.map +0 -1
  667. package/dist/chunk-HREE4JHI.js.map +0 -1
  668. package/dist/chunk-HZFHQ4AQ.js.map +0 -1
  669. package/dist/chunk-IKKWIPYN.js.map +0 -1
  670. package/dist/chunk-J7VGGECD.js.map +0 -1
  671. package/dist/chunk-N5Z4EVOR.js.map +0 -1
  672. package/dist/chunk-NVRYW264.js.map +0 -1
  673. package/dist/chunk-P2BM76KT.js.map +0 -1
  674. package/dist/chunk-PVGDJXVK.js +0 -21
  675. package/dist/chunk-QJAQNXWI.js.map +0 -1
  676. package/dist/chunk-RN7DY3FC.js.map +0 -1
  677. package/dist/chunk-RVLJEII5.js.map +0 -1
  678. package/dist/chunk-S2NCTZGJ.js.map +0 -1
  679. package/dist/chunk-TDHTVMPG.js.map +0 -1
  680. package/dist/chunk-UYLMNVY6.js.map +0 -1
  681. package/dist/chunk-VCD4PSK2.js.map +0 -1
  682. package/dist/chunk-VNA7W7QF.js.map +0 -1
  683. package/dist/chunk-VWAXN2BN.js.map +0 -1
  684. package/dist/chunk-WOCNN776.js.map +0 -1
  685. package/dist/chunk-XYTOI63Z.js.map +0 -1
  686. package/dist/chunk-YV32N67O.js.map +0 -1
  687. /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
  688. /package/dist/{chunk-VUPTKTDV.js.map → chunk-2MRHJNWL.js.map} +0 -0
  689. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  690. /package/dist/{chunk-5IVLTFOV.js.map → chunk-44N6ESJ4.js.map} +0 -0
  691. /package/dist/{chunk-HO3QBJEY.js.map → chunk-5546W5SI.js.map} +0 -0
  692. /package/dist/{chunk-U7GW7NE7.js.map → chunk-5CEECY6P.js.map} +0 -0
  693. /package/dist/{chunk-4UH4BTGK.js.map → chunk-5SNZSWWR.js.map} +0 -0
  694. /package/dist/{chunk-6CZPDBJS.js.map → chunk-5U7ID3EZ.js.map} +0 -0
  695. /package/dist/{chunk-GF22HWS2.js.map → chunk-6NNNURLK.js.map} +0 -0
  696. /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
  697. /package/dist/{chunk-E5UK4VPE.js.map → chunk-7SHJHPTY.js.map} +0 -0
  698. /package/dist/{chunk-UVIKWC7M.js.map → chunk-7YERSTN7.js.map} +0 -0
  699. /package/dist/{chunk-S5SLVSVY.js.map → chunk-BQIFZ2MP.js.map} +0 -0
  700. /package/dist/{chunk-E53DSZEN.js.map → chunk-C26TE27X.js.map} +0 -0
  701. /package/dist/{chunk-LZ4LDKHZ.js.map → chunk-CLB32OHM.js.map} +0 -0
  702. /package/dist/{chunk-Q6IP2ARR.js.map → chunk-CSOYVTRX.js.map} +0 -0
  703. /package/dist/{chunk-XOQSEF7X.js.map → chunk-CVILPI77.js.map} +0 -0
  704. /package/dist/{chunk-PDLBLTOK.js.map → chunk-EITZHSX6.js.map} +0 -0
  705. /package/dist/{chunk-WUNIWKY4.js.map → chunk-ELIL2A37.js.map} +0 -0
  706. /package/dist/{chunk-CINZGPSJ.js.map → chunk-GUMZC2BO.js.map} +0 -0
  707. /package/dist/{chunk-H24WNPA2.js.map → chunk-GWFSVJ4P.js.map} +0 -0
  708. /package/dist/{chunk-TSH56VPU.js.map → chunk-HAYSYUAB.js.map} +0 -0
  709. /package/dist/{chunk-PKNLM44P.js.map → chunk-JH6BPLOP.js.map} +0 -0
  710. /package/dist/{chunk-KXB4VXHY.js.map → chunk-JIYDRBVZ.js.map} +0 -0
  711. /package/dist/{chunk-AV5ZEH4M.js.map → chunk-KVJRXN2E.js.map} +0 -0
  712. /package/dist/{chunk-JVLCVFQ4.js.map → chunk-KXEFRMCF.js.map} +0 -0
  713. /package/dist/{chunk-WFTIGIIS.js.map → chunk-L6CQ7WIW.js.map} +0 -0
  714. /package/dist/{chunk-EJUEXZHX.js.map → chunk-LLJMAULE.js.map} +0 -0
  715. /package/dist/{chunk-AS7YMSL6.js.map → chunk-M23RF3LJ.js.map} +0 -0
  716. /package/dist/{chunk-3F2LKUMU.js.map → chunk-NIS256NW.js.map} +0 -0
  717. /package/dist/{chunk-YIAA2X3D.js.map → chunk-NK5RGJ65.js.map} +0 -0
  718. /package/dist/{chunk-OQ5PRDDS.js.map → chunk-NTOIP2E6.js.map} +0 -0
  719. /package/dist/{chunk-HLPD7B7P.js.map → chunk-NUEQKLNB.js.map} +0 -0
  720. /package/dist/{chunk-33PLLLL7.js.map → chunk-P7NGM24P.js.map} +0 -0
  721. /package/dist/{chunk-7TWUCYER.js.map → chunk-PNRA7FAD.js.map} +0 -0
  722. /package/dist/{chunk-5I4M26Q7.js.map → chunk-QBSFOKY6.js.map} +0 -0
  723. /package/dist/{chunk-P4DRWEYC.js.map → chunk-QVSBTCVP.js.map} +0 -0
  724. /package/dist/{chunk-AAIUERNB.js.map → chunk-R5RFK3CB.js.map} +0 -0
  725. /package/dist/{chunk-WDISJRMG.js.map → chunk-RMMVQQA6.js.map} +0 -0
  726. /package/dist/{chunk-5SM35XZR.js.map → chunk-S5NZBKKQ.js.map} +0 -0
  727. /package/dist/{chunk-WIPEXG6R.js.map → chunk-SXIMQLGV.js.map} +0 -0
  728. /package/dist/{chunk-OAEQLRCY.js.map → chunk-TN76AKO3.js.map} +0 -0
  729. /package/dist/{chunk-QN25OCUF.js.map → chunk-TQ4GD737.js.map} +0 -0
  730. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  731. /package/dist/{chunk-DNWXFTLD.js.map → chunk-TYISDI6B.js.map} +0 -0
  732. /package/dist/{chunk-4LMA77JH.js.map → chunk-U2VLVBBH.js.map} +0 -0
  733. /package/dist/{chunk-5ZE7QHTK.js.map → chunk-ULVR5KG7.js.map} +0 -0
  734. /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
  735. /package/dist/{chunk-S2BBISHU.js.map → chunk-VANZKHTN.js.map} +0 -0
  736. /package/dist/{chunk-3Y224NYC.js.map → chunk-VYISFWVX.js.map} +0 -0
  737. /package/dist/{chunk-TIHMZFIV.js.map → chunk-W3IC7QOY.js.map} +0 -0
  738. /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
  739. /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
  740. /package/dist/{chunk-T2TTP3KU.js.map → chunk-X4IDNPOS.js.map} +0 -0
  741. /package/dist/{chunk-BLAKS3CP.js.map → chunk-XL3TATMJ.js.map} +0 -0
  742. /package/dist/{chunk-W4XJFLAL.js.map → chunk-XPRJSHNI.js.map} +0 -0
  743. /package/dist/{chunk-JE7EK33X.js.map → chunk-Y7HRYCNW.js.map} +0 -0
  744. /package/dist/{chunk-E6EE5B67.js.map → chunk-YK6BDDHP.js.map} +0 -0
  745. /package/dist/{chunk-ES36HTSC.js.map → chunk-YLHM5BQQ.js.map} +0 -0
  746. /package/dist/{chunk-BJKPPZ6Z.js.map → chunk-ZFGZ6PZ2.js.map} +0 -0
  747. /package/dist/{chunk-64UDOIMI.js.map → chunk-ZLQ37WJX.js.map} +0 -0
@@ -1,3 +1,4 @@
1
+ import { createHash } from "node:crypto";
1
2
  import assert from "node:assert/strict";
2
3
  import { mkdtemp, mkdir, readFile, readdir, rename, rm, stat, utimes, writeFile } from "node:fs/promises";
3
4
  import { existsSync } from "node:fs";
@@ -10,8 +11,12 @@ import {
10
11
  buildExplicitCaptureDedupKey,
11
12
  TombstoneBlockedCaptureIndex,
12
13
  } from "./storage/tombstone-blocked-capture-index.js";
13
- import { TombstoneBlockedCaptureWriteLock } from "./storage/tombstone-blocked-capture-mutation.js";
14
- import { isEncryptedFile } from "./secure-store/secure-fs.js";
14
+ import {
15
+ buildCapturePathLockIdentity,
16
+ runTombstoneBlockedMutation,
17
+ TombstoneBlockedCaptureWriteLock,
18
+ } from "./storage/tombstone-blocked-capture-mutation.js";
19
+ import { isEncryptedFile, SECURE_STORE_ENVELOPE_OVERHEAD_BYTES } from "./secure-store/secure-fs.js";
15
20
  import type { MemoryFile } from "./types.js";
16
21
 
17
22
  // Issue #1909 (Part B): writeMemory("fact") used to rewrite the whole
@@ -54,6 +59,171 @@ test("capture write locks combine streamed hashes in canonical order", async ()
54
59
  );
55
60
  });
56
61
  });
62
+ test("active mutations recheck queued-review replacements inside coordinated identity locks", async () => {
63
+ const pathname = "/memory/facts/active.md";
64
+ const active = {
65
+ path: pathname,
66
+ content: "active content",
67
+ frontmatter: { id: "active", category: "fact", status: "active" },
68
+ } as MemoryFile;
69
+ const queued = {
70
+ path: pathname,
71
+ content: "queued content",
72
+ frontmatter: {
73
+ id: "queued",
74
+ category: "fact",
75
+ status: "pending_review",
76
+ tags: ["queued-review"],
77
+ sourceConnector: "provider-a",
78
+ },
79
+ } as MemoryFile;
80
+ const activeIdentity = buildExplicitCaptureDedupKey(
81
+ active.content,
82
+ active.frontmatter.category,
83
+ active.frontmatter.sourceConnector
84
+ );
85
+ const queuedIdentity = buildExplicitCaptureDedupKey(
86
+ queued.content,
87
+ queued.frontmatter.category,
88
+ queued.frontmatter.sourceConnector
89
+ );
90
+ let current = active;
91
+ const lockIdentities: string[][] = [];
92
+ let writes = 0;
93
+
94
+ await runTombstoneBlockedMutation(
95
+ {
96
+ readCurrent: async () => current,
97
+ isBlocked: () => false,
98
+ isQueuedReview: (memory) => memory?.frontmatter.id === queued.frontmatter.id,
99
+ memoryIdentity: (memory) => (memory.frontmatter.id === active.frontmatter.id ? activeIdentity : queuedIdentity),
100
+ prepareWrite: async () => "marker",
101
+ commitWrite: async () => {},
102
+ discardWrite: async () => {},
103
+ markUntrusted: () => {},
104
+ writeStorageSecureFile: async () => {
105
+ assert.equal(lockIdentities.length, 2);
106
+ assert.ok(lockIdentities[1]?.includes(queuedIdentity));
107
+ writes += 1;
108
+ },
109
+ withCaptureWriteLock: async (task, identity) => {
110
+ const identities = Array.isArray(identity) ? [...identity] : [identity];
111
+ lockIdentities.push(identities);
112
+ if (lockIdentities.length === 1) current = queued;
113
+ await task();
114
+ },
115
+ logWarning: () => {},
116
+ },
117
+ {
118
+ blocked: false,
119
+ pathname,
120
+ fileContent: "replacement",
121
+ identity: [
122
+ buildCapturePathLockIdentity(pathname),
123
+ activeIdentity,
124
+ buildExplicitCaptureDedupKey("replacement", "fact", undefined),
125
+ ],
126
+ updateIndex: async () => {},
127
+ }
128
+ );
129
+
130
+ assert.equal(writes, 1);
131
+ assert.equal(lockIdentities.length, 2);
132
+ assert.ok(lockIdentities[0]?.includes(activeIdentity));
133
+ assert.ok(lockIdentities[0]?.includes(buildCapturePathLockIdentity(pathname)));
134
+ });
135
+
136
+ test("shared memory writes include their pathname in the capture lock union", async () => {
137
+ await withMemoryDir(async (dir) => {
138
+ const storage = new StorageManager(dir);
139
+ await storage.ensureDirectories();
140
+ const storageWithOverride = storage as unknown as {
141
+ withTombstoneBlockedCaptureWriteLock: (
142
+ task: () => Promise<unknown>,
143
+ identity?: string | readonly string[]
144
+ ) => Promise<unknown>;
145
+ };
146
+ const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
147
+ const captured: Array<string | readonly string[] | undefined> = [];
148
+ storageWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
149
+ captured.push(identity);
150
+ return await originalLock(task, identity);
151
+ };
152
+ try {
153
+ const written = await storage.writeMemory("fact", "Every writer shares the deterministic pathname lock.", {
154
+ source: "test",
155
+ });
156
+ const memory = await storage.getMemoryById(written.id);
157
+ assert.ok(memory);
158
+ const pathIdentity = buildCapturePathLockIdentity(memory.path);
159
+ assert.ok(captured.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity)));
160
+ } finally {
161
+ storageWithOverride.withTombstoneBlockedCaptureWriteLock = originalLock;
162
+ }
163
+ });
164
+ });
165
+
166
+ test("offline sync reserves a marker when its locked snapshot became blocked with the same identity", async () => {
167
+ await withMemoryDir(async (dir) => {
168
+ const storage = new StorageManager(dir);
169
+ await storage.ensureDirectories();
170
+ const target = path.join(dir, "memory", "facts", "same-identity.md");
171
+ const active = {
172
+ path: target,
173
+ content: "Same identity, different review state.",
174
+ frontmatter: {
175
+ id: "same-identity",
176
+ category: "fact",
177
+ status: "active",
178
+ sourceConnector: "provider-a",
179
+ },
180
+ } as MemoryFile;
181
+ const blocked = {
182
+ ...active,
183
+ frontmatter: {
184
+ ...active.frontmatter,
185
+ status: "pending_review",
186
+ blockedBy: "same-identity-tombstone",
187
+ },
188
+ } as MemoryFile;
189
+ let readCount = 0;
190
+ let prepared = 0;
191
+ const fakeIndex = {
192
+ withCaptureWriteLock: async <T>(task: () => Promise<T>) => await task(),
193
+ prepareWrite: async () => {
194
+ prepared += 1;
195
+ return "same-identity-marker";
196
+ },
197
+ commitWrite: async () => {},
198
+ discardWrite: async () => {},
199
+ markUntrusted: () => {},
200
+ };
201
+ const storageWithOverrides = storage as unknown as {
202
+ readMemoryByPath: (pathname: string) => Promise<MemoryFile | null>;
203
+ getTombstoneBlockedCaptureIndex: () => typeof fakeIndex;
204
+ invalidateAfterOfflineSyncMutation: (pathname: string, marker?: string) => Promise<void>;
205
+ runTombstoneBlockedOfflineSyncMutation: (
206
+ pathname: string,
207
+ after: MemoryFile | null,
208
+ write: () => Promise<void>
209
+ ) => Promise<void>;
210
+ };
211
+ const originalRead = storageWithOverrides.readMemoryByPath.bind(storage);
212
+ const originalIndex = storageWithOverrides.getTombstoneBlockedCaptureIndex.bind(storage);
213
+ const originalInvalidate = storageWithOverrides.invalidateAfterOfflineSyncMutation.bind(storage);
214
+ storageWithOverrides.readMemoryByPath = async () => (readCount++ === 0 ? active : blocked);
215
+ storageWithOverrides.getTombstoneBlockedCaptureIndex = () => fakeIndex;
216
+ storageWithOverrides.invalidateAfterOfflineSyncMutation = async () => {};
217
+ try {
218
+ await storageWithOverrides.runTombstoneBlockedOfflineSyncMutation(target, active, async () => {});
219
+ assert.equal(prepared, 1);
220
+ } finally {
221
+ storageWithOverrides.readMemoryByPath = originalRead;
222
+ storageWithOverrides.getTombstoneBlockedCaptureIndex = originalIndex;
223
+ storageWithOverrides.invalidateAfterOfflineSyncMutation = originalInvalidate;
224
+ }
225
+ });
226
+ });
57
227
 
58
228
  test("deferred fact writes do NO per-fact index saves; a single flush persists all", async () => {
59
229
  await withMemoryDir(async (dir) => {
@@ -1662,6 +1832,45 @@ test("blocked chunk writes recheck identity after waiting on the capture lock",
1662
1832
  });
1663
1833
  });
1664
1834
 
1835
+ test("chunk rewrites reacquire discovered identities in canonical lock order", async () => {
1836
+ await withMemoryDir(async (dir) => {
1837
+ const storage = new StorageManager(dir);
1838
+ await storage.ensureDirectories();
1839
+ let queuedContent = "";
1840
+ let blockedContent = "";
1841
+ for (let index = 0; index < 100 && queuedContent.length === 0; index += 1) {
1842
+ const queuedCandidate = `queued identity ${index}`;
1843
+ const blockedCandidate = `blocked identity ${index}`;
1844
+ const queuedHash = createHash("sha256")
1845
+ .update(buildExplicitCaptureDedupKey(queuedCandidate, "fact", "provider-a"))
1846
+ .digest("hex");
1847
+ const blockedHash = createHash("sha256")
1848
+ .update(buildExplicitCaptureDedupKey(blockedCandidate, "fact", "provider-a"))
1849
+ .digest("hex");
1850
+ if (queuedHash < blockedHash) {
1851
+ queuedContent = queuedCandidate;
1852
+ blockedContent = blockedCandidate;
1853
+ }
1854
+ }
1855
+ assert.ok(queuedContent.length > 0);
1856
+
1857
+ await storage.writeChunk("nested-lock-order", 0, 1, "fact", queuedContent, {
1858
+ source: "explicit-inline-review",
1859
+ sourceConnector: "provider-a",
1860
+ status: "pending_review",
1861
+ tags: ["queued-review"],
1862
+ });
1863
+ const id = await storage.writeChunk("nested-lock-order", 0, 1, "fact", blockedContent, {
1864
+ source: "offline-sync",
1865
+ sourceConnector: "provider-a",
1866
+ status: "pending_review",
1867
+ blockedBy: "tombstone-lock-order",
1868
+ });
1869
+
1870
+ assert.equal((await storage.getMemoryById(id))?.content, blockedContent);
1871
+ });
1872
+ });
1873
+
1665
1874
  test("offline sync rechecks blocked identity after waiting on the capture lock", async () => {
1666
1875
  await withMemoryDir(async (dir) => {
1667
1876
  const storage = new StorageManager(dir);
@@ -1725,6 +1934,84 @@ test("offline sync rechecks blocked identity after waiting on the capture lock",
1725
1934
  assert.equal(matches[0]?.frontmatter.id, captureResult.id);
1726
1935
  });
1727
1936
  });
1937
+ test("offline sync locks queued-review target identities before replacement", async () => {
1938
+ await withMemoryDir(async (dir) => {
1939
+ const storage = new StorageManager(dir);
1940
+ await storage.ensureDirectories();
1941
+ const queuedContent = "A queued review must not disappear during capture dedupe.";
1942
+ const queuedResult = await storage.writeMemory("fact", queuedContent, {
1943
+ source: "explicit-inline-review",
1944
+ sourceConnector: "provider-a",
1945
+ status: "pending_review",
1946
+ tags: ["explicit-capture", "queued-review"],
1947
+ });
1948
+ const queuedMemory = await storage.getMemoryById(queuedResult.id);
1949
+ assert.ok(queuedMemory);
1950
+ const queuedIdentity = buildExplicitCaptureDedupKey(queuedContent, "fact", "provider-a");
1951
+ const entered = Promise.withResolvers<void>();
1952
+ const release = Promise.withResolvers<void>();
1953
+ const held = storage.withTombstoneBlockedCaptureWriteLock(async () => {
1954
+ entered.resolve();
1955
+ await release.promise;
1956
+ }, queuedIdentity);
1957
+ await entered.promise;
1958
+ const storageWithOverride = storage as unknown as {
1959
+ withTombstoneBlockedCaptureWriteLock: (
1960
+ task: () => Promise<unknown>,
1961
+ identity?: string | readonly string[]
1962
+ ) => Promise<unknown>;
1963
+ };
1964
+ const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
1965
+ const coordinationAttempted = Promise.withResolvers<void>();
1966
+ storageWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
1967
+ if ((Array.isArray(identity) ? identity : [identity]).includes(queuedIdentity)) {
1968
+ coordinationAttempted.resolve();
1969
+ }
1970
+ return await originalLock(task, identity);
1971
+ };
1972
+
1973
+ const replacementContent = "The reviewed replacement is now active.";
1974
+ const replacementFile = [
1975
+ "---",
1976
+ "id: queued-review-replacement",
1977
+ "category: fact",
1978
+ "created: 2026-01-01T00:00:00.000Z",
1979
+ "updated: 2026-01-01T00:00:00.000Z",
1980
+ "source: offline-sync",
1981
+ "confidence: 0.8",
1982
+ "confidenceTier: implied",
1983
+ "tags: []",
1984
+ "status: active",
1985
+ "---",
1986
+ "",
1987
+ replacementContent,
1988
+ "",
1989
+ ].join("\n");
1990
+ let completed = false;
1991
+ let replacement: Promise<void> | undefined;
1992
+ try {
1993
+ replacement = storage.writeOfflineSyncFile(queuedMemory.path, Buffer.from(replacementFile, "utf8")).then(() => {
1994
+ completed = true;
1995
+ });
1996
+ const first = await Promise.race([
1997
+ coordinationAttempted.promise.then(() => "coordinated" as const),
1998
+ replacement.then(() => "completed" as const),
1999
+ ]);
2000
+ assert.equal(first, "coordinated");
2001
+ assert.equal(completed, false, "offline sync must wait for the queued-review identity lock");
2002
+ release.resolve();
2003
+ await held;
2004
+ await replacement;
2005
+ assert.equal((await storage.getMemoryById("queued-review-replacement"))?.content, replacementContent);
2006
+ } finally {
2007
+ release.resolve();
2008
+ storageWithOverride.withTombstoneBlockedCaptureWriteLock = originalLock;
2009
+ await held.catch(() => undefined);
2010
+ await replacement?.catch(() => undefined);
2011
+ }
2012
+ });
2013
+ });
2014
+
1728
2015
  test("offline sync reacquires a rewritten blocked target identity", async () => {
1729
2016
  await withMemoryDir(async (dir) => {
1730
2017
  const storage = new StorageManager(dir);
@@ -1776,9 +2063,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
1776
2063
  contentA,
1777
2064
  "",
1778
2065
  ].join("\n");
1779
- const targetMemory = (await storage.readAllMemories()).find(
1780
- (memory) => memory.frontmatter.id === target.id
1781
- );
2066
+ const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
1782
2067
  assert.ok(targetMemory);
1783
2068
  const identityA = buildExplicitCaptureDedupKey(contentA, "fact", "provider-a");
1784
2069
  const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
@@ -1786,7 +2071,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
1786
2071
  const storageWithOverride = storage as unknown as {
1787
2072
  withTombstoneBlockedCaptureWriteLock: (
1788
2073
  task: () => Promise<unknown>,
1789
- identity?: string | readonly string[],
2074
+ identity?: string | readonly string[]
1790
2075
  ) => Promise<unknown>;
1791
2076
  };
1792
2077
  const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
@@ -1816,7 +2101,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
1816
2101
  await releaseMarker.promise;
1817
2102
  }
1818
2103
  return marker;
1819
- },
2104
+ }
1820
2105
  );
1821
2106
 
1822
2107
  const sync = storage.writeOfflineSyncFile(targetMemory.path, Buffer.from(incomingFile, "utf8"));
@@ -1826,11 +2111,11 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
1826
2111
  const secondKeys = capturedIdentities[1];
1827
2112
  assert.ok(
1828
2113
  (Array.isArray(firstKeys) ? firstKeys : [firstKeys]).includes(identityB),
1829
- "sync must first observe the original target identity",
2114
+ "sync must first observe the original target identity"
1830
2115
  );
1831
2116
  assert.ok(
1832
2117
  (Array.isArray(secondKeys) ? secondKeys : [secondKeys]).includes(identityC),
1833
- "sync must reacquire the rewritten target identity",
2118
+ "sync must reacquire the rewritten target identity"
1834
2119
  );
1835
2120
  let recaptureCompleted = false;
1836
2121
  const recapture = peer
@@ -1852,7 +2137,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
1852
2137
  assert.equal(
1853
2138
  after.find((memory) => memory.path === targetMemory.path)?.content,
1854
2139
  contentA,
1855
- "offline sync must replace the target after holding its current identity lock",
2140
+ "offline sync must replace the target after holding its current identity lock"
1856
2141
  );
1857
2142
  assert.equal(after.filter((memory) => memory.content === contentC).length, 1);
1858
2143
  } finally {
@@ -2309,6 +2594,52 @@ test("chunked offline sync scans oversized frontmatter before locking its identi
2309
2594
  });
2310
2595
  });
2311
2596
 
2597
+ test("chunked offline sync lowercases contextual Unicode across staged read boundaries", async () => {
2598
+ await withMemoryDir(async (dir) => {
2599
+ const storage = new StorageManager(dir);
2600
+ await storage.ensureDirectories();
2601
+ const header = (id: string) =>
2602
+ [
2603
+ "---",
2604
+ `id: ${id}`,
2605
+ "category: fact",
2606
+ "created: 2026-01-01T00:00:00.000Z",
2607
+ "updated: 2026-01-01T00:00:00.000Z",
2608
+ "source: offline-sync",
2609
+ "confidence: 0.8",
2610
+ "confidenceTier: implied",
2611
+ "tags: []",
2612
+ "sourceConnector: provider-a",
2613
+ "status: pending_review",
2614
+ "blockedBy: tombstone-unicode-boundary",
2615
+ "---",
2616
+ ].join("\n");
2617
+ const incomingHeader = header("unicode-boundary-incoming");
2618
+ const firstReadBoundary = SECURE_STORE_ENVELOPE_OVERHEAD_BYTES + 64 * 1024;
2619
+ const bodyOffset = Buffer.byteLength(`${incomingHeader}\n`);
2620
+ const prefixLength = firstReadBoundary - bodyOffset - Buffer.byteLength("\nΟΣ", "utf8");
2621
+ assert.ok(prefixLength > 0);
2622
+ const content = `${"x".repeat(prefixLength)}ΟΣΑ${"z".repeat(1_050_000)}`;
2623
+ assert.equal(Buffer.byteLength(`${incomingHeader}\n\n${"x".repeat(prefixLength)}ΟΣ`, "utf8"), firstReadBoundary);
2624
+ const memoryFile = (id: string) => `${header(id)}\n\n${content}\n`;
2625
+ const existingPath = path.join(dir, "facts", "2026-01-01", "unicode-boundary-existing.md");
2626
+ await storage.writeOfflineSyncFile(existingPath, Buffer.from(memoryFile("unicode-boundary-existing"), "utf8"));
2627
+
2628
+ const incomingPath = path.join(dir, "facts", "2026-01-01", "unicode-boundary-incoming.md");
2629
+ const incoming = Buffer.from(memoryFile("unicode-boundary-incoming"), "utf8");
2630
+ const chunks = (async function* (): AsyncIterable<Buffer> {
2631
+ for (let offset = 0; offset < incoming.length; offset += 32 * 1024) {
2632
+ yield incoming.subarray(offset, offset + 32 * 1024);
2633
+ }
2634
+ })();
2635
+ await storage.writeOfflineSyncFileChunks(incomingPath, chunks);
2636
+
2637
+ assert.equal(existsSync(incomingPath), false, "the normalized duplicate must not be published");
2638
+ const matches = (await storage.readAllMemories()).filter((memory) => memory.content === content);
2639
+ assert.equal(matches.length, 1);
2640
+ });
2641
+ });
2642
+
2312
2643
  test("chunked offline sync encrypts oversized staging files when secure storage is enabled", async () => {
2313
2644
  await withMemoryDir(async (dir) => {
2314
2645
  const storage = new StorageManager(dir);
@@ -2481,9 +2812,7 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
2481
2812
  });
2482
2813
  assert.ok(targetTombstone);
2483
2814
  assert.equal(target.tombstoneBlocked, false);
2484
- const targetMemory = (await storage.readAllMemories()).find(
2485
- (memory) => memory.frontmatter.id === target.id
2486
- );
2815
+ const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
2487
2816
  assert.ok(targetMemory);
2488
2817
  const incomingFile = [
2489
2818
  "---",
@@ -2512,13 +2841,13 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
2512
2841
  const storageWithOverrides = storage as unknown as {
2513
2842
  withTombstoneBlockedCaptureWriteLock: (
2514
2843
  task: () => Promise<unknown>,
2515
- identity?: string | readonly string[],
2844
+ identity?: string | readonly string[]
2516
2845
  ) => Promise<unknown>;
2517
2846
  runTombstoneBlockedOfflineSyncMutation: (
2518
2847
  target: string,
2519
2848
  after: MemoryFile | null,
2520
2849
  write: () => Promise<void>,
2521
- coordinate?: boolean,
2850
+ coordinate?: boolean
2522
2851
  ) => Promise<void>;
2523
2852
  };
2524
2853
  const originalLock = storageWithOverrides.withTombstoneBlockedCaptureWriteLock.bind(storage);
@@ -2532,17 +2861,10 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
2532
2861
  let pauseNextPrepare = false;
2533
2862
  const markerEntered = Promise.withResolvers<void>();
2534
2863
  const releaseMarker = Promise.withResolvers<void>();
2535
- storageWithOverrides.runTombstoneBlockedOfflineSyncMutation = async (
2536
- syncTarget,
2537
- after,
2538
- write,
2539
- coordinate,
2540
- ) => {
2864
+ storageWithOverrides.runTombstoneBlockedOfflineSyncMutation = async (syncTarget, after, write, coordinate) => {
2541
2865
  if (!rewroteTarget) {
2542
2866
  rewroteTarget = true;
2543
- const current = (await peer.readAllMemories()).find(
2544
- (memory) => memory.frontmatter.id === target.id
2545
- );
2867
+ const current = (await peer.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
2546
2868
  assert.ok(current);
2547
2869
  await peer.writeMemoryFrontmatter(current, {
2548
2870
  status: "pending_review",
@@ -2564,17 +2886,15 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
2564
2886
  await releaseMarker.promise;
2565
2887
  }
2566
2888
  return marker;
2567
- },
2889
+ }
2568
2890
  );
2569
2891
 
2570
2892
  const sync = storage.writeOfflineSyncFileChunks(targetMemory.path, chunks);
2571
2893
  try {
2572
2894
  await markerEntered.promise;
2573
2895
  assert.ok(
2574
- capturedIdentities.some((identity) =>
2575
- (Array.isArray(identity) ? identity : [identity]).includes(identityC)
2576
- ),
2577
- "nested chunk sync must acquire the identity discovered after the outer recheck",
2896
+ capturedIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(identityC)),
2897
+ "nested chunk sync must acquire the identity discovered after the outer recheck"
2578
2898
  );
2579
2899
  let recaptureCompleted = false;
2580
2900
  const recapture = peer
@@ -2596,7 +2916,7 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
2596
2916
  assert.equal(
2597
2917
  after.find((memory) => memory.path === targetMemory.path)?.content,
2598
2918
  incomingContent,
2599
- "chunk sync must replace the target only while holding its current identity lock",
2919
+ "chunk sync must replace the target only while holding its current identity lock"
2600
2920
  );
2601
2921
  assert.equal(after.filter((memory) => memory.content === targetContent).length, 1);
2602
2922
  } finally {
@@ -2672,7 +2992,7 @@ test("large blocked offline sync streams through bounded staging and deduplicate
2672
2992
  largeContent,
2673
2993
  "",
2674
2994
  ].join("\n"),
2675
- "utf8",
2995
+ "utf8"
2676
2996
  );
2677
2997
  assert.ok(incomingFile.byteLength > 1_048_576);
2678
2998
  const target = path.join(dir, "cold", "large-stream-incoming.md");
@@ -2689,10 +3009,9 @@ test("large blocked offline sync streams through bounded staging and deduplicate
2689
3009
 
2690
3010
  assert.equal(consumedBytes, incomingFile.byteLength);
2691
3011
  assert.equal(existsSync(target), false, "a streamed blocked duplicate must not publish a new row");
2692
- const matches = [
2693
- ...(await storage.readAllMemories()),
2694
- ...(await storage.readAllColdMemories()),
2695
- ].filter((memory) => memory.frontmatter.id === existing.id);
3012
+ const matches = [...(await storage.readAllMemories()), ...(await storage.readAllColdMemories())].filter(
3013
+ (memory) => memory.frontmatter.id === existing.id
3014
+ );
2696
3015
  assert.equal(matches.length, 1, "the existing blocked row remains the sole durable duplicate");
2697
3016
  });
2698
3017
  });
@@ -2827,10 +3146,7 @@ test("frontmatter rewrites invalidate cold cache before blocked index sync", asy
2827
3146
  );
2828
3147
  assert.ok(coldMemory, "migrated blocked memory must be readable from cold tier");
2829
3148
 
2830
- assert.equal(
2831
- await storage.writeMemoryFrontmatter(coldMemory, { sourceConnector: "provider-b" }),
2832
- true
2833
- );
3149
+ assert.equal(await storage.writeMemoryFrontmatter(coldMemory, { sourceConnector: "provider-b" }), true);
2834
3150
  assert.equal(
2835
3151
  await storage.hasTombstoneBlockedExplicitCapture(content, "fact", "provider-a"),
2836
3152
  false,
@@ -3207,7 +3523,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
3207
3523
  const storageWithOverride = storage as unknown as {
3208
3524
  withTombstoneBlockedCaptureWriteLock: (
3209
3525
  task: () => Promise<boolean>,
3210
- identity?: string | readonly string[],
3526
+ identity?: string | readonly string[]
3211
3527
  ) => Promise<boolean>;
3212
3528
  };
3213
3529
  let capturedIdentity: string | readonly string[] | undefined;
@@ -3229,7 +3545,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
3229
3545
  await release.promise;
3230
3546
  }
3231
3547
  return marker;
3232
- },
3548
+ }
3233
3549
  );
3234
3550
 
3235
3551
  const invalidation = storage.invalidateMemory(first.id);
@@ -3238,15 +3554,12 @@ test("blocked invalidation reserves the index marker before deleting under the i
3238
3554
  entered.promise.then(() => true),
3239
3555
  new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 100)),
3240
3556
  ]);
3241
- assert.equal(
3242
- enteredBeforeTimeout,
3243
- true,
3244
- "blocked invalidation must reserve its rebuild marker before unlinking",
3245
- );
3246
- assert.equal(capturedIdentity, identity);
3557
+ assert.equal(enteredBeforeTimeout, true, "blocked invalidation must reserve its rebuild marker before unlinking");
3558
+ assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.includes(identity));
3559
+ assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.some((key) => key.startsWith("path ")));
3247
3560
  assert.ok(
3248
3561
  (await readdir(path.join(dir, "state", "tombstone-blocked-capture", "rebuild-required"))).length > 0,
3249
- "blocked invalidation must publish its rebuild marker before unlinking",
3562
+ "blocked invalidation must publish its rebuild marker before unlinking"
3250
3563
  );
3251
3564
 
3252
3565
  let peerCompleted = false;
@@ -3266,10 +3579,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
3266
3579
  const second = await recapture;
3267
3580
  assert.equal(second.tombstoneBlocked, true);
3268
3581
  assert.notEqual(second.id, first.id);
3269
- assert.equal(
3270
- (await peer.readAllMemories()).filter((memory) => memory.content === content).length,
3271
- 1,
3272
- );
3582
+ assert.equal((await peer.readAllMemories()).filter((memory) => memory.content === content).length, 1);
3273
3583
  } finally {
3274
3584
  release.resolve();
3275
3585
  prepareSpy.mock.restore();
@@ -3313,7 +3623,7 @@ test("blocked archive serializes capture scans with the archive transition", asy
3313
3623
  const storageWithOverride = storage as unknown as {
3314
3624
  withTombstoneBlockedCaptureWriteLock: (
3315
3625
  task: () => Promise<unknown>,
3316
- identity?: string | readonly string[],
3626
+ identity?: string | readonly string[]
3317
3627
  ) => Promise<unknown>;
3318
3628
  };
3319
3629
  const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
@@ -3338,7 +3648,7 @@ test("blocked archive serializes capture scans with the archive transition", asy
3338
3648
  await releaseMarker.promise;
3339
3649
  }
3340
3650
  return marker;
3341
- },
3651
+ }
3342
3652
  );
3343
3653
 
3344
3654
  const archive = storage.archiveMemory(firstMemory);
@@ -3348,7 +3658,8 @@ test("blocked archive serializes capture scans with the archive transition", asy
3348
3658
  new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 100)),
3349
3659
  ]);
3350
3660
  assert.equal(enteredBeforeTimeout, true, "archive must reserve its marker under the capture lock");
3351
- assert.equal(capturedIdentity, identity);
3661
+ assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.includes(identity));
3662
+ assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.some((key) => key.startsWith("path ")));
3352
3663
 
3353
3664
  let recaptureCompleted = false;
3354
3665
  const recapture = peer
@@ -3372,12 +3683,12 @@ test("blocked archive serializes capture scans with the archive transition", asy
3372
3683
  assert.equal(
3373
3684
  (await peer.readAllMemories()).filter((memory) => memory.content === content).length,
3374
3685
  1,
3375
- "recapture must recreate the review row after archive removes the old row",
3686
+ "recapture must recreate the review row after archive removes the old row"
3376
3687
  );
3377
3688
  assert.equal(
3378
3689
  await peer.hasTombstoneBlockedExplicitCapture(content, "fact", "provider-a"),
3379
3690
  true,
3380
- "the recreated review row must remain indexed",
3691
+ "the recreated review row must remain indexed"
3381
3692
  );
3382
3693
  } finally {
3383
3694
  releaseMarker.resolve();
@@ -3396,7 +3707,7 @@ test("blocked archive failures discard their uncommitted rebuild marker", async
3396
3707
  protected override writeStorageSecureFile(
3397
3708
  filePath: string,
3398
3709
  content: string | Buffer,
3399
- forceEncrypt = false,
3710
+ forceEncrypt = false
3400
3711
  ): Promise<void> {
3401
3712
  if (this.failArchiveWrites && filePath.includes(`${path.sep}archive${path.sep}`)) {
3402
3713
  return Promise.reject(new Error("simulated archive write failure"));
@@ -3476,7 +3787,7 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
3476
3787
  const storageWithOverride = storage as unknown as {
3477
3788
  withTombstoneBlockedCaptureWriteLock: (
3478
3789
  task: () => Promise<unknown>,
3479
- identity?: string | readonly string[],
3790
+ identity?: string | readonly string[]
3480
3791
  ) => Promise<unknown>;
3481
3792
  };
3482
3793
  const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
@@ -3506,13 +3817,23 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
3506
3817
  await releaseMarker.promise;
3507
3818
  }
3508
3819
  return marker;
3509
- },
3820
+ }
3510
3821
  );
3511
3822
 
3512
3823
  const invalidation = storage.invalidateMemory(first.id);
3513
3824
  try {
3514
3825
  await markerEntered.promise;
3515
- assert.deepEqual(capturedIdentities, [identityA, identityB]);
3826
+ assert.deepEqual(
3827
+ capturedIdentities.map((identity) =>
3828
+ (Array.isArray(identity) ? identity : [identity]).filter((key) => key?.startsWith("category "))
3829
+ ),
3830
+ [[identityA], [identityA, identityB]]
3831
+ );
3832
+ assert.ok(
3833
+ capturedIdentities.every((identity) =>
3834
+ (Array.isArray(identity) ? identity : [identity]).some((key) => key?.startsWith("path "))
3835
+ )
3836
+ );
3516
3837
  let recaptureCompleted = false;
3517
3838
  const recapture = peer
3518
3839
  .writeMemory("fact", contentB, {
@@ -3530,10 +3851,7 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
3530
3851
  const second = await recapture;
3531
3852
  assert.equal(second.tombstoneBlocked, true);
3532
3853
  assert.notEqual(second.id, first.id);
3533
- assert.equal(
3534
- (await peer.readAllMemories()).filter((memory) => memory.content === contentB).length,
3535
- 1,
3536
- );
3854
+ assert.equal((await peer.readAllMemories()).filter((memory) => memory.content === contentB).length, 1);
3537
3855
  } finally {
3538
3856
  releaseMarker.resolve();
3539
3857
  prepareSpy.mock.restore();
@@ -3570,7 +3888,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
3570
3888
  createdBy: "user_correction",
3571
3889
  sourceMemoryId,
3572
3890
  rawContent,
3573
- }),
3891
+ })
3574
3892
  );
3575
3893
  }
3576
3894
  const target = await storage.writeMemory("fact", contentA, {
@@ -3578,9 +3896,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
3578
3896
  sourceConnector: "provider-a",
3579
3897
  });
3580
3898
  assert.equal(target.tombstoneBlocked, true);
3581
- const targetMemory = (await storage.readAllMemories()).find(
3582
- (memory) => memory.frontmatter.id === target.id
3583
- );
3899
+ const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
3584
3900
  assert.ok(targetMemory);
3585
3901
  const identityA = buildExplicitCaptureDedupKey(contentA, "fact", "provider-a");
3586
3902
  const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
@@ -3588,7 +3904,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
3588
3904
  const storageWithOverride = storage as unknown as {
3589
3905
  withTombstoneBlockedCaptureWriteLock: (
3590
3906
  task: () => Promise<unknown>,
3591
- identity?: string | readonly string[],
3907
+ identity?: string | readonly string[]
3592
3908
  ) => Promise<unknown>;
3593
3909
  };
3594
3910
  const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
@@ -3618,7 +3934,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
3618
3934
  await releaseMarker.promise;
3619
3935
  }
3620
3936
  return marker;
3621
- },
3937
+ }
3622
3938
  );
3623
3939
 
3624
3940
  const update = storage.updateMemory(target.id, contentC, { sourceConnector: "provider-a" });
@@ -3629,11 +3945,11 @@ test("blocked rewrites reacquire a target identity changed before update", async
3629
3945
  const secondKeys = capturedIdentities[1];
3630
3946
  assert.ok(
3631
3947
  (Array.isArray(firstKeys) ? firstKeys : [firstKeys]).includes(identityA),
3632
- "update must first lock the identity read before the peer rewrite",
3948
+ "update must first lock the identity read before the peer rewrite"
3633
3949
  );
3634
3950
  assert.ok(
3635
3951
  (Array.isArray(secondKeys) ? secondKeys : [secondKeys]).includes(identityB),
3636
- "update must reacquire the rewritten target identity",
3952
+ "update must reacquire the rewritten target identity"
3637
3953
  );
3638
3954
  let recaptureCompleted = false;
3639
3955
  const recapture = peer
@@ -3655,7 +3971,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
3655
3971
  assert.equal(
3656
3972
  after.find((memory) => memory.path === targetMemory.path)?.content,
3657
3973
  contentC,
3658
- "update must write only after holding the current target identity lock",
3974
+ "update must write only after holding the current target identity lock"
3659
3975
  );
3660
3976
  assert.equal(after.filter((memory) => memory.content === contentB).length, 1);
3661
3977
  } finally {
@@ -3914,130 +4230,97 @@ test("queued-review dispositions coordinate with explicit capture dedupe", async
3914
4230
  });
3915
4231
  });
3916
4232
 
3917
- test("active rewrites recheck a target that becomes blocked before the unlocked write", async () => {
4233
+ test("active rewrites serialize the target path across their read and write", async () => {
3918
4234
  await withMemoryDir(async (dir) => {
3919
4235
  const storage = new StorageManager(dir);
3920
4236
  const peer = new StorageManager(dir);
3921
4237
  await storage.ensureDirectories();
3922
4238
  await peer.ensureDirectories();
3923
- const tombstoneConfig = {
3924
- enabled: true,
3925
- semanticMatch: false,
3926
- semanticThreshold: 0.9,
3927
- namespace: "default",
3928
- };
3929
- storage.setTombstonesConfig(tombstoneConfig);
3930
- peer.setTombstonesConfig(tombstoneConfig);
3931
- const contentA = "An active target becomes blocked before an update writes.";
3932
- const contentB = "The rewritten blocked target identity must be locked.";
3933
- const contentC = "The stale update must publish only after locking identity B.";
3934
- const tombstoneId = await peer.appendTombstone({
3935
- reason: "correction",
3936
- createdBy: "user_correction",
3937
- sourceMemoryId: "active-rewrite-recheck",
3938
- rawContent: contentB,
3939
- });
3940
- assert.ok(tombstoneId);
4239
+ const contentA = "An active target is read before a concurrent update.";
4240
+ const contentB = "The concurrent update must run after the in-flight write.";
4241
+ const contentC = "The in-flight update holds the path through persistence.";
3941
4242
  const target = await storage.writeMemory("fact", contentA, {
3942
4243
  source: "test",
3943
4244
  sourceConnector: "provider-a",
3944
4245
  });
3945
4246
  const targetMemory = await storage.getMemoryById(target.id);
3946
4247
  assert.ok(targetMemory);
3947
- assert.equal(targetMemory.frontmatter.status, "active");
3948
- const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
3949
- await storage.hasTombstoneBlockedExplicitCapture(contentB, "fact", "provider-a");
3950
4248
 
4249
+ const readPaused = Promise.withResolvers<void>();
4250
+ const releaseRead = Promise.withResolvers<void>();
3951
4251
  const storageWithOverrides = storage as unknown as {
3952
4252
  readMemoryByPath: (filePath: string) => Promise<MemoryFile | null>;
3953
4253
  withTombstoneBlockedCaptureWriteLock: (
3954
4254
  task: () => Promise<unknown>,
3955
- identity?: string | readonly string[],
4255
+ identity?: string | readonly string[]
3956
4256
  ) => Promise<unknown>;
3957
4257
  };
3958
4258
  const originalRead = storageWithOverrides.readMemoryByPath.bind(storage);
3959
- let rewriteOnRead = true;
4259
+ let pauseRead = true;
3960
4260
  storageWithOverrides.readMemoryByPath = async (filePath) => {
3961
4261
  const current = await originalRead(filePath);
3962
- if (rewriteOnRead) {
3963
- rewriteOnRead = false;
3964
- assert.ok(current);
3965
- assert.equal(await peer.updateMemory(target.id, contentB, { sourceConnector: "provider-a" }), true);
3966
- const rewritten = await peer.getMemoryById(target.id);
3967
- assert.ok(rewritten);
3968
- assert.equal(
3969
- await peer.writeMemoryFrontmatter(rewritten, {
3970
- status: "pending_review",
3971
- blockedBy: tombstoneId,
3972
- }),
3973
- true,
3974
- );
3975
- pauseNextPrepare = true;
3976
- return await originalRead(filePath);
4262
+ if (pauseRead && filePath === targetMemory.path) {
4263
+ pauseRead = false;
4264
+ readPaused.resolve();
4265
+ await releaseRead.promise;
3977
4266
  }
3978
4267
  return current;
3979
4268
  };
3980
- const originalLock = storageWithOverrides.withTombstoneBlockedCaptureWriteLock.bind(storage);
3981
- const capturedIdentities: Array<string | readonly string[] | undefined> = [];
4269
+ const originalStorageLock = storageWithOverrides.withTombstoneBlockedCaptureWriteLock.bind(storage);
4270
+ const storageIdentities: Array<string | readonly string[] | undefined> = [];
3982
4271
  storageWithOverrides.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
3983
- capturedIdentities.push(identity);
3984
- return await originalLock(task, identity);
4272
+ storageIdentities.push(identity);
4273
+ return await originalStorageLock(task, identity);
4274
+ };
4275
+
4276
+ const peerWithOverride = peer as unknown as {
4277
+ withTombstoneBlockedCaptureWriteLock: (
4278
+ task: () => Promise<unknown>,
4279
+ identity?: string | readonly string[]
4280
+ ) => Promise<unknown>;
4281
+ };
4282
+ const originalPeerLock = peerWithOverride.withTombstoneBlockedCaptureWriteLock.bind(peer);
4283
+ const peerLockRequested = Promise.withResolvers<void>();
4284
+ const peerIdentities: Array<string | readonly string[] | undefined> = [];
4285
+ peerWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
4286
+ peerIdentities.push(identity);
4287
+ peerLockRequested.resolve();
4288
+ return await originalPeerLock(task, identity);
3985
4289
  };
3986
- const releaseMarker = Promise.withResolvers<void>();
3987
- const markerEntered = Promise.withResolvers<void>();
3988
- let pauseNextPrepare = false;
3989
- const originalPrepare = TombstoneBlockedCaptureIndex.prototype.prepareWrite;
3990
- const prepareSpy = mock.method(
3991
- TombstoneBlockedCaptureIndex.prototype,
3992
- "prepareWrite",
3993
- async function (this: TombstoneBlockedCaptureIndex) {
3994
- const marker = await originalPrepare.call(this);
3995
- if (pauseNextPrepare) {
3996
- pauseNextPrepare = false;
3997
- markerEntered.resolve();
3998
- await releaseMarker.promise;
3999
- }
4000
- return marker;
4001
- }
4002
- );
4003
4290
 
4004
4291
  const update = storage.updateMemory(target.id, contentC, { sourceConnector: "provider-a" });
4292
+ let competingUpdate: Promise<boolean> | undefined;
4293
+ let competingFinished = false;
4005
4294
  try {
4006
- await markerEntered.promise;
4295
+ await readPaused.promise;
4296
+ competingUpdate = peer.updateMemory(target.id, contentB, { sourceConnector: "provider-a" }).then((updated) => {
4297
+ competingFinished = true;
4298
+ return updated;
4299
+ });
4300
+ await peerLockRequested.promise;
4301
+ const contentionWindow = Promise.withResolvers<void>();
4302
+ setTimeout(contentionWindow.resolve, 50);
4303
+ await contentionWindow.promise;
4304
+ const pathIdentity = buildCapturePathLockIdentity(targetMemory.path);
4007
4305
  assert.ok(
4008
- capturedIdentities.some((identity) =>
4009
- (Array.isArray(identity) ? identity : [identity]).includes(identityB)
4010
- ),
4011
- "active rewrite must reacquire the current blocked target identity",
4306
+ storageIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity))
4012
4307
  );
4013
- let recaptureCompleted = false;
4014
- const recapture = peer
4015
- .writeMemory("fact", contentB, {
4016
- source: "test",
4017
- sourceConnector: "provider-a",
4018
- })
4019
- .then((result) => {
4020
- recaptureCompleted = true;
4021
- return result;
4022
- });
4023
- await new Promise((resolve) => setTimeout(resolve, 50));
4024
- assert.equal(recaptureCompleted, false, "recapture must wait for the current target identity lock");
4025
- releaseMarker.resolve();
4026
- assert.equal(await update, true);
4027
- assert.equal((await recapture).tombstoneBlocked, true);
4028
- const after = await peer.readAllMemories();
4029
- assert.equal(
4030
- after.find((memory) => memory.path === targetMemory.path)?.content,
4031
- contentC,
4032
- "the stale update must write the requested content",
4308
+ assert.ok(
4309
+ peerIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity))
4033
4310
  );
4034
- assert.equal(await peer.hasTombstoneBlockedExplicitCapture(contentB, "fact", "provider-a"), true);
4311
+ assert.equal(competingFinished, false, "the peer must wait while the first writer holds the target path");
4312
+
4313
+ releaseRead.resolve();
4314
+ assert.equal(await update, true);
4315
+ assert.equal(await competingUpdate, true);
4316
+ assert.equal((await peer.getMemoryById(target.id))?.content, contentB);
4035
4317
  } finally {
4036
- releaseMarker.resolve();
4037
- prepareSpy.mock.restore();
4318
+ releaseRead.resolve();
4038
4319
  storageWithOverrides.readMemoryByPath = originalRead;
4039
- storageWithOverrides.withTombstoneBlockedCaptureWriteLock = originalLock;
4320
+ storageWithOverrides.withTombstoneBlockedCaptureWriteLock = originalStorageLock;
4321
+ peerWithOverride.withTombstoneBlockedCaptureWriteLock = originalPeerLock;
4040
4322
  await update.catch(() => false);
4323
+ await competingUpdate?.catch(() => false);
4041
4324
  }
4042
4325
  });
4043
4326
  });