@remnic/core 10.0.36 → 10.0.38

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 (422) hide show
  1. package/dist/access-admin-ops-surface.js +84 -84
  2. package/dist/access-authorization-probe.js +85 -85
  3. package/dist/access-boundary.js +84 -84
  4. package/dist/access-citation-namespace.js +2 -2
  5. package/dist/access-cli.js +178 -176
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-extraction-force-flush.js +84 -84
  8. package/dist/access-http-briefing.js +85 -85
  9. package/dist/access-http-query.js +86 -86
  10. package/dist/access-http.js +108 -108
  11. package/dist/access-identity-continuity-surface.js +84 -84
  12. package/dist/access-lcm-surface.js +84 -84
  13. package/dist/access-mcp.js +97 -97
  14. package/dist/access-namespace-preflight.js +84 -84
  15. package/dist/access-observe-write-category.js +13 -13
  16. package/dist/access-observe-write-surface.js +84 -84
  17. package/dist/access-offline-manifest.js +12 -12
  18. package/dist/access-operations-batch.js +88 -88
  19. package/dist/access-operations.js +95 -95
  20. package/dist/access-recall-concurrency.js +84 -84
  21. package/dist/access-recall-diagnostics.js +2 -2
  22. package/dist/access-recall-response.js +84 -84
  23. package/dist/access-recall-surface.js +84 -84
  24. package/dist/access-schema.js +8 -8
  25. package/dist/access-service.js +84 -84
  26. package/dist/access-surface-catalog.js +86 -86
  27. package/dist/active-recall.js +43 -43
  28. package/dist/adapters/index.js +7 -7
  29. package/dist/adapters/registry.js +3 -3
  30. package/dist/{auto-sync-VPHR3FBI.js → auto-sync-432USQDH.js} +9 -9
  31. package/dist/briefing.js +32 -32
  32. package/dist/buffer-eviction.d.ts +16 -0
  33. package/dist/buffer-eviction.d.ts.map +1 -0
  34. package/dist/buffer-eviction.js +8 -0
  35. package/dist/buffer-persistence.d.ts +45 -0
  36. package/dist/buffer-persistence.d.ts.map +1 -0
  37. package/dist/buffer-persistence.js +8 -0
  38. package/dist/buffer.d.ts +5 -2
  39. package/dist/buffer.d.ts.map +1 -1
  40. package/dist/buffer.js +13 -11
  41. package/dist/calibration.js +1 -1
  42. package/dist/causal-behavior.js +2 -2
  43. package/dist/causal-chain.js +2 -2
  44. package/dist/causal-consolidation.js +35 -35
  45. package/dist/causal-retrieval.js +2 -2
  46. package/dist/causal-trajectory-graph.js +2 -2
  47. package/dist/causal-trajectory.js +1 -1
  48. package/dist/{chunk-FL6SLVAJ.js → chunk-2AKIVSHP.js} +2 -2
  49. package/dist/{chunk-ORWDCX5Q.js → chunk-3AODCBKX.js} +11 -11
  50. package/dist/{chunk-XFDHL252.js → chunk-3K5IEJTK.js} +4 -4
  51. package/dist/{chunk-6FIFEXFF.js → chunk-3PLAL2KP.js} +21 -7
  52. package/dist/chunk-3PLAL2KP.js.map +1 -0
  53. package/dist/{chunk-XVZA6VXC.js → chunk-3SL52JKD.js} +4 -4
  54. package/dist/{chunk-ZSAQSLKL.js → chunk-3XVBGGF3.js} +2 -2
  55. package/dist/{chunk-XO4HOBM2.js → chunk-4B37KNMP.js} +2 -2
  56. package/dist/{chunk-NIANATGL.js → chunk-4IZ6AC2U.js} +2 -2
  57. package/dist/chunk-4OFXLQJD.js +58 -0
  58. package/dist/chunk-4OFXLQJD.js.map +1 -0
  59. package/dist/{chunk-S2PDFSXS.js → chunk-4P4VLPGB.js} +1 -1
  60. package/dist/{chunk-G5UR4DXQ.js → chunk-53BLBDV6.js} +2 -2
  61. package/dist/{chunk-PDYP7SUC.js → chunk-5ANUG4JZ.js} +2 -2
  62. package/dist/{chunk-2ZYIAUYU.js → chunk-5CWH2LKL.js} +4 -4
  63. package/dist/{chunk-S2S4U4G3.js → chunk-5DCS4C4S.js} +4 -4
  64. package/dist/{chunk-7WTTE5FW.js → chunk-5K23NQRI.js} +2 -2
  65. package/dist/{chunk-V3JZZJ2E.js → chunk-5UPOKIFP.js} +12 -12
  66. package/dist/{chunk-K567EIW3.js → chunk-63YPKHAU.js} +2 -2
  67. package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
  68. package/dist/{chunk-HJM23E65.js → chunk-6DTIYAAN.js} +2 -2
  69. package/dist/{chunk-G7XAZU2L.js → chunk-6F5BGIAF.js} +3 -3
  70. package/dist/{chunk-IHTKBQBS.js → chunk-6JEEY42N.js} +2 -2
  71. package/dist/{chunk-NHB4RC3G.js → chunk-6QOL4G76.js} +2 -2
  72. package/dist/{chunk-AD3ZB72W.js → chunk-6SYS5YX3.js} +2 -2
  73. package/dist/{chunk-DFP37GUN.js → chunk-7HXZOWTR.js} +2 -2
  74. package/dist/{chunk-DGBWPSM6.js → chunk-7VFNGQ4V.js} +2 -2
  75. package/dist/{chunk-77ZK533I.js → chunk-7ZRRJ6RG.js} +2 -2
  76. package/dist/{chunk-GMMZ45C4.js → chunk-AVVCPA7U.js} +6 -8
  77. package/dist/chunk-AVVCPA7U.js.map +1 -0
  78. package/dist/{chunk-QISYYK4L.js → chunk-AYBAC2N4.js} +3 -3
  79. package/dist/{chunk-V44DWTFA.js → chunk-AYXRK264.js} +6 -6
  80. package/dist/{chunk-LJSBF6PW.js → chunk-C2KOW2UQ.js} +2 -2
  81. package/dist/{chunk-GY4R4P2A.js → chunk-CUWOSRCS.js} +2 -2
  82. package/dist/{chunk-VNAIUNXI.js → chunk-CVMAOPAH.js} +10 -10
  83. package/dist/{chunk-CJKHLACF.js → chunk-DG4H56SK.js} +2 -2
  84. package/dist/{chunk-BQ6DGL6A.js → chunk-DKHX2FHI.js} +2 -2
  85. package/dist/{chunk-77IXBNV6.js → chunk-E24RUQEN.js} +2 -2
  86. package/dist/{chunk-HRT2SJPC.js → chunk-E3NBMTTX.js} +2 -2
  87. package/dist/{chunk-PTQZPVRQ.js → chunk-E5PVMB3I.js} +2 -2
  88. package/dist/{chunk-AHS3QEEA.js → chunk-EEOYF3IB.js} +2 -2
  89. package/dist/{chunk-5XTSIZ3L.js → chunk-EGNONTVT.js} +6 -6
  90. package/dist/{chunk-PH33R7GN.js → chunk-EHIKY2IA.js} +2 -2
  91. package/dist/{chunk-4ISHIPOC.js → chunk-FGEY2AGV.js} +2 -2
  92. package/dist/{chunk-O6YJI5VX.js → chunk-FKTMWDN2.js} +2 -2
  93. package/dist/{chunk-KQUN4RSX.js → chunk-FQFMLOAC.js} +18 -18
  94. package/dist/{chunk-5LWODP5R.js → chunk-FRAL3EU4.js} +2 -2
  95. package/dist/{chunk-AAANTXCQ.js → chunk-FZVZYU5C.js} +2 -2
  96. package/dist/{chunk-TGAXRT7N.js → chunk-GFYFKXWZ.js} +2 -2
  97. package/dist/{chunk-ID2PLENW.js → chunk-GGI6FLO6.js} +2 -2
  98. package/dist/{chunk-GDYLZ6FR.js → chunk-HJ3UTGIW.js} +3 -3
  99. package/dist/{chunk-X3IFRQKS.js → chunk-I73ZSORJ.js} +4 -4
  100. package/dist/{chunk-X73SCHKR.js → chunk-I75BWXRZ.js} +2 -2
  101. package/dist/{chunk-M3GKSCFN.js → chunk-J7G656MY.js} +4 -4
  102. package/dist/{chunk-EH6KLYIE.js → chunk-JF3MEIHO.js} +4 -4
  103. package/dist/{chunk-XUB4I2N6.js → chunk-JFI3ATK4.js} +2 -2
  104. package/dist/{chunk-R4SATHCV.js → chunk-JH2ALMPR.js} +2 -2
  105. package/dist/{chunk-TKBW4YLS.js → chunk-JH4FCVWJ.js} +2 -2
  106. package/dist/{chunk-DG5UKN2Y.js → chunk-JIA435P3.js} +2 -2
  107. package/dist/chunk-KASJJGRG.js +29 -0
  108. package/dist/chunk-KASJJGRG.js.map +1 -0
  109. package/dist/{chunk-4Z7O2QVJ.js → chunk-KOAVX2IT.js} +2 -2
  110. package/dist/{chunk-6NXHX6MI.js → chunk-KOY25HUB.js} +2 -2
  111. package/dist/{chunk-TRW7N4FS.js → chunk-L2JQSG5M.js} +2 -2
  112. package/dist/{chunk-QQ4T622E.js → chunk-L7PGPH4E.js} +2 -2
  113. package/dist/{chunk-TYT4TEQV.js → chunk-LDWE7OZS.js} +6 -2
  114. package/dist/chunk-LDWE7OZS.js.map +1 -0
  115. package/dist/{chunk-23VGZ65V.js → chunk-LHBOFROT.js} +2 -2
  116. package/dist/{chunk-VKB2FGNW.js → chunk-LOMSBYNS.js} +90 -90
  117. package/dist/{chunk-NDJ42GKB.js → chunk-MCPSMWUC.js} +6 -6
  118. package/dist/{chunk-ERMT5WQM.js → chunk-MKE5DP3S.js} +2 -2
  119. package/dist/{chunk-64IO6ZEE.js → chunk-MZWHIAOL.js} +2 -2
  120. package/dist/{chunk-LDXS746V.js → chunk-N7DVBHU3.js} +3 -3
  121. package/dist/{chunk-F2JLBXMG.js → chunk-NH6GZEQN.js} +8 -8
  122. package/dist/{chunk-7FG2JSU6.js → chunk-NMKETOAX.js} +2 -2
  123. package/dist/{chunk-GAARPWMN.js → chunk-OKKBOTRA.js} +2 -2
  124. package/dist/{chunk-PCIIKQXW.js → chunk-OLH4XCLU.js} +2 -2
  125. package/dist/{chunk-XA32GZ6B.js → chunk-OLHN4ZNT.js} +3 -3
  126. package/dist/{chunk-UR25IQVT.js → chunk-P5CUEB2Q.js} +8 -8
  127. package/dist/{chunk-LO775P3S.js → chunk-POGPI5GR.js} +2 -2
  128. package/dist/{chunk-FXO43NBW.js → chunk-PSQ2P2T3.js} +3 -3
  129. package/dist/{chunk-KRAMCBIW.js → chunk-QKXPOLQD.js} +4 -4
  130. package/dist/{chunk-65JLKIVA.js → chunk-QO5KDQGG.js} +8 -8
  131. package/dist/{chunk-A4B7WL5N.js → chunk-QOUKZ2N3.js} +2 -2
  132. package/dist/{chunk-ZABEDRGQ.js → chunk-RGKXF4W3.js} +2 -2
  133. package/dist/{chunk-IKCGNTGS.js → chunk-RWRHGE75.js} +2 -2
  134. package/dist/{chunk-NBH7IRME.js → chunk-SWZOAQUM.js} +54 -54
  135. package/dist/{chunk-FQ52AJXX.js → chunk-SZPPCEYT.js} +2 -2
  136. package/dist/{chunk-4YYIZ475.js → chunk-TAEJ2MRR.js} +52 -52
  137. package/dist/{chunk-3ODEGTVV.js → chunk-TDCR6PQL.js} +2 -2
  138. package/dist/{chunk-QCP75JGO.js → chunk-TFA6HPOA.js} +5 -5
  139. package/dist/{chunk-BBDASWNT.js → chunk-TJ5YGCPV.js} +81 -76
  140. package/dist/chunk-TJ5YGCPV.js.map +1 -0
  141. package/dist/{chunk-SE3JAD22.js → chunk-TPKB7T6Z.js} +2 -2
  142. package/dist/{chunk-6VYY2XFK.js → chunk-TVIGN3XZ.js} +19 -19
  143. package/dist/{chunk-OHMGR6QN.js → chunk-TXP7Q7T5.js} +2 -2
  144. package/dist/{chunk-ZG3HZZ6K.js → chunk-TYGLV6ZG.js} +5 -1
  145. package/dist/{chunk-ZG3HZZ6K.js.map → chunk-TYGLV6ZG.js.map} +1 -1
  146. package/dist/{chunk-AI2VXOSO.js → chunk-TYLNWE4D.js} +2 -2
  147. package/dist/{chunk-WI6MIJYK.js → chunk-U7HJBODU.js} +5 -5
  148. package/dist/{chunk-IS4HKNWP.js → chunk-UBN5AOLT.js} +2 -2
  149. package/dist/{chunk-A6PKEU7T.js → chunk-UFM3PJDT.js} +1 -1
  150. package/dist/chunk-UFM3PJDT.js.map +1 -0
  151. package/dist/{chunk-JNELS2TW.js → chunk-UJDTXWMT.js} +2 -2
  152. package/dist/{chunk-DJMC4W6N.js → chunk-VC3X7XP3.js} +2 -2
  153. package/dist/{chunk-A2D3WICT.js → chunk-VGFNTY3Y.js} +2 -2
  154. package/dist/{chunk-X544TW54.js → chunk-VGRM43X6.js} +2 -2
  155. package/dist/{chunk-CSGFGQBI.js → chunk-VPO53QMG.js} +2 -2
  156. package/dist/{chunk-BRZRP5WD.js → chunk-VSSQIBVU.js} +2 -2
  157. package/dist/{chunk-O3VKQMWC.js → chunk-WCBLPKG3.js} +366 -168
  158. package/dist/chunk-WCBLPKG3.js.map +1 -0
  159. package/dist/{chunk-GKNX4QO3.js → chunk-WCIDCJOQ.js} +3 -3
  160. package/dist/{chunk-7VJEZQYF.js → chunk-WEK3OUGO.js} +3 -3
  161. package/dist/{chunk-IVYAPAHG.js → chunk-WRDFYSUC.js} +2 -2
  162. package/dist/{chunk-5EILJ6W2.js → chunk-WXPBDEMW.js} +2 -2
  163. package/dist/{chunk-QZP3RMYP.js → chunk-X247CYL6.js} +4 -4
  164. package/dist/{chunk-UAYA4NJN.js → chunk-XHVO3CGX.js} +28 -36
  165. package/dist/chunk-XHVO3CGX.js.map +1 -0
  166. package/dist/{chunk-YLF42JQ7.js → chunk-XHX67LX6.js} +2 -2
  167. package/dist/{chunk-C6S2Y7HE.js → chunk-XKDQTDXN.js} +4 -4
  168. package/dist/{chunk-4AHKNZW7.js → chunk-XLEP7SS3.js} +2 -2
  169. package/dist/{chunk-B6L7BKA7.js → chunk-XRFLR3XF.js} +4 -4
  170. package/dist/{chunk-H7QC7WCU.js → chunk-XTBEXZFN.js} +4 -4
  171. package/dist/{chunk-CIJRM6SQ.js → chunk-Y5ZHZKZD.js} +2 -2
  172. package/dist/{chunk-H6SKBCNI.js → chunk-YC2C67F7.js} +2 -2
  173. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  174. package/dist/{chunk-YOL56HY5.js → chunk-YQ6SLFNZ.js} +3 -3
  175. package/dist/{chunk-SIIWHIBK.js → chunk-YYGZ4EIY.js} +2 -2
  176. package/dist/{chunk-G22A6WJQ.js → chunk-Z2T5BPOZ.js} +2 -2
  177. package/dist/{chunk-RYUSWAAU.js → chunk-ZAP7BKTZ.js} +6 -6
  178. package/dist/cli.js +136 -136
  179. package/dist/coding/export-okf-codegraph.js +33 -33
  180. package/dist/coding/pre-action-gate.js +2 -2
  181. package/dist/compounding/engine.js +34 -34
  182. package/dist/config.d.ts.map +1 -1
  183. package/dist/config.js +43 -43
  184. package/dist/connectors/codex-materialize-runner.js +32 -32
  185. package/dist/connectors/index.js +32 -32
  186. package/dist/contradiction/index.js +5 -5
  187. package/dist/convergence-refresh.js +34 -34
  188. package/dist/conversation-index/backend.js +2 -2
  189. package/dist/corpus-watermark.js +34 -34
  190. package/dist/dashboard-runtime.js +2 -2
  191. package/dist/deep-recall-http-glue.js +9 -9
  192. package/dist/deep-recall-policy-llm.js +2 -2
  193. package/dist/entity-retrieval.js +34 -34
  194. package/dist/explicit-capture.js +7 -7
  195. package/dist/external-wiki-access.js +85 -85
  196. package/dist/extraction-faithfulness.js +2 -2
  197. package/dist/extraction-judge.d.ts +42 -2
  198. package/dist/extraction-judge.d.ts.map +1 -1
  199. package/dist/extraction-judge.js +12 -2
  200. package/dist/extraction-span-materialize.js +2 -2
  201. package/dist/extraction.js +47 -47
  202. package/dist/fallback-llm.d.ts +1 -0
  203. package/dist/fallback-llm.d.ts.map +1 -1
  204. package/dist/fallback-llm.js +1 -1
  205. package/dist/{graph-edge-decay-IU75NV42.js → graph-edge-decay-2BZTY2IM.js} +5 -5
  206. package/dist/graph-edge-decay-2BZTY2IM.js.map +1 -0
  207. package/dist/graph-jsonl.js +3 -3
  208. package/dist/graph-snapshot.js +3 -3
  209. package/dist/graph.js +2 -2
  210. package/dist/harmonic-retrieval.js +33 -33
  211. package/dist/harmonic-source-lookup.js +2 -2
  212. package/dist/index.js +236 -234
  213. package/dist/lcm/index.js +3 -3
  214. package/dist/location/index.js +35 -35
  215. package/dist/maintenance/memory-governance.js +32 -32
  216. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +32 -32
  217. package/dist/maintenance/rebuild-memory-projection-runner.js +34 -34
  218. package/dist/maintenance/rebuild-memory-projection.js +33 -33
  219. package/dist/memory-browse-operations.js +85 -85
  220. package/dist/memory-browse.js +5 -5
  221. package/dist/memory-subject.js +3 -3
  222. package/dist/namespaces/migrate.js +33 -33
  223. package/dist/namespaces/search.js +11 -11
  224. package/dist/namespaces/storage.js +32 -32
  225. package/dist/offline-sync-changeset-generations.js +3 -3
  226. package/dist/offline-sync-embedding-generation.js +2 -2
  227. package/dist/offline-sync-file-io.js +2 -2
  228. package/dist/offline-sync-impression-drain.js +3 -3
  229. package/dist/offline-sync-runtime-state.d.ts.map +1 -1
  230. package/dist/offline-sync-runtime-state.js +1 -1
  231. package/dist/offline-sync-snapshot-stream.js +8 -8
  232. package/dist/offline-sync-upload-staging.js +3 -3
  233. package/dist/offline-sync.js +8 -8
  234. package/dist/operator-doctor-corpus.js +35 -35
  235. package/dist/operator-toolkit.js +54 -54
  236. package/dist/orchestration/maintenance.js +44 -44
  237. package/dist/orchestrator.js +183 -181
  238. package/dist/qmd.js +4 -4
  239. package/dist/recall-explain-renderer.js +3 -3
  240. package/dist/recall-navigate-access.js +2 -2
  241. package/dist/recall-navigate-disclosure.js +2 -2
  242. package/dist/recall-navigate.js +2 -2
  243. package/dist/recall-navigation-operations.js +85 -85
  244. package/dist/recall-navigation.js +84 -84
  245. package/dist/recall-planner-llm.js +1 -1
  246. package/dist/recall-state-view-admission.js +5 -5
  247. package/dist/recall-why-service.js +5 -5
  248. package/dist/recall-xray-cli.js +4 -4
  249. package/dist/recall-xray-renderer.js +3 -3
  250. package/dist/recall-xray.js +2 -2
  251. package/dist/reconcile/manifest.js +3 -3
  252. package/dist/{resolution-V6JBMW7U.js → resolution-4ZEQPXUZ.js} +6 -6
  253. package/dist/resolution-4ZEQPXUZ.js.map +1 -0
  254. package/dist/resume-bundles.js +44 -44
  255. package/dist/retrieval-agents.js +2 -2
  256. package/dist/salvage-envelope.js +5 -5
  257. package/dist/search/factory.js +10 -10
  258. package/dist/search/index.js +14 -14
  259. package/dist/search/lancedb-backend.js +2 -2
  260. package/dist/search/meilisearch-backend.js +2 -2
  261. package/dist/search/orama-backend.js +2 -2
  262. package/dist/secure-store/index.js +2 -2
  263. package/dist/semantic-consolidation.js +33 -33
  264. package/dist/semantic-rule-promotion.js +32 -32
  265. package/dist/semantic-rule-verifier.js +32 -32
  266. package/dist/source-agent-qualifier.js +37 -37
  267. package/dist/standup/build.js +32 -32
  268. package/dist/storage/buffer-session-files.d.ts +69 -0
  269. package/dist/storage/buffer-session-files.d.ts.map +1 -0
  270. package/dist/storage.d.ts +5 -1
  271. package/dist/storage.d.ts.map +1 -1
  272. package/dist/storage.js +31 -31
  273. package/dist/subject-config.js +4 -4
  274. package/dist/summarizer.js +2 -2
  275. package/dist/support-passport/index.js +87 -87
  276. package/dist/transfer/export-okf.js +33 -33
  277. package/dist/types.d.ts +12 -0
  278. package/dist/types.d.ts.map +1 -1
  279. package/dist/types.js +1 -1
  280. package/dist/verified-recall.js +32 -32
  281. package/dist/who-knows-cli.js +33 -33
  282. package/dist/who-knows.js +32 -32
  283. package/dist/write-envelope.js +4 -4
  284. package/package.json +2 -2
  285. package/src/buffer-eviction.ts +51 -0
  286. package/src/buffer-incremental-persistence.test.ts +256 -0
  287. package/src/buffer-persistence.ts +89 -0
  288. package/src/buffer.ts +32 -61
  289. package/src/config.test.ts +16 -0
  290. package/src/config.ts +14 -0
  291. package/src/extraction-judge-chain.test.ts +298 -2
  292. package/src/extraction-judge.ts +147 -82
  293. package/src/fallback-llm.test.ts +94 -0
  294. package/src/fallback-llm.ts +7 -7
  295. package/src/offline-sync-runtime-state.ts +24 -2
  296. package/src/offline-sync.test.ts +9 -0
  297. package/src/secure-store/secure-fs.ts +11 -0
  298. package/src/secure-store/secure-store.test.ts +22 -0
  299. package/src/storage/buffer-session-files.ts +249 -0
  300. package/src/storage-buffer-sessions.test.ts +369 -0
  301. package/src/storage.ts +11 -16
  302. package/src/types.ts +12 -0
  303. package/dist/chunk-6FIFEXFF.js.map +0 -1
  304. package/dist/chunk-A6PKEU7T.js.map +0 -1
  305. package/dist/chunk-BBDASWNT.js.map +0 -1
  306. package/dist/chunk-GMMZ45C4.js.map +0 -1
  307. package/dist/chunk-O3VKQMWC.js.map +0 -1
  308. package/dist/chunk-TYT4TEQV.js.map +0 -1
  309. package/dist/chunk-UAYA4NJN.js.map +0 -1
  310. /package/dist/{auto-sync-VPHR3FBI.js.map → auto-sync-432USQDH.js.map} +0 -0
  311. /package/dist/{graph-edge-decay-IU75NV42.js.map → buffer-eviction.js.map} +0 -0
  312. /package/dist/{resolution-V6JBMW7U.js.map → buffer-persistence.js.map} +0 -0
  313. /package/dist/{chunk-FL6SLVAJ.js.map → chunk-2AKIVSHP.js.map} +0 -0
  314. /package/dist/{chunk-ORWDCX5Q.js.map → chunk-3AODCBKX.js.map} +0 -0
  315. /package/dist/{chunk-XFDHL252.js.map → chunk-3K5IEJTK.js.map} +0 -0
  316. /package/dist/{chunk-XVZA6VXC.js.map → chunk-3SL52JKD.js.map} +0 -0
  317. /package/dist/{chunk-ZSAQSLKL.js.map → chunk-3XVBGGF3.js.map} +0 -0
  318. /package/dist/{chunk-XO4HOBM2.js.map → chunk-4B37KNMP.js.map} +0 -0
  319. /package/dist/{chunk-NIANATGL.js.map → chunk-4IZ6AC2U.js.map} +0 -0
  320. /package/dist/{chunk-S2PDFSXS.js.map → chunk-4P4VLPGB.js.map} +0 -0
  321. /package/dist/{chunk-G5UR4DXQ.js.map → chunk-53BLBDV6.js.map} +0 -0
  322. /package/dist/{chunk-PDYP7SUC.js.map → chunk-5ANUG4JZ.js.map} +0 -0
  323. /package/dist/{chunk-2ZYIAUYU.js.map → chunk-5CWH2LKL.js.map} +0 -0
  324. /package/dist/{chunk-S2S4U4G3.js.map → chunk-5DCS4C4S.js.map} +0 -0
  325. /package/dist/{chunk-7WTTE5FW.js.map → chunk-5K23NQRI.js.map} +0 -0
  326. /package/dist/{chunk-V3JZZJ2E.js.map → chunk-5UPOKIFP.js.map} +0 -0
  327. /package/dist/{chunk-K567EIW3.js.map → chunk-63YPKHAU.js.map} +0 -0
  328. /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
  329. /package/dist/{chunk-HJM23E65.js.map → chunk-6DTIYAAN.js.map} +0 -0
  330. /package/dist/{chunk-G7XAZU2L.js.map → chunk-6F5BGIAF.js.map} +0 -0
  331. /package/dist/{chunk-IHTKBQBS.js.map → chunk-6JEEY42N.js.map} +0 -0
  332. /package/dist/{chunk-NHB4RC3G.js.map → chunk-6QOL4G76.js.map} +0 -0
  333. /package/dist/{chunk-AD3ZB72W.js.map → chunk-6SYS5YX3.js.map} +0 -0
  334. /package/dist/{chunk-DFP37GUN.js.map → chunk-7HXZOWTR.js.map} +0 -0
  335. /package/dist/{chunk-DGBWPSM6.js.map → chunk-7VFNGQ4V.js.map} +0 -0
  336. /package/dist/{chunk-77ZK533I.js.map → chunk-7ZRRJ6RG.js.map} +0 -0
  337. /package/dist/{chunk-QISYYK4L.js.map → chunk-AYBAC2N4.js.map} +0 -0
  338. /package/dist/{chunk-V44DWTFA.js.map → chunk-AYXRK264.js.map} +0 -0
  339. /package/dist/{chunk-LJSBF6PW.js.map → chunk-C2KOW2UQ.js.map} +0 -0
  340. /package/dist/{chunk-GY4R4P2A.js.map → chunk-CUWOSRCS.js.map} +0 -0
  341. /package/dist/{chunk-VNAIUNXI.js.map → chunk-CVMAOPAH.js.map} +0 -0
  342. /package/dist/{chunk-CJKHLACF.js.map → chunk-DG4H56SK.js.map} +0 -0
  343. /package/dist/{chunk-BQ6DGL6A.js.map → chunk-DKHX2FHI.js.map} +0 -0
  344. /package/dist/{chunk-77IXBNV6.js.map → chunk-E24RUQEN.js.map} +0 -0
  345. /package/dist/{chunk-HRT2SJPC.js.map → chunk-E3NBMTTX.js.map} +0 -0
  346. /package/dist/{chunk-PTQZPVRQ.js.map → chunk-E5PVMB3I.js.map} +0 -0
  347. /package/dist/{chunk-AHS3QEEA.js.map → chunk-EEOYF3IB.js.map} +0 -0
  348. /package/dist/{chunk-5XTSIZ3L.js.map → chunk-EGNONTVT.js.map} +0 -0
  349. /package/dist/{chunk-PH33R7GN.js.map → chunk-EHIKY2IA.js.map} +0 -0
  350. /package/dist/{chunk-4ISHIPOC.js.map → chunk-FGEY2AGV.js.map} +0 -0
  351. /package/dist/{chunk-O6YJI5VX.js.map → chunk-FKTMWDN2.js.map} +0 -0
  352. /package/dist/{chunk-KQUN4RSX.js.map → chunk-FQFMLOAC.js.map} +0 -0
  353. /package/dist/{chunk-5LWODP5R.js.map → chunk-FRAL3EU4.js.map} +0 -0
  354. /package/dist/{chunk-AAANTXCQ.js.map → chunk-FZVZYU5C.js.map} +0 -0
  355. /package/dist/{chunk-TGAXRT7N.js.map → chunk-GFYFKXWZ.js.map} +0 -0
  356. /package/dist/{chunk-ID2PLENW.js.map → chunk-GGI6FLO6.js.map} +0 -0
  357. /package/dist/{chunk-GDYLZ6FR.js.map → chunk-HJ3UTGIW.js.map} +0 -0
  358. /package/dist/{chunk-X3IFRQKS.js.map → chunk-I73ZSORJ.js.map} +0 -0
  359. /package/dist/{chunk-X73SCHKR.js.map → chunk-I75BWXRZ.js.map} +0 -0
  360. /package/dist/{chunk-M3GKSCFN.js.map → chunk-J7G656MY.js.map} +0 -0
  361. /package/dist/{chunk-EH6KLYIE.js.map → chunk-JF3MEIHO.js.map} +0 -0
  362. /package/dist/{chunk-XUB4I2N6.js.map → chunk-JFI3ATK4.js.map} +0 -0
  363. /package/dist/{chunk-R4SATHCV.js.map → chunk-JH2ALMPR.js.map} +0 -0
  364. /package/dist/{chunk-TKBW4YLS.js.map → chunk-JH4FCVWJ.js.map} +0 -0
  365. /package/dist/{chunk-DG5UKN2Y.js.map → chunk-JIA435P3.js.map} +0 -0
  366. /package/dist/{chunk-4Z7O2QVJ.js.map → chunk-KOAVX2IT.js.map} +0 -0
  367. /package/dist/{chunk-6NXHX6MI.js.map → chunk-KOY25HUB.js.map} +0 -0
  368. /package/dist/{chunk-TRW7N4FS.js.map → chunk-L2JQSG5M.js.map} +0 -0
  369. /package/dist/{chunk-QQ4T622E.js.map → chunk-L7PGPH4E.js.map} +0 -0
  370. /package/dist/{chunk-23VGZ65V.js.map → chunk-LHBOFROT.js.map} +0 -0
  371. /package/dist/{chunk-VKB2FGNW.js.map → chunk-LOMSBYNS.js.map} +0 -0
  372. /package/dist/{chunk-NDJ42GKB.js.map → chunk-MCPSMWUC.js.map} +0 -0
  373. /package/dist/{chunk-ERMT5WQM.js.map → chunk-MKE5DP3S.js.map} +0 -0
  374. /package/dist/{chunk-64IO6ZEE.js.map → chunk-MZWHIAOL.js.map} +0 -0
  375. /package/dist/{chunk-LDXS746V.js.map → chunk-N7DVBHU3.js.map} +0 -0
  376. /package/dist/{chunk-F2JLBXMG.js.map → chunk-NH6GZEQN.js.map} +0 -0
  377. /package/dist/{chunk-7FG2JSU6.js.map → chunk-NMKETOAX.js.map} +0 -0
  378. /package/dist/{chunk-GAARPWMN.js.map → chunk-OKKBOTRA.js.map} +0 -0
  379. /package/dist/{chunk-PCIIKQXW.js.map → chunk-OLH4XCLU.js.map} +0 -0
  380. /package/dist/{chunk-XA32GZ6B.js.map → chunk-OLHN4ZNT.js.map} +0 -0
  381. /package/dist/{chunk-UR25IQVT.js.map → chunk-P5CUEB2Q.js.map} +0 -0
  382. /package/dist/{chunk-LO775P3S.js.map → chunk-POGPI5GR.js.map} +0 -0
  383. /package/dist/{chunk-FXO43NBW.js.map → chunk-PSQ2P2T3.js.map} +0 -0
  384. /package/dist/{chunk-KRAMCBIW.js.map → chunk-QKXPOLQD.js.map} +0 -0
  385. /package/dist/{chunk-65JLKIVA.js.map → chunk-QO5KDQGG.js.map} +0 -0
  386. /package/dist/{chunk-A4B7WL5N.js.map → chunk-QOUKZ2N3.js.map} +0 -0
  387. /package/dist/{chunk-ZABEDRGQ.js.map → chunk-RGKXF4W3.js.map} +0 -0
  388. /package/dist/{chunk-IKCGNTGS.js.map → chunk-RWRHGE75.js.map} +0 -0
  389. /package/dist/{chunk-NBH7IRME.js.map → chunk-SWZOAQUM.js.map} +0 -0
  390. /package/dist/{chunk-FQ52AJXX.js.map → chunk-SZPPCEYT.js.map} +0 -0
  391. /package/dist/{chunk-4YYIZ475.js.map → chunk-TAEJ2MRR.js.map} +0 -0
  392. /package/dist/{chunk-3ODEGTVV.js.map → chunk-TDCR6PQL.js.map} +0 -0
  393. /package/dist/{chunk-QCP75JGO.js.map → chunk-TFA6HPOA.js.map} +0 -0
  394. /package/dist/{chunk-SE3JAD22.js.map → chunk-TPKB7T6Z.js.map} +0 -0
  395. /package/dist/{chunk-6VYY2XFK.js.map → chunk-TVIGN3XZ.js.map} +0 -0
  396. /package/dist/{chunk-OHMGR6QN.js.map → chunk-TXP7Q7T5.js.map} +0 -0
  397. /package/dist/{chunk-AI2VXOSO.js.map → chunk-TYLNWE4D.js.map} +0 -0
  398. /package/dist/{chunk-WI6MIJYK.js.map → chunk-U7HJBODU.js.map} +0 -0
  399. /package/dist/{chunk-IS4HKNWP.js.map → chunk-UBN5AOLT.js.map} +0 -0
  400. /package/dist/{chunk-JNELS2TW.js.map → chunk-UJDTXWMT.js.map} +0 -0
  401. /package/dist/{chunk-DJMC4W6N.js.map → chunk-VC3X7XP3.js.map} +0 -0
  402. /package/dist/{chunk-A2D3WICT.js.map → chunk-VGFNTY3Y.js.map} +0 -0
  403. /package/dist/{chunk-X544TW54.js.map → chunk-VGRM43X6.js.map} +0 -0
  404. /package/dist/{chunk-CSGFGQBI.js.map → chunk-VPO53QMG.js.map} +0 -0
  405. /package/dist/{chunk-BRZRP5WD.js.map → chunk-VSSQIBVU.js.map} +0 -0
  406. /package/dist/{chunk-GKNX4QO3.js.map → chunk-WCIDCJOQ.js.map} +0 -0
  407. /package/dist/{chunk-7VJEZQYF.js.map → chunk-WEK3OUGO.js.map} +0 -0
  408. /package/dist/{chunk-IVYAPAHG.js.map → chunk-WRDFYSUC.js.map} +0 -0
  409. /package/dist/{chunk-5EILJ6W2.js.map → chunk-WXPBDEMW.js.map} +0 -0
  410. /package/dist/{chunk-QZP3RMYP.js.map → chunk-X247CYL6.js.map} +0 -0
  411. /package/dist/{chunk-YLF42JQ7.js.map → chunk-XHX67LX6.js.map} +0 -0
  412. /package/dist/{chunk-C6S2Y7HE.js.map → chunk-XKDQTDXN.js.map} +0 -0
  413. /package/dist/{chunk-4AHKNZW7.js.map → chunk-XLEP7SS3.js.map} +0 -0
  414. /package/dist/{chunk-B6L7BKA7.js.map → chunk-XRFLR3XF.js.map} +0 -0
  415. /package/dist/{chunk-H7QC7WCU.js.map → chunk-XTBEXZFN.js.map} +0 -0
  416. /package/dist/{chunk-CIJRM6SQ.js.map → chunk-Y5ZHZKZD.js.map} +0 -0
  417. /package/dist/{chunk-H6SKBCNI.js.map → chunk-YC2C67F7.js.map} +0 -0
  418. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  419. /package/dist/{chunk-YOL56HY5.js.map → chunk-YQ6SLFNZ.js.map} +0 -0
  420. /package/dist/{chunk-SIIWHIBK.js.map → chunk-YYGZ4EIY.js.map} +0 -0
  421. /package/dist/{chunk-G22A6WJQ.js.map → chunk-Z2T5BPOZ.js.map} +0 -0
  422. /package/dist/{chunk-RYUSWAAU.js.map → chunk-ZAP7BKTZ.js.map} +0 -0
package/dist/who-knows.js CHANGED
@@ -9,37 +9,37 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-BRZRP5WD.js";
13
- import "./chunk-O3VKQMWC.js";
14
- import "./chunk-DM5QZ3YU.js";
12
+ } from "./chunk-VSSQIBVU.js";
13
+ import "./chunk-WCBLPKG3.js";
15
14
  import "./chunk-UHVXE24Y.js";
15
+ import "./chunk-DM5QZ3YU.js";
16
16
  import "./chunk-VY6BD5KB.js";
17
- import "./chunk-TKBW4YLS.js";
18
- import "./chunk-23VGZ65V.js";
19
- import "./chunk-UR25IQVT.js";
17
+ import "./chunk-JH4FCVWJ.js";
18
+ import "./chunk-LHBOFROT.js";
19
+ import "./chunk-P5CUEB2Q.js";
20
+ import "./chunk-XRFLR3XF.js";
20
21
  import "./chunk-7VO6E5UD.js";
21
22
  import "./chunk-EXYT52NR.js";
22
- import "./chunk-2ZYIAUYU.js";
23
- import "./chunk-C6S2Y7HE.js";
24
- import "./chunk-CYEPCZN5.js";
25
- import "./chunk-B6L7BKA7.js";
26
- import "./chunk-Y5NLBXPV.js";
23
+ import "./chunk-5CWH2LKL.js";
24
+ import "./chunk-XKDQTDXN.js";
27
25
  import "./chunk-WNEVEMJ3.js";
28
- import "./chunk-QCP75JGO.js";
29
- import "./chunk-A7Q43EUZ.js";
26
+ import "./chunk-Y5NLBXPV.js";
27
+ import "./chunk-CYEPCZN5.js";
28
+ import "./chunk-TFA6HPOA.js";
30
29
  import "./chunk-F4TWWUMP.js";
31
30
  import "./chunk-72A4L5JJ.js";
31
+ import "./chunk-A7Q43EUZ.js";
32
32
  import "./chunk-S2V7RUCL.js";
33
33
  import "./chunk-PPUNC7UX.js";
34
34
  import "./chunk-X3724WL4.js";
35
- import "./chunk-S2HLHAZ4.js";
36
35
  import "./chunk-MRPOZBJC.js";
36
+ import "./chunk-S2HLHAZ4.js";
37
37
  import "./chunk-DM2T26WE.js";
38
38
  import "./chunk-LDXUBPMO.js";
39
39
  import "./chunk-FF6N7BXC.js";
40
- import "./chunk-5EILJ6W2.js";
40
+ import "./chunk-WXPBDEMW.js";
41
41
  import "./chunk-AAD2ZS6P.js";
42
- import "./chunk-YOL56HY5.js";
42
+ import "./chunk-YQ6SLFNZ.js";
43
43
  import "./chunk-ZIKENA2C.js";
44
44
  import "./chunk-YXZG5TVN.js";
45
45
  import "./chunk-3OUGSOJP.js";
@@ -55,45 +55,45 @@ import "./chunk-LWRIGKFM.js";
55
55
  import "./chunk-5WITETWU.js";
56
56
  import "./chunk-6CIAGZ6X.js";
57
57
  import "./chunk-7CT3AI52.js";
58
- import "./chunk-GMMZ45C4.js";
59
- import "./chunk-I55KAVET.js";
60
- import "./chunk-L2EXJQJP.js";
61
- import "./chunk-45GF7Y3V.js";
62
- import "./chunk-YIJECSIX.js";
63
- import "./chunk-E2AWJ7KQ.js";
64
- import "./chunk-UUZ7KZAO.js";
65
- import "./chunk-V44DWTFA.js";
58
+ import "./chunk-AYXRK264.js";
59
+ import "./chunk-IUM3VSHI.js";
66
60
  import "./chunk-G26YNEOC.js";
67
61
  import "./chunk-VILPVT4S.js";
68
62
  import "./chunk-AF2XMJKD.js";
69
63
  import "./chunk-OR42ZI54.js";
70
- import "./chunk-IUM3VSHI.js";
64
+ import "./chunk-23G5P7TA.js";
71
65
  import "./chunk-C64XATK7.js";
72
66
  import "./chunk-42JKGUFJ.js";
73
- import "./chunk-23G5P7TA.js";
67
+ import "./chunk-AVVCPA7U.js";
68
+ import "./chunk-I55KAVET.js";
69
+ import "./chunk-L2EXJQJP.js";
70
+ import "./chunk-45GF7Y3V.js";
71
+ import "./chunk-YIJECSIX.js";
72
+ import "./chunk-E2AWJ7KQ.js";
73
+ import "./chunk-UUZ7KZAO.js";
74
74
  import "./chunk-HADD45AR.js";
75
75
  import "./chunk-RNFMFC37.js";
76
76
  import "./chunk-YCVB7X56.js";
77
77
  import "./chunk-PQVCH2AE.js";
78
78
  import "./chunk-PJKTFXE2.js";
79
79
  import "./chunk-W5BIQOAJ.js";
80
- import "./chunk-A6PKEU7T.js";
80
+ import "./chunk-UFM3PJDT.js";
81
81
  import "./chunk-YBA52OKG.js";
82
- import "./chunk-3ODEGTVV.js";
82
+ import "./chunk-TDCR6PQL.js";
83
83
  import "./chunk-BT7NVCML.js";
84
- import "./chunk-PTQZPVRQ.js";
84
+ import "./chunk-E5PVMB3I.js";
85
85
  import "./chunk-BJMBJZ2Y.js";
86
86
  import "./chunk-UKJAGEXH.js";
87
87
  import "./chunk-FP2373TW.js";
88
88
  import "./chunk-L272A5QW.js";
89
- import "./chunk-JNELS2TW.js";
89
+ import "./chunk-UJDTXWMT.js";
90
90
  import "./chunk-ZA53AZND.js";
91
91
  import "./chunk-7RJUVTVF.js";
92
92
  import "./chunk-AL3UYZ5N.js";
93
93
  import "./chunk-RL6NEVXT.js";
94
94
  import "./chunk-YET735EZ.js";
95
95
  import "./chunk-PWPIERBM.js";
96
- import "./chunk-IS4HKNWP.js";
96
+ import "./chunk-UBN5AOLT.js";
97
97
  import "./chunk-5FVVY2EB.js";
98
98
  import "./chunk-BTNNL7ZW.js";
99
99
  import "./chunk-JDSVLVCG.js";
@@ -111,7 +111,7 @@ import "./chunk-3MUKQQ7A.js";
111
111
  import "./chunk-R2MBW2S4.js";
112
112
  import "./chunk-QUIRIG2P.js";
113
113
  import "./chunk-LDPPTPO5.js";
114
- import "./chunk-ZG3HZZ6K.js";
114
+ import "./chunk-TYGLV6ZG.js";
115
115
  import "./chunk-A6XUJE5D.js";
116
116
  import "./chunk-C7HJ3NEI.js";
117
117
  import "./chunk-VS2IYZRU.js";
@@ -12,10 +12,10 @@ import {
12
12
  isMemoryCategory,
13
13
  isSealedMemoryEnvelope,
14
14
  sealedWriteToLegacyArgs
15
- } from "./chunk-3ODEGTVV.js";
15
+ } from "./chunk-TDCR6PQL.js";
16
16
  import "./chunk-BT7NVCML.js";
17
- import "./chunk-PTQZPVRQ.js";
18
- import "./chunk-IS4HKNWP.js";
17
+ import "./chunk-E5PVMB3I.js";
18
+ import "./chunk-UBN5AOLT.js";
19
19
  import "./chunk-5FVVY2EB.js";
20
20
  import "./chunk-JDSVLVCG.js";
21
21
  import "./chunk-5GKPFL3S.js";
@@ -24,7 +24,7 @@ import "./chunk-EBRG7ZIK.js";
24
24
  import "./chunk-P7FMDTKL.js";
25
25
  import "./chunk-X4OZMANG.js";
26
26
  import "./chunk-R2MBW2S4.js";
27
- import "./chunk-ZG3HZZ6K.js";
27
+ import "./chunk-TYGLV6ZG.js";
28
28
  import "./chunk-A6XUJE5D.js";
29
29
  import "./chunk-C7HJ3NEI.js";
30
30
  import "./chunk-VS2IYZRU.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.36",
3
+ "version": "10.0.38",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3347,7 +3347,7 @@
3347
3347
  "core"
3348
3348
  ],
3349
3349
  "peerDependencies": {
3350
- "@remnic/coding-graph": "^10.0.36"
3350
+ "@remnic/coding-graph": "^10.0.38"
3351
3351
  },
3352
3352
  "peerDependenciesMeta": {
3353
3353
  "@remnic/coding-graph": {
@@ -0,0 +1,51 @@
1
+ import type { BufferEntryState } from "./types.js";
2
+
3
+ const EMPTY_ENTRY: BufferEntryState = { turns: [], lastExtractionAt: null, extractionCount: 0 };
4
+
5
+ export interface BufferEvictionHooks {
6
+ /** Last activity time (ms) of an entry; older entries are evicted first. */
7
+ activityAt(entry: BufferEntryState): number;
8
+ /** Accepted captures exit via refusal/backpressure, never eviction (#3251). */
9
+ holdsAcceptedCapture(entry: BufferEntryState | undefined): boolean;
10
+ }
11
+
12
+ /**
13
+ * Pick the keys to evict so `entries` returns to `maxCount`: the oldest empty
14
+ * sessions first; retained failed extractions (#1908) keep their turns, so if
15
+ * empty entries alone cannot reach the cap the oldest NON-empty sessions go
16
+ * too rather than growing unboundedly. "default", the retained keys and
17
+ * entries holding an accepted capture are never chosen.
18
+ */
19
+ export function selectEvictedBufferKeys(
20
+ entries: Readonly<Record<string, BufferEntryState>>,
21
+ retainKeys: readonly string[],
22
+ maxCount: number,
23
+ hooks: BufferEvictionHooks,
24
+ ): string[] {
25
+ const keys = Object.keys(entries);
26
+ if (keys.length <= maxCount) return [];
27
+
28
+ const insertionOrder = new Map(keys.map((key, index) => [key, index]));
29
+ const byOldestActivity = (left: string, right: string): number => {
30
+ const leftAt = hooks.activityAt(entries[left] ?? EMPTY_ENTRY);
31
+ const rightAt = hooks.activityAt(entries[right] ?? EMPTY_ENTRY);
32
+ if (leftAt !== rightAt) return leftAt - rightAt;
33
+ return (insertionOrder.get(left) ?? 0) - (insertionOrder.get(right) ?? 0);
34
+ };
35
+ const candidates = keys.filter(
36
+ (key) => key !== "default" && !retainKeys.includes(key) && !hooks.holdsAcceptedCapture(entries[key]),
37
+ );
38
+ const emptyRemovable = candidates
39
+ .filter((key) => (entries[key]?.turns.length ?? 0) === 0)
40
+ .sort(byOldestActivity);
41
+
42
+ const removableCount = Math.max(0, keys.length - maxCount);
43
+ const evicted = emptyRemovable.slice(0, removableCount);
44
+ if (evicted.length < removableCount) {
45
+ const nonEmptyRemovable = candidates
46
+ .filter((key) => (entries[key]?.turns.length ?? 0) > 0)
47
+ .sort(byOldestActivity);
48
+ return evicted.concat(nonEmptyRemovable.slice(0, removableCount - evicted.length));
49
+ }
50
+ return evicted;
51
+ }
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Per-session incremental buffer persistence (SmartBuffer layer).
3
+ *
4
+ * Pins the hot-path contract on top of the storage primitives tested in
5
+ * storage-buffer-sessions.test.ts:
6
+ *
7
+ * - a storage that exposes saveBufferSession/deleteBufferSession gets
8
+ * INCREMENTAL saves: only the sessions whose state actually changed are
9
+ * written, only on boundaries that need durability;
10
+ * - sessions whose state did not change are never rewritten;
11
+ * - eviction and resetToEmpty delete the corresponding session files;
12
+ * - a legacy storage (only loadBuffer/saveBuffer) keeps the exact old
13
+ * whole-state behavior — existing deployments and test doubles are
14
+ * unaffected.
15
+ *
16
+ * All saves flow through SmartBuffer's mutation chain, so there is exactly
17
+ * one writer per session file.
18
+ */
19
+ import test from "node:test";
20
+ import assert from "node:assert/strict";
21
+ import { mkdtemp, rm } from "node:fs/promises";
22
+ import os from "node:os";
23
+ import path from "node:path";
24
+
25
+ import { SmartBuffer } from "./buffer.js";
26
+ import { parseConfig } from "./config.js";
27
+ import { StorageManager } from "./storage.js";
28
+ import type { BufferEntryState, BufferState, BufferTurn } from "./types.js";
29
+
30
+ interface SessionFileRecord {
31
+ entry: BufferEntryState;
32
+ writeCount: number;
33
+ }
34
+
35
+ /**
36
+ * Storage double implementing the incremental per-session surface. Records
37
+ * per-session writes/deletes and whole-state saves separately so tests can
38
+ * assert exactly which files the hot path touched.
39
+ */
40
+ class IncrementalStorage {
41
+ readonly sessions = new Map<string, SessionFileRecord>();
42
+ readonly deleted: string[] = [];
43
+ wholeStateSaves = 0;
44
+ private initial: BufferState;
45
+
46
+ constructor(initial: BufferState) {
47
+ this.initial = initial;
48
+ }
49
+
50
+ async loadBuffer(): Promise<BufferState> {
51
+ return structuredClone(this.initial);
52
+ }
53
+
54
+ async saveBuffer(state: BufferState): Promise<void> {
55
+ this.wholeStateSaves += 1;
56
+ this.initial = structuredClone(state);
57
+ }
58
+
59
+ async saveBufferSession(key: string, entry: BufferEntryState): Promise<void> {
60
+ const record = this.sessions.get(key) ?? { entry, writeCount: 0 };
61
+ record.entry = structuredClone(entry);
62
+ record.writeCount += 1;
63
+ this.sessions.set(key, record);
64
+ }
65
+
66
+ async deleteBufferSession(key: string): Promise<void> {
67
+ this.deleted.push(key);
68
+ this.sessions.delete(key);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Storage double implementing ONLY the legacy whole-state surface — every
74
+ * pre-existing test double in the repo looks like this from SmartBuffer's
75
+ * point of view, and must keep working unchanged.
76
+ */
77
+ class LegacyOnlyStorage {
78
+ wholeStateSaves = 0;
79
+ lastSaved: BufferState | null = null;
80
+
81
+ constructor(private initial: BufferState) {}
82
+
83
+ async loadBuffer(): Promise<BufferState> {
84
+ return structuredClone(this.initial);
85
+ }
86
+
87
+ async saveBuffer(state: BufferState): Promise<void> {
88
+ this.wholeStateSaves += 1;
89
+ this.lastSaved = structuredClone(state);
90
+ }
91
+ }
92
+
93
+ function makeTurn(sessionKey: string, content: string): BufferTurn {
94
+ return {
95
+ role: "user",
96
+ content,
97
+ timestamp: "2026-10-29T12:00:00.000Z",
98
+ sessionKey,
99
+ };
100
+ }
101
+
102
+ function emptyState(): BufferState {
103
+ return { turns: [], lastExtractionAt: null, extractionCount: 0 };
104
+ }
105
+
106
+ test("steady-state observe persists only the active session's file", async () => {
107
+ const storage = new IncrementalStorage(emptyState());
108
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
109
+
110
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "alpha"));
111
+ await buffer.flushPendingSave();
112
+ assert.equal(storage.wholeStateSaves, 0, "hot path fell back to whole-state save");
113
+ assert.equal(storage.sessions.get("thread-a")?.writeCount, 1);
114
+ assert.equal(storage.sessions.get("thread-a")?.entry.turns[0]?.content, "alpha");
115
+
116
+ await buffer.addTurn("thread-b", makeTurn("thread-b", "beta"));
117
+ await buffer.flushPendingSave();
118
+ assert.equal(storage.sessions.get("thread-b")?.writeCount, 1);
119
+ // Session A's turn did NOT touch session A's file again.
120
+ assert.equal(storage.sessions.get("thread-a")?.writeCount, 1, "unchanged session file was rewritten");
121
+ });
122
+
123
+ test("a second turn in the same session rewrites only that session's file", async () => {
124
+ const storage = new IncrementalStorage(emptyState());
125
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
126
+
127
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "one"));
128
+ await buffer.flushPendingSave();
129
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "two"));
130
+ await buffer.flushPendingSave();
131
+
132
+ const record = storage.sessions.get("thread-a");
133
+ assert.equal(record?.writeCount, 2);
134
+ assert.equal(record?.entry.turns.length, 2);
135
+ });
136
+
137
+ test("extraction-boundary turn persists inline and durably", async () => {
138
+ const storage = new IncrementalStorage(emptyState());
139
+ // bufferMaxTurns: 1 → the very first turn triggers extract_batch.
140
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 1 }), storage);
141
+
142
+ const outcome = await buffer.addTurnWithOutcome("thread-a", makeTurn("thread-a", "trigger"));
143
+ assert.equal(outcome.decision, "extract_batch");
144
+ // Inline save already ran inside the mutation — no flush needed.
145
+ assert.equal(storage.sessions.get("thread-a")?.writeCount, 1);
146
+ assert.equal(storage.wholeStateSaves, 0, "extraction boundary fell back to whole-state save");
147
+ });
148
+
149
+ test("clearAfterExtraction persists the cleared session state", async () => {
150
+ const storage = new IncrementalStorage(emptyState());
151
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
152
+
153
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "alpha"));
154
+ await buffer.flushPendingSave();
155
+ const before = storage.sessions.get("thread-a")?.writeCount ?? 0;
156
+
157
+ await buffer.clearAfterExtraction("thread-a");
158
+ const record = storage.sessions.get("thread-a");
159
+ assert.equal(record?.writeCount, before + 1, "clearAfterExtraction did not persist the session");
160
+ assert.equal(record?.entry.turns.length, 0);
161
+ assert.equal(record?.entry.extractionCount, 1);
162
+ });
163
+
164
+ test("evicted sessions get their files deleted", async () => {
165
+ const storage = new IncrementalStorage(emptyState());
166
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
167
+
168
+ // normalizeState always materializes a "default" entry, so 198 seeded
169
+ // sessions + default = 199; new-session reaches exactly 200 (the
170
+ // addTurnBounded cap). One more UNBOUNDED addTurn pushes to 201 and
171
+ // pruneEntries evicts the oldest non-default session (s0).
172
+ for (let i = 0; i < 198; i++) {
173
+ const key = `s${i}`;
174
+ await buffer.addTurnBounded(key, makeTurn(key, `content ${i}`));
175
+ }
176
+ await buffer.flushPendingSave();
177
+
178
+ const outcome = await buffer.addTurnBounded("new-session", makeTurn("new-session", "fresh"));
179
+ assert.notEqual(outcome, null, "addTurnBounded refused below capacity");
180
+ await buffer.addTurn("overflow", makeTurn("overflow", "one too many"));
181
+ // The evicted key's file deletion lands on the next persist, like any
182
+ // other buffered state change.
183
+ await buffer.flushPendingSave();
184
+ assert.ok(storage.deleted.includes("s0"), "oldest session was not evicted under capacity pressure");
185
+ assert.ok(
186
+ storage.deleted.length > 0,
187
+ "capacity pressure evicted entries without deleting their session files",
188
+ );
189
+ for (const key of storage.deleted) {
190
+ assert.equal(storage.sessions.has(key), false, `evicted session ${key} still has a file record`);
191
+ }
192
+ });
193
+
194
+ test("resetToEmpty drops every session file on the next persist", async () => {
195
+ const storage = new IncrementalStorage(emptyState());
196
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
197
+
198
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "alpha"));
199
+ await buffer.flushPendingSave();
200
+ buffer.resetToEmpty();
201
+ await buffer.flushPendingSave();
202
+ // resetToEmpty marks every known key for deletion; deleting a key whose
203
+ // file never existed is an ENOENT no-op on real storage (covered in the
204
+ // storage contract tests). The session that HAD a file must be gone.
205
+ assert.ok(storage.deleted.includes("thread-a"));
206
+ assert.equal(storage.sessions.size, 0);
207
+ });
208
+
209
+ test("retained turns survive the per-session persist", async () => {
210
+ const storage = new IncrementalStorage(emptyState());
211
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
212
+
213
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "alpha"));
214
+ await buffer.flushPendingSave();
215
+ await buffer.retainDeferredTurns("thread-a", [makeTurn("thread-a", "alpha")], 5);
216
+ await buffer.flushPendingSave();
217
+
218
+ const record = storage.sessions.get("thread-a");
219
+ assert.equal(record?.entry.retainedTurns?.length, 1, "retained turns were not persisted");
220
+ assert.equal(record?.entry.retainedTurns?.[0]?.content, "alpha");
221
+ });
222
+
223
+ test("buffer state survives a restart through per-session files", async () => {
224
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-bufio-restart-"));
225
+ try {
226
+ const storage = new StorageManager(root);
227
+ const config = parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 });
228
+ const first = new SmartBuffer(config, storage);
229
+ await first.addTurn("thread-a", makeTurn("thread-a", "alpha"));
230
+ await first.addTurn("thread-b", makeTurn("thread-b", "beta"));
231
+ await first.flushPendingSave();
232
+
233
+ // A fresh process reads the buffer back from the per-session files.
234
+ const second = new SmartBuffer(config, storage);
235
+ await second.load();
236
+ assert.equal(second.getTurns("thread-a").length, 1);
237
+ assert.equal(second.getTurns("thread-a")[0]?.content, "alpha");
238
+ assert.equal(second.getTurns("thread-b")[0]?.content, "beta");
239
+ } finally {
240
+ await rm(root, { recursive: true, force: true });
241
+ }
242
+ });
243
+
244
+ test("legacy-only storage keeps the whole-state saveBuffer behavior", async () => {
245
+ const storage = new LegacyOnlyStorage(emptyState());
246
+ const buffer = new SmartBuffer(parseConfig({ triggerMode: "every_n", bufferMaxTurns: 100 }), storage);
247
+
248
+ await buffer.addTurn("thread-a", makeTurn("thread-a", "alpha"));
249
+ await buffer.flushPendingSave();
250
+ await buffer.addTurn("thread-b", makeTurn("thread-b", "beta"));
251
+ await buffer.flushPendingSave();
252
+
253
+ assert.ok(storage.wholeStateSaves >= 2, "legacy storage did not receive whole-state saves");
254
+ assert.equal(storage.lastSaved?.entries?.["thread-a"]?.turns[0]?.content, "alpha");
255
+ assert.equal(storage.lastSaved?.entries?.["thread-b"]?.turns[0]?.content, "beta");
256
+ });
@@ -0,0 +1,89 @@
1
+ import type { BufferEntryState, BufferState, BufferSurpriseEvent } from "./types.js";
2
+
3
+ /**
4
+ * The buffer persistence surface SmartBuffer depends on.
5
+ *
6
+ * `saveBufferSession` / `deleteBufferSession` are the per-session incremental
7
+ * writes (one file per session); when a storage backend does not provide
8
+ * them, the buffer falls back to the whole-state `saveBuffer`. Both are
9
+ * optional in the type so a storage double only has to implement what it
10
+ * actually supports.
11
+ */
12
+ export interface BufferStorage {
13
+ loadBuffer(): Promise<BufferState>;
14
+ saveBuffer(state: BufferState): Promise<void>;
15
+ saveBufferSession?(key: string, entry: BufferEntryState): Promise<void>;
16
+ deleteBufferSession?(key: string): Promise<void>;
17
+ /** Optional surprise-telemetry sink; older storage and test doubles omit it. */
18
+ appendBufferSurpriseEvents?(events: BufferSurpriseEvent[]): Promise<number>;
19
+ }
20
+
21
+ /**
22
+ * Tracks which sessions' persisted files are stale and writes only those.
23
+ *
24
+ * Marks are cleared only after a durable write of that session. All calls
25
+ * happen under SmartBuffer's serialized mutation chain: one writer.
26
+ */
27
+ export class BufferSessionPersistence {
28
+ private readonly dirty = new Set<string>();
29
+ private readonly deleted = new Set<string>();
30
+
31
+ markDirty(key: string): void {
32
+ this.dirty.add(key);
33
+ this.deleted.delete(key);
34
+ }
35
+
36
+ markDeleted(key: string): void {
37
+ this.deleted.add(key);
38
+ this.dirty.delete(key);
39
+ }
40
+
41
+ /** Eviction removed `key` from memory: its session file must go, any pending write is moot. */
42
+ markEvicted(keys: readonly string[]): void {
43
+ for (const key of keys) this.markDeleted(key);
44
+ }
45
+
46
+ hasPending(): boolean {
47
+ return this.dirty.size > 0 || this.deleted.size > 0;
48
+ }
49
+
50
+ /**
51
+ * Persist buffer state. On session-capable storage this writes ONLY the
52
+ * sessions whose state changed since the last successful persist and
53
+ * deletes files for evicted/reset sessions, so the observe path never
54
+ * re-serializes other sessions' turns. On legacy storage it falls back to
55
+ * the whole-state saveBuffer. Files are deleted before dirty writes: a
56
+ * crash mid-persist can then only resurrect already-evicted data (the same
57
+ * exposure as a whole-file rewrite), never drop sessions the state says
58
+ * exist.
59
+ */
60
+ async persist(
61
+ storage: BufferStorage,
62
+ state: BufferState,
63
+ peekEntry: (key: string) => BufferEntryState | undefined,
64
+ ): Promise<void> {
65
+ const saveSession = storage.saveBufferSession?.bind(storage);
66
+ const deleteSession = storage.deleteBufferSession?.bind(storage);
67
+ if (!saveSession || !deleteSession) {
68
+ await storage.saveBuffer(state);
69
+ this.dirty.clear();
70
+ this.deleted.clear();
71
+ return;
72
+ }
73
+ for (const key of [...this.deleted]) {
74
+ await deleteSession(key);
75
+ this.deleted.delete(key);
76
+ }
77
+ for (const key of [...this.dirty]) {
78
+ const entry = peekEntry(key);
79
+ if (!entry) {
80
+ // A dirty key without state must not be written from a fabricated
81
+ // empty entry: treat it as a deletion instead.
82
+ this.markDeleted(key);
83
+ continue;
84
+ }
85
+ await saveSession(key, entry);
86
+ this.dirty.delete(key);
87
+ }
88
+ }
89
+ }