@remnic/core 10.0.3 → 10.0.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 (410) hide show
  1. package/dist/access-admin-ops-surface.js +62 -62
  2. package/dist/access-authorization-probe.js +63 -63
  3. package/dist/access-boundary.js +62 -62
  4. package/dist/access-cli.d.ts.map +1 -1
  5. package/dist/access-cli.js +146 -139
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-extraction-force-flush.js +62 -62
  8. package/dist/access-http-briefing.js +63 -63
  9. package/dist/access-http-query.js +64 -64
  10. package/dist/access-http.d.ts.map +1 -1
  11. package/dist/access-http.js +86 -85
  12. package/dist/access-identity-continuity-surface.js +62 -62
  13. package/dist/access-lcm-surface.js +62 -62
  14. package/dist/access-mcp-correction-tools.d.ts +10 -0
  15. package/dist/access-mcp-correction-tools.d.ts.map +1 -0
  16. package/dist/access-mcp-correction-tools.js +8 -0
  17. package/dist/access-mcp.d.ts.map +1 -1
  18. package/dist/access-mcp.js +76 -75
  19. package/dist/access-namespace-preflight.js +62 -62
  20. package/dist/access-observe-write-category.js +5 -5
  21. package/dist/access-observe-write-surface.js +62 -62
  22. package/dist/access-offline-manifest.js +8 -8
  23. package/dist/access-operations-batch.js +65 -65
  24. package/dist/access-operations.d.ts +1 -0
  25. package/dist/access-operations.d.ts.map +1 -1
  26. package/dist/access-operations.js +72 -72
  27. package/dist/access-recall-concurrency.js +62 -62
  28. package/dist/access-recall-diagnostics.js +2 -2
  29. package/dist/access-recall-response.js +62 -62
  30. package/dist/access-recall-surface.js +62 -62
  31. package/dist/access-service.d.ts.map +1 -1
  32. package/dist/access-service.js +62 -62
  33. package/dist/access-surface-catalog.js +64 -64
  34. package/dist/active-recall.js +31 -30
  35. package/dist/active-recall.js.map +1 -1
  36. package/dist/adapters/index.js +7 -7
  37. package/dist/adapters/registry.js +3 -3
  38. package/dist/{auto-sync-PAWBFQWL.js → auto-sync-FN7E3OTO.js} +6 -6
  39. package/dist/briefing.js +26 -26
  40. package/dist/buffer.js +8 -8
  41. package/dist/causal-consolidation.js +26 -26
  42. package/dist/{chunk-YQSWNFZE.js → chunk-2CP577K6.js} +2 -2
  43. package/dist/{chunk-6JIHC5AS.js → chunk-37HCPM56.js} +78 -67
  44. package/dist/chunk-37HCPM56.js.map +1 -0
  45. package/dist/{chunk-345MEMRU.js → chunk-3OUGSOJP.js} +2 -2
  46. package/dist/{chunk-CHI37EHP.js → chunk-4CWUZBPF.js} +8 -6
  47. package/dist/chunk-4CWUZBPF.js.map +1 -0
  48. package/dist/{chunk-G2STTRYB.js → chunk-4D2YH47Z.js} +2 -2
  49. package/dist/{chunk-IXYIW3MZ.js → chunk-4K2H4KTR.js} +5 -5
  50. package/dist/{chunk-UVVSOSHL.js → chunk-52CQKST6.js} +53 -53
  51. package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
  52. package/dist/{chunk-BLHPADUX.js → chunk-5BPXMAUP.js} +22 -78
  53. package/dist/chunk-5BPXMAUP.js.map +1 -0
  54. package/dist/{chunk-ZS7RK6H6.js → chunk-5BY3IA2U.js} +16 -53
  55. package/dist/chunk-5BY3IA2U.js.map +1 -0
  56. package/dist/{chunk-2QZFZNXO.js → chunk-5CQO6LVM.js} +2 -2
  57. package/dist/{chunk-NLDMTXWV.js → chunk-5LNPW7NE.js} +2 -2
  58. package/dist/{chunk-WHTMVTU4.js → chunk-5X4ZJESN.js} +2 -2
  59. package/dist/{chunk-WI37MWRZ.js → chunk-63UNVGZW.js} +5 -5
  60. package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
  61. package/dist/{chunk-CFCEJNOE.js → chunk-6KHF6PAB.js} +2 -2
  62. package/dist/{chunk-5GINB5LC.js → chunk-6MKLMEBE.js} +1 -1
  63. package/dist/{chunk-5GINB5LC.js.map → chunk-6MKLMEBE.js.map} +1 -1
  64. package/dist/{chunk-35A7GCHG.js → chunk-6T42L5FI.js} +2 -2
  65. package/dist/{chunk-JDOBIFBK.js → chunk-7CXL25AA.js} +2 -2
  66. package/dist/{chunk-YLBE6PLR.js → chunk-7IGMKQWK.js} +2 -2
  67. package/dist/{chunk-CSLK7BN6.js → chunk-7LYRFI5A.js} +2 -2
  68. package/dist/{chunk-IB63OVUB.js → chunk-AJ6ORARY.js} +6 -6
  69. package/dist/{chunk-CGOKNQDK.js → chunk-ANZXWOYD.js} +2 -2
  70. package/dist/{chunk-5QXMESS7.js → chunk-AXC7UTLM.js} +2 -2
  71. package/dist/{chunk-RFIJRZ4K.js → chunk-B657ZGDH.js} +2 -2
  72. package/dist/{chunk-AW4QUFQF.js → chunk-BTNNL7ZW.js} +3 -2
  73. package/dist/{chunk-AW4QUFQF.js.map → chunk-BTNNL7ZW.js.map} +1 -1
  74. package/dist/{chunk-MY7B3HYC.js → chunk-CLCMDKTB.js} +2 -2
  75. package/dist/{chunk-QPWUG2S3.js → chunk-CYEK6Z3P.js} +4 -4
  76. package/dist/{chunk-IHCYCE6D.js → chunk-DJMVSUPK.js} +4 -4
  77. package/dist/{chunk-HP4CU2ZA.js → chunk-DST7HRSG.js} +2 -2
  78. package/dist/{chunk-IIFFC3RL.js → chunk-EDR6CVWZ.js} +2 -2
  79. package/dist/{chunk-AUWMKDKL.js → chunk-EMVJU7WC.js} +2 -2
  80. package/dist/{chunk-O6AYMAPJ.js → chunk-ENNC3RZ6.js} +2 -2
  81. package/dist/{chunk-2JRB3Z5N.js → chunk-EP5WXE2G.js} +3 -3
  82. package/dist/{chunk-QLK3SL7Q.js → chunk-ETSJD5IV.js} +131 -12
  83. package/dist/chunk-ETSJD5IV.js.map +1 -0
  84. package/dist/chunk-EWMRFW3F.js +38 -0
  85. package/dist/chunk-EWMRFW3F.js.map +1 -0
  86. package/dist/{chunk-I2KEH2LS.js → chunk-FC6RCOIU.js} +2 -2
  87. package/dist/{chunk-OZVHLBH6.js → chunk-FLV7M7CT.js} +2 -2
  88. package/dist/{chunk-Q6GI7HEC.js → chunk-FRH2UC7Q.js} +2 -2
  89. package/dist/{chunk-3SL52JKD.js → chunk-FZVROZKC.js} +5 -5
  90. package/dist/{chunk-2EZB2DL5.js → chunk-GE6HETIF.js} +3 -3
  91. package/dist/{chunk-2DHJTJIY.js → chunk-GEGUBU3D.js} +2 -2
  92. package/dist/{chunk-6AA7XFMO.js → chunk-GF4H3B3R.js} +8 -8
  93. package/dist/{chunk-NGOZH7R5.js → chunk-GVUW5XK5.js} +311 -142
  94. package/dist/chunk-GVUW5XK5.js.map +1 -0
  95. package/dist/{chunk-ME2LMFHF.js → chunk-HPAOMYKM.js} +92 -92
  96. package/dist/{chunk-4NRZ7BRS.js → chunk-I25RINZK.js} +2 -2
  97. package/dist/{chunk-XG4XXI66.js → chunk-I25RQA65.js} +2 -2
  98. package/dist/chunk-I56MTWE7.js +80 -0
  99. package/dist/chunk-I56MTWE7.js.map +1 -0
  100. package/dist/{chunk-EJJMDLVB.js → chunk-IJ4FEGZR.js} +2 -2
  101. package/dist/{chunk-EUL3S3LE.js → chunk-J5WI4QRP.js} +4 -4
  102. package/dist/{chunk-LMMC55WM.js → chunk-JA54KIYD.js} +4 -4
  103. package/dist/{chunk-5FLFPTDK.js → chunk-JA72X46J.js} +2 -2
  104. package/dist/{chunk-6GU3TNJJ.js → chunk-JMF5Q4JY.js} +246 -49
  105. package/dist/chunk-JMF5Q4JY.js.map +1 -0
  106. package/dist/{chunk-IDSSDL4W.js → chunk-JXSYWTFK.js} +21 -4
  107. package/dist/{chunk-IDSSDL4W.js.map → chunk-JXSYWTFK.js.map} +1 -1
  108. package/dist/{chunk-NLYOOGZ7.js → chunk-KE5PWLI6.js} +3 -3
  109. package/dist/chunk-KIUVEMBI.js +49 -0
  110. package/dist/chunk-KIUVEMBI.js.map +1 -0
  111. package/dist/{chunk-4DDIWRT7.js → chunk-KQI2PKYP.js} +2 -2
  112. package/dist/{chunk-Y2ADLCB3.js → chunk-KSUOM3YU.js} +9 -9
  113. package/dist/{chunk-BTOHGPHC.js → chunk-KZEMFD6E.js} +3 -3
  114. package/dist/{chunk-NXVD46HT.js → chunk-L2VS27PZ.js} +4 -4
  115. package/dist/{chunk-MYYHACOW.js → chunk-L34W4W4I.js} +2 -2
  116. package/dist/{chunk-KRTIHXWC.js → chunk-L3PWXD73.js} +2 -2
  117. package/dist/{chunk-NQHSXHJP.js → chunk-L6GNS5GB.js} +2 -2
  118. package/dist/{chunk-44PBRUXB.js → chunk-M47Q6566.js} +2 -2
  119. package/dist/{chunk-E7FN5N5E.js → chunk-MQNOIH2C.js} +7 -7
  120. package/dist/{chunk-IDSZNHIP.js → chunk-MULNBSPP.js} +4 -4
  121. package/dist/{chunk-RKSGUMVL.js → chunk-NBQIFCJE.js} +2 -2
  122. package/dist/{chunk-I6WFBNA4.js → chunk-NHSVW7UT.js} +15 -15
  123. package/dist/{chunk-32HO62I4.js → chunk-OFEHITAZ.js} +2 -2
  124. package/dist/{chunk-PCO3P7WJ.js → chunk-OGVJXIHX.js} +2 -2
  125. package/dist/{chunk-RYN4AIRM.js → chunk-OZABSIOV.js} +4 -4
  126. package/dist/{chunk-HO7IQP7G.js → chunk-QMFKW4OU.js} +3 -3
  127. package/dist/{chunk-34G4U6HS.js → chunk-QRZMJ2WN.js} +2 -2
  128. package/dist/{chunk-RKDSELA3.js → chunk-QWWMS4AE.js} +1 -1
  129. package/dist/chunk-QWWMS4AE.js.map +1 -0
  130. package/dist/{chunk-GUD6FYQG.js → chunk-RSMIRLKM.js} +2 -2
  131. package/dist/{chunk-TNVZCLJU.js → chunk-S5TGRZWY.js} +2 -2
  132. package/dist/{chunk-O24EWFPQ.js → chunk-SNXBXYUE.js} +3 -3
  133. package/dist/{chunk-KW77LGDX.js → chunk-SUAX5JWY.js} +2 -2
  134. package/dist/{chunk-PNFWIB4X.js → chunk-SWRN6U7Q.js} +2 -2
  135. package/dist/{chunk-X6X4UASX.js → chunk-SZXPKUMN.js} +232 -83
  136. package/dist/chunk-SZXPKUMN.js.map +1 -0
  137. package/dist/{chunk-R4NGLTUS.js → chunk-TDMNADPI.js} +2 -2
  138. package/dist/{chunk-QCP75JGO.js → chunk-TFA6HPOA.js} +5 -5
  139. package/dist/{chunk-LI76ESJL.js → chunk-TZQOCQXB.js} +2 -2
  140. package/dist/{chunk-OV7EYM6M.js → chunk-U6OXJQEH.js} +12 -12
  141. package/dist/{chunk-OWHPA4JS.js → chunk-V32NHP2R.js} +2 -2
  142. package/dist/{chunk-JSUA4YFE.js → chunk-WG4TMZJ2.js} +2 -2
  143. package/dist/{chunk-DQTCGVFK.js → chunk-WHCD4Z3D.js} +2 -2
  144. package/dist/{chunk-GBA4N2SG.js → chunk-WRICYGYG.js} +27 -26
  145. package/dist/chunk-WRICYGYG.js.map +1 -0
  146. package/dist/{chunk-KATEWTQJ.js → chunk-X7J56GPG.js} +2 -2
  147. package/dist/{chunk-7KICGR5W.js → chunk-XPRAOTJY.js} +2 -2
  148. package/dist/{chunk-2NV7MMMM.js → chunk-XQSJXNWC.js} +2 -2
  149. package/dist/{chunk-22DYJLFN.js → chunk-XVC7JU2N.js} +39 -18
  150. package/dist/chunk-XVC7JU2N.js.map +1 -0
  151. package/dist/{chunk-RXT6UB25.js → chunk-YJAOYEWI.js} +2 -2
  152. package/dist/{chunk-L6DJJEFW.js → chunk-YJEUHGZZ.js} +2 -2
  153. package/dist/{chunk-AXFWMRKI.js → chunk-YQJCWR4R.js} +2 -2
  154. package/dist/cli.js +110 -108
  155. package/dist/coding/export-okf-codegraph.js +25 -25
  156. package/dist/compounding/engine.js +25 -25
  157. package/dist/config.d.ts.map +1 -1
  158. package/dist/config.js +31 -30
  159. package/dist/connectors/codex-materialize-runner.js +25 -25
  160. package/dist/connectors/index.js +25 -25
  161. package/dist/consolidation-provenance-check.js +2 -2
  162. package/dist/contradiction/index.js +7 -7
  163. package/dist/convergence-refresh.js +27 -27
  164. package/dist/conversation-index/backend.js +2 -2
  165. package/dist/corpus-read-cancellation.d.ts +7 -0
  166. package/dist/corpus-read-cancellation.d.ts.map +1 -1
  167. package/dist/corpus-read-cancellation.js +1 -1
  168. package/dist/corpus-watermark.js +27 -27
  169. package/dist/correction/correction-access-wiring.d.ts +6 -6
  170. package/dist/correction/correction-access-wiring.d.ts.map +1 -1
  171. package/dist/correction/correction-classify.d.ts +25 -0
  172. package/dist/correction/correction-classify.d.ts.map +1 -0
  173. package/dist/correction/correction-config.d.ts +11 -0
  174. package/dist/correction/correction-config.d.ts.map +1 -0
  175. package/dist/correction/correction-contract.d.ts +13 -1
  176. package/dist/correction/correction-contract.d.ts.map +1 -1
  177. package/dist/correction/correction-executor.d.ts +2 -0
  178. package/dist/correction/correction-executor.d.ts.map +1 -1
  179. package/dist/correction/correction-planner.d.ts +24 -3
  180. package/dist/correction/correction-planner.d.ts.map +1 -1
  181. package/dist/directory-sidecars.js +2 -2
  182. package/dist/entity-retrieval.js +25 -25
  183. package/dist/event-order-recall.js +2 -2
  184. package/dist/explicit-capture.js +2 -2
  185. package/dist/external-wiki-access.js +63 -63
  186. package/dist/extraction-span-materialize.js +2 -2
  187. package/dist/extraction.js +34 -34
  188. package/dist/harmonic-retrieval.js +25 -25
  189. package/dist/index.js +221 -218
  190. package/dist/lcm/index.js +3 -3
  191. package/dist/local-llm.d.ts.map +1 -1
  192. package/dist/local-llm.js +1 -1
  193. package/dist/location/index.js +28 -28
  194. package/dist/maintenance/archive-observations.js +2 -2
  195. package/dist/maintenance/atomic-file.d.ts +1 -1
  196. package/dist/maintenance/atomic-file.d.ts.map +1 -1
  197. package/dist/maintenance/atomic-file.js +1 -1
  198. package/dist/maintenance/memory-governance.js +25 -25
  199. package/dist/maintenance/migrate-observations.js +3 -3
  200. package/dist/maintenance/observation-ledger-utils.js +2 -2
  201. package/dist/maintenance/projection-rebuild-abort.d.ts +17 -0
  202. package/dist/maintenance/projection-rebuild-abort.d.ts.map +1 -0
  203. package/dist/maintenance/projection-timeline.d.ts +19 -0
  204. package/dist/maintenance/projection-timeline.d.ts.map +1 -0
  205. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -25
  206. package/dist/maintenance/rebuild-memory-projection-runner.d.ts +8 -0
  207. package/dist/maintenance/rebuild-memory-projection-runner.d.ts.map +1 -0
  208. package/dist/maintenance/rebuild-memory-projection-runner.js +113 -0
  209. package/dist/maintenance/rebuild-memory-projection-runner.js.map +1 -0
  210. package/dist/maintenance/rebuild-memory-projection.d.ts +8 -0
  211. package/dist/maintenance/rebuild-memory-projection.d.ts.map +1 -1
  212. package/dist/maintenance/rebuild-memory-projection.js +26 -26
  213. package/dist/maintenance/rebuild-observations.js +3 -3
  214. package/dist/memory-browse-operations.js +63 -63
  215. package/dist/memory-browse.js +7 -7
  216. package/dist/memory-subject.js +1 -1
  217. package/dist/namespaces/migrate.js +26 -26
  218. package/dist/namespaces/search.js +10 -10
  219. package/dist/namespaces/storage.js +25 -25
  220. package/dist/offline-sync-impression-drain.js +3 -3
  221. package/dist/operator-doctor-corpus.js +28 -28
  222. package/dist/operator-toolkit.js +41 -40
  223. package/dist/orchestration/full-corpus-heap-guard.d.ts +25 -0
  224. package/dist/orchestration/full-corpus-heap-guard.d.ts.map +1 -0
  225. package/dist/orchestration/maintenance.d.ts.map +1 -1
  226. package/dist/orchestration/maintenance.js +38 -36
  227. package/dist/orchestration/projection-rebuild-schedule.d.ts +40 -0
  228. package/dist/orchestration/projection-rebuild-schedule.d.ts.map +1 -1
  229. package/dist/orchestration/session-context.d.ts.map +1 -1
  230. package/dist/orchestrator.js +142 -139
  231. package/dist/projection-rebuild-config.d.ts +52 -0
  232. package/dist/projection-rebuild-config.d.ts.map +1 -0
  233. package/dist/projection-rebuild-config.js +14 -0
  234. package/dist/projection-rebuild-config.js.map +1 -0
  235. package/dist/qmd.js +4 -4
  236. package/dist/recall-explain-renderer.js +3 -3
  237. package/dist/recall-navigate-access.js +2 -2
  238. package/dist/recall-navigate-disclosure.js +2 -2
  239. package/dist/recall-navigate.js +2 -2
  240. package/dist/recall-navigation-operations.js +63 -63
  241. package/dist/recall-navigation.js +62 -62
  242. package/dist/recall-state-view-admission.js +7 -7
  243. package/dist/recall-state.js +2 -2
  244. package/dist/recall-why-service.js +8 -8
  245. package/dist/recall-xray-cli.js +4 -4
  246. package/dist/recall-xray-renderer.js +3 -3
  247. package/dist/recall-xray.js +2 -2
  248. package/dist/reconcile/manifest.js +3 -3
  249. package/dist/relevance.js +2 -2
  250. package/dist/{resolution-RSG4HZTL.js → resolution-TV3F7ZTH.js} +7 -7
  251. package/dist/resolution-TV3F7ZTH.js.map +1 -0
  252. package/dist/resume-bundles.js +32 -31
  253. package/dist/salvage-envelope.js +1 -1
  254. package/dist/search/factory.js +9 -9
  255. package/dist/search/index.js +17 -17
  256. package/dist/semantic-consolidation.js +31 -31
  257. package/dist/semantic-rule-promotion.js +25 -25
  258. package/dist/semantic-rule-verifier.js +25 -25
  259. package/dist/source-agent-qualifier.js +29 -29
  260. package/dist/standup/build.js +25 -25
  261. package/dist/storage/memory-lifecycle-ledger-access.d.ts +5 -3
  262. package/dist/storage/memory-lifecycle-ledger-access.d.ts.map +1 -1
  263. package/dist/storage/memory-read-store.d.ts +2 -2
  264. package/dist/storage/memory-read-store.d.ts.map +1 -1
  265. package/dist/storage.d.ts +4 -2
  266. package/dist/storage.d.ts.map +1 -1
  267. package/dist/storage.js +24 -24
  268. package/dist/subject-config.js +1 -1
  269. package/dist/summarizer.js +3 -3
  270. package/dist/support-passport/index.js +78 -78
  271. package/dist/transfer/export-okf.js +26 -26
  272. package/dist/types.d.ts +8 -40
  273. package/dist/types.d.ts.map +1 -1
  274. package/dist/types.js +1 -1
  275. package/dist/verified-recall.js +25 -25
  276. package/dist/who-knows-cli.js +26 -26
  277. package/dist/who-knows.js +25 -25
  278. package/dist/write-envelope.js +1 -1
  279. package/package.json +2 -2
  280. package/src/access-cli.ts +4 -0
  281. package/src/access-http.ts +1 -0
  282. package/src/access-mcp-correction-tools.ts +56 -0
  283. package/src/access-mcp.ts +4 -49
  284. package/src/access-operations.ts +3 -0
  285. package/src/access-service.ts +12 -21
  286. package/src/config.test.ts +35 -0
  287. package/src/config.ts +6 -65
  288. package/src/corpus-read-cancellation.ts +7 -0
  289. package/src/correction/correction-access-wiring.ts +56 -16
  290. package/src/correction/correction-classify.test.ts +185 -0
  291. package/src/correction/correction-classify.ts +157 -0
  292. package/src/correction/correction-config.ts +93 -0
  293. package/src/correction/correction-contract.ts +61 -14
  294. package/src/correction/correction-executor.test.ts +102 -2
  295. package/src/correction/correction-executor.ts +19 -1
  296. package/src/correction/correction-planner.test.ts +141 -0
  297. package/src/correction/correction-planner.ts +117 -11
  298. package/src/correction/correction-surfaces.test.ts +22 -1
  299. package/src/local-llm-qos.test.ts +36 -0
  300. package/src/local-llm.ts +20 -3
  301. package/src/maintenance/atomic-file.ts +2 -0
  302. package/src/maintenance/projection-rebuild-abort.ts +40 -0
  303. package/src/maintenance/projection-timeline.ts +209 -0
  304. package/src/maintenance/rebuild-memory-projection-runner.ts +94 -0
  305. package/src/maintenance/rebuild-memory-projection.memory.test.ts +159 -0
  306. package/src/maintenance/rebuild-memory-projection.retain-raw.test.ts +202 -0
  307. package/src/maintenance/rebuild-memory-projection.ts +63 -91
  308. package/src/orchestration/full-corpus-heap-guard.ts +38 -0
  309. package/src/orchestration/maintenance.test.ts +2 -2
  310. package/src/orchestration/maintenance.ts +2 -0
  311. package/src/orchestration/projection-rebuild-schedule.test.ts +498 -0
  312. package/src/orchestration/projection-rebuild-schedule.ts +280 -9
  313. package/src/orchestration/session-context.ts +0 -15
  314. package/src/projection-rebuild-config.ts +82 -0
  315. package/src/recall-handles-wiring.test.ts +24 -0
  316. package/src/storage/memory-lifecycle-ledger-access.ts +61 -33
  317. package/src/storage/memory-read-store.ts +10 -4
  318. package/src/storage.ts +45 -33
  319. package/src/types.ts +8 -41
  320. package/dist/chunk-22DYJLFN.js.map +0 -1
  321. package/dist/chunk-6GU3TNJJ.js.map +0 -1
  322. package/dist/chunk-6JIHC5AS.js.map +0 -1
  323. package/dist/chunk-BLHPADUX.js.map +0 -1
  324. package/dist/chunk-CHI37EHP.js.map +0 -1
  325. package/dist/chunk-GBA4N2SG.js.map +0 -1
  326. package/dist/chunk-NGOZH7R5.js.map +0 -1
  327. package/dist/chunk-QLK3SL7Q.js.map +0 -1
  328. package/dist/chunk-RKDSELA3.js.map +0 -1
  329. package/dist/chunk-X6X4UASX.js.map +0 -1
  330. package/dist/chunk-ZS7RK6H6.js.map +0 -1
  331. /package/dist/{resolution-RSG4HZTL.js.map → access-mcp-correction-tools.js.map} +0 -0
  332. /package/dist/{auto-sync-PAWBFQWL.js.map → auto-sync-FN7E3OTO.js.map} +0 -0
  333. /package/dist/{chunk-YQSWNFZE.js.map → chunk-2CP577K6.js.map} +0 -0
  334. /package/dist/{chunk-345MEMRU.js.map → chunk-3OUGSOJP.js.map} +0 -0
  335. /package/dist/{chunk-G2STTRYB.js.map → chunk-4D2YH47Z.js.map} +0 -0
  336. /package/dist/{chunk-IXYIW3MZ.js.map → chunk-4K2H4KTR.js.map} +0 -0
  337. /package/dist/{chunk-UVVSOSHL.js.map → chunk-52CQKST6.js.map} +0 -0
  338. /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
  339. /package/dist/{chunk-2QZFZNXO.js.map → chunk-5CQO6LVM.js.map} +0 -0
  340. /package/dist/{chunk-NLDMTXWV.js.map → chunk-5LNPW7NE.js.map} +0 -0
  341. /package/dist/{chunk-WHTMVTU4.js.map → chunk-5X4ZJESN.js.map} +0 -0
  342. /package/dist/{chunk-WI37MWRZ.js.map → chunk-63UNVGZW.js.map} +0 -0
  343. /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
  344. /package/dist/{chunk-CFCEJNOE.js.map → chunk-6KHF6PAB.js.map} +0 -0
  345. /package/dist/{chunk-35A7GCHG.js.map → chunk-6T42L5FI.js.map} +0 -0
  346. /package/dist/{chunk-JDOBIFBK.js.map → chunk-7CXL25AA.js.map} +0 -0
  347. /package/dist/{chunk-YLBE6PLR.js.map → chunk-7IGMKQWK.js.map} +0 -0
  348. /package/dist/{chunk-CSLK7BN6.js.map → chunk-7LYRFI5A.js.map} +0 -0
  349. /package/dist/{chunk-IB63OVUB.js.map → chunk-AJ6ORARY.js.map} +0 -0
  350. /package/dist/{chunk-CGOKNQDK.js.map → chunk-ANZXWOYD.js.map} +0 -0
  351. /package/dist/{chunk-5QXMESS7.js.map → chunk-AXC7UTLM.js.map} +0 -0
  352. /package/dist/{chunk-RFIJRZ4K.js.map → chunk-B657ZGDH.js.map} +0 -0
  353. /package/dist/{chunk-MY7B3HYC.js.map → chunk-CLCMDKTB.js.map} +0 -0
  354. /package/dist/{chunk-QPWUG2S3.js.map → chunk-CYEK6Z3P.js.map} +0 -0
  355. /package/dist/{chunk-IHCYCE6D.js.map → chunk-DJMVSUPK.js.map} +0 -0
  356. /package/dist/{chunk-HP4CU2ZA.js.map → chunk-DST7HRSG.js.map} +0 -0
  357. /package/dist/{chunk-IIFFC3RL.js.map → chunk-EDR6CVWZ.js.map} +0 -0
  358. /package/dist/{chunk-AUWMKDKL.js.map → chunk-EMVJU7WC.js.map} +0 -0
  359. /package/dist/{chunk-O6AYMAPJ.js.map → chunk-ENNC3RZ6.js.map} +0 -0
  360. /package/dist/{chunk-2JRB3Z5N.js.map → chunk-EP5WXE2G.js.map} +0 -0
  361. /package/dist/{chunk-I2KEH2LS.js.map → chunk-FC6RCOIU.js.map} +0 -0
  362. /package/dist/{chunk-OZVHLBH6.js.map → chunk-FLV7M7CT.js.map} +0 -0
  363. /package/dist/{chunk-Q6GI7HEC.js.map → chunk-FRH2UC7Q.js.map} +0 -0
  364. /package/dist/{chunk-3SL52JKD.js.map → chunk-FZVROZKC.js.map} +0 -0
  365. /package/dist/{chunk-2EZB2DL5.js.map → chunk-GE6HETIF.js.map} +0 -0
  366. /package/dist/{chunk-2DHJTJIY.js.map → chunk-GEGUBU3D.js.map} +0 -0
  367. /package/dist/{chunk-6AA7XFMO.js.map → chunk-GF4H3B3R.js.map} +0 -0
  368. /package/dist/{chunk-ME2LMFHF.js.map → chunk-HPAOMYKM.js.map} +0 -0
  369. /package/dist/{chunk-4NRZ7BRS.js.map → chunk-I25RINZK.js.map} +0 -0
  370. /package/dist/{chunk-XG4XXI66.js.map → chunk-I25RQA65.js.map} +0 -0
  371. /package/dist/{chunk-EJJMDLVB.js.map → chunk-IJ4FEGZR.js.map} +0 -0
  372. /package/dist/{chunk-EUL3S3LE.js.map → chunk-J5WI4QRP.js.map} +0 -0
  373. /package/dist/{chunk-LMMC55WM.js.map → chunk-JA54KIYD.js.map} +0 -0
  374. /package/dist/{chunk-5FLFPTDK.js.map → chunk-JA72X46J.js.map} +0 -0
  375. /package/dist/{chunk-NLYOOGZ7.js.map → chunk-KE5PWLI6.js.map} +0 -0
  376. /package/dist/{chunk-4DDIWRT7.js.map → chunk-KQI2PKYP.js.map} +0 -0
  377. /package/dist/{chunk-Y2ADLCB3.js.map → chunk-KSUOM3YU.js.map} +0 -0
  378. /package/dist/{chunk-BTOHGPHC.js.map → chunk-KZEMFD6E.js.map} +0 -0
  379. /package/dist/{chunk-NXVD46HT.js.map → chunk-L2VS27PZ.js.map} +0 -0
  380. /package/dist/{chunk-MYYHACOW.js.map → chunk-L34W4W4I.js.map} +0 -0
  381. /package/dist/{chunk-KRTIHXWC.js.map → chunk-L3PWXD73.js.map} +0 -0
  382. /package/dist/{chunk-NQHSXHJP.js.map → chunk-L6GNS5GB.js.map} +0 -0
  383. /package/dist/{chunk-44PBRUXB.js.map → chunk-M47Q6566.js.map} +0 -0
  384. /package/dist/{chunk-E7FN5N5E.js.map → chunk-MQNOIH2C.js.map} +0 -0
  385. /package/dist/{chunk-IDSZNHIP.js.map → chunk-MULNBSPP.js.map} +0 -0
  386. /package/dist/{chunk-RKSGUMVL.js.map → chunk-NBQIFCJE.js.map} +0 -0
  387. /package/dist/{chunk-I6WFBNA4.js.map → chunk-NHSVW7UT.js.map} +0 -0
  388. /package/dist/{chunk-32HO62I4.js.map → chunk-OFEHITAZ.js.map} +0 -0
  389. /package/dist/{chunk-PCO3P7WJ.js.map → chunk-OGVJXIHX.js.map} +0 -0
  390. /package/dist/{chunk-RYN4AIRM.js.map → chunk-OZABSIOV.js.map} +0 -0
  391. /package/dist/{chunk-HO7IQP7G.js.map → chunk-QMFKW4OU.js.map} +0 -0
  392. /package/dist/{chunk-34G4U6HS.js.map → chunk-QRZMJ2WN.js.map} +0 -0
  393. /package/dist/{chunk-GUD6FYQG.js.map → chunk-RSMIRLKM.js.map} +0 -0
  394. /package/dist/{chunk-TNVZCLJU.js.map → chunk-S5TGRZWY.js.map} +0 -0
  395. /package/dist/{chunk-O24EWFPQ.js.map → chunk-SNXBXYUE.js.map} +0 -0
  396. /package/dist/{chunk-KW77LGDX.js.map → chunk-SUAX5JWY.js.map} +0 -0
  397. /package/dist/{chunk-PNFWIB4X.js.map → chunk-SWRN6U7Q.js.map} +0 -0
  398. /package/dist/{chunk-R4NGLTUS.js.map → chunk-TDMNADPI.js.map} +0 -0
  399. /package/dist/{chunk-QCP75JGO.js.map → chunk-TFA6HPOA.js.map} +0 -0
  400. /package/dist/{chunk-LI76ESJL.js.map → chunk-TZQOCQXB.js.map} +0 -0
  401. /package/dist/{chunk-OV7EYM6M.js.map → chunk-U6OXJQEH.js.map} +0 -0
  402. /package/dist/{chunk-OWHPA4JS.js.map → chunk-V32NHP2R.js.map} +0 -0
  403. /package/dist/{chunk-JSUA4YFE.js.map → chunk-WG4TMZJ2.js.map} +0 -0
  404. /package/dist/{chunk-DQTCGVFK.js.map → chunk-WHCD4Z3D.js.map} +0 -0
  405. /package/dist/{chunk-KATEWTQJ.js.map → chunk-X7J56GPG.js.map} +0 -0
  406. /package/dist/{chunk-7KICGR5W.js.map → chunk-XPRAOTJY.js.map} +0 -0
  407. /package/dist/{chunk-2NV7MMMM.js.map → chunk-XQSJXNWC.js.map} +0 -0
  408. /package/dist/{chunk-RXT6UB25.js.map → chunk-YJAOYEWI.js.map} +0 -0
  409. /package/dist/{chunk-L6DJJEFW.js.map → chunk-YJEUHGZZ.js.map} +0 -0
  410. /package/dist/{chunk-AXFWMRKI.js.map → chunk-YQJCWR4R.js.map} +0 -0
@@ -0,0 +1,498 @@
1
+ import assert from "node:assert/strict";
2
+ import { fork } from "node:child_process";
3
+ import { once } from "node:events";
4
+ import { existsSync } from "node:fs";
5
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import test from "node:test";
10
+ import { commitPreparedFileAtomically } from "../maintenance/atomic-file.js";
11
+ import { watchProjectionRebuildParent } from "../maintenance/projection-rebuild-abort.js";
12
+ import { loadProjectionTimeline } from "../maintenance/projection-timeline.js";
13
+ import { rebuildMemoryProjection } from "../maintenance/rebuild-memory-projection.js";
14
+ import { initLogger, resetLogger, type LoggerBackend } from "../logger.js";
15
+ import { probeProjectionHealth } from "../memory-projection-store.js";
16
+ import { StorageManager } from "../storage.js";
17
+ import type { MemoryLifecycleEvent, PluginConfig } from "../types.js";
18
+ import {
19
+ createProjectionRebuildScheduleState,
20
+ forkProjectionRebuild,
21
+ maybeRebuildMemoryProjectionScheduled,
22
+ projectionRebuildChildEnv,
23
+ projectionRebuildForkTimeoutMs,
24
+ terminateScheduledProjectionRebuilds,
25
+ type ProjectionRebuildForkRequest,
26
+ type ProjectionRebuildForkResult,
27
+ } from "./projection-rebuild-schedule.js";
28
+
29
+ const PARENT_DISCONNECT_FLAG = "--projection-parent-disconnect-child";
30
+
31
+ if (process.argv.includes(PARENT_DISCONNECT_FLAG)) {
32
+ const memoryDir = process.argv[process.argv.indexOf(PARENT_DISCONNECT_FLAG) + 1];
33
+ if (!memoryDir) process.exit(1);
34
+ try {
35
+ const signal = watchProjectionRebuildParent();
36
+ process.send?.({ ready: true });
37
+ await new Promise<void>((resolve) => {
38
+ if (signal.aborted) {
39
+ resolve();
40
+ return;
41
+ }
42
+ signal.addEventListener("abort", () => resolve(), { once: true });
43
+ });
44
+ await rebuildMemoryProjection({
45
+ memoryDir,
46
+ dryRun: false,
47
+ now: new Date("2026-06-01T00:00:00.000Z"),
48
+ signal,
49
+ });
50
+ } catch {
51
+ process.exit(1);
52
+ }
53
+ process.exit(0);
54
+ }
55
+
56
+ function config(memoryDir: string, overrides: Record<string, unknown> = {}): PluginConfig {
57
+ return {
58
+ memoryDir,
59
+ defaultNamespace: "ns-schedule",
60
+ projectionRebuildEnabled: true,
61
+ projectionRebuildIntervalMs: 6 * 60 * 60 * 1000,
62
+ projectionRebuildHeapUsageLimit: 0.6,
63
+ ...overrides,
64
+ } as unknown as PluginConfig;
65
+ }
66
+
67
+ function quietHeap() {
68
+ return { used_heap_size: 1, heap_size_limit: 100 };
69
+ }
70
+
71
+ /** Windows reports TerminateProcess as an exit code, not SIGKILL. */
72
+ function assertChildKilled(child: { signalCode: NodeJS.Signals | null; exitCode: number | null }): void {
73
+ if (process.platform === "win32") {
74
+ assert.notEqual(child.exitCode, null);
75
+ return;
76
+ }
77
+ assert.equal(child.signalCode, "SIGKILL");
78
+ }
79
+
80
+ /** A storage stand-in whose corpus reads fail the test if the daemon calls them. */
81
+ function corpusGuard(memoryDir: string): StorageManager {
82
+ const fail = async (): Promise<never> => {
83
+ throw new Error("daemon read the corpus");
84
+ };
85
+ return {
86
+ dir: memoryDir,
87
+ isSecureStoreUnlocked: () => false,
88
+ readAllMemories: fail,
89
+ readAllColdMemories: fail,
90
+ readArchivedMemories: fail,
91
+ iterateMemoryLifecycleEvents: async function* () {
92
+ throw new Error("daemon read the ledger");
93
+ },
94
+ } as unknown as StorageManager;
95
+ }
96
+
97
+ async function seedFact(memoryDir: string): Promise<void> {
98
+ const dir = path.join(memoryDir, "facts", "2026-01-01");
99
+ await mkdir(dir, { recursive: true });
100
+ await writeFile(
101
+ path.join(dir, "fact-1.md"),
102
+ [
103
+ "---",
104
+ "id: fact-1",
105
+ "category: fact",
106
+ "confidence: 0.8",
107
+ "created: 2026-01-01T00:00:00.000Z",
108
+ "updated: 2026-01-01T00:00:00.000Z",
109
+ "status: active",
110
+ "source: test",
111
+ "---",
112
+ "",
113
+ "scheduled rebuild fixture",
114
+ "",
115
+ ].join("\n"),
116
+ "utf8",
117
+ );
118
+ }
119
+
120
+ test("shutting down the parent kills the projection rebuild child", async () => {
121
+ const child = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
122
+ const pending = forkProjectionRebuild(
123
+ { memoryDir: "/tmp/unused", defaultNamespace: "default", now: new Date("2026-06-01T00:00:00.000Z") },
124
+ { timeoutMs: 60_000, spawnChild: () => child },
125
+ );
126
+ terminateScheduledProjectionRebuilds();
127
+ await assert.rejects(pending, /exited/);
128
+ assertChildKilled(child);
129
+ });
130
+
131
+ test("disposing one scheduler does not kill another scheduler's rebuild", async () => {
132
+ const first = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
133
+ const second = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
134
+ const request = {
135
+ memoryDir: "/tmp/unused",
136
+ defaultNamespace: "default",
137
+ now: new Date("2026-06-01T00:00:00.000Z"),
138
+ };
139
+ const stateA = createProjectionRebuildScheduleState();
140
+ const stateB = createProjectionRebuildScheduleState();
141
+ const pendingA = forkProjectionRebuild(request, { timeoutMs: 60_000, spawnChild: () => first, owner: stateA });
142
+ const pendingB = forkProjectionRebuild(request, { timeoutMs: 60_000, spawnChild: () => second, owner: stateB });
143
+ terminateScheduledProjectionRebuilds(stateA);
144
+ await assert.rejects(pendingA, /exited/);
145
+ assertChildKilled(first);
146
+ assert.equal(second.exitCode, null);
147
+ assert.equal(second.signalCode, null);
148
+ terminateScheduledProjectionRebuilds(stateB);
149
+ await assert.rejects(pendingB, /exited/);
150
+ assertChildKilled(second);
151
+ });
152
+
153
+ test("a disconnected parent does not let the rebuild child publish", async () => {
154
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-orphan-"));
155
+ const projection = path.join(memoryDir, "state", "memory-projection.sqlite");
156
+ try {
157
+ await seedFact(memoryDir);
158
+ const child = fork(fileURLToPath(import.meta.url), [
159
+ PARENT_DISCONNECT_FLAG,
160
+ memoryDir,
161
+ ], {
162
+ execArgv: ["--import", "tsx"],
163
+ stdio: ["ignore", "inherit", "inherit", "ipc"],
164
+ });
165
+ const outcome = await Promise.race([
166
+ once(child, "message").then(() => "ready" as const),
167
+ once(child, "exit").then(() => "exit" as const),
168
+ ]);
169
+ assert.equal(outcome, "ready");
170
+ child.disconnect();
171
+ const [code] = await once(child, "exit");
172
+ assert.notEqual(code, 0);
173
+ assert.equal(existsSync(projection), false);
174
+ assert.equal(existsSync(`${projection}.tmp`), false);
175
+ } finally {
176
+ await rm(memoryDir, { recursive: true, force: true });
177
+ }
178
+ });
179
+
180
+ test("a hung projection rebuild child is killed at the timeout", async () => {
181
+ const child = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
182
+ await assert.rejects(
183
+ () => forkProjectionRebuild(
184
+ { memoryDir: "/tmp/unused", defaultNamespace: "default", now: new Date("2026-06-01T00:00:00.000Z") },
185
+ { timeoutMs: 200, spawnChild: () => child },
186
+ ),
187
+ /timed out after 200ms/,
188
+ );
189
+ await new Promise<void>((resolve) => {
190
+ if (child.exitCode !== null || child.signalCode !== null) resolve();
191
+ else child.once("exit", () => resolve());
192
+ });
193
+ assertChildKilled(child);
194
+ });
195
+
196
+ test("an aborted signal stops the corpus scan before the projection is published", async () => {
197
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-abort-scan-"));
198
+ const projection = path.join(memoryDir, "state", "memory-projection.sqlite");
199
+ try {
200
+ await seedFact(memoryDir);
201
+ const signal = AbortSignal.abort(new Error("projection rebuild runner parent disconnected"));
202
+ await assert.rejects(
203
+ () => rebuildMemoryProjection({
204
+ memoryDir,
205
+ dryRun: false,
206
+ now: new Date("2026-06-01T00:00:00.000Z"),
207
+ signal,
208
+ }),
209
+ (err: unknown) => {
210
+ assert.ok(err instanceof Error);
211
+ assert.equal(err.name, "AbortError");
212
+ assert.match(err.message, /corpus read aborted/);
213
+ return true;
214
+ },
215
+ );
216
+ assert.equal(existsSync(projection), false);
217
+ assert.equal(existsSync(`${projection}.tmp`), false);
218
+ } finally {
219
+ await rm(memoryDir, { recursive: true, force: true });
220
+ }
221
+ });
222
+
223
+ test("an aborted signal stops an archive scan and the lifecycle ledger mid-stream", async () => {
224
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-abort-rest-"));
225
+ try {
226
+ const storage = new StorageManager(memoryDir);
227
+ await assert.rejects(
228
+ () => storage.readArchivedMemories({ retainRaw: false, abortSignal: AbortSignal.abort() }),
229
+ (err: unknown) => {
230
+ assert.ok(err instanceof Error);
231
+ assert.equal(err.name, "AbortError");
232
+ return true;
233
+ },
234
+ );
235
+ const controller = new AbortController();
236
+ let pulled = 0;
237
+ await assert.rejects(
238
+ () => loadProjectionTimeline({
239
+ storage: {
240
+ iterateMemoryLifecycleEvents(): AsyncIterable<MemoryLifecycleEvent> {
241
+ return (async function* () {
242
+ for (let index = 0; index < 5; index += 1) {
243
+ pulled += 1;
244
+ if (index === 1) controller.abort();
245
+ yield {
246
+ eventId: `e${index}`,
247
+ memoryId: "m",
248
+ eventType: "created",
249
+ timestamp: "2026-01-01T00:00:00.000Z",
250
+ actor: "test",
251
+ ruleVersion: "1",
252
+ };
253
+ }
254
+ })();
255
+ },
256
+ },
257
+ memoryDir,
258
+ memories: [],
259
+ signal: controller.signal,
260
+ }),
261
+ /projection rebuild aborted/,
262
+ );
263
+ assert.ok(pulled < 5);
264
+ } finally {
265
+ await rm(memoryDir, { recursive: true, force: true });
266
+ }
267
+ });
268
+
269
+ test("an abort after the projection backup does not rename over the live file", async () => {
270
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-rename-"));
271
+ const output = path.join(dir, "memory-projection.sqlite");
272
+ const temp = `${output}.tmp`;
273
+ const backup = path.join(dir, "backup.sqlite");
274
+ try {
275
+ await writeFile(output, "live");
276
+ await writeFile(temp, "orphan");
277
+ await assert.rejects(
278
+ () => commitPreparedFileAtomically(temp, output, backup, async () => {
279
+ throw new Error("projection rebuild runner parent disconnected");
280
+ }),
281
+ /parent disconnected/,
282
+ );
283
+ assert.equal(await readFile(output, "utf8"), "live");
284
+ assert.equal(existsSync(temp), false);
285
+ assert.equal(await readFile(backup, "utf8"), "live");
286
+ } finally {
287
+ await rm(dir, { recursive: true, force: true });
288
+ }
289
+ });
290
+
291
+ test("the fork hang cap follows a long interval and stays at least 30 minutes", () => {
292
+ assert.equal(projectionRebuildForkTimeoutMs(60_000), 30 * 60 * 1000);
293
+ assert.equal(projectionRebuildForkTimeoutMs(6 * 60 * 60 * 1000), 6 * 60 * 60 * 1000);
294
+ assert.equal(projectionRebuildForkTimeoutMs(Number.NaN), 30 * 60 * 1000);
295
+ assert.equal(projectionRebuildForkTimeoutMs(30 * 24 * 60 * 60 * 1000), 2_147_483_647);
296
+ });
297
+
298
+ test("projection rebuild child env keeps locators and drops secrets", () => {
299
+ const env = projectionRebuildChildEnv({
300
+ PATH: "/usr/bin",
301
+ HOME: "/tmp/remnic-home",
302
+ OPENAI_API_KEY: "sk-test",
303
+ REMNIC_SECURE_STORE_KEY: "unlock-material",
304
+ NODE_OPTIONS: "--conditions=remnic-source",
305
+ });
306
+ assert.equal(env.PATH, "/usr/bin");
307
+ assert.equal(env.HOME, "/tmp/remnic-home");
308
+ assert.equal(env.NODE_OPTIONS, "--conditions=remnic-source");
309
+ assert.equal(env.OPENAI_API_KEY, undefined);
310
+ assert.equal(env.REMNIC_SECURE_STORE_KEY, undefined);
311
+ });
312
+
313
+ test("scheduled projection rebuild forks and does not read the corpus in the daemon", async () => {
314
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-fork-"));
315
+ const calls: ProjectionRebuildForkRequest[] = [];
316
+ const timeouts: number[] = [];
317
+ try {
318
+ const state = createProjectionRebuildScheduleState();
319
+ await maybeRebuildMemoryProjectionScheduled({
320
+ config: config(memoryDir),
321
+ getStorage: () => corpusGuard(memoryDir),
322
+ state,
323
+ heapStatistics: quietHeap,
324
+ forkRebuild: async (request, options) => {
325
+ calls.push(request);
326
+ if (options?.timeoutMs !== undefined) timeouts.push(options.timeoutMs);
327
+ return { currentRows: 4, timelineRows: 5, entityMentionRows: 6 };
328
+ },
329
+ });
330
+ assert.equal(calls.length, 1);
331
+ assert.deepEqual(timeouts, [6 * 60 * 60 * 1000]);
332
+ assert.equal(calls[0]?.memoryDir, memoryDir);
333
+ assert.equal(calls[0]?.defaultNamespace, "ns-schedule");
334
+ assert.equal(state.inFlight, false);
335
+ assert.ok(state.lastRebuildAtMs > 0);
336
+
337
+ const again = calls.length;
338
+ await maybeRebuildMemoryProjectionScheduled({
339
+ config: config(memoryDir),
340
+ getStorage: () => corpusGuard(memoryDir),
341
+ state,
342
+ heapStatistics: quietHeap,
343
+ forkRebuild: async () => {
344
+ calls.push({ memoryDir, defaultNamespace: "ns-schedule", now: new Date() });
345
+ return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
346
+ },
347
+ });
348
+ assert.equal(calls.length, again, "success interval suppresses a second fork");
349
+ } finally {
350
+ await rm(memoryDir, { recursive: true, force: true });
351
+ }
352
+ });
353
+
354
+ test("scheduled projection rebuild keeps in-flight and failure backoff", async () => {
355
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-backoff-"));
356
+ try {
357
+ const inFlight = createProjectionRebuildScheduleState();
358
+ inFlight.inFlight = true;
359
+ let forks = 0;
360
+ const forkRebuild = async (): Promise<ProjectionRebuildForkResult> => {
361
+ forks += 1;
362
+ return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
363
+ };
364
+ await maybeRebuildMemoryProjectionScheduled({
365
+ config: config(memoryDir),
366
+ state: inFlight,
367
+ heapStatistics: quietHeap,
368
+ forkRebuild,
369
+ });
370
+ assert.equal(forks, 0, "in-flight rebuild is not started again");
371
+
372
+ const failing = createProjectionRebuildScheduleState();
373
+ await maybeRebuildMemoryProjectionScheduled({
374
+ config: config(memoryDir),
375
+ state: failing,
376
+ heapStatistics: quietHeap,
377
+ forkRebuild: async () => {
378
+ throw new Error("runner failed");
379
+ },
380
+ });
381
+ assert.equal(failing.inFlight, false);
382
+ assert.equal(failing.lastRebuildAtMs, 0);
383
+ assert.ok(failing.lastFailureAtMs > 0);
384
+ await maybeRebuildMemoryProjectionScheduled({
385
+ config: config(memoryDir),
386
+ state: failing,
387
+ heapStatistics: quietHeap,
388
+ forkRebuild,
389
+ });
390
+ assert.equal(forks, 0, "failure backoff suppresses the retry");
391
+ } finally {
392
+ await rm(memoryDir, { recursive: true, force: true });
393
+ }
394
+ });
395
+
396
+ test("heap guard postpones a scheduled projection rebuild", async () => {
397
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-heap-"));
398
+ const warnings: string[] = [];
399
+ const backend: LoggerBackend = {
400
+ info() {},
401
+ warn(msg) {
402
+ warnings.push(msg);
403
+ },
404
+ error() {},
405
+ debug() {},
406
+ };
407
+ initLogger(backend, false, { timestamps: false });
408
+ try {
409
+ const state = createProjectionRebuildScheduleState();
410
+ let forks = 0;
411
+ await maybeRebuildMemoryProjectionScheduled({
412
+ config: config(memoryDir),
413
+ getStorage: () => corpusGuard(memoryDir),
414
+ state,
415
+ heapStatistics: () => ({ used_heap_size: 70, heap_size_limit: 100 }),
416
+ forkRebuild: async () => {
417
+ forks += 1;
418
+ return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
419
+ },
420
+ });
421
+ assert.equal(forks, 0);
422
+ assert.equal(state.inFlight, false);
423
+ assert.equal(state.lastRebuildAtMs, 0);
424
+ assert.ok(state.lastFailureAtMs > 0);
425
+ assert.equal(warnings.length, 1);
426
+ assert.match(warnings[0] ?? "", /postponed/);
427
+ assert.match(warnings[0] ?? "", /heap used 70 of limit 100/);
428
+ assert.match(warnings[0] ?? "", /ratio 0\.700/);
429
+ assert.match(warnings[0] ?? "", /projectionRebuildHeapUsageLimit 0\.6/);
430
+ } finally {
431
+ resetLogger();
432
+ await rm(memoryDir, { recursive: true, force: true });
433
+ }
434
+ });
435
+
436
+ test("heap guard does not postpone at the limit or with an unusable cap", async () => {
437
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-heap-ok-"));
438
+ try {
439
+ let forks = 0;
440
+ const forkRebuild = async (): Promise<ProjectionRebuildForkResult> => {
441
+ forks += 1;
442
+ return { currentRows: 1, timelineRows: 0, entityMentionRows: 0 };
443
+ };
444
+ const atLimit = createProjectionRebuildScheduleState();
445
+ await maybeRebuildMemoryProjectionScheduled({
446
+ config: config(memoryDir),
447
+ state: atLimit,
448
+ heapStatistics: () => ({ used_heap_size: 60, heap_size_limit: 100 }),
449
+ forkRebuild,
450
+ });
451
+ assert.equal(forks, 1, "ratio equal to the limit still runs");
452
+
453
+ const disabled = createProjectionRebuildScheduleState();
454
+ await maybeRebuildMemoryProjectionScheduled({
455
+ config: config(memoryDir, { projectionRebuildHeapUsageLimit: 1 }),
456
+ state: disabled,
457
+ heapStatistics: () => ({ used_heap_size: 100, heap_size_limit: 100 }),
458
+ forkRebuild,
459
+ });
460
+ assert.equal(forks, 2, "a limit of 1 never postpones");
461
+
462
+ const unusable = createProjectionRebuildScheduleState();
463
+ await maybeRebuildMemoryProjectionScheduled({
464
+ config: config(memoryDir),
465
+ state: unusable,
466
+ heapStatistics: () => ({ used_heap_size: 10, heap_size_limit: 0 }),
467
+ forkRebuild,
468
+ });
469
+ assert.equal(forks, 3, "a non-positive heap cap does not postpone");
470
+ } finally {
471
+ await rm(memoryDir, { recursive: true, force: true });
472
+ }
473
+ });
474
+
475
+ test("an unlocked secure store rebuilds in-process instead of forking", async () => {
476
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-unlocked-"));
477
+ try {
478
+ await seedFact(memoryDir);
479
+ const storage = new StorageManager(memoryDir);
480
+ storage.setSecureStoreKey(Buffer.alloc(32, 4), false);
481
+ assert.equal(storage.isSecureStoreUnlocked(), true);
482
+ let forks = 0;
483
+ await maybeRebuildMemoryProjectionScheduled({
484
+ config: config(memoryDir),
485
+ getStorage: () => storage,
486
+ state: createProjectionRebuildScheduleState(),
487
+ heapStatistics: quietHeap,
488
+ forkRebuild: async () => {
489
+ forks += 1;
490
+ throw new Error("forked an unlocked store");
491
+ },
492
+ });
493
+ assert.equal(forks, 0);
494
+ assert.equal(probeProjectionHealth(memoryDir).state, "openable");
495
+ } finally {
496
+ await rm(memoryDir, { recursive: true, force: true });
497
+ }
498
+ });