@remnic/core 9.45.3 → 9.45.5

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 (766) 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 -75
  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 -76
  8. package/dist/access-boundary.d.ts +15 -11
  9. package/dist/access-boundary.js +84 -75
  10. package/dist/access-citation-namespace.js +2 -2
  11. package/dist/access-cli.js +191 -177
  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 -75
  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 -75
  27. package/dist/access-http.d.ts +15 -11
  28. package/dist/access-http.js +104 -90
  29. package/dist/access-identity-continuity-surface.d.ts +9 -8
  30. package/dist/access-identity-continuity-surface.js +84 -75
  31. package/dist/access-lcm-surface.d.ts +14 -10
  32. package/dist/access-lcm-surface.js +84 -75
  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 -82
  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 -75
  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 -75
  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 -77
  48. package/dist/access-operations.d.ts +18 -14
  49. package/dist/access-operations.js +91 -79
  50. package/dist/access-recall-concurrency.d.ts +16 -26
  51. package/dist/access-recall-concurrency.js +86 -76
  52. package/dist/access-recall-response.d.ts +18 -14
  53. package/dist/access-recall-response.js +84 -75
  54. package/dist/access-recall-surface.d.ts +29 -24
  55. package/dist/access-recall-surface.js +84 -75
  56. package/dist/access-schema.d.ts +84 -84
  57. package/dist/access-schema.js +3 -3
  58. package/dist/{access-service-CiJRsgAB.d.ts → access-service-CNN89xyn.d.ts} +25 -16
  59. package/dist/access-service-helpers.d.ts +14 -10
  60. package/dist/access-service.d.ts +14 -10
  61. package/dist/access-service.js +84 -75
  62. package/dist/access-surface-catalog.d.ts +14 -10
  63. package/dist/access-surface-catalog.js +4 -0
  64. package/dist/access-surface-catalog.js.map +1 -1
  65. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  66. package/dist/action-confidence.d.ts +2 -1
  67. package/dist/active-memory-bridge.d.ts +2 -1
  68. package/dist/active-recall.d.ts +2 -1
  69. package/dist/active-recall.js +10 -8
  70. package/dist/active-recall.js.map +1 -1
  71. package/dist/adapters/index.js +4 -4
  72. package/dist/adapters/registry.js +2 -2
  73. package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +6 -6
  74. package/dist/behavior-learner.d.ts +2 -1
  75. package/dist/behavior-learner.js +1 -1
  76. package/dist/behavior-signals.d.ts +2 -1
  77. package/dist/bootstrap.d.ts +9 -8
  78. package/dist/briefing.d.ts +3 -2
  79. package/dist/briefing.js +24 -22
  80. package/dist/buffer-surprise-report.d.ts +2 -1
  81. package/dist/buffer-turn-helpers.d.ts +2 -1
  82. package/dist/buffer.d.ts +3 -2
  83. package/dist/buffer.js +12 -11
  84. package/dist/bulk-import/index.d.ts +4 -3
  85. package/dist/calibration.d.ts +2 -1
  86. package/dist/capabilities.d.ts +2 -1
  87. package/dist/{capsule-merge-IDWJPCWK.js → capsule-merge-Q6AR3XL7.js} +67 -54
  88. package/dist/capsule-merge-Q6AR3XL7.js.map +1 -0
  89. package/dist/{catalog-scBmy0sO.d.ts → catalog-bctMURhN.d.ts} +1 -1
  90. package/dist/causal-behavior.d.ts +2 -1
  91. package/dist/causal-behavior.js +2 -2
  92. package/dist/causal-chain.js +2 -2
  93. package/dist/causal-consolidation.d.ts +2 -1
  94. package/dist/causal-consolidation.js +28 -26
  95. package/dist/causal-consolidation.js.map +1 -1
  96. package/dist/causal-retrieval.js +2 -2
  97. package/dist/causal-trajectory-graph.d.ts +2 -1
  98. package/dist/causal-trajectory.js +1 -1
  99. package/dist/{chunk-E5UK4VPE.js → chunk-2FSTB6BJ.js} +5 -5
  100. package/dist/{chunk-5ZE7QHTK.js → chunk-2X2T2UVE.js} +5 -5
  101. package/dist/{chunk-P4DRWEYC.js → chunk-3COYXTGM.js} +2 -2
  102. package/dist/{chunk-5IVLTFOV.js → chunk-44N6ESJ4.js} +2 -2
  103. package/dist/{chunk-DL7ZD3JH.js → chunk-4FBVAGV3.js} +14 -9
  104. package/dist/chunk-4FBVAGV3.js.map +1 -0
  105. package/dist/{chunk-WOCNN776.js → chunk-4POAMKV6.js} +100 -41
  106. package/dist/chunk-4POAMKV6.js.map +1 -0
  107. package/dist/{chunk-HO3QBJEY.js → chunk-5546W5SI.js} +2 -2
  108. package/dist/{chunk-AAIUERNB.js → chunk-5QJQHBLE.js} +6 -6
  109. package/dist/{chunk-6CZPDBJS.js → chunk-5U7ID3EZ.js} +3 -3
  110. package/dist/{chunk-RN7DY3FC.js → chunk-6ISC4AVB.js} +31 -12
  111. package/dist/chunk-6ISC4AVB.js.map +1 -0
  112. package/dist/chunk-773TRRGT.js +36 -0
  113. package/dist/chunk-773TRRGT.js.map +1 -0
  114. package/dist/chunk-7T4TOGMS.js +242 -0
  115. package/dist/chunk-7T4TOGMS.js.map +1 -0
  116. package/dist/{chunk-DLVPUX7U.js → chunk-7YKVM5H3.js} +8 -6
  117. package/dist/chunk-7YKVM5H3.js.map +1 -0
  118. package/dist/chunk-7YQ6ESEA.js +322 -0
  119. package/dist/chunk-7YQ6ESEA.js.map +1 -0
  120. package/dist/{chunk-DNWXFTLD.js → chunk-A4IJCD2Z.js} +2 -2
  121. package/dist/{chunk-3CE77VAP.js → chunk-A4JMGKCD.js} +87 -74
  122. package/dist/chunk-A4JMGKCD.js.map +1 -0
  123. package/dist/chunk-A5KNZSNA.js +26 -0
  124. package/dist/chunk-A5KNZSNA.js.map +1 -0
  125. package/dist/{chunk-PKNLM44P.js → chunk-AC5OWJLV.js} +9 -9
  126. package/dist/{chunk-LZ4LDKHZ.js → chunk-AMAUBUKY.js} +6 -6
  127. package/dist/{chunk-CUM2BBPN.js → chunk-AUMWZSE7.js} +19 -10
  128. package/dist/chunk-AUMWZSE7.js.map +1 -0
  129. package/dist/{chunk-BUE5E2HL.js → chunk-BGLY7EEM.js} +5 -314
  130. package/dist/chunk-BGLY7EEM.js.map +1 -0
  131. package/dist/chunk-BIPBQQFI.js +44 -0
  132. package/dist/chunk-BIPBQQFI.js.map +1 -0
  133. package/dist/{chunk-S5SLVSVY.js → chunk-BQIFZ2MP.js} +5 -5
  134. package/dist/chunk-BTTPKDIL.js +34 -0
  135. package/dist/{chunk-PVGDJXVK.js.map → chunk-BTTPKDIL.js.map} +1 -1
  136. package/dist/chunk-CK5KOVHW.js +69 -0
  137. package/dist/chunk-CK5KOVHW.js.map +1 -0
  138. package/dist/{chunk-Q6IP2ARR.js → chunk-CSOYVTRX.js} +2 -2
  139. package/dist/{chunk-XOQSEF7X.js → chunk-CVILPI77.js} +6 -6
  140. package/dist/{chunk-VWAXN2BN.js → chunk-CX4ZUMC6.js} +91 -83
  141. package/dist/chunk-CX4ZUMC6.js.map +1 -0
  142. package/dist/{chunk-NVRYW264.js → chunk-DAJPRXBR.js} +16 -13
  143. package/dist/chunk-DAJPRXBR.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-4LMA77JH.js → chunk-E5XQIWAL.js} +3 -3
  147. package/dist/{chunk-WUNIWKY4.js → chunk-ELIL2A37.js} +6 -6
  148. package/dist/{chunk-OQ5PRDDS.js → chunk-ERZ2R42X.js} +6 -6
  149. package/dist/{chunk-U7GW7NE7.js → chunk-FIK3CQNA.js} +10 -10
  150. package/dist/{chunk-D3J5SLQK.js → chunk-FR27HBBA.js} +81 -20
  151. package/dist/chunk-FR27HBBA.js.map +1 -0
  152. package/dist/{chunk-E6PNLPGJ.js → chunk-FUCYDRE5.js} +838 -480
  153. package/dist/chunk-FUCYDRE5.js.map +1 -0
  154. package/dist/{chunk-HZFHQ4AQ.js → chunk-G7A5HLUS.js} +23 -17
  155. package/dist/chunk-G7A5HLUS.js.map +1 -0
  156. package/dist/{chunk-33PLLLL7.js → chunk-GFCVUY6G.js} +6 -6
  157. package/dist/{chunk-HREE4JHI.js → chunk-GODSPTOT.js} +477 -278
  158. package/dist/chunk-GODSPTOT.js.map +1 -0
  159. package/dist/{chunk-S2NCTZGJ.js → chunk-GRUYA45P.js} +15 -15
  160. package/dist/chunk-GRUYA45P.js.map +1 -0
  161. package/dist/{chunk-VUPTKTDV.js → chunk-GUAL4PQH.js} +3 -3
  162. package/dist/{chunk-CINZGPSJ.js → chunk-GUMZC2BO.js} +2 -2
  163. package/dist/{chunk-H24WNPA2.js → chunk-GWFSVJ4P.js} +3 -3
  164. package/dist/{chunk-7XC2HX75.js → chunk-GYPQL6XN.js} +157 -16
  165. package/dist/chunk-GYPQL6XN.js.map +1 -0
  166. package/dist/{chunk-TSH56VPU.js → chunk-HAYSYUAB.js} +2 -2
  167. package/dist/{chunk-PDLBLTOK.js → chunk-HC3PBX23.js} +9 -9
  168. package/dist/{chunk-TDHTVMPG.js → chunk-HFPASSFV.js} +7 -2
  169. package/dist/chunk-HFPASSFV.js.map +1 -0
  170. package/dist/chunk-J2WC5LF4.js +395 -0
  171. package/dist/chunk-J2WC5LF4.js.map +1 -0
  172. package/dist/{chunk-KXB4VXHY.js → chunk-JIYDRBVZ.js} +2 -2
  173. package/dist/chunk-JV3C2MNQ.js +74 -0
  174. package/dist/chunk-JV3C2MNQ.js.map +1 -0
  175. package/dist/{chunk-HLPD7B7P.js → chunk-JZH4LWHB.js} +2 -2
  176. package/dist/{chunk-AV5ZEH4M.js → chunk-KVJRXN2E.js} +2 -2
  177. package/dist/{chunk-WFTIGIIS.js → chunk-L6CQ7WIW.js} +5 -5
  178. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  179. package/dist/{chunk-EJUEXZHX.js → chunk-LLJMAULE.js} +2 -2
  180. package/dist/{chunk-N5Z4EVOR.js → chunk-LNEWDF2A.js} +36 -11
  181. package/dist/chunk-LNEWDF2A.js.map +1 -0
  182. package/dist/{chunk-QN25OCUF.js → chunk-LPYDOLSM.js} +5 -5
  183. package/dist/{chunk-AS7YMSL6.js → chunk-M23RF3LJ.js} +4 -4
  184. package/dist/{chunk-OAEQLRCY.js → chunk-MO4HSXHZ.js} +5 -5
  185. package/dist/{chunk-ECK75GDJ.js → chunk-N3LL5NEU.js} +43 -24
  186. package/dist/chunk-N3LL5NEU.js.map +1 -0
  187. package/dist/chunk-NEF7LR5J.js +29 -0
  188. package/dist/chunk-NEF7LR5J.js.map +1 -0
  189. package/dist/{chunk-3F2LKUMU.js → chunk-NIS256NW.js} +2 -2
  190. package/dist/{chunk-YIAA2X3D.js → chunk-NK5RGJ65.js} +3 -3
  191. package/dist/chunk-NLDVVWCL.js +84 -0
  192. package/dist/chunk-NLDVVWCL.js.map +1 -0
  193. package/dist/{chunk-4J7G5SY4.js → chunk-NZBZ7IS2.js} +72 -24
  194. package/dist/chunk-NZBZ7IS2.js.map +1 -0
  195. package/dist/{chunk-3TBLDMJA.js → chunk-O4KMGRXE.js} +5 -2
  196. package/dist/chunk-O4KMGRXE.js.map +1 -0
  197. package/dist/{chunk-7TWUCYER.js → chunk-PNRA7FAD.js} +7 -7
  198. package/dist/{chunk-5I4M26Q7.js → chunk-QBSFOKY6.js} +4 -4
  199. package/dist/{chunk-E53DSZEN.js → chunk-QR6G5KF4.js} +3 -3
  200. package/dist/{chunk-CJ2ZR7UA.js → chunk-QUENPGWZ.js} +261 -211
  201. package/dist/chunk-QUENPGWZ.js.map +1 -0
  202. package/dist/{chunk-4UH4BTGK.js → chunk-QVJPH7SH.js} +84 -84
  203. package/dist/{chunk-UYLMNVY6.js → chunk-R3KHKU7M.js} +16 -9
  204. package/dist/chunk-R3KHKU7M.js.map +1 -0
  205. package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
  206. package/dist/{chunk-WDISJRMG.js → chunk-RMMVQQA6.js} +2 -2
  207. package/dist/{chunk-JVLCVFQ4.js → chunk-RNHVVMFN.js} +3 -3
  208. package/dist/{chunk-QJAQNXWI.js → chunk-RVO6TCTU.js} +81 -84
  209. package/dist/chunk-RVO6TCTU.js.map +1 -0
  210. package/dist/chunk-S2HLHAZ4.js +16 -0
  211. package/dist/chunk-S2HLHAZ4.js.map +1 -0
  212. package/dist/{chunk-KWMXR7XS.js → chunk-S2V7RUCL.js} +8 -1
  213. package/dist/{chunk-KWMXR7XS.js.map → chunk-S2V7RUCL.js.map} +1 -1
  214. package/dist/{chunk-5SM35XZR.js → chunk-S5NZBKKQ.js} +2 -2
  215. package/dist/{chunk-VNA7W7QF.js → chunk-SVH57F5Z.js} +12 -4
  216. package/dist/chunk-SVH57F5Z.js.map +1 -0
  217. package/dist/{chunk-WIPEXG6R.js → chunk-SXIMQLGV.js} +2 -2
  218. package/dist/{chunk-RVLJEII5.js → chunk-SYUBB3WM.js} +256 -187
  219. package/dist/chunk-SYUBB3WM.js.map +1 -0
  220. package/dist/{chunk-VCD4PSK2.js → chunk-TQZ4DVBC.js} +7 -4
  221. package/dist/chunk-TQZ4DVBC.js.map +1 -0
  222. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  223. package/dist/{chunk-YV32N67O.js → chunk-URS5GSM7.js} +1 -1
  224. package/dist/chunk-URS5GSM7.js.map +1 -0
  225. package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
  226. package/dist/{chunk-BJKPPZ6Z.js → chunk-UW66OZTD.js} +2 -2
  227. package/dist/{chunk-XYTOI63Z.js → chunk-V2TNYF6Q.js} +19 -11
  228. package/dist/chunk-V2TNYF6Q.js.map +1 -0
  229. package/dist/{chunk-S2BBISHU.js → chunk-VANZKHTN.js} +3 -3
  230. package/dist/chunk-VHFXP27N.js +250 -0
  231. package/dist/chunk-VHFXP27N.js.map +1 -0
  232. package/dist/chunk-VL35ZFSZ.js +102 -0
  233. package/dist/chunk-VL35ZFSZ.js.map +1 -0
  234. package/dist/{chunk-3Y224NYC.js → chunk-VYISFWVX.js} +2 -2
  235. package/dist/{chunk-JE7EK33X.js → chunk-W2V7UESE.js} +2 -2
  236. package/dist/{chunk-TIHMZFIV.js → chunk-W3IC7QOY.js} +3 -3
  237. package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
  238. package/dist/{chunk-P2BM76KT.js → chunk-WAS4HV46.js} +174 -43
  239. package/dist/chunk-WAS4HV46.js.map +1 -0
  240. package/dist/{chunk-57QKLRBV.js → chunk-WB7JSQCP.js} +2 -1
  241. package/dist/chunk-WB7JSQCP.js.map +1 -0
  242. package/dist/{chunk-A5OJCXZL.js → chunk-WZ3TOIDW.js} +15 -4
  243. package/dist/chunk-WZ3TOIDW.js.map +1 -0
  244. package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
  245. package/dist/{chunk-T2TTP3KU.js → chunk-X4IDNPOS.js} +2 -2
  246. package/dist/{chunk-UVIKWC7M.js → chunk-XAGYS7X6.js} +17 -17
  247. package/dist/{chunk-BLAKS3CP.js → chunk-XL3TATMJ.js} +3 -3
  248. package/dist/{chunk-W4XJFLAL.js → chunk-XPRJSHNI.js} +2 -2
  249. package/dist/{chunk-5TFP4CUL.js → chunk-XQ3HXAQH.js} +14 -11
  250. package/dist/chunk-XQ3HXAQH.js.map +1 -0
  251. package/dist/{chunk-E6EE5B67.js → chunk-YK6BDDHP.js} +4 -4
  252. package/dist/{chunk-ES36HTSC.js → chunk-YLHM5BQQ.js} +3 -3
  253. package/dist/{chunk-ULARSG5Z.js → chunk-YN6ASZUG.js} +10 -8
  254. package/dist/{chunk-ULARSG5Z.js.map → chunk-YN6ASZUG.js.map} +1 -1
  255. package/dist/{chunk-VOUOLGIP.js → chunk-YRFAYOFQ.js} +11 -13
  256. package/dist/chunk-YRFAYOFQ.js.map +1 -0
  257. package/dist/{chunk-IKKWIPYN.js → chunk-YYQAKIDJ.js} +37 -1
  258. package/dist/chunk-YYQAKIDJ.js.map +1 -0
  259. package/dist/{chunk-GF22HWS2.js → chunk-Z54EM5YZ.js} +4 -4
  260. package/dist/{chunk-64UDOIMI.js → chunk-ZLQ37WJX.js} +2 -2
  261. package/dist/{cli-BUGN3d6_.d.ts → cli-BHBswmUa.d.ts} +5 -5
  262. package/dist/cli.d.ts +16 -12
  263. package/dist/cli.js +138 -123
  264. package/dist/compounding/engine.d.ts +3 -2
  265. package/dist/compounding/engine.js +25 -23
  266. package/dist/compounding/preference-consolidator.d.ts +2 -1
  267. package/dist/compression-optimizer.d.ts +2 -1
  268. package/dist/config.d.ts +2 -1
  269. package/dist/config.js +10 -8
  270. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  271. package/dist/connectors/codex-materialize-runner.js +24 -22
  272. package/dist/connectors/codex-materialize.d.ts +2 -1
  273. package/dist/connectors/index.d.ts +2 -1
  274. package/dist/connectors/index.js +27 -25
  275. package/dist/consolidation-provenance-check.d.ts +3 -2
  276. package/dist/consolidation-provenance-check.js +4 -4
  277. package/dist/consolidation-undo.d.ts +3 -2
  278. package/dist/consolidation-undo.js +10 -7
  279. package/dist/consolidation-undo.js.map +1 -1
  280. package/dist/contradiction/index.d.ts +3 -2
  281. package/dist/converge-config.d.ts +2 -1
  282. package/dist/convergence-refresh.d.ts +4 -3
  283. package/dist/convergence-refresh.js +28 -26
  284. package/dist/conversation-index/backend.d.ts +2 -1
  285. package/dist/conversation-index/backend.js +2 -2
  286. package/dist/conversation-index/chunker.d.ts +2 -1
  287. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  288. package/dist/conversation-index/indexer.d.ts +2 -1
  289. package/dist/conversation-index/search.d.ts +2 -1
  290. package/dist/corpus-watermark.d.ts +2 -1
  291. package/dist/corpus-watermark.js +43 -41
  292. package/dist/day-summary.d.ts +2 -1
  293. package/dist/delinearize.d.ts +2 -1
  294. package/dist/direct-answer-wiring.d.ts +2 -1
  295. package/dist/direct-answer-wiring.js +2 -2
  296. package/dist/direct-answer.d.ts +2 -1
  297. package/dist/embedding-fallback.d.ts +2 -1
  298. package/dist/embedding-fallback.js +2 -2
  299. package/dist/enrichment/index.d.ts +2 -1
  300. package/dist/entity-retrieval-boundaries.js +1 -1
  301. package/dist/entity-retrieval.d.ts +3 -2
  302. package/dist/entity-retrieval.js +25 -23
  303. package/dist/entity-schema.d.ts +2 -1
  304. package/dist/explicit-capture.d.ts +9 -8
  305. package/dist/explicit-capture.js +11 -9
  306. package/dist/external-wiki-access.d.ts +127 -0
  307. package/dist/external-wiki-access.js +187 -0
  308. package/dist/external-wiki-access.js.map +1 -0
  309. package/dist/external-wiki-cli.d.ts +13 -0
  310. package/dist/external-wiki-cli.js +10 -0
  311. package/dist/external-wiki-cli.js.map +1 -0
  312. package/dist/external-wiki-collection-registration.d.ts +39 -0
  313. package/dist/external-wiki-collection-registration.js +79 -0
  314. package/dist/external-wiki-collection-registration.js.map +1 -0
  315. package/dist/external-wiki-collection.d.ts +50 -0
  316. package/dist/external-wiki-collection.js +387 -0
  317. package/dist/external-wiki-collection.js.map +1 -0
  318. package/dist/external-wiki-config.d.ts +13 -0
  319. package/dist/external-wiki-config.js +13 -0
  320. package/dist/external-wiki-config.js.map +1 -0
  321. package/dist/external-wiki-guard.d.ts +11 -0
  322. package/dist/external-wiki-guard.js +18 -0
  323. package/dist/external-wiki-guard.js.map +1 -0
  324. package/dist/external-wiki-mcp-tools.d.ts +123 -0
  325. package/dist/external-wiki-mcp-tools.js +8 -0
  326. package/dist/external-wiki-mcp-tools.js.map +1 -0
  327. package/dist/external-wiki-search.d.ts +42 -0
  328. package/dist/external-wiki-search.js +11 -0
  329. package/dist/external-wiki-search.js.map +1 -0
  330. package/dist/external-wiki.d.ts +39 -0
  331. package/dist/external-wiki.js +14 -0
  332. package/dist/external-wiki.js.map +1 -0
  333. package/dist/extraction-error-classification.d.ts +2 -1
  334. package/dist/extraction-faithfulness.d.ts +2 -1
  335. package/dist/extraction-judge-telemetry.d.ts +2 -1
  336. package/dist/extraction-judge-training.d.ts +2 -1
  337. package/dist/extraction-judge.d.ts +2 -1
  338. package/dist/extraction-liveness.d.ts +2 -1
  339. package/dist/extraction-source-grounding-helpers.d.ts +5 -3
  340. package/dist/extraction-source-grounding-helpers.js +1 -1
  341. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  342. package/dist/extraction-source-grounding-rules.js +2 -2
  343. package/dist/extraction-source-grounding.d.ts +2 -1
  344. package/dist/extraction-source-grounding.js +5 -5
  345. package/dist/extraction.d.ts +2 -1
  346. package/dist/extraction.js +46 -43
  347. package/dist/fallback-llm.d.ts +2 -1
  348. package/dist/{first-start-migration-F2QJD66E.js → first-start-migration-ZSHEFEI3.js} +10 -12
  349. package/dist/{first-start-migration-F2QJD66E.js.map → first-start-migration-ZSHEFEI3.js.map} +1 -1
  350. package/dist/graph-dashboard-diff.d.ts +2 -1
  351. package/dist/graph-dashboard-key.d.ts +2 -1
  352. package/dist/graph-dashboard-parser.d.ts +2 -1
  353. package/dist/graph-edge-reinforcement.d.ts +2 -1
  354. package/dist/graph-snapshot.d.ts +2 -1
  355. package/dist/graph.d.ts +2 -1
  356. package/dist/harmonic-retrieval.js +2 -2
  357. package/dist/importance.d.ts +2 -1
  358. package/dist/importers/index.d.ts +2 -1
  359. package/dist/in-flight-reads.d.ts +2 -1
  360. package/dist/index.d.ts +443 -430
  361. package/dist/index.js +304 -269
  362. package/dist/intent.d.ts +2 -1
  363. package/dist/lcm/engine.d.ts +2 -1
  364. package/dist/lcm/engine.js +2 -2
  365. package/dist/lcm/index.d.ts +2 -1
  366. package/dist/lcm/index.js +7 -7
  367. package/dist/lcm/tools.d.ts +2 -1
  368. package/dist/lifecycle.d.ts +2 -1
  369. package/dist/live-connectors-runner.d.ts +2 -1
  370. package/dist/local-llm.d.ts +2 -1
  371. package/dist/local-llm.js +2 -2
  372. package/dist/local-model-endpoint.d.ts +2 -1
  373. package/dist/maintenance/memory-governance.d.ts +2 -1
  374. package/dist/maintenance/memory-governance.js +25 -23
  375. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  376. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -23
  377. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  378. package/dist/maintenance/rebuild-memory-projection.js +27 -25
  379. package/dist/{maintenance-LbuS2rUA.d.ts → maintenance-CoRikzIt.d.ts} +3 -3
  380. package/dist/mcp-memory-inspector-app.d.ts +14 -10
  381. package/dist/mcp-read-only-tools.js +1 -1
  382. package/dist/memory-action-policy.d.ts +2 -1
  383. package/dist/memory-cache.d.ts +2 -1
  384. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  385. package/dist/memory-projection-store.d.ts +2 -1
  386. package/dist/memory-provenance.d.ts +2 -1
  387. package/dist/memory-snapshot.d.ts +10 -0
  388. package/dist/memory-snapshot.js +8 -0
  389. package/dist/memory-snapshot.js.map +1 -0
  390. package/dist/memory-worth-outcomes.d.ts +3 -2
  391. package/dist/models-json.d.ts +2 -1
  392. package/dist/namespaces/migrate.d.ts +4 -3
  393. package/dist/namespaces/migrate.js +41 -39
  394. package/dist/namespaces/principal.d.ts +2 -1
  395. package/dist/namespaces/search.d.ts +2 -1
  396. package/dist/namespaces/search.js +18 -18
  397. package/dist/namespaces/storage.d.ts +4 -3
  398. package/dist/namespaces/storage.js +24 -22
  399. package/dist/native-knowledge.d.ts +2 -1
  400. package/dist/offline-sync-impression-drain.d.ts +2 -1
  401. package/dist/offline-sync-impression-drain.js +11 -9
  402. package/dist/offline-sync.d.ts +29 -3
  403. package/dist/offline-sync.js +6 -2
  404. package/dist/operator-doctor-corpus.d.ts +2 -1
  405. package/dist/operator-doctor-corpus.js +46 -44
  406. package/dist/operator-doctor-replica.d.ts +2 -1
  407. package/dist/operator-doctor-replica.js +3 -3
  408. package/dist/operator-toolkit.d.ts +4 -3
  409. package/dist/operator-toolkit.js +60 -55
  410. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  411. package/dist/orchestration/maintenance.d.ts +5 -4
  412. package/dist/orchestration/maintenance.js +37 -33
  413. package/dist/{orchestrator-rHiWt32X.d.ts → orchestrator-BJeq7Pw1.d.ts} +14 -7
  414. package/dist/orchestrator.d.ts +9 -8
  415. package/dist/orchestrator.js +200 -186
  416. package/dist/page-versioning.js +3 -3
  417. package/dist/patterns-cli.d.ts +2 -1
  418. package/dist/{pipeline-W_97O8BV.d.ts → pipeline-CNjY4wk3.d.ts} +1 -1
  419. package/dist/policy-runtime.d.ts +2 -1
  420. package/dist/policy-runtime.js +1 -1
  421. package/dist/proactive-contention.d.ts +2 -1
  422. package/dist/provenance.d.ts +2 -1
  423. package/dist/provenance.js +2 -2
  424. package/dist/{qmd-LWtMofAf.d.ts → qmd-C0UDZidt.d.ts} +9 -7
  425. package/dist/qmd-preflight.d.ts +5 -4
  426. package/dist/qmd-preflight.js +2 -2
  427. package/dist/qmd-recall-cache.d.ts +2 -1
  428. package/dist/qmd.d.ts +4 -3
  429. package/dist/qmd.js +8 -8
  430. package/dist/recall-concurrency-config.d.ts +2 -1
  431. package/dist/recall-disclosure-escalation.d.ts +2 -1
  432. package/dist/recall-explain-renderer.d.ts +2 -1
  433. package/dist/recall-explain-renderer.js +3 -3
  434. package/dist/recall-memory-map.d.ts +2 -1
  435. package/dist/recall-planner-llm.d.ts +2 -1
  436. package/dist/recall-state.d.ts +2 -1
  437. package/dist/recall-tag-filter.d.ts +2 -1
  438. package/dist/recall-timings.d.ts +2 -1
  439. package/dist/recall-xray-cli.d.ts +2 -1
  440. package/dist/recall-xray-cli.js +4 -4
  441. package/dist/recall-xray-renderer.d.ts +2 -1
  442. package/dist/recall-xray-renderer.js +3 -3
  443. package/dist/recall-xray.d.ts +8 -1
  444. package/dist/recall-xray.js +2 -2
  445. package/dist/reconcile/cursor.d.ts +12 -2
  446. package/dist/reconcile/cursor.js +46 -7
  447. package/dist/reconcile/cursor.js.map +1 -1
  448. package/dist/reconcile/manifest.d.ts +9 -2
  449. package/dist/reconcile/manifest.js +15 -268
  450. package/dist/reconcile/manifest.js.map +1 -1
  451. package/dist/reconcile/plan.d.ts +4 -1
  452. package/dist/reconcile/plan.js +4 -4
  453. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  454. package/dist/replay/normalizers/claude.d.ts +2 -1
  455. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  456. package/dist/replay/normalizers/shared.d.ts +2 -1
  457. package/dist/replay/runner.d.ts +2 -1
  458. package/dist/replay/types.d.ts +2 -1
  459. package/dist/replica-divergence.d.ts +2 -1
  460. package/dist/replica-divergence.js +2 -2
  461. package/dist/replica-peers-config.d.ts +2 -1
  462. package/dist/resolve-auth-token.d.ts +2 -1
  463. package/dist/resume-bundles.js +12 -10
  464. package/dist/retrieval-agents.d.ts +4 -3
  465. package/dist/retrieval-agents.js +2 -2
  466. package/dist/retrieval-tiers.d.ts +2 -1
  467. package/dist/routing/engine.d.ts +2 -1
  468. package/dist/routing/store.d.ts +2 -1
  469. package/dist/salvage-envelope.d.ts +2 -1
  470. package/dist/schemas.d.ts +54 -54
  471. package/dist/{scope-profiles-BiQKOE-p.d.ts → scope-profiles-BJzp2F5A.d.ts} +1 -1
  472. package/dist/search/embed-helper.d.ts +2 -1
  473. package/dist/search/embed-helper.js +3 -3
  474. package/dist/search/factory.d.ts +4 -2
  475. package/dist/search/factory.js +20 -18
  476. package/dist/search/index.d.ts +2 -1
  477. package/dist/search/index.js +20 -20
  478. package/dist/search/lancedb-backend.d.ts +2 -1
  479. package/dist/search/lancedb-backend.js +4 -4
  480. package/dist/search/meilisearch-backend.d.ts +2 -1
  481. package/dist/search/meilisearch-backend.js +4 -4
  482. package/dist/search/noop-backend.d.ts +2 -1
  483. package/dist/search/orama-backend.d.ts +2 -1
  484. package/dist/search/orama-backend.js +4 -4
  485. package/dist/search/port.d.ts +18 -1
  486. package/dist/search/port.js +1 -1
  487. package/dist/search/remote-backend.d.ts +2 -1
  488. package/dist/search/remote-backend.js +2 -2
  489. package/dist/secure-store/index.js +2 -2
  490. package/dist/{semantic-consolidation-dHYCyqgh.d.ts → semantic-consolidation-D4KAZO2G.d.ts} +1 -1
  491. package/dist/semantic-consolidation.d.ts +3 -2
  492. package/dist/semantic-consolidation.js +26 -24
  493. package/dist/semantic-rule-promotion.js +24 -22
  494. package/dist/semantic-rule-verifier.d.ts +2 -1
  495. package/dist/semantic-rule-verifier.js +25 -23
  496. package/dist/{service-DJG3KCQ4.d.ts → service-DWC4tq7p.d.ts} +2 -2
  497. package/dist/session-observer-bands.d.ts +2 -1
  498. package/dist/session-observer-state.d.ts +2 -1
  499. package/dist/shared-context/manager.d.ts +10 -9
  500. package/dist/shared-context/manager.js +2 -2
  501. package/dist/signal.d.ts +2 -1
  502. package/dist/source-agent-qualifier.d.ts +2 -1
  503. package/dist/source-agent-qualifier.js +43 -40
  504. package/dist/{storage-F9FVh-w9.d.ts → storage-DPGjB-8e.d.ts} +28 -13
  505. package/dist/storage.d.ts +3 -2
  506. package/dist/storage.js +26 -24
  507. package/dist/summarizer.d.ts +2 -1
  508. package/dist/summarizer.js +5 -5
  509. package/dist/summary-snapshot.d.ts +2 -1
  510. package/dist/temporal-supersession.d.ts +3 -2
  511. package/dist/temporal-timeline-recall.d.ts +2 -1
  512. package/dist/temporal-validity.d.ts +2 -1
  513. package/dist/threading.d.ts +2 -1
  514. package/dist/tier-migration.d.ts +3 -2
  515. package/dist/tier-migration.js +1 -1
  516. package/dist/tier-routing.d.ts +2 -1
  517. package/dist/tool-scoped-memory.d.ts +5 -1
  518. package/dist/tool-scoped-memory.js +3 -1
  519. package/dist/topics.d.ts +2 -1
  520. package/dist/transcript.d.ts +2 -1
  521. package/dist/transfer/capsule-import.js +4 -4
  522. package/dist/transfer/types.d.ts +66 -66
  523. package/dist/trust-score-stage.d.ts +2 -1
  524. package/dist/trust-score.d.ts +2 -1
  525. package/dist/{types-rEwubvim.d.ts → types-yX_FwERf.d.ts} +8 -1
  526. package/dist/types.d.ts +2 -1
  527. package/dist/types.js +1 -1
  528. package/dist/utility-runtime.d.ts +2 -1
  529. package/dist/verified-recall.js +25 -23
  530. package/dist/write-envelope.d.ts +2 -1
  531. package/package.json +2 -2
  532. package/src/abort-error.ts +17 -0
  533. package/src/access-admin-ops-surface.ts +1 -0
  534. package/src/access-boundary.ts +1 -0
  535. package/src/access-coding-context-resolution.ts +42 -0
  536. package/src/access-extraction-force-flush.ts +38 -2
  537. package/src/access-http-lcm-compaction.ts +5 -2
  538. package/src/access-http-offline-stream.ts +80 -0
  539. package/src/access-http.test.ts +310 -3
  540. package/src/access-http.ts +84 -77
  541. package/src/access-mcp-output-schemas.ts +36 -0
  542. package/src/access-mcp.test.ts +95 -1
  543. package/src/access-mcp.ts +7 -9
  544. package/src/access-observe-helpers.ts +64 -22
  545. package/src/access-observe-write-surface.ts +8 -0
  546. package/src/access-offline-manifest.ts +54 -0
  547. package/src/access-operations-batch.ts +3 -3
  548. package/src/access-operations.ts +13 -7
  549. package/src/access-recall-concurrency.ts +3 -27
  550. package/src/access-recall-surface.ts +3 -0
  551. package/src/access-service-health.test.ts +32 -7
  552. package/src/access-service-namespace.test.ts +55 -0
  553. package/src/access-service-observe-idempotency.test.ts +34 -2
  554. package/src/access-service-observe-lcm-parity.test.ts +183 -23
  555. package/src/access-service-observe-scope.test.ts +160 -1
  556. package/src/access-service-offline-file-content.test.ts +345 -1
  557. package/src/access-service.ts +88 -62
  558. package/src/access-surface-catalog.ts +4 -0
  559. package/src/admin/admin-surfaces.ts +2 -0
  560. package/src/binary-lifecycle/pipeline.test.ts +106 -1
  561. package/src/binary-lifecycle/pipeline.ts +3 -0
  562. package/src/coding/git-context.test.ts +47 -0
  563. package/src/coding/git-context.ts +129 -27
  564. package/src/config.test.ts +24 -0
  565. package/src/config.ts +9 -12
  566. package/src/connector-provenance.test.ts +101 -0
  567. package/src/consolidation-undo.ts +3 -0
  568. package/src/convergence-refresh.ts +14 -2
  569. package/src/correction/correction-access-wiring.ts +9 -7
  570. package/src/correction/correction-executor.test.ts +206 -2
  571. package/src/correction/correction-executor.ts +29 -20
  572. package/src/correction/correction-planner.test.ts +36 -0
  573. package/src/correction/correction-planner.ts +9 -15
  574. package/src/correction/correction-service.ts +3 -1
  575. package/src/correction/correction-storage-integration.test.ts +77 -0
  576. package/src/correction/correction-surfaces.test.ts +41 -28
  577. package/src/correction/passive-capture.test.ts +59 -0
  578. package/src/correction/passive-capture.ts +4 -1
  579. package/src/entity-retrieval-boundaries.ts +17 -4
  580. package/src/entity-retrieval.ts +27 -6
  581. package/src/external-wiki-access.test.ts +65 -0
  582. package/src/external-wiki-access.ts +31 -0
  583. package/src/external-wiki-cli.ts +100 -0
  584. package/src/external-wiki-collection-registration.test.ts +163 -0
  585. package/src/external-wiki-collection-registration.ts +101 -0
  586. package/src/external-wiki-collection.test.ts +502 -0
  587. package/src/external-wiki-collection.ts +503 -0
  588. package/src/external-wiki-config.test.ts +135 -0
  589. package/src/external-wiki-config.ts +100 -0
  590. package/src/external-wiki-guard.ts +83 -0
  591. package/src/external-wiki-mcp-tools.ts +23 -0
  592. package/src/external-wiki-search.test.ts +367 -0
  593. package/src/external-wiki-search.ts +362 -0
  594. package/src/external-wiki.test.ts +240 -0
  595. package/src/external-wiki.ts +427 -0
  596. package/src/extraction-scope-source-agent.test.ts +21 -0
  597. package/src/extraction-source-grounding-helpers.ts +243 -53
  598. package/src/extraction-source-grounding-rules.ts +133 -39
  599. package/src/extraction-source-grounding.test.ts +363 -33
  600. package/src/extraction-timeout.test.ts +1 -0
  601. package/src/extraction-watermark.test.ts +150 -7
  602. package/src/extraction.ts +8 -1
  603. package/src/index.ts +9 -5
  604. package/src/maintenance/first-start-migration.ts +11 -11
  605. package/src/mcp-read-only-tools.ts +1 -0
  606. package/src/memory-snapshot.ts +15 -0
  607. package/src/offline-sync.test.ts +194 -0
  608. package/src/offline-sync.ts +217 -13
  609. package/src/orchestration/external-wiki-recall-guard.test.ts +94 -0
  610. package/src/orchestration/extraction-persist.ts +19 -2
  611. package/src/orchestration/extraction-run-helpers.ts +37 -19
  612. package/src/orchestration/extraction-run.test.ts +171 -2
  613. package/src/orchestration/extraction-run.ts +11 -13
  614. package/src/orchestration/extraction-watermark.ts +106 -17
  615. package/src/orchestration/generic-recall-paths.ts +14 -0
  616. package/src/orchestration/orchestrator-helpers.ts +2 -0
  617. package/src/orchestration/orchestrator-init.ts +9 -0
  618. package/src/orchestration/recall-internal-deps.ts +6 -0
  619. package/src/orchestration/recall-internal.ts +154 -33
  620. package/src/orchestration/recall-rerank-coordinator.ts +60 -25
  621. package/src/orchestration/recall-search-pipeline.test.ts +75 -1
  622. package/src/orchestration/recall-search-pipeline.ts +50 -10
  623. package/src/orchestrator-convergence-refresh.test.ts +36 -2
  624. package/src/orchestrator.ts +13 -3
  625. package/src/page-versioning.ts +5 -19
  626. package/src/procedural/procedure-recall.ts +5 -1
  627. package/src/provenance-surfaces.test.ts +3 -0
  628. package/src/qmd-client.test.ts +78 -17
  629. package/src/qmd.test.ts +24 -0
  630. package/src/qmd.ts +224 -315
  631. package/src/recall-explain-renderer.ts +3 -0
  632. package/src/recall-rerank-coordinator.test.ts +61 -0
  633. package/src/recall-xray-renderer.test.ts +6 -0
  634. package/src/recall-xray.test.ts +88 -1
  635. package/src/recall-xray.ts +15 -0
  636. package/src/reconcile/cursor.test.ts +48 -0
  637. package/src/reconcile/cursor.ts +58 -11
  638. package/src/reconcile/manifest.test.ts +4 -0
  639. package/src/reconcile/manifest.ts +41 -51
  640. package/src/reconcile/plan.test.ts +4 -0
  641. package/src/reconcile/plan.ts +28 -16
  642. package/src/search/factory.ts +6 -6
  643. package/src/search/port.ts +25 -9
  644. package/src/secure-store/secure-fs.ts +20 -12
  645. package/src/secure-store/secure-store.test.ts +41 -2
  646. package/src/spaces/index.test.ts +61 -2
  647. package/src/spaces/index.ts +44 -18
  648. package/src/storage/entity-alias-config.ts +97 -0
  649. package/src/storage/entity-canonical-id-lock.ts +53 -23
  650. package/src/storage/entity-canonical-id-migration.ts +53 -22
  651. package/src/storage/entity-canonical-id-references.ts +3 -0
  652. package/src/storage/entity-id-safety.ts +7 -0
  653. package/src/storage/entity-store.ts +6 -2
  654. package/src/storage/memory-frontmatter-metadata.ts +4 -9
  655. package/src/storage/memory-migration-serialization.ts +10 -15
  656. package/src/storage/tombstone-blocked-capture-mutation.ts +52 -64
  657. package/src/storage/tombstone-blocked-capture-sync.ts +244 -199
  658. package/src/storage-contract/cache-coherence.test.ts +99 -0
  659. package/src/storage-deletion-revisions.test.ts +91 -0
  660. package/src/storage-fact-hash-index-defer.test.ts +460 -170
  661. package/src/storage.ts +572 -284
  662. package/src/testing/subjects/first-start-tier-migration.test.ts +75 -0
  663. package/src/tier-migration.ts +10 -12
  664. package/src/tool-scoped-memory.ts +10 -0
  665. package/src/transfer/capsule-import.ts +13 -0
  666. package/src/transfer/capsule-merge.ts +13 -0
  667. package/src/trust-score-recall-paths.test.ts +75 -1
  668. package/src/types.ts +7 -3
  669. package/dist/capsule-merge-IDWJPCWK.js.map +0 -1
  670. package/dist/chunk-3CE77VAP.js.map +0 -1
  671. package/dist/chunk-3TBLDMJA.js.map +0 -1
  672. package/dist/chunk-4J7G5SY4.js.map +0 -1
  673. package/dist/chunk-57QKLRBV.js.map +0 -1
  674. package/dist/chunk-5TFP4CUL.js.map +0 -1
  675. package/dist/chunk-7XC2HX75.js.map +0 -1
  676. package/dist/chunk-A5OJCXZL.js.map +0 -1
  677. package/dist/chunk-BUE5E2HL.js.map +0 -1
  678. package/dist/chunk-CJ2ZR7UA.js.map +0 -1
  679. package/dist/chunk-CUM2BBPN.js.map +0 -1
  680. package/dist/chunk-D3J5SLQK.js.map +0 -1
  681. package/dist/chunk-DL7ZD3JH.js.map +0 -1
  682. package/dist/chunk-DLVPUX7U.js.map +0 -1
  683. package/dist/chunk-E6PNLPGJ.js.map +0 -1
  684. package/dist/chunk-ECK75GDJ.js.map +0 -1
  685. package/dist/chunk-HREE4JHI.js.map +0 -1
  686. package/dist/chunk-HZFHQ4AQ.js.map +0 -1
  687. package/dist/chunk-IKKWIPYN.js.map +0 -1
  688. package/dist/chunk-J7VGGECD.js.map +0 -1
  689. package/dist/chunk-N5Z4EVOR.js.map +0 -1
  690. package/dist/chunk-NVRYW264.js.map +0 -1
  691. package/dist/chunk-P2BM76KT.js.map +0 -1
  692. package/dist/chunk-PVGDJXVK.js +0 -21
  693. package/dist/chunk-QJAQNXWI.js.map +0 -1
  694. package/dist/chunk-RN7DY3FC.js.map +0 -1
  695. package/dist/chunk-RVLJEII5.js.map +0 -1
  696. package/dist/chunk-S2NCTZGJ.js.map +0 -1
  697. package/dist/chunk-TDHTVMPG.js.map +0 -1
  698. package/dist/chunk-UYLMNVY6.js.map +0 -1
  699. package/dist/chunk-VCD4PSK2.js.map +0 -1
  700. package/dist/chunk-VNA7W7QF.js.map +0 -1
  701. package/dist/chunk-VOUOLGIP.js.map +0 -1
  702. package/dist/chunk-VWAXN2BN.js.map +0 -1
  703. package/dist/chunk-WOCNN776.js.map +0 -1
  704. package/dist/chunk-XYTOI63Z.js.map +0 -1
  705. package/dist/chunk-YV32N67O.js.map +0 -1
  706. /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
  707. /package/dist/{chunk-E5UK4VPE.js.map → chunk-2FSTB6BJ.js.map} +0 -0
  708. /package/dist/{chunk-5ZE7QHTK.js.map → chunk-2X2T2UVE.js.map} +0 -0
  709. /package/dist/{chunk-P4DRWEYC.js.map → chunk-3COYXTGM.js.map} +0 -0
  710. /package/dist/{chunk-5IVLTFOV.js.map → chunk-44N6ESJ4.js.map} +0 -0
  711. /package/dist/{chunk-HO3QBJEY.js.map → chunk-5546W5SI.js.map} +0 -0
  712. /package/dist/{chunk-AAIUERNB.js.map → chunk-5QJQHBLE.js.map} +0 -0
  713. /package/dist/{chunk-6CZPDBJS.js.map → chunk-5U7ID3EZ.js.map} +0 -0
  714. /package/dist/{chunk-DNWXFTLD.js.map → chunk-A4IJCD2Z.js.map} +0 -0
  715. /package/dist/{chunk-PKNLM44P.js.map → chunk-AC5OWJLV.js.map} +0 -0
  716. /package/dist/{chunk-LZ4LDKHZ.js.map → chunk-AMAUBUKY.js.map} +0 -0
  717. /package/dist/{chunk-S5SLVSVY.js.map → chunk-BQIFZ2MP.js.map} +0 -0
  718. /package/dist/{chunk-Q6IP2ARR.js.map → chunk-CSOYVTRX.js.map} +0 -0
  719. /package/dist/{chunk-XOQSEF7X.js.map → chunk-CVILPI77.js.map} +0 -0
  720. /package/dist/{chunk-4LMA77JH.js.map → chunk-E5XQIWAL.js.map} +0 -0
  721. /package/dist/{chunk-WUNIWKY4.js.map → chunk-ELIL2A37.js.map} +0 -0
  722. /package/dist/{chunk-OQ5PRDDS.js.map → chunk-ERZ2R42X.js.map} +0 -0
  723. /package/dist/{chunk-U7GW7NE7.js.map → chunk-FIK3CQNA.js.map} +0 -0
  724. /package/dist/{chunk-33PLLLL7.js.map → chunk-GFCVUY6G.js.map} +0 -0
  725. /package/dist/{chunk-VUPTKTDV.js.map → chunk-GUAL4PQH.js.map} +0 -0
  726. /package/dist/{chunk-CINZGPSJ.js.map → chunk-GUMZC2BO.js.map} +0 -0
  727. /package/dist/{chunk-H24WNPA2.js.map → chunk-GWFSVJ4P.js.map} +0 -0
  728. /package/dist/{chunk-TSH56VPU.js.map → chunk-HAYSYUAB.js.map} +0 -0
  729. /package/dist/{chunk-PDLBLTOK.js.map → chunk-HC3PBX23.js.map} +0 -0
  730. /package/dist/{chunk-KXB4VXHY.js.map → chunk-JIYDRBVZ.js.map} +0 -0
  731. /package/dist/{chunk-HLPD7B7P.js.map → chunk-JZH4LWHB.js.map} +0 -0
  732. /package/dist/{chunk-AV5ZEH4M.js.map → chunk-KVJRXN2E.js.map} +0 -0
  733. /package/dist/{chunk-WFTIGIIS.js.map → chunk-L6CQ7WIW.js.map} +0 -0
  734. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  735. /package/dist/{chunk-EJUEXZHX.js.map → chunk-LLJMAULE.js.map} +0 -0
  736. /package/dist/{chunk-QN25OCUF.js.map → chunk-LPYDOLSM.js.map} +0 -0
  737. /package/dist/{chunk-AS7YMSL6.js.map → chunk-M23RF3LJ.js.map} +0 -0
  738. /package/dist/{chunk-OAEQLRCY.js.map → chunk-MO4HSXHZ.js.map} +0 -0
  739. /package/dist/{chunk-3F2LKUMU.js.map → chunk-NIS256NW.js.map} +0 -0
  740. /package/dist/{chunk-YIAA2X3D.js.map → chunk-NK5RGJ65.js.map} +0 -0
  741. /package/dist/{chunk-7TWUCYER.js.map → chunk-PNRA7FAD.js.map} +0 -0
  742. /package/dist/{chunk-5I4M26Q7.js.map → chunk-QBSFOKY6.js.map} +0 -0
  743. /package/dist/{chunk-E53DSZEN.js.map → chunk-QR6G5KF4.js.map} +0 -0
  744. /package/dist/{chunk-4UH4BTGK.js.map → chunk-QVJPH7SH.js.map} +0 -0
  745. /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
  746. /package/dist/{chunk-WDISJRMG.js.map → chunk-RMMVQQA6.js.map} +0 -0
  747. /package/dist/{chunk-JVLCVFQ4.js.map → chunk-RNHVVMFN.js.map} +0 -0
  748. /package/dist/{chunk-5SM35XZR.js.map → chunk-S5NZBKKQ.js.map} +0 -0
  749. /package/dist/{chunk-WIPEXG6R.js.map → chunk-SXIMQLGV.js.map} +0 -0
  750. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  751. /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
  752. /package/dist/{chunk-BJKPPZ6Z.js.map → chunk-UW66OZTD.js.map} +0 -0
  753. /package/dist/{chunk-S2BBISHU.js.map → chunk-VANZKHTN.js.map} +0 -0
  754. /package/dist/{chunk-3Y224NYC.js.map → chunk-VYISFWVX.js.map} +0 -0
  755. /package/dist/{chunk-JE7EK33X.js.map → chunk-W2V7UESE.js.map} +0 -0
  756. /package/dist/{chunk-TIHMZFIV.js.map → chunk-W3IC7QOY.js.map} +0 -0
  757. /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
  758. /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
  759. /package/dist/{chunk-T2TTP3KU.js.map → chunk-X4IDNPOS.js.map} +0 -0
  760. /package/dist/{chunk-UVIKWC7M.js.map → chunk-XAGYS7X6.js.map} +0 -0
  761. /package/dist/{chunk-BLAKS3CP.js.map → chunk-XL3TATMJ.js.map} +0 -0
  762. /package/dist/{chunk-W4XJFLAL.js.map → chunk-XPRJSHNI.js.map} +0 -0
  763. /package/dist/{chunk-E6EE5B67.js.map → chunk-YK6BDDHP.js.map} +0 -0
  764. /package/dist/{chunk-ES36HTSC.js.map → chunk-YLHM5BQQ.js.map} +0 -0
  765. /package/dist/{chunk-GF22HWS2.js.map → chunk-Z54EM5YZ.js.map} +0 -0
  766. /package/dist/{chunk-64UDOIMI.js.map → chunk-ZLQ37WJX.js.map} +0 -0
package/src/storage.ts CHANGED
@@ -4,18 +4,21 @@ import {
4
4
  readdir,
5
5
  readFile,
6
6
  realpath,
7
+ rename,
7
8
  stat,
8
9
  writeFile,
9
10
  mkdir,
10
11
  unlink,
11
12
  appendFile,
12
13
  open,
14
+ type FileHandle,
13
15
  } from "node:fs/promises";
14
16
  import { appendFileSync, createReadStream, mkdirSync, readFileSync, statSync, type Dirent } from "node:fs";
15
- import { createHash } from "node:crypto";
17
+ import { createHash, randomUUID } from "node:crypto";
16
18
  import { normalizeContent, computeContentHash } from "./content-hash.js";
17
19
  import path from "node:path";
18
20
  import { log } from "./logger.js";
21
+ import { createMemorySnapshot } from "./memory-snapshot.js";
19
22
  import { assertMemoryFrontmatterId, warnProjectionFallback } from "./storage-guards.js";
20
23
  import { MemoryReadStore } from "./storage/memory-read-store.js";
21
24
  import { renderProfileWithLastUpdated } from "./storage/profile-header.js";
@@ -45,10 +48,13 @@ import {
45
48
  import { EntityCanonicalIdMigrationRunner } from "./storage/entity-canonical-id-migration-runner.js";
46
49
  import { rememberRawFrontmatter } from "./storage/memory-frontmatter-metadata.js";
47
50
  import { createMemoryEntityRefSerializer } from "./storage/memory-migration-serialization.js";
51
+ import { readEntityAliasConfigSync } from "./storage/entity-alias-config.js";
52
+ import { assertSafeEntityId } from "./storage/entity-id-safety.js";
48
53
  export { normalizeEntityName } from "./entity-id-normalization.js";
49
54
  import { isErrnoCode } from "./utils/errno.js";
50
55
  import { getCategoryDir, categoryDirName } from "./utils/category-dir.js";
51
56
  import { decodeYamlScalar } from "./utils/yaml-scalar.js";
57
+ import { withHeldFileLock, type HeldFileLockController } from "./utils/serialize-mutations.js";
52
58
  import { qmdCollectionPathParts, qmdResultPathCandidates } from "./orchestration/qmd-result-resolver.js";
53
59
  import {
54
60
  clearMemoryCache,
@@ -72,6 +78,7 @@ import {
72
78
  } from "./in-flight-reads.js";
73
79
  import { rotateMarkdownFileToArchive } from "./hygiene.js";
74
80
  import { sanitizeMemoryContent } from "./sanitize.js";
81
+ import { withholdToolScopedFromSharedNamespace } from "./tool-scoped-memory.js";
75
82
  import {
76
83
  serializeProvenanceFields,
77
84
  parseProvenanceSources,
@@ -191,6 +198,11 @@ import {
191
198
  parseTombstoneBlockedOfflineSyncMemory,
192
199
  type TombstoneBlockedCaptureIndexOptions,
193
200
  } from "./storage/tombstone-blocked-capture-index.js";
201
+ import {
202
+ buildCapturePathLockIdentity,
203
+ isQueuedReviewMemory,
204
+ tombstoneBlocked,
205
+ } from "./storage/tombstone-blocked-capture-mutation.js";
194
206
  export { ContentHashIndex, FactHashIndexNotAuthoritativeError };
195
207
  export type { ContentHashIndexLockOptions };
196
208
  export {
@@ -264,6 +276,37 @@ type OfflineSyncDigestCacheEntry = {
264
276
  bytes: number;
265
277
  };
266
278
 
279
+ type DeletionRevisionMetadata = {
280
+ version: 1;
281
+ deletions: Array<{ path: string; mtimeMs: number }>;
282
+ };
283
+
284
+ const DELETION_REVISION_MAX_MTIME_MS = 8_640_000_000_000_000;
285
+ const DELETION_REVISION_LOCK_STALE_MS = 60_000;
286
+ const DELETION_REVISION_LOCK_MAX_WAIT_MS = 120_000;
287
+
288
+ function isValidDeletionRevisionPath(value: unknown): value is string {
289
+ return (
290
+ typeof value === "string" &&
291
+ value.length > 0 &&
292
+ !value.includes("\\") &&
293
+ !value.includes("\0") &&
294
+ !path.posix.isAbsolute(value) &&
295
+ path.posix.normalize(value) === value &&
296
+ value !== "." &&
297
+ value !== ".." &&
298
+ !value.startsWith("../")
299
+ );
300
+ }
301
+
302
+ function deletionRevisionPathIdentity(value: string): string {
303
+ return value
304
+ .normalize("NFC")
305
+ .toUpperCase()
306
+ .toLowerCase()
307
+ .replace(/\u00df/g, "ss");
308
+ }
309
+
267
310
  export interface ReextractJobRequest {
268
311
  memoryId: string;
269
312
  model: string;
@@ -343,6 +386,7 @@ function serializeFrontmatter(fm: MemoryFrontmatter): string {
343
386
  const safe = /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(fm.sourceConnector);
344
387
  lines.push(`sourceConnector: ${safe ? fm.sourceConnector : JSON.stringify(fm.sourceConnector)}`);
345
388
  }
389
+ if (fm.toolScoped === true) lines.push("toolScoped: true");
346
390
  if (fm.supersedes) lines.push(`supersedes: ${fm.supersedes}`);
347
391
  if (fm.expiresAt) lines.push(`expiresAt: ${fm.expiresAt}`);
348
392
  if (fm.lineage && fm.lineage.length > 0) {
@@ -609,7 +653,7 @@ function parseReinforcementCountField(raw: string | undefined): number | undefin
609
653
  }
610
654
 
611
655
  export function parseFrontmatter(raw: string): { frontmatter: MemoryFrontmatter; content: string } | null {
612
- const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
656
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/);
613
657
  if (!match) return null;
614
658
 
615
659
  const fmBlock = match[1];
@@ -867,6 +911,7 @@ export function parseFrontmatter(raw: string): { frontmatter: MemoryFrontmatter;
867
911
  tags,
868
912
  entityRef: fm.entityRef || undefined,
869
913
  sourceConnector: fm.sourceConnector ? decodeYamlScalar(fm.sourceConnector) || undefined : undefined,
914
+ toolScoped: fm.toolScoped === "true" ? true : undefined,
870
915
  supersedes: fm.supersedes || undefined,
871
916
  expiresAt: fm.expiresAt || undefined,
872
917
  lineage: lineage && lineage.length > 0 ? lineage : undefined,
@@ -1024,7 +1069,6 @@ function inferCurrentStateStatus(
1024
1069
  return inferMemoryStatus(frontmatter, pathRel, fallbackStatus);
1025
1070
  }
1026
1071
 
1027
-
1028
1072
  /**
1029
1073
  * Simple Levenshtein distance between two strings.
1030
1074
  */
@@ -1720,6 +1764,7 @@ export interface WriteMemoryOptions {
1720
1764
  sources?: ProvenanceSource[];
1721
1765
  provenance?: "verified" | "unverified" | "none";
1722
1766
  sourceConnector?: string;
1767
+ toolScoped?: true;
1723
1768
  }
1724
1769
 
1725
1770
  /**
@@ -1735,6 +1780,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
1735
1780
  private knowledgeIndexCache: { result: string; builtAt: number } | null = null;
1736
1781
  private artifactIndexCache: { memories: MemoryFile[]; loadedAtMs: number; writeVersion: number } | null = null;
1737
1782
  private projectionLedgerLagManager = new ProjectionLedgerLagManager();
1783
+ private static readonly loadedMemorySnapshots = new WeakMap<MemoryFile, string>();
1738
1784
  static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600_000; // 10 minutes (entity mutations invalidate)
1739
1785
  /** Read by storage/memory-read-store.ts (decomposition). */
1740
1786
  static readonly ARTIFACT_INDEX_CACHE_TTL_MS = 60_000; // 1 minute
@@ -2005,9 +2051,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2005
2051
  setSecureStoreKey(key: Buffer | null, encryptOnWrite = true): void {
2006
2052
  if (!this.applySecureStoreKey(key, encryptOnWrite) || key === null) return;
2007
2053
  void this.entityCanonicalIdMigration.triggerAfterUnlock().catch((error: unknown) => {
2008
- log.warn(
2009
- `secure-store unlock migration failed: ${error instanceof Error ? error.message : String(error)}`,
2010
- );
2054
+ log.warn(`secure-store unlock migration failed: ${error instanceof Error ? error.message : String(error)}`);
2011
2055
  });
2012
2056
  }
2013
2057
 
@@ -2316,10 +2360,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2316
2360
  return path.join(this.stateDir, `.${kind}-version.log`);
2317
2361
  }
2318
2362
 
2319
- private bumpSharedVersion(
2320
- kind: SharedVersionKind,
2321
- fallbackMap: Map<string, number>
2322
- ): number {
2363
+ private bumpSharedVersion(kind: SharedVersionKind, fallbackMap: Map<string, number>): number {
2323
2364
  const filePath = this.versionFilePath(kind);
2324
2365
  try {
2325
2366
  mkdirSync(this.stateDir, { recursive: true });
@@ -2334,10 +2375,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2334
2375
  }
2335
2376
  }
2336
2377
 
2337
- private readSharedVersion(
2338
- kind: SharedVersionKind,
2339
- fallbackMap: Map<string, number>
2340
- ): number {
2378
+ private readSharedVersion(kind: SharedVersionKind, fallbackMap: Map<string, number>): number {
2341
2379
  const filePath = this.versionFilePath(kind);
2342
2380
  try {
2343
2381
  return statSync(filePath).size;
@@ -2364,15 +2402,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2364
2402
  }
2365
2403
 
2366
2404
  /**
2367
- * Entity-mutation sentinel: advanced only by entity-store content writes.
2368
- * The migration fingerprint keys on this instead of memory-status, so
2369
- * supersede/archive/delete no longer re-trigger discovery scans (#2213).
2405
+ * Entity content revision used by migration discovery and entity-page cache coherence.
2370
2406
  */
2371
2407
  getEntityMutationVersion(): number {
2372
2408
  return this.readSharedVersion("entity-mutation", StorageManager.entityMutationVersionByDir);
2373
2409
  }
2374
2410
 
2375
2411
  protected bumpEntityMutationVersion(): void {
2412
+ invalidateForScope(this.baseDir, "entity-write");
2376
2413
  this.bumpSharedVersion("entity-mutation", StorageManager.entityMutationVersionByDir);
2377
2414
  }
2378
2415
 
@@ -2646,6 +2683,217 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2646
2683
  return resolved;
2647
2684
  }
2648
2685
 
2686
+ private parseDeletionRevisionMetadata(raw: string): Map<string, number> {
2687
+ let parsed: unknown;
2688
+ try {
2689
+ parsed = JSON.parse(raw);
2690
+ } catch {
2691
+ throw new Error("Deletion revision metadata is invalid.");
2692
+ }
2693
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2694
+ throw new Error("Deletion revision metadata is invalid.");
2695
+ }
2696
+ const root = parsed as Record<string, unknown>;
2697
+ if (
2698
+ Object.keys(root).sort().join(",") !== "deletions,version" ||
2699
+ root.version !== 1 ||
2700
+ !Array.isArray(root.deletions)
2701
+ ) {
2702
+ throw new Error("Deletion revision metadata is invalid.");
2703
+ }
2704
+ const revisions = new Map<string, number>();
2705
+ const pathByIdentity = new Map<string, string>();
2706
+ for (const rawEntry of root.deletions) {
2707
+ if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) {
2708
+ throw new Error("Deletion revision metadata is invalid.");
2709
+ }
2710
+ const entry = rawEntry as Record<string, unknown>;
2711
+ if (
2712
+ Object.keys(entry).sort().join(",") !== "mtimeMs,path" ||
2713
+ !isValidDeletionRevisionPath(entry.path) ||
2714
+ typeof entry.mtimeMs !== "number" ||
2715
+ !Number.isFinite(entry.mtimeMs) ||
2716
+ entry.mtimeMs < 0 ||
2717
+ entry.mtimeMs > DELETION_REVISION_MAX_MTIME_MS ||
2718
+ revisions.has(entry.path)
2719
+ ) {
2720
+ throw new Error("Deletion revision metadata is invalid.");
2721
+ }
2722
+ const identity = deletionRevisionPathIdentity(entry.path);
2723
+ if (pathByIdentity.has(identity)) {
2724
+ throw new Error("Deletion revision metadata is invalid.");
2725
+ }
2726
+ pathByIdentity.set(identity, entry.path);
2727
+ revisions.set(entry.path, entry.mtimeMs);
2728
+ }
2729
+ return new Map([...revisions.entries()].sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)));
2730
+ }
2731
+
2732
+ private async readDeletionRevisionMetadata(): Promise<Map<string, number>> {
2733
+ let raw: string;
2734
+ try {
2735
+ raw = await readFile(this.deletionRevisionMetadataPath, "utf8");
2736
+ } catch (error) {
2737
+ if (isErrnoCode(error, "ENOENT")) return new Map();
2738
+ throw new Error("Deletion revision metadata is unavailable.");
2739
+ }
2740
+ return this.parseDeletionRevisionMetadata(raw);
2741
+ }
2742
+
2743
+ private async writeDeletionRevisionMetadata(
2744
+ revisions: ReadonlyMap<string, number>,
2745
+ lock: HeldFileLockController
2746
+ ): Promise<void> {
2747
+ const deletions = [...revisions.entries()]
2748
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
2749
+ .map(([entryPath, mtimeMs]) => ({ path: entryPath, mtimeMs }));
2750
+ const metadata: DeletionRevisionMetadata = { version: 1, deletions };
2751
+ const temporaryPath = `${this.deletionRevisionMetadataPath}.${process.pid}.${randomUUID()}.tmp`;
2752
+ let handle: FileHandle | null = null;
2753
+ try {
2754
+ handle = await open(temporaryPath, "wx", 0o600);
2755
+ await handle.writeFile(`${JSON.stringify(metadata)}\n`, "utf8");
2756
+ await handle.sync();
2757
+ await handle.close();
2758
+ handle = null;
2759
+ if (!(await lock.refresh())) {
2760
+ throw new Error("Deletion revision metadata lock was lost.");
2761
+ }
2762
+ await rename(temporaryPath, this.deletionRevisionMetadataPath);
2763
+ } finally {
2764
+ if (handle !== null) await handle.close().catch(() => undefined);
2765
+ await unlink(temporaryPath).catch((error: unknown) => {
2766
+ if (!isErrnoCode(error, "ENOENT")) throw error;
2767
+ });
2768
+ }
2769
+ }
2770
+
2771
+ private async withDeletionRevisionLock<T>(task: (lock: HeldFileLockController) => Promise<T>): Promise<T> {
2772
+ return withHeldFileLock(
2773
+ this.deletionRevisionLockPath,
2774
+ {
2775
+ staleMs: DELETION_REVISION_LOCK_STALE_MS,
2776
+ maxWaitMs: DELETION_REVISION_LOCK_MAX_WAIT_MS,
2777
+ },
2778
+ async (acquired, lock) => {
2779
+ if (!acquired) throw new Error("Deletion revision metadata lock is unavailable.");
2780
+ return task(lock);
2781
+ }
2782
+ );
2783
+ }
2784
+
2785
+ async readDeletionRevisions(): Promise<ReadonlyMap<string, number>> {
2786
+ return this.withDeletionRevisionLock(async () => this.readDeletionRevisionMetadata());
2787
+ }
2788
+
2789
+ async recordReplicatedDeletionRevision(filePath: string, mtimeMs: number): Promise<void> {
2790
+ const target = this.assertManagedStoragePath(filePath, "storage.recordReplicatedDeletionRevision");
2791
+ if (
2792
+ typeof mtimeMs !== "number" ||
2793
+ !Number.isFinite(mtimeMs) ||
2794
+ mtimeMs < 0 ||
2795
+ mtimeMs > DELETION_REVISION_MAX_MTIME_MS
2796
+ ) {
2797
+ throw new Error("Deletion revision timestamp is invalid.");
2798
+ }
2799
+ const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
2800
+ if (!isValidDeletionRevisionPath(relativePath)) {
2801
+ throw new Error("Deletion revision path is invalid.");
2802
+ }
2803
+ await this.withDeletionRevisionLock(async (lock) => {
2804
+ const revisions = await this.readDeletionRevisionMetadata();
2805
+ const identity = deletionRevisionPathIdentity(relativePath);
2806
+ let existingPath: string | undefined;
2807
+ for (const candidatePath of revisions.keys()) {
2808
+ if (deletionRevisionPathIdentity(candidatePath) === identity) {
2809
+ existingPath = candidatePath;
2810
+ break;
2811
+ }
2812
+ }
2813
+ const existingMtimeMs = existingPath === undefined ? undefined : revisions.get(existingPath);
2814
+ if (existingMtimeMs !== undefined && existingMtimeMs >= mtimeMs) return;
2815
+
2816
+ const updated = new Map(revisions);
2817
+ if (existingPath !== undefined) updated.delete(existingPath);
2818
+ updated.set(relativePath, mtimeMs);
2819
+ await this.writeDeletionRevisionMetadata(updated, lock);
2820
+ });
2821
+ }
2822
+
2823
+ protected async writeManagedStorageFile(filePath: string, write: () => Promise<void>): Promise<void> {
2824
+ const target = this.assertManagedStoragePath(filePath, "storage.writeManagedStorageFile");
2825
+ const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
2826
+ if (!isValidDeletionRevisionPath(relativePath)) {
2827
+ throw new Error("Deletion revision path is invalid.");
2828
+ }
2829
+ await this.withDeletionRevisionLock(async (lock) => {
2830
+ const before = await this.readDeletionRevisionMetadata();
2831
+ const identity = deletionRevisionPathIdentity(relativePath);
2832
+ const existingPath = [...before.keys()].find(
2833
+ (candidatePath) => deletionRevisionPathIdentity(candidatePath) === identity
2834
+ );
2835
+ await write();
2836
+ if (existingPath === undefined) return;
2837
+ const updated = new Map(before);
2838
+ updated.delete(existingPath);
2839
+ await this.writeDeletionRevisionMetadata(updated, lock);
2840
+ });
2841
+ }
2842
+
2843
+ protected async deleteManagedStorageFile(filePath: string, deletionMtimeMs?: number | null): Promise<boolean> {
2844
+ const target = this.assertManagedStoragePath(filePath, "storage.deleteManagedStorageFile");
2845
+ if (
2846
+ deletionMtimeMs !== undefined &&
2847
+ deletionMtimeMs !== null &&
2848
+ (typeof deletionMtimeMs !== "number" ||
2849
+ !Number.isFinite(deletionMtimeMs) ||
2850
+ deletionMtimeMs < 0 ||
2851
+ deletionMtimeMs > DELETION_REVISION_MAX_MTIME_MS)
2852
+ ) {
2853
+ throw new Error("Deletion revision timestamp is invalid.");
2854
+ }
2855
+ return this.withDeletionRevisionLock(async (lock) => {
2856
+ try {
2857
+ await lstat(target);
2858
+ } catch (error) {
2859
+ if (isErrnoCode(error, "ENOENT")) return false;
2860
+ throw error;
2861
+ }
2862
+ const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
2863
+ if (!isValidDeletionRevisionPath(relativePath)) {
2864
+ throw new Error("Deletion revision path is invalid.");
2865
+ }
2866
+ const revision = deletionMtimeMs === null ? undefined : (deletionMtimeMs ?? Date.now());
2867
+ const before = await this.readDeletionRevisionMetadata();
2868
+ const identity = deletionRevisionPathIdentity(relativePath);
2869
+ let existingPath: string | undefined;
2870
+ for (const candidatePath of before.keys()) {
2871
+ if (deletionRevisionPathIdentity(candidatePath) === identity) {
2872
+ existingPath = candidatePath;
2873
+ break;
2874
+ }
2875
+ }
2876
+ const existing = existingPath === undefined ? undefined : before.get(existingPath);
2877
+ const changed =
2878
+ (existingPath !== undefined && existingPath !== relativePath) ||
2879
+ (revision === undefined ? existing !== undefined : existing !== revision);
2880
+ if (changed) {
2881
+ const updated = new Map(before);
2882
+ if (existingPath !== undefined) updated.delete(existingPath);
2883
+ if (revision !== undefined) updated.set(relativePath, revision);
2884
+ await this.writeDeletionRevisionMetadata(updated, lock);
2885
+ }
2886
+ try {
2887
+ await unlink(target);
2888
+ return true;
2889
+ } catch (error) {
2890
+ if (changed) await this.writeDeletionRevisionMetadata(before, lock);
2891
+ if (isErrnoCode(error, "ENOENT")) return false;
2892
+ throw error;
2893
+ }
2894
+ });
2895
+ }
2896
+
2649
2897
  async readOfflineSyncFile(filePath: string): Promise<Buffer> {
2650
2898
  const target = this.assertManagedStoragePath(filePath, "storage.readOfflineSyncFile");
2651
2899
  return readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
@@ -2929,6 +3177,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2929
3177
  private get offlineSyncDigestCachePath(): string {
2930
3178
  return path.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
2931
3179
  }
3180
+ private get deletionRevisionMetadataPath(): string {
3181
+ return path.join(this.baseDir, ".offline-sync", "deletion-revisions.v1.json");
3182
+ }
3183
+ private get deletionRevisionLockPath(): string {
3184
+ return `${this.deletionRevisionMetadataPath}.lock`;
3185
+ }
2932
3186
  private get entitySynthesisQueuePath(): string {
2933
3187
  return path.join(this.stateDir, "entity-synthesis-queue.json");
2934
3188
  }
@@ -3062,7 +3316,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3062
3316
  () => this.currentHistoricalIds(),
3063
3317
  (identity) => store.appendTombstone({ ...input, rawContent: strippedRawContent, ...identity }),
3064
3318
  (tombstoneId) => store.revoke(tombstoneId, input.createdBy),
3065
- input.sourceMemoryId,
3319
+ input.sourceMemoryId
3066
3320
  );
3067
3321
  } catch (err) {
3068
3322
  log.warn(`tombstone append failed (memory=${input.sourceMemoryId}): ${err}`);
@@ -3455,12 +3709,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3455
3709
  private readonly entityCanonicalIdMigration = new EntityCanonicalIdMigrationRunner(
3456
3710
  () => !(this._secureStoreRequired && !this.isSecureStoreUnlocked()),
3457
3711
  () => this.runLegacyEntityCanonicalIdMigration(),
3458
- () => entityMigration.getFingerprint(this.baseDir, this.entitiesDir, () => String(this.getEntityMutationVersion())),
3712
+ () => entityMigration.getFingerprint(this.baseDir, this.entitiesDir, () => String(this.getEntityMutationVersion()))
3459
3713
  );
3460
3714
  normalizeEntityName(raw: string, type: string): string {
3461
3715
  return entityRefs.resolveHistoricalEntityCanonicalId(
3462
3716
  this.entityStore.normalizeEntityName(raw, type),
3463
- this.currentHistoricalIds(),
3717
+ this.currentHistoricalIds()
3464
3718
  );
3465
3719
  }
3466
3720
 
@@ -3485,27 +3739,28 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3485
3739
 
3486
3740
  private loadAliasesSync(): void {
3487
3741
  const aliasPath = path.join(this.baseDir, "config", "aliases.json");
3488
- // Re-derive from the file on every call: a reload after the file was
3489
- // fixed, emptied, or removed must never leave a previous table active.
3490
3742
  this.userAliases = {};
3743
+ const raw = readEntityAliasConfigSync(this.baseDir);
3744
+ if (raw === undefined) return;
3745
+ let parsed: unknown;
3491
3746
  try {
3492
- const raw = readFileSync(aliasPath, "utf-8");
3493
- const parsed = JSON.parse(raw);
3494
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3495
- const cleaned: Record<string, string> = {};
3496
- for (const [key, value] of Object.entries(parsed)) {
3497
- if (typeof value === "string" && value.trim().length > 0) {
3498
- cleaned[key] = value;
3499
- }
3747
+ parsed = JSON.parse(raw);
3748
+ } catch {
3749
+ log.debug("invalid config/aliases.json using built-in aliases only");
3750
+ return;
3751
+ }
3752
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3753
+ const cleaned: Record<string, string> = {};
3754
+ for (const [key, value] of Object.entries(parsed)) {
3755
+ if (typeof value === "string" && value.trim().length > 0) {
3756
+ assertSafeEntityId(value);
3757
+ cleaned[key] = value;
3500
3758
  }
3501
- this.userAliases = cleaned;
3502
- log.debug(`loaded ${Object.keys(cleaned).length} entity aliases from ${aliasPath}`);
3503
- } else {
3504
- log.warn(`ignoring ${aliasPath}: payload must be a JSON object mapping variant → canonical strings`);
3505
3759
  }
3506
- } catch {
3507
- // No aliases file — that's fine, use built-in only
3508
- log.debug("no config/aliases.json found — using built-in aliases only");
3760
+ this.userAliases = cleaned;
3761
+ log.debug(`loaded ${Object.keys(cleaned).length} entity aliases from ${aliasPath}`);
3762
+ } else {
3763
+ log.warn(`ignoring ${aliasPath}: payload must be a JSON object mapping variant → canonical strings`);
3509
3764
  }
3510
3765
  }
3511
3766
  private async runLegacyEntityCanonicalIdMigration(): Promise<string | undefined> {
@@ -3513,7 +3768,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3513
3768
  this as unknown as EntityCanonicalIdMigrationHost,
3514
3769
  (content) => parseEntityFile(content, this.entitySchemas),
3515
3770
  (entity) => serializeEntityFile(entity, this.entitySchemas),
3516
- createMemoryEntityRefSerializer(serializeFrontmatter),
3771
+ createMemoryEntityRefSerializer(serializeFrontmatter)
3517
3772
  );
3518
3773
  return completionFingerprint;
3519
3774
  }
@@ -3690,6 +3945,15 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3690
3945
  if (!sanitized.clean) {
3691
3946
  log.warn(`memory content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
3692
3947
  }
3948
+ if (
3949
+ options.toolScoped ||
3950
+ withholdToolScopedFromSharedNamespace({
3951
+ content: sanitized.text,
3952
+ sourceConnector: options.sourceConnector,
3953
+ })
3954
+ ) {
3955
+ fm.toolScoped = true;
3956
+ }
3693
3957
 
3694
3958
  // Persist the raw-content dedup hash on the frontmatter so archive and
3695
3959
  // consolidation paths can remove the correct hash from ContentHashIndex
@@ -3754,14 +4018,41 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3754
4018
  await this.writeTombstoneBlockedMemory(filePath, fileContent, fm, sanitized.text, async () => {
3755
4019
  this.invalidateAllMemoriesCache();
3756
4020
  });
4021
+ if (refIds && typeof rawEntityRef === "string") {
4022
+ const refBeforeRepair = fm.entityRef;
4023
+ try {
4024
+ await entityRefs.repairEntityRefAfterJournalMove({
4025
+ stateDir: this.stateDir,
4026
+ currentIds: () => this.currentHistoricalIds(),
4027
+ idsAtResolve: refIds,
4028
+ rawRef: rawEntityRef,
4029
+ frontmatter: fm,
4030
+ rewrite: async () => {
4031
+ await applyTombstoneGate();
4032
+ await this.writeTombstoneBlockedMemory(
4033
+ filePath,
4034
+ `${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`,
4035
+ fm,
4036
+ sanitized.text,
4037
+ async () => this.invalidateAllMemoriesCache()
4038
+ );
4039
+ this.invalidateAllMemoriesCache();
4040
+ },
4041
+ });
4042
+ } catch (err) {
4043
+ await unlink(filePath).catch(() => undefined);
4044
+ this.invalidateAllMemoriesCache();
4045
+ await this.rebuildTombstoneBlockedCaptureAfterInvalidationForPath(filePath);
4046
+ throw err;
4047
+ }
4048
+ await this.entityRefRepair.syncProjection(id, refBeforeRepair, fm.entityRef);
4049
+ }
3757
4050
  return null;
3758
4051
  };
3759
- const duplicateBlocked = tombstoneBlocked
3760
- ? await this.withTombstoneBlockedCaptureWriteLock(
3761
- persistFile,
3762
- buildExplicitCaptureDedupKey(sanitized.text, category, fm.sourceConnector)
3763
- )
3764
- : await persistFile();
4052
+ const duplicateBlocked = await this.withTombstoneBlockedCaptureWriteLock(persistFile, [
4053
+ buildCapturePathLockIdentity(filePath),
4054
+ buildExplicitCaptureDedupKey(sanitized.text, category, fm.sourceConnector),
4055
+ ]);
3765
4056
  if (duplicateBlocked) {
3766
4057
  return {
3767
4058
  id: duplicateBlocked.frontmatter.id,
@@ -3770,38 +4061,6 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
3770
4061
  duplicateOf: duplicateBlocked.frontmatter.id,
3771
4062
  };
3772
4063
  }
3773
- if (refIds && typeof rawEntityRef === "string") {
3774
- const refBeforeRepair = fm.entityRef;
3775
- try {
3776
- await entityRefs.repairEntityRefAfterJournalMove({
3777
- stateDir: this.stateDir,
3778
- currentIds: () => this.currentHistoricalIds(),
3779
- idsAtResolve: refIds,
3780
- rawRef: rawEntityRef,
3781
- frontmatter: fm,
3782
- rewrite: async () => {
3783
- // Re-gate under the final ref, then rewrite THROUGH the blocked-
3784
- // capture surface so any verdict change keeps the index consistent.
3785
- await applyTombstoneGate();
3786
- await this.writeTombstoneBlockedMemory(
3787
- filePath,
3788
- `${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`,
3789
- fm,
3790
- sanitized.text,
3791
- async () => this.invalidateAllMemoriesCache(),
3792
- );
3793
- this.invalidateAllMemoriesCache();
3794
- },
3795
- });
3796
- } catch (err) {
3797
- // Remove the just-created file before propagating (§14): it would
3798
- // linger un-bumped/un-indexed and a retry would duplicate it.
3799
- await unlink(filePath).catch(() => undefined);
3800
- this.invalidateAllMemoriesCache();
3801
- throw err;
3802
- }
3803
- await this.entityRefRepair.syncProjection(id, refBeforeRepair, fm.entityRef);
3804
- }
3805
4064
  await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
3806
4065
  this.notifyMemoryWrite(filePath);
3807
4066
  await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.writeMemory", {
@@ -4073,6 +4332,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4073
4332
  intentActionType?: string;
4074
4333
  intentEntityTypes?: string[];
4075
4334
  sourceConnector?: string;
4335
+ toolScoped?: true;
4076
4336
  } = {}
4077
4337
  ): Promise<string> {
4078
4338
  await this.ensureDirectories();
@@ -4098,6 +4358,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4098
4358
  intentActionType: options.intentActionType,
4099
4359
  intentEntityTypes: options.intentEntityTypes,
4100
4360
  ...(options.sourceConnector ? { sourceConnector: options.sourceConnector } : {}),
4361
+ ...(options.toolScoped ? { toolScoped: true as const } : {}),
4101
4362
  };
4102
4363
 
4103
4364
  const sanitized = sanitizeMemoryContent(quote);
@@ -4227,16 +4488,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4227
4488
  if (newBullets.length === 0) return;
4228
4489
 
4229
4490
  if (!existing) {
4230
- const content = [
4231
- "# Behavioral Profile",
4232
- "",
4233
- ...newBullets.map((b) => `- ${b}`),
4234
- "",
4235
- ].join("\n");
4491
+ const content = ["# Behavioral Profile", "", ...newBullets.map((b) => `- ${b}`), ""].join("\n");
4236
4492
  await this.writeProfile(content);
4237
4493
  } else {
4238
- const withBullets =
4239
- existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
4494
+ const withBullets = existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
4240
4495
  await this.writeProfile(withBullets);
4241
4496
  }
4242
4497
  }
@@ -4251,13 +4506,19 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4251
4506
  return lineCount > threshold;
4252
4507
  }
4253
4508
 
4509
+ private rememberMemorySnapshot<T extends MemoryFile | null>(memory: T): T {
4510
+ if (memory !== null && !StorageManager.loadedMemorySnapshots.has(memory)) {
4511
+ StorageManager.loadedMemorySnapshots.set(memory, createMemorySnapshot(memory));
4512
+ }
4513
+ return memory;
4514
+ }
4515
+
4516
+ private rememberMemorySnapshots(memories: MemoryFile[]): MemoryFile[] {
4517
+ for (const memory of memories) this.rememberMemorySnapshot(memory);
4518
+ return memories;
4519
+ }
4520
+
4254
4521
  async readAllMemories(): Promise<MemoryFile[]> {
4255
- // Version-keyed hot-memories cache (issue #1902): once populated, serve the
4256
- // full parsed corpus from memory within a version epoch. getCachedMemories
4257
- // returns null when the sentinel is 0 (fresh/test dirs) or the stored
4258
- // version differs from the current on-disk sentinel (a peer or local write
4259
- // bumped it), so a stale entry is never served — the miss falls through to
4260
- // a fresh disk scan below.
4261
4522
  if (this.hotMemoriesCacheEnabled) {
4262
4523
  const cached = getCachedMemories(
4263
4524
  this.baseDir,
@@ -4265,13 +4526,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4265
4526
  this.hotCacheKeyId(),
4266
4527
  this.hotCacheTtlMs()
4267
4528
  );
4268
- // Null-check, not truthiness (kilo WARNING): getCachedMemories returns []
4269
- // for a cached EMPTY corpus, which is falsy — a truthiness guard would
4270
- // force a full disk scan on every read of an empty/near-empty store.
4271
- if (cached !== null) return cached;
4529
+ if (cached !== null) return this.rememberMemorySnapshots(cached);
4272
4530
  }
4273
- // Deduplicate concurrent reads for the same directory so multiple
4274
- // callers in the same recall share one disk scan.
4275
4531
  // Snapshot the secure-store key identity ONCE (issue #1902, Codex Medium):
4276
4532
  // hotCacheKeyId() can change mid-scan if setSecureStoreKey(null/other) runs
4277
4533
  // during the await. Recomputing it at publish time would store K-decrypted
@@ -4281,13 +4537,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4281
4537
  // key change can't orphan the slot registered under the old identity.
4282
4538
  const keyId = this.hotCacheKeyId();
4283
4539
  const inFlight = getInFlightRead(this.baseDir, keyId);
4284
- if (inFlight) return inFlight;
4540
+ if (inFlight) return this.rememberMemorySnapshots(await inFlight);
4285
4541
 
4286
4542
  const readPromise = (async (): Promise<MemoryFile[]> => {
4287
- // Capture the version BEFORE the scan and store under it. If a concurrent
4288
- // bump (peer or local write) lands during the scan, the stored entry's
4289
- // version is older than the sentinel, so the next getCachedMemories()
4290
- // rejects it (version mismatch → rescan) — correct, never stale.
4291
4543
  const version = this.getMemoryCorpusVersion();
4292
4544
  const memories = await this._readAllMemoriesFromDisk();
4293
4545
  // Publish only if neither the corpus version NOR the key identity changed
@@ -4301,11 +4553,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4301
4553
  })();
4302
4554
  setInFlightRead(this.baseDir, keyId, readPromise);
4303
4555
  try {
4304
- return await readPromise;
4556
+ return this.rememberMemorySnapshots(await readPromise);
4305
4557
  } finally {
4306
- // Only delete if we still own the slot for our snapshot key identity —
4307
- // invalidateAllMemoriesCache() may have already cleared it and a new read
4308
- // may have claimed it (the expected-promise guard enforces owner-only).
4309
4558
  deleteInFlightRead(this.baseDir, keyId, readPromise);
4310
4559
  }
4311
4560
  }
@@ -4601,15 +4850,18 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4601
4850
  const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
4602
4851
  const parsed = parseFrontmatter(raw);
4603
4852
  if (!parsed) return null;
4604
- return rememberRawFrontmatter({
4605
- path: fullPath,
4606
- frontmatter: normalizeFrontmatterForPath(
4607
- parsed.frontmatter,
4608
- toMemoryPathRel(this.baseDir, fullPath),
4609
- parsed.content
4610
- ),
4611
- content: parsed.content,
4612
- } satisfies MemoryFile, raw);
4853
+ return rememberRawFrontmatter(
4854
+ {
4855
+ path: fullPath,
4856
+ frontmatter: normalizeFrontmatterForPath(
4857
+ parsed.frontmatter,
4858
+ toMemoryPathRel(this.baseDir, fullPath),
4859
+ parsed.content
4860
+ ),
4861
+ content: parsed.content,
4862
+ } satisfies MemoryFile,
4863
+ raw
4864
+ );
4613
4865
  } catch (err) {
4614
4866
  // Re-throw store-locked errors so a locked encrypted store fails
4615
4867
  // loudly rather than appearing as an empty memory corpus (Cursor
@@ -4737,7 +4989,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4737
4989
  }
4738
4990
 
4739
4991
  async readAllColdMemories(): Promise<MemoryFile[]> {
4740
- return this.memoryReadStore.readAllColdMemories();
4992
+ return this.rememberMemorySnapshots(await this.memoryReadStore.readAllColdMemories());
4741
4993
  }
4742
4994
 
4743
4995
  /**
@@ -4760,15 +5012,20 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4760
5012
  const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
4761
5013
  const parsed = parseFrontmatter(raw);
4762
5014
  if (parsed) {
4763
- memories.push(rememberRawFrontmatter({
4764
- path: fullPath,
4765
- frontmatter: normalizeFrontmatterForPath(
4766
- parsed.frontmatter,
4767
- toMemoryPathRel(this.baseDir, fullPath),
4768
- parsed.content
4769
- ),
4770
- content: parsed.content,
4771
- }, raw));
5015
+ memories.push(
5016
+ rememberRawFrontmatter(
5017
+ {
5018
+ path: fullPath,
5019
+ frontmatter: normalizeFrontmatterForPath(
5020
+ parsed.frontmatter,
5021
+ toMemoryPathRel(this.baseDir, fullPath),
5022
+ parsed.content
5023
+ ),
5024
+ content: parsed.content,
5025
+ },
5026
+ raw
5027
+ )
5028
+ );
4772
5029
  }
4773
5030
  } catch (err) {
4774
5031
  // Re-throw store-locked errors — a locked encrypted store
@@ -4784,11 +5041,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4784
5041
  };
4785
5042
 
4786
5043
  await readDir(root);
4787
- return memories;
5044
+ return this.rememberMemorySnapshots(memories);
4788
5045
  }
4789
5046
 
4790
5047
  async readMemoryByPath(filePath: string): Promise<MemoryFile | null> {
4791
- return this.memoryReadStore.readMemoryByPath(filePath);
5048
+ return this.rememberMemorySnapshot(await this.memoryReadStore.readMemoryByPath(filePath));
4792
5049
  }
4793
5050
 
4794
5051
  private resolveTierRootDir(tier: "hot" | "cold"): string {
@@ -4816,12 +5073,6 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4816
5073
  // corrections/ is flat (no date subdir); preserved across tier moves.
4817
5074
  return path.join(root, "corrections", `${memory.frontmatter.id}.md`);
4818
5075
  }
4819
- // Every other category — decisions/, preferences/, reasoning-traces/, ...
4820
- // plus the facts/ fallback for fact/entity/unknown — resolves through the
4821
- // shared categoryDirName() chokepoint so tier moves land in the SAME dir the
4822
- // writer used, instead of funneling non-{correction,procedure,reasoning_trace}
4823
- // categories into facts/ (issue #564 PR 3 preserved reasoning-traces/; #1546
4824
- // generalizes it to every category dir).
4825
5076
  const dir = categoryDirName(memory.frontmatter.category);
4826
5077
  return path.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4827
5078
  }
@@ -4838,7 +5089,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4838
5089
  `${serializeFrontmatter(frontmatter)}\n\n${memory.content}\n`,
4839
5090
  this.resolveWriteKey(),
4840
5091
  {},
4841
- this.baseDir,
5092
+ this.baseDir
4842
5093
  );
4843
5094
  // Snapshot pre-write destination bytes (raw — encryption-agnostic) so a
4844
5095
  // repair failure restores them or removes a fresh copy (§14): a retained
@@ -4876,25 +5127,67 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4876
5127
  this.invalidateAllMemoriesCache();
4877
5128
  this.notifyCatalogWrite();
4878
5129
  }
4879
- async moveMemoryToPath(memory: MemoryFile, targetPath: string): Promise<void> {
4880
- await this.writeMemoryFileAtomic(targetPath, memory);
4881
- const sourcePath = path.resolve(memory.path);
4882
- const destPath = path.resolve(targetPath);
4883
- if (sourcePath !== destPath) {
4884
- try {
4885
- await unlink(memory.path);
4886
- } catch (err) {
4887
- const message = err instanceof Error ? err.message : String(err);
4888
- if (!message.includes("ENOENT")) {
4889
- throw err;
5130
+ async moveMemoryToPath(memory: MemoryFile, targetPath: string): Promise<boolean> {
5131
+ const changed = await this.withTombstoneBlockedMemoryPathLock(
5132
+ memory.path,
5133
+ async (current) => {
5134
+ const destination = await this.readMemoryByPath(targetPath);
5135
+ if (current?.frontmatter.id !== memory.frontmatter.id) {
5136
+ if (current === null && destination?.frontmatter.id === memory.frontmatter.id) return false;
5137
+ throw new Error(`memory ${memory.frontmatter.id} changed before its tier move`);
4890
5138
  }
4891
- }
4892
- // Re-invalidate after the unlink — writeMemoryFileAtomic already
4893
- // invalidated, but a concurrent readAllMemories() may have re-populated
4894
- // the cache between the write and the unlink.
4895
- this.invalidateAllMemoriesCache();
4896
- updateProjectedMemoryPath(this.baseDir, memory.frontmatter.id, toMemoryPathRel(this.baseDir, targetPath));
5139
+ const callerSnapshot = StorageManager.loadedMemorySnapshots.get(memory);
5140
+ const currentSnapshot = createMemorySnapshot(current);
5141
+ if (
5142
+ callerSnapshot === undefined
5143
+ ? current.frontmatter.updated !== memory.frontmatter.updated
5144
+ : currentSnapshot !== callerSnapshot
5145
+ ) {
5146
+ throw new Error(`memory ${memory.frontmatter.id} changed before its tier move`);
5147
+ }
5148
+ const coordinate =
5149
+ tombstoneBlocked(current.frontmatter) ||
5150
+ isQueuedReviewMemory(current) ||
5151
+ (destination !== null && tombstoneBlocked(destination.frontmatter)) ||
5152
+ isQueuedReviewMemory(destination);
5153
+ const index = this.getTombstoneBlockedCaptureIndex();
5154
+ const marker = coordinate ? await index.prepareWrite() : undefined;
5155
+ const projectedPath = toMemoryPathRel(this.baseDir, targetPath);
5156
+ let durable = false;
5157
+ try {
5158
+ if (destination?.frontmatter.id === current.frontmatter.id) {
5159
+ await this.deleteManagedStorageFile(current.path);
5160
+ durable = true;
5161
+ this.invalidateAllMemoriesCache();
5162
+ updateProjectedMemoryPath(this.baseDir, current.frontmatter.id, projectedPath);
5163
+ } else {
5164
+ await this.writeMemoryFileAtomic(targetPath, current);
5165
+ if (memory.frontmatter.entityRef !== current.frontmatter.entityRef) {
5166
+ memory.frontmatter.entityRef = current.frontmatter.entityRef;
5167
+ }
5168
+ durable = true;
5169
+ const sourcePath = path.resolve(current.path);
5170
+ const destPath = path.resolve(targetPath);
5171
+ if (sourcePath !== destPath) {
5172
+ await this.deleteManagedStorageFile(current.path);
5173
+ this.invalidateAllMemoriesCache();
5174
+ updateProjectedMemoryPath(this.baseDir, current.frontmatter.id, projectedPath);
5175
+ }
5176
+ }
5177
+ if (marker !== undefined) await this.rebuildTombstoneBlockedCaptureAfterInvalidation(marker);
5178
+ } catch (error) {
5179
+ if (marker !== undefined && !durable) await index.discardWrite(marker).catch(() => index.markUntrusted());
5180
+ if (marker !== undefined && durable) index.markUntrusted();
5181
+ throw error;
5182
+ }
5183
+ return true;
5184
+ },
5185
+ [targetPath]
5186
+ );
5187
+ if (this.isColdOrArchiveTierPath(memory.path) || this.isColdOrArchiveTierPath(targetPath)) {
5188
+ this.invalidateColdMemoriesCache();
4897
5189
  }
5190
+ return changed;
4898
5191
  }
4899
5192
 
4900
5193
  async migrateMemoryToTier(
@@ -4907,31 +5200,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4907
5200
  if (sourcePath === destPath) {
4908
5201
  return { changed: false, targetPath };
4909
5202
  }
4910
-
4911
- const existing = await this.readMemoryByPath(targetPath);
4912
- if (existing?.frontmatter.id === memory.frontmatter.id) {
4913
- try {
4914
- await unlink(memory.path);
4915
- } catch (err) {
4916
- const message = err instanceof Error ? err.message : String(err);
4917
- if (!message.includes("ENOENT")) {
4918
- throw err;
4919
- }
4920
- }
4921
- updateProjectedMemoryPath(this.baseDir, memory.frontmatter.id, toMemoryPathRel(this.baseDir, targetPath));
4922
- this.bumpMemoryStatusVersion();
4923
- return { changed: false, targetPath };
4924
- }
4925
-
4926
- await this.moveMemoryToPath(memory, targetPath);
4927
- this.invalidateAllMemoriesCache();
4928
- // If moving to cold, also invalidate the cold-scan cache so the next
4929
- // readAllColdMemories() call sees the newly-demoted file (Finding UOGi fix).
4930
- if (targetTier === "cold") {
4931
- this.invalidateColdMemoriesCache();
4932
- }
5203
+ const changed = await this.moveMemoryToPath(memory, targetPath);
5204
+ if (!changed) return { changed: false, targetPath };
4933
5205
  this.bumpMemoryStatusVersion();
4934
- return { changed: true, targetPath };
5206
+ return { changed, targetPath };
4935
5207
  }
4936
5208
 
4937
5209
  private get archiveDir(): string {
@@ -4959,7 +5231,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4959
5231
  archivedAt: now.toISOString(),
4960
5232
  updated: now.toISOString(),
4961
5233
  },
4962
- refIdsAtWrite,
5234
+ refIdsAtWrite
4963
5235
  );
4964
5236
  const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
4965
5237
  const destPath = path.join(destDir, path.basename(current.path));
@@ -4970,7 +5242,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4970
5242
  if (typeof current.frontmatter.entityRef === "string") {
4971
5243
  try {
4972
5244
  await this.entityRefRepair.repair(
4973
- destPath, updatedFm, current.frontmatter.entityRef, refIdsAtWrite, current.content,
5245
+ destPath,
5246
+ updatedFm,
5247
+ current.frontmatter.entityRef,
5248
+ refIdsAtWrite,
5249
+ current.content
4974
5250
  );
4975
5251
  } catch (err) {
4976
5252
  // Restore/remove the destination before reporting failure (§14):
@@ -4983,7 +5259,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4983
5259
  throw err;
4984
5260
  }
4985
5261
  }
4986
- await unlink(current.path);
5262
+ if (!(await this.deleteManagedStorageFile(current.path))) return null;
4987
5263
  markDurable();
4988
5264
  markProjectedMemoryPathInvalid(this.baseDir, current.frontmatter.id);
4989
5265
  this.invalidateAllMemoriesCache();
@@ -5076,25 +5352,21 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
5076
5352
  return null;
5077
5353
  }
5078
5354
 
5079
-
5080
5355
  async invalidateMemory(id: string): Promise<boolean> {
5081
5356
  const memories = await this.readAllMemories();
5082
5357
  const memory = memories.find((candidate) => candidate.frontmatter.id === id);
5083
5358
  if (!memory) return false;
5084
5359
 
5085
- return await this.runTombstoneBlockedInvalidation(
5086
- memory,
5087
- async (current, rebuildMarker, markDurable) => {
5088
- await unlink(current.path);
5089
- markDurable();
5090
- markProjectedMemoryPathInvalid(this.baseDir, id);
5091
- this.invalidateAllMemoriesCache();
5092
- await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);
5093
- this.bumpMemoryStatusVersion();
5094
- log.debug(`invalidated memory ${id}`);
5095
- return true;
5096
- }
5097
- );
5360
+ return await this.runTombstoneBlockedInvalidation(memory, async (current, rebuildMarker, markDurable) => {
5361
+ if (!(await this.deleteManagedStorageFile(current.path))) return false;
5362
+ markDurable();
5363
+ markProjectedMemoryPathInvalid(this.baseDir, id);
5364
+ this.invalidateAllMemoriesCache();
5365
+ await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);
5366
+ this.bumpMemoryStatusVersion();
5367
+ log.debug(`invalidated memory ${id}`);
5368
+ return true;
5369
+ });
5098
5370
  }
5099
5371
 
5100
5372
  async updateMemory(
@@ -5122,7 +5394,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
5122
5394
  ? { sourceConnector: options.sourceConnector }
5123
5395
  : {}),
5124
5396
  },
5125
- refIdsAtWrite,
5397
+ refIdsAtWrite
5126
5398
  );
5127
5399
  const sanitized = sanitizeMemoryContent(newContent);
5128
5400
  if (!sanitized.clean) {
@@ -5134,8 +5406,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
5134
5406
  });
5135
5407
  if (typeof memory.frontmatter.entityRef === "string") {
5136
5408
  await this.entityRefRepair.repair(
5137
- memory.path, updated, memory.frontmatter.entityRef, refIdsAtWrite, sanitized.text,
5138
- { onFailRestore: memory },
5409
+ memory.path,
5410
+ updated,
5411
+ memory.frontmatter.entityRef,
5412
+ refIdsAtWrite,
5413
+ sanitized.text,
5414
+ { onFailRestore: memory }
5139
5415
  );
5140
5416
  }
5141
5417
  await this.patchHotMemoriesCache({ addedPath: memory.path });
@@ -5170,7 +5446,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
5170
5446
  const resolveIds = this.currentHistoricalIds();
5171
5447
  const updated: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
5172
5448
  { ...memory.frontmatter, ...patch },
5173
- resolveIds,
5449
+ resolveIds
5174
5450
  );
5175
5451
  const refIds = typeof updated.entityRef === "string" ? resolveIds : null;
5176
5452
  const afterStatus = updated.status ?? "active";
@@ -5185,10 +5461,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
5185
5461
  });
5186
5462
  const rawMergedRef = typeof patch.entityRef === "string" ? patch.entityRef : memory.frontmatter.entityRef;
5187
5463
  if (refIds && typeof rawMergedRef === "string") {
5188
- await this.entityRefRepair.repair(
5189
- memory.path, updated, rawMergedRef, refIds, memory.content,
5190
- { onFailRestore: memory },
5191
- );
5464
+ await this.entityRefRepair.repair(memory.path, updated, rawMergedRef, refIds, memory.content, {
5465
+ onFailRestore: memory,
5466
+ });
5192
5467
  }
5193
5468
  await this.patchHotMemoriesCache({ addedPath: memory.path });
5194
5469
  if (memory.path.includes(`${path.sep}cold${path.sep}`)) {
@@ -6336,26 +6611,31 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6336
6611
  : memoryMap.get(entry.memoryId);
6337
6612
  if (!memory) continue;
6338
6613
 
6339
- const rowIds = this.currentHistoricalIds();
6340
- const newFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
6341
- { ...memory.frontmatter, accessCount: entry.newCount, lastAccessed: entry.lastAccessed },
6342
- rowIds,
6343
- );
6344
-
6345
6614
  try {
6346
- const fileContent = `${serializeFrontmatter(newFm)}\n\n${memory.content}\n`;
6347
- await this.writeStorageSecureFile(memory.path, fileContent);
6348
- if (typeof memory.frontmatter.entityRef === "string") {
6349
- // onFailRestore (§14): the count patch was never reported applied.
6350
- await this.entityRefRepair.repair(
6351
- memory.path, newFm, memory.frontmatter.entityRef, rowIds, memory.content,
6352
- { onFailRestore: memory },
6615
+ const applied = await this.withTombstoneBlockedMemoryPathLock(memory.path, async (current) => {
6616
+ if (current?.frontmatter.id !== entry.memoryId) return null;
6617
+ const rowIds = this.currentHistoricalIds();
6618
+ const newFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
6619
+ { ...current.frontmatter, accessCount: entry.newCount, lastAccessed: entry.lastAccessed },
6620
+ rowIds
6353
6621
  );
6354
- }
6355
- // Patch the hot corpus cache entry in place (#1902); the shared
6356
- // sentinel is bumped once after the loop for cross-process coherence.
6622
+ const fileContent = `${serializeFrontmatter(newFm)}\n\n${current.content}\n`;
6623
+ await this.writeTombstoneBlockedFrontmatter(current, fileContent, newFm);
6624
+ if (typeof current.frontmatter.entityRef === "string") {
6625
+ await this.entityRefRepair.repair(
6626
+ current.path,
6627
+ newFm,
6628
+ current.frontmatter.entityRef,
6629
+ rowIds,
6630
+ current.content,
6631
+ { onFailRestore: current }
6632
+ );
6633
+ }
6634
+ return { current, newFm };
6635
+ });
6636
+ if (applied === null) continue;
6357
6637
  if (warm) {
6358
- updateCacheOnWrite(this.baseDir, { ...memory, frontmatter: newFm }, keyId);
6638
+ updateCacheOnWrite(this.baseDir, { ...applied.current, frontmatter: applied.newFm }, keyId);
6359
6639
  }
6360
6640
  appliedPatches.set(path.resolve(memory.path), {
6361
6641
  accessCount: entry.newCount,
@@ -6602,6 +6882,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6602
6882
  observedAt?: string;
6603
6883
  eventTimeSource?: "extracted" | "assumed";
6604
6884
  sourceConnector?: string;
6885
+ toolScoped?: true;
6605
6886
  } = {}
6606
6887
  ): Promise<string> {
6607
6888
  await this.ensureDirectories();
@@ -6616,6 +6897,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6616
6897
  const validAt = normalizeMemoryWriteTimestamp("validAt", options.validAt);
6617
6898
  const chunkInvalidAt = normalizeMemoryWriteTimestamp("invalidAt", options.invalidAt);
6618
6899
  const chunkObservedAt = normalizeMemoryWriteTimestamp("observedAt", options.observedAt);
6900
+ const sanitized = sanitizeMemoryContent(content);
6901
+ if (!sanitized.clean) {
6902
+ log.warn(`chunk content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
6903
+ }
6619
6904
 
6620
6905
  const fm: MemoryFrontmatter = {
6621
6906
  id,
@@ -6645,28 +6930,17 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6645
6930
  ...(options.sources ? { sources: options.sources } : {}),
6646
6931
  ...(options.provenance ? { provenance: options.provenance } : {}),
6647
6932
  ...(options.sourceConnector ? { sourceConnector: options.sourceConnector } : {}),
6933
+ ...(options.toolScoped ||
6934
+ withholdToolScopedFromSharedNamespace({
6935
+ content: sanitized.text,
6936
+ sourceConnector: options.sourceConnector,
6937
+ })
6938
+ ? { toolScoped: true as const }
6939
+ : {}),
6648
6940
  };
6649
6941
 
6650
- const sanitized = sanitizeMemoryContent(content);
6651
- if (!sanitized.clean) {
6652
- log.warn(`chunk content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
6653
- }
6654
6942
  const filePath = await this.resolveCategoryWritePath(category, id, today);
6655
6943
  const fileContent = `${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`;
6656
- // A retried chunk write lands on the SAME deterministic path, so the
6657
- // target can already hold a valid prior chunk: snapshot it, and a repair
6658
- // failure restores it — unlink only a file THIS invocation created
6659
- // (Codex P2, round 22).
6660
- let priorChunk: MemoryFile | null = null;
6661
- try {
6662
- const priorRaw = await readMaybeEncryptedFile(filePath, this._secureStoreKey, this.baseDir);
6663
- const parsedPrior = parseFrontmatter(priorRaw);
6664
- if (parsedPrior) {
6665
- priorChunk = { path: filePath, frontmatter: parsedPrior.frontmatter, content: parsedPrior.content };
6666
- }
6667
- } catch {
6668
- priorChunk = null;
6669
- }
6670
6944
 
6671
6945
  const written = await this.writeTombstoneBlockedChunk(
6672
6946
  filePath,
@@ -6674,24 +6948,19 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6674
6948
  fm,
6675
6949
  sanitized.text,
6676
6950
  () => this.findExistingTombstoneBlockedMemory(sanitized.text, category, fm.sourceConnector),
6677
- async () => {
6951
+ async (priorChunk) => {
6952
+ if (refIds && typeof rawEntityRef === "string") {
6953
+ await this.entityRefRepair.repair(filePath, fm, rawEntityRef, refIds, sanitized.text, {
6954
+ regateFact: true,
6955
+ ...(priorChunk ? { onFailRestore: priorChunk } : { onFailRemove: filePath }),
6956
+ });
6957
+ }
6678
6958
  // Keep the version-keyed hot-memories cache coherent with the new chunk
6679
6959
  // file (issue #1902) — same single-file patch path writeMemory uses.
6680
6960
  await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
6681
6961
  log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
6682
6962
  }
6683
6963
  );
6684
- // Repair only when THIS chunk persisted: a tombstone-dedupe result
6685
- // returns an existing id without writing filePath, and an unconditional
6686
- // repair rewrite would create a stray second chunk from scratch. The
6687
- // rewrite RE-GATES under the final ref (Bugbot): a journal move into
6688
- // tombstone-blocked identity space must not leave a fact chunk active.
6689
- if (written === id && refIds && typeof rawEntityRef === "string") {
6690
- await this.entityRefRepair.repair(filePath, fm, rawEntityRef, refIds, sanitized.text, {
6691
- regateFact: true,
6692
- ...(priorChunk ? { onFailRestore: priorChunk } : { onFailRemove: filePath }),
6693
- });
6694
- }
6695
6964
  return written;
6696
6965
  }
6697
6966
 
@@ -6720,25 +6989,33 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6720
6989
  if (!oldMemory) return false;
6721
6990
 
6722
6991
  const now = new Date().toISOString();
6723
- // Whole-record rewrite — inherited-entityRef rule (issue #2213).
6724
- const refIdsAtWrite = this.currentHistoricalIds();
6725
- const updatedFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
6726
- { ...oldMemory.frontmatter, status: "superseded", supersededBy: newMemoryId, supersededAt: now, updated: now },
6727
- refIdsAtWrite,
6728
- );
6729
-
6730
- const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${oldMemory.content}\n`;
6992
+ let currentBefore = oldMemory;
6993
+ let updatedFm = oldMemory.frontmatter;
6731
6994
 
6732
6995
  try {
6733
- await this.writeStorageSecureFile(oldMemory.path, fileContent);
6734
- if (typeof oldMemory.frontmatter.entityRef === "string") {
6735
- // onFailRestore (§14): a record left superseded on disk would skip
6736
- // its non-resurrection tombstone while caches expose the old state.
6737
- await this.entityRefRepair.repair(
6738
- oldMemory.path, updatedFm, oldMemory.frontmatter.entityRef, refIdsAtWrite, oldMemory.content,
6739
- { onFailRestore: oldMemory },
6996
+ const written = await this.withTombstoneBlockedMemoryPathLock(oldMemory.path, async (current) => {
6997
+ if (current?.frontmatter.id !== oldMemoryId) return false;
6998
+ currentBefore = current;
6999
+ const refIdsAtWrite = this.currentHistoricalIds();
7000
+ updatedFm = entityRefs.canonicalizeEntityRefOption(
7001
+ { ...current.frontmatter, status: "superseded", supersededBy: newMemoryId, supersededAt: now, updated: now },
7002
+ refIdsAtWrite
6740
7003
  );
6741
- }
7004
+ const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
7005
+ await this.writeTombstoneBlockedFrontmatter(current, fileContent, updatedFm);
7006
+ if (typeof current.frontmatter.entityRef === "string") {
7007
+ await this.entityRefRepair.repair(
7008
+ current.path,
7009
+ updatedFm,
7010
+ current.frontmatter.entityRef,
7011
+ refIdsAtWrite,
7012
+ current.content,
7013
+ { onFailRestore: current }
7014
+ );
7015
+ }
7016
+ return true;
7017
+ });
7018
+ if (!written) return false;
6742
7019
  // Advance the corpus sentinel immediately after the on-disk write, BEFORE
6743
7020
  // the awaited lifecycle append (Cursor Medium, #1902). Otherwise a warm
6744
7021
  // hot-memories cache keeps serving the pre-supersede snapshot during the
@@ -6751,8 +7028,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6751
7028
  timestamp: now,
6752
7029
  actor: "storage.supersedeMemory",
6753
7030
  reasonCode: reason,
6754
- before: this.summarizeLifecycleState(oldMemory.frontmatter, oldMemory.path),
6755
- after: this.summarizeLifecycleState(updatedFm, oldMemory.path),
7031
+ before: this.summarizeLifecycleState(currentBefore.frontmatter, currentBefore.path),
7032
+ after: this.summarizeLifecycleState(updatedFm, currentBefore.path),
6756
7033
  relatedMemoryIds: [newMemoryId],
6757
7034
  });
6758
7035
  this.bumpMemoryStatusVersion();
@@ -6762,14 +7039,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6762
7039
  // so emitting covers each exactly once (rule 22); facts only. One
6763
7040
  // tombstone PER derived supersession key (thread Oci-Y) so a
6764
7041
  // paraphrased re-write is caught on the keyed tier.
6765
- if (oldMemory.frontmatter.category === "fact") {
7042
+ if (currentBefore.frontmatter.category === "fact") {
6766
7043
  for (const input of buildRetiredFactTombstoneInputs(
6767
7044
  {
6768
7045
  id: oldMemoryId,
6769
- content: stripCitationForTemplate(oldMemory.content, this.citationTemplate),
6770
- contentHash: oldMemory.frontmatter.contentHash,
7046
+ content: stripCitationForTemplate(currentBefore.content, this.citationTemplate),
7047
+ contentHash: currentBefore.frontmatter.contentHash,
6771
7048
  entityRef: updatedFm.entityRef,
6772
- structuredAttributes: oldMemory.frontmatter.structuredAttributes,
7049
+ structuredAttributes: currentBefore.frontmatter.structuredAttributes,
6773
7050
  },
6774
7051
  {
6775
7052
  reason: "contradiction_resolution",
@@ -6783,7 +7060,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6783
7060
  }
6784
7061
 
6785
7062
  // Audit-trail correction — sealed even INSIDE the engine (#2022 review).
6786
- const auditBody = `Superseded: ${oldMemory.content}\n\nReason: ${reason}`;
7063
+ const auditBody = `Superseded: ${currentBefore.content}\n\nReason: ${reason}`;
6787
7064
  const auditInput = {
6788
7065
  content: auditBody,
6789
7066
  category: "correction" as const,
@@ -6854,22 +7131,33 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6854
7131
  if (!memory) continue;
6855
7132
 
6856
7133
  const now = new Date().toISOString();
6857
- const rowIds = this.currentHistoricalIds();
6858
- const updatedFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
6859
- { ...memory.frontmatter, status: "archived", archivedAt: now, updated: now },
6860
- rowIds,
6861
- );
7134
+ let currentBefore = memory;
7135
+ let updatedFm = memory.frontmatter;
6862
7136
 
6863
7137
  try {
6864
- const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${memory.content}\n`;
6865
- await this.writeStorageSecureFile(memory.path, fileContent);
6866
- if (typeof memory.frontmatter.entityRef === "string") {
6867
- // onFailRestore (§14): the method reports the row NOT archived.
6868
- await this.entityRefRepair.repair(
6869
- memory.path, updatedFm, memory.frontmatter.entityRef, rowIds, memory.content,
6870
- { onFailRestore: memory },
7138
+ const written = await this.withTombstoneBlockedMemoryPathLock(memory.path, async (current) => {
7139
+ if (current?.frontmatter.id !== id) return false;
7140
+ currentBefore = current;
7141
+ const rowIds = this.currentHistoricalIds();
7142
+ updatedFm = entityRefs.canonicalizeEntityRefOption(
7143
+ { ...current.frontmatter, status: "archived", archivedAt: now, updated: now },
7144
+ rowIds
6871
7145
  );
6872
- }
7146
+ const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
7147
+ await this.writeTombstoneBlockedFrontmatter(current, fileContent, updatedFm);
7148
+ if (typeof current.frontmatter.entityRef === "string") {
7149
+ await this.entityRefRepair.repair(
7150
+ current.path,
7151
+ updatedFm,
7152
+ current.frontmatter.entityRef,
7153
+ rowIds,
7154
+ current.content,
7155
+ { onFailRestore: current }
7156
+ );
7157
+ }
7158
+ return true;
7159
+ });
7160
+ if (!written) continue;
6873
7161
  // Per-file corpus bump BEFORE the awaited lifecycle append (#1902):
6874
7162
  // the end-of-loop status bump fires only after the whole batch.
6875
7163
  this.bumpMemoryCorpusVersion();
@@ -6879,8 +7167,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6879
7167
  timestamp: updatedFm.archivedAt ?? updatedFm.updated,
6880
7168
  actor: "storage.archiveMemories",
6881
7169
  reasonCode: `summary:${summaryId}`,
6882
- before: this.summarizeLifecycleState(memory.frontmatter, memory.path),
6883
- after: this.summarizeLifecycleState(updatedFm, memory.path),
7170
+ before: this.summarizeLifecycleState(currentBefore.frontmatter, currentBefore.path),
7171
+ after: this.summarizeLifecycleState(updatedFm, currentBefore.path),
6884
7172
  relatedMemoryIds: [summaryId],
6885
7173
  });
6886
7174
  archived++;