@remnic/core 10.0.59 → 10.0.61

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 (370) hide show
  1. package/dist/access-admin-ops-surface.js +53 -50
  2. package/dist/access-authorization-probe.js +54 -51
  3. package/dist/access-boundary.js +53 -50
  4. package/dist/access-cli.js +143 -140
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +53 -50
  7. package/dist/access-http-briefing.js +54 -51
  8. package/dist/access-http-query.js +55 -52
  9. package/dist/access-http.js +76 -73
  10. package/dist/access-identity-continuity-surface.js +53 -50
  11. package/dist/access-lcm-surface.js +53 -50
  12. package/dist/access-mcp.js +64 -61
  13. package/dist/access-namespace-preflight.js +53 -50
  14. package/dist/access-observe-write-category.js +10 -10
  15. package/dist/access-observe-write-surface.js +53 -50
  16. package/dist/access-offline-manifest.js +7 -7
  17. package/dist/access-operations-batch.js +56 -53
  18. package/dist/access-operations.js +63 -60
  19. package/dist/access-recall-concurrency.js +53 -50
  20. package/dist/access-recall-response.js +53 -50
  21. package/dist/access-recall-surface.js +53 -50
  22. package/dist/access-schema.js +9 -9
  23. package/dist/access-service.js +53 -50
  24. package/dist/access-surface-catalog.js +55 -52
  25. package/dist/access-surface-catalog.js.map +1 -1
  26. package/dist/active-recall.js +24 -20
  27. package/dist/active-recall.js.map +1 -1
  28. package/dist/adapters/index.js +7 -7
  29. package/dist/adapters/registry.js +3 -3
  30. package/dist/briefing.js +16 -12
  31. package/dist/buffer-persistence.d.ts +14 -3
  32. package/dist/buffer-persistence.d.ts.map +1 -1
  33. package/dist/buffer-persistence.js +1 -1
  34. package/dist/buffer-turn-helpers.d.ts +7 -0
  35. package/dist/buffer-turn-helpers.d.ts.map +1 -1
  36. package/dist/buffer-turn-helpers.js +5 -3
  37. package/dist/buffer.d.ts +2 -0
  38. package/dist/buffer.d.ts.map +1 -1
  39. package/dist/buffer.js +7 -7
  40. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
  41. package/dist/causal-behavior.js +2 -2
  42. package/dist/causal-chain.js +2 -2
  43. package/dist/causal-consolidation.js +19 -15
  44. package/dist/causal-consolidation.js.map +1 -1
  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-ZAZZOQAQ.js → chunk-23OEPU3K.js} +2 -2
  49. package/dist/{chunk-XDKEHZUC.js → chunk-264B57GV.js} +2 -2
  50. package/dist/{chunk-5U2BBF7E.js → chunk-46U6L5DM.js} +20 -10
  51. package/dist/chunk-46U6L5DM.js.map +1 -0
  52. package/dist/chunk-4LZ7SVKM.js +211 -0
  53. package/dist/chunk-4LZ7SVKM.js.map +1 -0
  54. package/dist/{chunk-NRGQ5HJO.js → chunk-4P4VLPGB.js} +1 -1
  55. package/dist/{chunk-GIRWNTMV.js → chunk-4PG5R6BJ.js} +2 -2
  56. package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
  57. package/dist/{chunk-RG3I2663.js → chunk-64JLBFCQ.js} +2 -2
  58. package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
  59. package/dist/{chunk-WASVDS6G.js → chunk-6HTEPYOI.js} +4 -4
  60. package/dist/{chunk-6AEKSOWV.js → chunk-6I6DFULH.js} +8 -8
  61. package/dist/{chunk-DJR37Q37.js → chunk-6T4CMKNP.js} +2 -2
  62. package/dist/{chunk-RHJ5VGB3.js → chunk-73A2DDDR.js} +2 -2
  63. package/dist/{chunk-4B73TQQV.js → chunk-7AKPLEJV.js} +2 -2
  64. package/dist/{chunk-UHH67NLU.js → chunk-7OKYO2UC.js} +2 -2
  65. package/dist/{chunk-KAL5SXPP.js → chunk-7ULSP7AU.js} +6 -6
  66. package/dist/{chunk-USNU3BEQ.js → chunk-A4FZLM6Q.js} +2 -2
  67. package/dist/{chunk-VV73XT3A.js → chunk-BJLCV2P3.js} +2 -2
  68. package/dist/{chunk-KQAFEZQX.js → chunk-BUKK5SWA.js} +2 -2
  69. package/dist/{chunk-DJFULNXK.js → chunk-C2AYUXEF.js} +2 -2
  70. package/dist/{chunk-QY24FSXT.js → chunk-D3BYJSHX.js} +51 -51
  71. package/dist/{chunk-JZRQY7ZQ.js → chunk-D4WR56FR.js} +2 -2
  72. package/dist/{chunk-3E3Z6UA3.js → chunk-DMYNM3WG.js} +124 -97
  73. package/dist/chunk-DMYNM3WG.js.map +1 -0
  74. package/dist/{chunk-FB4JQEFS.js → chunk-DP22K7IC.js} +2 -2
  75. package/dist/{chunk-EJFOGYF3.js → chunk-DTQJ7BRN.js} +3 -3
  76. package/dist/{chunk-MLUPSZFK.js → chunk-DZL5PBEJ.js} +2 -2
  77. package/dist/{chunk-JD5F5MYN.js → chunk-EGCC5OJE.js} +3 -3
  78. package/dist/{chunk-IQSRVR6Z.js → chunk-EJ4RS7I7.js} +2 -2
  79. package/dist/{chunk-WBN66HPI.js → chunk-ELHJK7LM.js} +6 -6
  80. package/dist/{chunk-EH46DHBU.js → chunk-ENAPZQA6.js} +2 -2
  81. package/dist/{chunk-LLG5VNK7.js → chunk-F2UAAI6B.js} +2 -2
  82. package/dist/{chunk-YZNTAOPZ.js → chunk-FKNNWH7P.js} +2 -2
  83. package/dist/{chunk-AAANTXCQ.js → chunk-FZVZYU5C.js} +2 -2
  84. package/dist/{chunk-ON77FQXH.js → chunk-G6GMZJQ4.js} +2 -2
  85. package/dist/{chunk-OL7A7NKH.js → chunk-GNP4BV4Z.js} +2 -2
  86. package/dist/{chunk-GDYLZ6FR.js → chunk-HJ3UTGIW.js} +3 -3
  87. package/dist/{chunk-CCL2OXFO.js → chunk-HSHLDSPX.js} +3 -3
  88. package/dist/{chunk-R4BR62UO.js → chunk-HWMGQDZI.js} +2 -2
  89. package/dist/{chunk-BPIAXMGC.js → chunk-IIUEHIQ2.js} +2 -2
  90. package/dist/{chunk-RTJJPW3C.js → chunk-ILMB3X4X.js} +5 -5
  91. package/dist/{chunk-RFT4OPYI.js → chunk-IPN67KVR.js} +2 -2
  92. package/dist/chunk-JCL7RO2G.js +674 -0
  93. package/dist/chunk-JCL7RO2G.js.map +1 -0
  94. package/dist/{chunk-IEW6NDHX.js → chunk-JGSWWD33.js} +9 -9
  95. package/dist/{chunk-A3UFV4K3.js → chunk-JIYJIH5N.js} +2 -2
  96. package/dist/{chunk-4G2A7MH3.js → chunk-JKUVPVKR.js} +3 -3
  97. package/dist/{chunk-YJHOVA42.js → chunk-JL5FHZ7O.js} +30 -6
  98. package/dist/chunk-JL5FHZ7O.js.map +1 -0
  99. package/dist/{chunk-VCLNU6MY.js → chunk-L2HSSVVD.js} +2 -2
  100. package/dist/{chunk-U2A56LLF.js → chunk-L334PSLW.js} +8 -8
  101. package/dist/{chunk-HQUYENKK.js → chunk-LIUI46BX.js} +3 -3
  102. package/dist/{chunk-ERMT5WQM.js → chunk-MKE5DP3S.js} +2 -2
  103. package/dist/{chunk-4OFXLQJD.js → chunk-MPDLLLOG.js} +8 -3
  104. package/dist/chunk-MPDLLLOG.js.map +1 -0
  105. package/dist/{chunk-6BO27AWQ.js → chunk-MPJ7VHHA.js} +2 -2
  106. package/dist/{chunk-WXBVGKS6.js → chunk-N7RAABFM.js} +182 -421
  107. package/dist/chunk-N7RAABFM.js.map +1 -0
  108. package/dist/{chunk-KMJDH4KX.js → chunk-NSUGAIIB.js} +16 -16
  109. package/dist/{chunk-7NT3FKAF.js → chunk-NXHBQC2O.js} +2 -2
  110. package/dist/{chunk-JEX2JL3U.js → chunk-OH55F76C.js} +2 -2
  111. package/dist/{chunk-37VTMUAL.js → chunk-OUJ4DVR5.js} +2 -2
  112. package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
  113. package/dist/{chunk-2IVK5IDY.js → chunk-P5F7ISLV.js} +2 -2
  114. package/dist/{chunk-PM4PKC3Y.js → chunk-PNVQNAJM.js} +3 -3
  115. package/dist/{chunk-FXWX7VD3.js → chunk-PRYDNBCO.js} +12 -12
  116. package/dist/{chunk-YDDLSGYE.js → chunk-PUTH5REB.js} +2 -2
  117. package/dist/{chunk-GFAEKSFR.js → chunk-QBK3IM6W.js} +5 -5
  118. package/dist/{chunk-KRAMCBIW.js → chunk-QKXPOLQD.js} +4 -4
  119. package/dist/{chunk-YDT3OEYF.js → chunk-R4ZHF4K2.js} +2 -2
  120. package/dist/{chunk-ISNPYOXR.js → chunk-RBUR6USI.js} +5 -5
  121. package/dist/{chunk-WZYAXOGO.js → chunk-RZSHIJYY.js} +2 -2
  122. package/dist/{chunk-TYSD7UQO.js → chunk-SVTIWBSA.js} +2 -2
  123. package/dist/{chunk-AMKIIRLL.js → chunk-TBFAQHQZ.js} +2 -2
  124. package/dist/{chunk-ZE5N4JSY.js → chunk-TKCJI7WA.js} +2 -2
  125. package/dist/{chunk-RYB553SS.js → chunk-TLOAAOT3.js} +2 -2
  126. package/dist/{chunk-RKRX4C4H.js → chunk-TPKB7T6Z.js} +2 -2
  127. package/dist/{chunk-JZCBMKR5.js → chunk-TUCEP2LS.js} +5 -5
  128. package/dist/{chunk-KZMRMKC7.js → chunk-U7MIMS2Y.js} +11 -1
  129. package/dist/chunk-U7MIMS2Y.js.map +1 -0
  130. package/dist/{chunk-OMWQO7H6.js → chunk-UEDC2VGP.js} +2 -2
  131. package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
  132. package/dist/{chunk-JY2BGCYN.js → chunk-VCYH2XUY.js} +2 -2
  133. package/dist/{chunk-NGH74LDV.js → chunk-WD2QH3JM.js} +9 -9
  134. package/dist/{chunk-G6A3SGCE.js → chunk-WVEEVYMH.js} +8 -25
  135. package/dist/chunk-WVEEVYMH.js.map +1 -0
  136. package/dist/{chunk-UGTYADB4.js → chunk-WWSJQ7MP.js} +3 -3
  137. package/dist/{chunk-UQBOPCDK.js → chunk-X4PAATLA.js} +2 -2
  138. package/dist/{chunk-KBOQQEVC.js → chunk-XAFSZ4DP.js} +2 -2
  139. package/dist/{chunk-2S6JADBB.js → chunk-XICJL56Z.js} +2 -2
  140. package/dist/{chunk-Y5KESB7T.js → chunk-XJDSZFBZ.js} +45 -45
  141. package/dist/{chunk-24SIB3EW.js → chunk-XWE3EOWX.js} +2 -2
  142. package/dist/{chunk-Y77FXULH.js → chunk-XWXBXBOX.js} +2 -2
  143. package/dist/{chunk-VKQI47DJ.js → chunk-Y7427SL7.js} +4 -4
  144. package/dist/{chunk-TEH5MDX5.js → chunk-YH7HJNWV.js} +22 -22
  145. package/dist/chunk-YHTG64XV.js +117 -0
  146. package/dist/chunk-YHTG64XV.js.map +1 -0
  147. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  148. package/dist/{chunk-2M36PR7R.js → chunk-Z2T5BPOZ.js} +2 -2
  149. package/dist/cli.js +100 -97
  150. package/dist/coding/export-okf-codegraph.js +15 -11
  151. package/dist/coding/export-okf-codegraph.js.map +1 -1
  152. package/dist/coding/pre-action-gate.js +2 -2
  153. package/dist/compounding/engine.js +17 -13
  154. package/dist/config.js +24 -20
  155. package/dist/connectors/codex-materialize-runner.js +16 -12
  156. package/dist/connectors/index.js +16 -12
  157. package/dist/convergence-refresh.js +18 -14
  158. package/dist/corpus-scan-worker-host.d.ts +109 -0
  159. package/dist/corpus-scan-worker-host.d.ts.map +1 -0
  160. package/dist/corpus-scan-worker-host.js +15 -0
  161. package/dist/corpus-scan-worker.entry.d.ts +21 -0
  162. package/dist/corpus-scan-worker.entry.d.ts.map +1 -0
  163. package/dist/corpus-scan-worker.entry.js +60 -0
  164. package/dist/corpus-scan-worker.entry.js.map +1 -0
  165. package/dist/corpus-scan-worker.entry.mjs +176 -0
  166. package/dist/corpus-scan.d.ts +71 -0
  167. package/dist/corpus-scan.d.ts.map +1 -0
  168. package/dist/corpus-scan.js +16 -0
  169. package/dist/corpus-watermark.d.ts.map +1 -1
  170. package/dist/corpus-watermark.js +18 -14
  171. package/dist/dashboard-runtime.js +2 -2
  172. package/dist/deep-recall-http-glue.js +10 -10
  173. package/dist/embedding-fallback.js +2 -2
  174. package/dist/{entity-canonical-id-migration-F3JVG6K6.js → entity-canonical-id-migration-CUDCKWPF.js} +4 -2
  175. package/dist/entity-canonical-id-migration-CUDCKWPF.js.map +1 -0
  176. package/dist/entity-retrieval.js +18 -14
  177. package/dist/event-order-recall.js +3 -3
  178. package/dist/external-wiki-access.js +54 -51
  179. package/dist/extraction.js +21 -17
  180. package/dist/{graph-edge-decay-IU75NV42.js → graph-edge-decay-2BZTY2IM.js} +5 -5
  181. package/dist/graph-edge-decay-2BZTY2IM.js.map +1 -0
  182. package/dist/graph-jsonl.js +3 -3
  183. package/dist/graph-snapshot.js +3 -3
  184. package/dist/graph.js +2 -2
  185. package/dist/harmonic-retrieval.js +16 -12
  186. package/dist/index.d.ts +1 -1
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +174 -169
  189. package/dist/lcm/engine.js +2 -2
  190. package/dist/lcm/index.js +5 -5
  191. package/dist/location/index.js +18 -14
  192. package/dist/maintenance/memory-governance.js +16 -12
  193. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +16 -12
  194. package/dist/maintenance/rebuild-memory-projection-runner.js +18 -14
  195. package/dist/maintenance/rebuild-memory-projection.js +17 -13
  196. package/dist/memory-browse-operations.js +54 -51
  197. package/dist/memory-browse.js +5 -5
  198. package/dist/namespaces/migrate.js +17 -13
  199. package/dist/namespaces/search.js +7 -7
  200. package/dist/namespaces/storage.js +16 -12
  201. package/dist/offline-sync-changeset-generations.js +4 -4
  202. package/dist/offline-sync-embedding-generation.js +3 -3
  203. package/dist/offline-sync-snapshot-stream.js +7 -7
  204. package/dist/offline-sync.js +6 -6
  205. package/dist/operator-doctor-corpus.js +19 -15
  206. package/dist/operator-toolkit.js +35 -31
  207. package/dist/orchestration/buffer-drain-gate.d.ts +21 -0
  208. package/dist/orchestration/buffer-drain-gate.d.ts.map +1 -0
  209. package/dist/orchestration/buffer-drain-runner.d.ts +79 -0
  210. package/dist/orchestration/buffer-drain-runner.d.ts.map +1 -0
  211. package/dist/orchestration/buffer-drain-runner.js +780 -0
  212. package/dist/orchestration/buffer-drain-runner.js.map +1 -0
  213. package/dist/orchestration/buffer-swap.d.ts +12 -0
  214. package/dist/orchestration/buffer-swap.d.ts.map +1 -0
  215. package/dist/orchestration/maintenance.js +26 -22
  216. package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
  217. package/dist/orchestrator.d.ts +4 -1
  218. package/dist/orchestrator.d.ts.map +1 -1
  219. package/dist/orchestrator.js +143 -140
  220. package/dist/qmd.js +4 -4
  221. package/dist/recall-navigation-operations.js +54 -51
  222. package/dist/recall-navigation.js +53 -50
  223. package/dist/recall-state-view-admission.js +5 -5
  224. package/dist/recall-why-service.js +5 -5
  225. package/dist/resume-bundles.js +25 -21
  226. package/dist/search/factory.js +6 -6
  227. package/dist/search/index.js +12 -12
  228. package/dist/semantic-consolidation.js +17 -13
  229. package/dist/semantic-rule-promotion.js +16 -12
  230. package/dist/semantic-rule-verifier.js +16 -12
  231. package/dist/source-agent-qualifier.js +19 -15
  232. package/dist/standup/build.js +16 -12
  233. package/dist/storage/buffer-drain-claims.d.ts +159 -0
  234. package/dist/storage/buffer-drain-claims.d.ts.map +1 -0
  235. package/dist/storage/buffer-drain-claims.js +18 -0
  236. package/dist/storage/buffer-drain-claims.js.map +1 -0
  237. package/dist/storage/buffer-session-files.d.ts +14 -2
  238. package/dist/storage/buffer-session-files.d.ts.map +1 -1
  239. package/dist/storage/buffer-session-files.js +22 -0
  240. package/dist/storage/buffer-session-files.js.map +1 -0
  241. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  242. package/dist/storage/memory-read-store.d.ts +5 -9
  243. package/dist/storage/memory-read-store.d.ts.map +1 -1
  244. package/dist/storage.d.ts +6 -1
  245. package/dist/storage.d.ts.map +1 -1
  246. package/dist/storage.js +17 -13
  247. package/dist/support-passport/index.js +56 -53
  248. package/dist/transfer/backup.js +2 -2
  249. package/dist/transfer/capsule-export.js +2 -2
  250. package/dist/transfer/capsule-import.js +2 -2
  251. package/dist/transfer/export-okf.js +16 -12
  252. package/dist/verified-recall.js +16 -12
  253. package/dist/who-knows-cli.js +17 -13
  254. package/dist/who-knows.js +16 -12
  255. package/package.json +32 -2
  256. package/scripts/build-with-heap.mjs +8 -0
  257. package/src/buffer-drain-handover.test.ts +307 -0
  258. package/src/buffer-persistence.ts +27 -5
  259. package/src/buffer-turn-helpers.ts +16 -0
  260. package/src/buffer.ts +32 -2
  261. package/src/corpus-scan-worker-host.ts +314 -0
  262. package/src/corpus-scan-worker.entry.mjs +176 -0
  263. package/src/corpus-scan-worker.entry.ts +95 -0
  264. package/src/corpus-scan.ts +215 -0
  265. package/src/corpus-watermark.ts +28 -12
  266. package/src/index.ts +1 -1
  267. package/src/orchestration/buffer-drain-gate.test.ts +40 -0
  268. package/src/orchestration/buffer-drain-gate.ts +38 -0
  269. package/src/orchestration/buffer-drain-runner.ts +312 -0
  270. package/src/orchestration/buffer-swap.ts +27 -0
  271. package/src/orchestration/turn-ingestion.ts +2 -0
  272. package/src/orchestrator.ts +9 -6
  273. package/src/storage/buffer-drain-claims.test.ts +448 -0
  274. package/src/storage/buffer-drain-claims.ts +593 -0
  275. package/src/storage/buffer-session-files.ts +50 -3
  276. package/src/storage/entity-canonical-id-migration.ts +4 -26
  277. package/src/storage/memory-read-store.ts +17 -99
  278. package/src/storage.ts +8 -11
  279. package/src/testing/subjects/extraction-lifecycle.test.ts +34 -0
  280. package/dist/chunk-3E3Z6UA3.js.map +0 -1
  281. package/dist/chunk-4OFXLQJD.js.map +0 -1
  282. package/dist/chunk-5U2BBF7E.js.map +0 -1
  283. package/dist/chunk-G6A3SGCE.js.map +0 -1
  284. package/dist/chunk-KZMRMKC7.js.map +0 -1
  285. package/dist/chunk-WXBVGKS6.js.map +0 -1
  286. package/dist/chunk-YJHOVA42.js.map +0 -1
  287. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  288. /package/dist/{chunk-ZAZZOQAQ.js.map → chunk-23OEPU3K.js.map} +0 -0
  289. /package/dist/{chunk-XDKEHZUC.js.map → chunk-264B57GV.js.map} +0 -0
  290. /package/dist/{chunk-NRGQ5HJO.js.map → chunk-4P4VLPGB.js.map} +0 -0
  291. /package/dist/{chunk-GIRWNTMV.js.map → chunk-4PG5R6BJ.js.map} +0 -0
  292. /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
  293. /package/dist/{chunk-RG3I2663.js.map → chunk-64JLBFCQ.js.map} +0 -0
  294. /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
  295. /package/dist/{chunk-WASVDS6G.js.map → chunk-6HTEPYOI.js.map} +0 -0
  296. /package/dist/{chunk-6AEKSOWV.js.map → chunk-6I6DFULH.js.map} +0 -0
  297. /package/dist/{chunk-DJR37Q37.js.map → chunk-6T4CMKNP.js.map} +0 -0
  298. /package/dist/{chunk-RHJ5VGB3.js.map → chunk-73A2DDDR.js.map} +0 -0
  299. /package/dist/{chunk-4B73TQQV.js.map → chunk-7AKPLEJV.js.map} +0 -0
  300. /package/dist/{chunk-UHH67NLU.js.map → chunk-7OKYO2UC.js.map} +0 -0
  301. /package/dist/{chunk-KAL5SXPP.js.map → chunk-7ULSP7AU.js.map} +0 -0
  302. /package/dist/{chunk-USNU3BEQ.js.map → chunk-A4FZLM6Q.js.map} +0 -0
  303. /package/dist/{chunk-VV73XT3A.js.map → chunk-BJLCV2P3.js.map} +0 -0
  304. /package/dist/{chunk-KQAFEZQX.js.map → chunk-BUKK5SWA.js.map} +0 -0
  305. /package/dist/{chunk-DJFULNXK.js.map → chunk-C2AYUXEF.js.map} +0 -0
  306. /package/dist/{chunk-QY24FSXT.js.map → chunk-D3BYJSHX.js.map} +0 -0
  307. /package/dist/{chunk-JZRQY7ZQ.js.map → chunk-D4WR56FR.js.map} +0 -0
  308. /package/dist/{chunk-FB4JQEFS.js.map → chunk-DP22K7IC.js.map} +0 -0
  309. /package/dist/{chunk-EJFOGYF3.js.map → chunk-DTQJ7BRN.js.map} +0 -0
  310. /package/dist/{chunk-MLUPSZFK.js.map → chunk-DZL5PBEJ.js.map} +0 -0
  311. /package/dist/{chunk-JD5F5MYN.js.map → chunk-EGCC5OJE.js.map} +0 -0
  312. /package/dist/{chunk-IQSRVR6Z.js.map → chunk-EJ4RS7I7.js.map} +0 -0
  313. /package/dist/{chunk-WBN66HPI.js.map → chunk-ELHJK7LM.js.map} +0 -0
  314. /package/dist/{chunk-EH46DHBU.js.map → chunk-ENAPZQA6.js.map} +0 -0
  315. /package/dist/{chunk-LLG5VNK7.js.map → chunk-F2UAAI6B.js.map} +0 -0
  316. /package/dist/{chunk-YZNTAOPZ.js.map → chunk-FKNNWH7P.js.map} +0 -0
  317. /package/dist/{chunk-AAANTXCQ.js.map → chunk-FZVZYU5C.js.map} +0 -0
  318. /package/dist/{chunk-ON77FQXH.js.map → chunk-G6GMZJQ4.js.map} +0 -0
  319. /package/dist/{chunk-OL7A7NKH.js.map → chunk-GNP4BV4Z.js.map} +0 -0
  320. /package/dist/{chunk-GDYLZ6FR.js.map → chunk-HJ3UTGIW.js.map} +0 -0
  321. /package/dist/{chunk-CCL2OXFO.js.map → chunk-HSHLDSPX.js.map} +0 -0
  322. /package/dist/{chunk-R4BR62UO.js.map → chunk-HWMGQDZI.js.map} +0 -0
  323. /package/dist/{chunk-BPIAXMGC.js.map → chunk-IIUEHIQ2.js.map} +0 -0
  324. /package/dist/{chunk-RTJJPW3C.js.map → chunk-ILMB3X4X.js.map} +0 -0
  325. /package/dist/{chunk-RFT4OPYI.js.map → chunk-IPN67KVR.js.map} +0 -0
  326. /package/dist/{chunk-IEW6NDHX.js.map → chunk-JGSWWD33.js.map} +0 -0
  327. /package/dist/{chunk-A3UFV4K3.js.map → chunk-JIYJIH5N.js.map} +0 -0
  328. /package/dist/{chunk-4G2A7MH3.js.map → chunk-JKUVPVKR.js.map} +0 -0
  329. /package/dist/{chunk-VCLNU6MY.js.map → chunk-L2HSSVVD.js.map} +0 -0
  330. /package/dist/{chunk-U2A56LLF.js.map → chunk-L334PSLW.js.map} +0 -0
  331. /package/dist/{chunk-HQUYENKK.js.map → chunk-LIUI46BX.js.map} +0 -0
  332. /package/dist/{chunk-ERMT5WQM.js.map → chunk-MKE5DP3S.js.map} +0 -0
  333. /package/dist/{chunk-6BO27AWQ.js.map → chunk-MPJ7VHHA.js.map} +0 -0
  334. /package/dist/{chunk-KMJDH4KX.js.map → chunk-NSUGAIIB.js.map} +0 -0
  335. /package/dist/{chunk-7NT3FKAF.js.map → chunk-NXHBQC2O.js.map} +0 -0
  336. /package/dist/{chunk-JEX2JL3U.js.map → chunk-OH55F76C.js.map} +0 -0
  337. /package/dist/{chunk-37VTMUAL.js.map → chunk-OUJ4DVR5.js.map} +0 -0
  338. /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
  339. /package/dist/{chunk-2IVK5IDY.js.map → chunk-P5F7ISLV.js.map} +0 -0
  340. /package/dist/{chunk-PM4PKC3Y.js.map → chunk-PNVQNAJM.js.map} +0 -0
  341. /package/dist/{chunk-FXWX7VD3.js.map → chunk-PRYDNBCO.js.map} +0 -0
  342. /package/dist/{chunk-YDDLSGYE.js.map → chunk-PUTH5REB.js.map} +0 -0
  343. /package/dist/{chunk-GFAEKSFR.js.map → chunk-QBK3IM6W.js.map} +0 -0
  344. /package/dist/{chunk-KRAMCBIW.js.map → chunk-QKXPOLQD.js.map} +0 -0
  345. /package/dist/{chunk-YDT3OEYF.js.map → chunk-R4ZHF4K2.js.map} +0 -0
  346. /package/dist/{chunk-ISNPYOXR.js.map → chunk-RBUR6USI.js.map} +0 -0
  347. /package/dist/{chunk-WZYAXOGO.js.map → chunk-RZSHIJYY.js.map} +0 -0
  348. /package/dist/{chunk-TYSD7UQO.js.map → chunk-SVTIWBSA.js.map} +0 -0
  349. /package/dist/{chunk-AMKIIRLL.js.map → chunk-TBFAQHQZ.js.map} +0 -0
  350. /package/dist/{chunk-ZE5N4JSY.js.map → chunk-TKCJI7WA.js.map} +0 -0
  351. /package/dist/{chunk-RYB553SS.js.map → chunk-TLOAAOT3.js.map} +0 -0
  352. /package/dist/{chunk-RKRX4C4H.js.map → chunk-TPKB7T6Z.js.map} +0 -0
  353. /package/dist/{chunk-JZCBMKR5.js.map → chunk-TUCEP2LS.js.map} +0 -0
  354. /package/dist/{chunk-OMWQO7H6.js.map → chunk-UEDC2VGP.js.map} +0 -0
  355. /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
  356. /package/dist/{chunk-JY2BGCYN.js.map → chunk-VCYH2XUY.js.map} +0 -0
  357. /package/dist/{chunk-NGH74LDV.js.map → chunk-WD2QH3JM.js.map} +0 -0
  358. /package/dist/{chunk-UGTYADB4.js.map → chunk-WWSJQ7MP.js.map} +0 -0
  359. /package/dist/{chunk-UQBOPCDK.js.map → chunk-X4PAATLA.js.map} +0 -0
  360. /package/dist/{chunk-KBOQQEVC.js.map → chunk-XAFSZ4DP.js.map} +0 -0
  361. /package/dist/{chunk-2S6JADBB.js.map → chunk-XICJL56Z.js.map} +0 -0
  362. /package/dist/{chunk-Y5KESB7T.js.map → chunk-XJDSZFBZ.js.map} +0 -0
  363. /package/dist/{chunk-24SIB3EW.js.map → chunk-XWE3EOWX.js.map} +0 -0
  364. /package/dist/{chunk-Y77FXULH.js.map → chunk-XWXBXBOX.js.map} +0 -0
  365. /package/dist/{chunk-VKQI47DJ.js.map → chunk-Y7427SL7.js.map} +0 -0
  366. /package/dist/{chunk-TEH5MDX5.js.map → chunk-YH7HJNWV.js.map} +0 -0
  367. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  368. /package/dist/{chunk-2M36PR7R.js.map → chunk-Z2T5BPOZ.js.map} +0 -0
  369. /package/dist/{entity-canonical-id-migration-F3JVG6K6.js.map → corpus-scan-worker-host.js.map} +0 -0
  370. /package/dist/{graph-edge-decay-IU75NV42.js.map → corpus-scan.js.map} +0 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Corpus maintenance scans (the pure, read-only filesystem work the daemon
3
+ * runs periodically).
4
+ *
5
+ * Three scans live here, all of them corpus-sized:
6
+ * - the recall-corpus path walk (hot + cold tiers);
7
+ * - the entity-entry fingerprint the canonical-id migration reads on every
8
+ * entity unlock;
9
+ * - the watermark's freshness stat over the newest hot partition.
10
+ *
11
+ * They are plain functions over plain inputs so the corpus-scan worker can run
12
+ * them off the main event loop: `src/corpus-scan-worker.entry.ts` is bundled
13
+ * into a plain-JavaScript worker entry (`src/corpus-scan-worker.entry.mjs`,
14
+ * generated — see scripts/sync-corpus-scan-worker.mjs) and the host falls back
15
+ * to these functions inline when a worker cannot start. One implementation,
16
+ * two execution sites, identical results.
17
+ */
18
+
19
+ import type { Dirent, Stats } from "node:fs";
20
+ import { createHash } from "node:crypto";
21
+ import { lstat, readdir, realpath, stat } from "node:fs/promises";
22
+ import path from "node:path";
23
+ import { isErrnoCode } from "./utils/errno.js";
24
+ import { isMacOsReplicationJunkBasename } from "./utils/macos-replication-junk.js";
25
+
26
+ /** An errno-carrying filesystem failure. */
27
+ export type ErrnoFailure = NodeJS.ErrnoException;
28
+
29
+ /**
30
+ * A backend READ failure worth propagating from a strict (census) scan: an
31
+ * errno-coded fs error that is NOT `ENOENT`. `ENOENT` (an absent dir) and
32
+ * code-less rejections are expected and skipped; `EACCES`/`EIO`/… mean the
33
+ * corpus is unreadable and a divergence census must fail loud rather than
34
+ * silently publish a partial count (issue #2156 round-5). Non-strict (recall)
35
+ * callers ignore this and degrade to a best-effort partial scan.
36
+ */
37
+ export function isPropagatableReadError(error: ErrnoFailure): boolean {
38
+ return error.code !== undefined && error.code !== "ENOENT";
39
+ }
40
+
41
+ export interface CorpusScanWalkOptions {
42
+ /** Memory root the walk is contained in. */
43
+ baseDir: string;
44
+ /** Directories to walk (category roots, cold root, archive root). */
45
+ startDirs: readonly string[];
46
+ /** Strict mode: backend read failures propagate instead of being skipped. */
47
+ propagateReadErrors?: boolean;
48
+ /**
49
+ * Cancellation check at every directory/entry boundary. The inline reader
50
+ * passes the corpus-read abort check; the worker passes its cancel flag.
51
+ */
52
+ checkCancelled?(): void;
53
+ }
54
+
55
+ /**
56
+ * Recursively collect `*.md` paths under `startDirs`. Paths only — no
57
+ * frontmatter parse. Never throws for a missing root (an empty result), and
58
+ * throws in strict mode when a backend read failure makes the corpus
59
+ * unreadable.
60
+ *
61
+ * Containment is established once, not per file: the memory root is resolved
62
+ * with a single `realpath`, every directory the walk enters is `lstat`ed (a
63
+ * symlinked or non-directory entry is never followed), and the entry TYPE
64
+ * comes from `readdir(withFileTypes)` — so a symlinked entry, file or
65
+ * directory, is skipped without a per-entry `realpath`. Reads refuse
66
+ * symlinked files at open time with `O_NOFOLLOW`, so a path swapped to a
67
+ * symlink mid-scan is refused rather than followed.
68
+ */
69
+ export async function collectContainedMarkdownPaths(options: CorpusScanWalkOptions): Promise<string[]> {
70
+ const { baseDir, startDirs, propagateReadErrors = false, checkCancelled } = options;
71
+ const filePaths: string[] = [];
72
+
73
+ // Resolve the memory root once: a missing root is an empty corpus and an
74
+ // unreadable root is a backend failure the strict census must surface.
75
+ try {
76
+ await realpath(baseDir);
77
+ } catch (error) {
78
+ // SAFETY: node:fs/promises rejects with an Error; the errno `code` is
79
+ // optional on that type, so this adds no unchecked claim.
80
+ const failure = error as ErrnoFailure;
81
+ // ENOENT: a not-yet-created root ⇒ empty. Any other errno is a backend
82
+ // read failure — propagate for strict census callers (never publish an
83
+ // unreadable corpus as empty); non-strict (recall) callers degrade.
84
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
85
+ return filePaths;
86
+ }
87
+
88
+ const collectPaths = async (dir: string): Promise<void> => {
89
+ checkCancelled?.();
90
+ // Directory-level guard, isolated from per-entry handling: skip symlinked
91
+ // or non-directory category dirs. A failure here means the whole subtree
92
+ // does not exist or escaped the store — fail closed by skipping it.
93
+ let dirStat: Stats;
94
+ try {
95
+ dirStat = await lstat(dir);
96
+ } catch (error) {
97
+ // SAFETY: node:fs/promises rejects with an Error; `code` is optional.
98
+ const failure = error as ErrnoFailure;
99
+ // ENOENT (absent category dir) is expected; a backend read error
100
+ // (EACCES/EIO/…) propagates in strict census mode.
101
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
102
+ return;
103
+ }
104
+ if (dirStat.isSymbolicLink()) return; // never follow symlinks out of the store (both modes)
105
+ if (!dirStat.isDirectory()) {
106
+ // A category root that EXISTS but is not a directory (e.g. `facts/`
107
+ // replaced by a regular file) is a layout/backend failure: a strict
108
+ // census must not silently publish the remaining categories as healthy.
109
+ // Non-strict (recall) stays best-effort and skips it (issue #2156 round-10).
110
+ if (propagateReadErrors) {
111
+ throw new Error(`corpus scan: expected a directory but found a non-directory at ${dir}`);
112
+ }
113
+ return;
114
+ }
115
+ let entries: Dirent[];
116
+ try {
117
+ entries = await readdir(dir, { withFileTypes: true });
118
+ } catch (error) {
119
+ // SAFETY: node:fs/promises rejects with an Error; `code` is optional.
120
+ const failure = error as ErrnoFailure;
121
+ // A backend read error (EACCES …) propagates in strict census mode so a
122
+ // partial subtree is not silently counted. ENOENT (vanished mid-scan)
123
+ // and other non-propagatable failures skip the directory.
124
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
125
+ return;
126
+ }
127
+
128
+ const subdirs: string[] = [];
129
+ for (const entry of entries) {
130
+ // Outside the per-entry handling below, which deliberately swallows
131
+ // non-propagatable errors — a cancellation must never be swallowed with
132
+ // them (issue #2307).
133
+ checkCancelled?.();
134
+ // Never follow symlinked entries out of the store.
135
+ if (entry.isSymbolicLink()) continue;
136
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
137
+ const fullPath = path.join(dir, entry.name);
138
+ if (entry.isDirectory()) {
139
+ subdirs.push(fullPath);
140
+ } else if (entry.name.endsWith(".md")) {
141
+ filePaths.push(fullPath);
142
+ }
143
+ }
144
+ // Recurse into real subdirectories regardless of any single poisoned entry
145
+ // above, so valid nested in-store memories are never dropped.
146
+ for (const subdir of subdirs) {
147
+ await collectPaths(subdir);
148
+ }
149
+ };
150
+
151
+ for (const dir of startDirs) {
152
+ await collectPaths(dir);
153
+ }
154
+ // A signal that fired during the last directory read would otherwise return a
155
+ // truncated path list as if it were the whole corpus (issue #2307 review).
156
+ checkCancelled?.();
157
+ return filePaths;
158
+ }
159
+
160
+ /**
161
+ * Fingerprint of the entity entries a migration's completion verdict depends
162
+ * on: the sorted entry names plus each entry's identity and timestamps. Two
163
+ * runs over the same entries produce the same string, and an in-place edit of
164
+ * an entity file changes it.
165
+ */
166
+ export async function fingerprintEntityEntries(entitiesDir: string): Promise<string> {
167
+ let names: string[];
168
+ try {
169
+ names = (await readdir(entitiesDir))
170
+ .filter((name) => path.extname(name) === ".md" && !isMacOsReplicationJunkBasename(name))
171
+ .sort();
172
+ } catch (error) {
173
+ if (isErrnoCode(error, "ENOENT")) return "missing";
174
+ throw error;
175
+ }
176
+ const hash = createHash("sha256");
177
+ for (const name of names) {
178
+ hash.update(`${name.length}:${name}:`);
179
+ try {
180
+ const entry = await lstat(path.join(entitiesDir, name), { bigint: true });
181
+ hash.update(`${entry.dev}:${entry.ino}:${entry.size}:${entry.mtimeNs}:${entry.ctimeNs}`);
182
+ } catch (error) {
183
+ if (!isErrnoCode(error, "ENOENT")) throw error;
184
+ hash.update("missing");
185
+ }
186
+ hash.update("\n");
187
+ }
188
+ return hash.digest("hex");
189
+ }
190
+
191
+ /**
192
+ * Stat a batch of files and return their mtimes, `null` for files that
193
+ * vanished (ENOENT). A backend read failure (EACCES/EIO/…) throws with its
194
+ * errno code intact so the caller can omit an unreadable corpus instead of
195
+ * publishing a stale freshness value.
196
+ */
197
+ export async function statMtimes(paths: readonly string[]): Promise<Array<number | null>> {
198
+ const results: Array<number | null> = new Array(paths.length).fill(null);
199
+ // Fixed-size batches: an unbounded Promise.all submits one libuv operation
200
+ // per file at once, and the worker and main thread share that threadpool, so
201
+ // a large bulk import would delay every other filesystem operation.
202
+ const STAT_BATCH_SIZE = 256;
203
+ for (let start = 0; start < paths.length; start += STAT_BATCH_SIZE) {
204
+ await Promise.all(paths.slice(start, start + STAT_BATCH_SIZE).map(async (filePath, offset) => {
205
+ try {
206
+ const entry = await stat(filePath);
207
+ results[start + offset] = entry.mtimeMs;
208
+ } catch (error) {
209
+ if (isErrnoCode(error, "ENOENT")) return;
210
+ throw error;
211
+ }
212
+ }));
213
+ }
214
+ return results;
215
+ }
@@ -37,10 +37,11 @@
37
37
  */
38
38
 
39
39
  import { createHash } from "node:crypto";
40
- import { stat } from "node:fs/promises";
41
40
  import path from "node:path";
41
+ import { setImmediate as yieldToEventLoop } from "node:timers/promises";
42
42
  import { capabilityAllowsNamespace, type TokenCapabilities } from "./access-token-capabilities.js";
43
43
  import { listNamespaces } from "./namespaces/migrate.js";
44
+ import { corpusScanWorker } from "./corpus-scan-worker-host.js";
44
45
  import type { PluginConfig } from "./types.js";
45
46
 
46
47
  export interface CorpusWatermark {
@@ -67,6 +68,9 @@ export const UNPARTITIONED_BUCKET = "unpartitioned";
67
68
  /** Storage tier a memory file lives in. */
68
69
  export type CorpusTier = "hot" | "cold";
69
70
 
71
+ /** Paths parsed between event-loop yields while building a census. */
72
+ const CENSUS_YIELD_EVERY = 4_096;
73
+
70
74
  const DAY_PARTITION_RE = /^\d{4}-\d{2}-\d{2}$/;
71
75
  /** Cold-tier root segment (relative to a namespace base dir): `<baseDir>/cold/...`. */
72
76
  const COLD_TIER_DIR = "cold";
@@ -155,7 +159,17 @@ export async function computeCorpusWatermark(input: {
155
159
  const census = new Map<string, number>();
156
160
  let newestPartition: string | null = null;
157
161
  const parsedByPath: ParsedPath[] = [];
162
+ let sinceYield = 0;
158
163
  for (const filePath of paths) {
164
+ // Parsing one path is cheap, but a census covers the whole corpus (100k+
165
+ // paths): one uninterrupted pass holds the main thread for hundreds of
166
+ // milliseconds. Yield to the event loop every CENSUS_YIELD_EVERY paths so
167
+ // observe/recall interleave; the result is order-independent and identical.
168
+ if (sinceYield >= CENSUS_YIELD_EVERY) {
169
+ sinceYield = 0;
170
+ await yieldToEventLoop();
171
+ }
172
+ sinceYield += 1;
159
173
  const parsed = parsePartition(baseDir, filePath);
160
174
  parsedByPath.push(parsed);
161
175
  census.set(parsed.bucket, (census.get(parsed.bucket) ?? 0) + 1);
@@ -171,19 +185,21 @@ export async function computeCorpusWatermark(input: {
171
185
 
172
186
  let newestWriteAt: string | null = null;
173
187
  if (newestPartition !== null) {
174
- let maxMtimeMs = Number.NEGATIVE_INFINITY;
188
+ const newestPaths: string[] = [];
175
189
  for (let i = 0; i < paths.length; i += 1) {
176
190
  if (parsedByPath[i].tier !== "hot" || parsedByPath[i].date !== newestPartition) continue;
177
- try {
178
- const st = await stat(paths[i]);
179
- if (st.mtimeMs > maxMtimeMs) maxMtimeMs = st.mtimeMs;
180
- } catch (err) {
181
- // A file vanishing between scan and stat (ENOENT) is an expected race —
182
- // skip it. A backend read failure (EACCES/EIO/…) means the corpus is
183
- // unreadable: propagate so the namespace is omitted, not published with
184
- // a stale/null freshness (issue #2156 round-6).
185
- if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
186
- }
191
+ newestPaths.push(paths[i]);
192
+ }
193
+ // The freshness sweep is one stat per file in the newest hot partition; it
194
+ // runs in the corpus-scan worker so the periodic census does not spend
195
+ // main-thread time on a per-file syscall sweep. A file that vanished
196
+ // (ENOENT) reports null; a backend read failure (EACCES/EIO/…) propagates
197
+ // with its errno code so the namespace is omitted, not published with a
198
+ // stale/null freshness (issue #2156 round-6).
199
+ const mtimes = await corpusScanWorker.request({ kind: "stat-mtimes", paths: newestPaths });
200
+ let maxMtimeMs = Number.NEGATIVE_INFINITY;
201
+ for (const mtimeMs of mtimes) {
202
+ if (mtimeMs !== null && mtimeMs > maxMtimeMs) maxMtimeMs = mtimeMs;
187
203
  }
188
204
  if (maxMtimeMs > Number.NEGATIVE_INFINITY) {
189
205
  newestWriteAt = new Date(maxMtimeMs).toISOString();
package/src/index.ts CHANGED
@@ -346,7 +346,7 @@ export { MeilisearchBackend } from "./search/meilisearch-backend.js";
346
346
  // ---------------------------------------------------------------------------
347
347
 
348
348
  export { buildEntityRecallSection } from "./entity-retrieval.js";
349
- export { isNamespacePolicyCovered, resolvePrincipal } from "./namespaces/principal.js";
349
+ export { defaultNamespaceForPrincipal, isNamespacePolicyCovered, resolvePrincipal } from "./namespaces/principal.js";
350
350
  export {
351
351
  NamespaceCatalog,
352
352
  type NamespaceRecord,
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `skipClaimedSession` gate: a buffer without a claim registry never reports a
3
+ * claim (the legacy/test-double shape), and a claimed session settles as
4
+ * skipped without running an extraction.
5
+ */
6
+ import assert from "node:assert/strict";
7
+ import test from "node:test";
8
+ import { skipClaimedSession, type ClaimAwareBuffer } from "./buffer-drain-gate.js";
9
+ import type { ExtractionRunResult } from "./extraction-run.js";
10
+
11
+ test("a buffer without isSessionClaimed is never treated as claimed", () => {
12
+ const settled: ExtractionRunResult[] = [];
13
+ const buffer: ClaimAwareBuffer = {};
14
+ const result = skipClaimedSession(buffer, "sess-1", (r) => settled.push(r));
15
+ assert.equal(result, false);
16
+ assert.deepEqual(settled, []);
17
+ });
18
+
19
+ test("an unclaimed session with the method proceeds", () => {
20
+ const settled: ExtractionRunResult[] = [];
21
+ const result = skipClaimedSession({ isSessionClaimed: () => false }, "sess-1", (r) => settled.push(r));
22
+ assert.equal(result, false);
23
+ assert.deepEqual(settled, []);
24
+ });
25
+
26
+ test("a claimed session settles as skipped without extracting", () => {
27
+ const settled: ExtractionRunResult[] = [];
28
+ const result = skipClaimedSession({ isSessionClaimed: () => true }, "sess-1", (r) => settled.push(r));
29
+ assert.equal(result, true);
30
+ assert.equal(settled.length, 1);
31
+ assert.equal(settled[0].status, "skipped");
32
+ assert.equal(settled[0].reason, "claimed_by_buffer_drain");
33
+ });
34
+
35
+ test("a buffer-less deps bundle (older host or test double) is never claimed", () => {
36
+ const settled: ExtractionRunResult[] = [];
37
+ const result = skipClaimedSession(undefined, "sess-1", (r) => settled.push(r));
38
+ assert.equal(result, false);
39
+ assert.deepEqual(settled, []);
40
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Extraction gate for sessions claimed by `remnic buffer drain`.
3
+ *
4
+ * A claimed session's turns belong to the drain: they live in a durable
5
+ * claim file and are extracted out of process. The live buffer owner hands
6
+ * its copy of such a session into the claim instead of writing it back, so
7
+ * extracting it here as well would persist the same content twice.
8
+ */
9
+
10
+ import { log } from "../logger.js";
11
+ import type { ExtractionRunResult } from "./extraction-run.js";
12
+
13
+ /** The claim check a buffer owner exposes. Optional: buffers without a claim
14
+ * registry (older hosts, test doubles) simply never report a claim. */
15
+ export interface ClaimAwareBuffer {
16
+ isSessionClaimed?(key: string): boolean;
17
+ }
18
+
19
+ /**
20
+ * Settle the extraction as skipped when `bufferKey` is claimed by a drain.
21
+ * Returns true when the caller must stop (the window stays in the claim).
22
+ * A missing buffer (deps without one) is never claimed.
23
+ */
24
+ export function skipClaimedSession(
25
+ buffer: ClaimAwareBuffer | undefined,
26
+ bufferKey: string,
27
+ settle: (result: ExtractionRunResult) => void,
28
+ ): boolean {
29
+ if (!buffer?.isSessionClaimed?.(bufferKey)) return false;
30
+ log.debug(`extraction skip: session claimed by buffer drain (${bufferKey})`);
31
+ settle({
32
+ status: "skipped",
33
+ reason: "claimed_by_buffer_drain",
34
+ persistedCount: 0,
35
+ durableOutputCount: 0,
36
+ });
37
+ return true;
38
+ }