@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
@@ -8,6 +8,15 @@
8
8
  * maintenance request — interval-throttled, single-flighted, never awaited,
9
9
  * never throws.
10
10
  *
11
+ * The rebuild runs in a forked child so the corpus and lifecycle ledger are
12
+ * not allocated in the daemon heap. An unlocked secure store stays in-process:
13
+ * the key is process-local and is never placed on the child's argv or env.
14
+ * The child is killed on scheduler dispose and on parent exit. If the parent
15
+ * dies without running those hooks, the child sees the IPC channel close and
16
+ * stops before it publishes the projection.
17
+ * When the daemon heap is already above `projectionRebuildHeapUsageLimit`,
18
+ * the job is postponed with the failure backoff instead of starting.
19
+ *
11
20
  * `projectionRebuildEnabled` gates it (via the lifecycle capabilities
12
21
  * resolver, default true); `projectionRebuildIntervalMs` is the cadence.
13
22
  *
@@ -24,6 +33,11 @@
24
33
  * not yet scheduled here (they are still served by their own rebuild paths);
25
34
  * the fallback WARN surfaces staleness for any namespace that lags.
26
35
  */
36
+ import { existsSync } from "node:fs";
37
+ import { fork, type ChildProcess } from "node:child_process";
38
+ import path from "node:path";
39
+ import v8 from "node:v8";
40
+ import { fileURLToPath } from "node:url";
27
41
  import { log } from "../logger.js";
28
42
  import type { PluginConfig } from "../types.js";
29
43
  import { resolveMemoryLifecycleCapabilities } from "../capabilities.js";
@@ -31,7 +45,10 @@ import {
31
45
  rebuildMemoryProjection,
32
46
  type RebuildMemoryProjectionOptions,
33
47
  } from "../maintenance/rebuild-memory-projection.js";
48
+ import { PROJECTION_REBUILD_RUNNER_FLAG } from "../maintenance/rebuild-memory-projection-runner.js";
34
49
  import { readProjectionRebuiltAt } from "../maintenance/projection-support.js";
50
+ import { DEFAULT_PROJECTION_REBUILD_HEAP_USAGE_LIMIT } from "../projection-rebuild-config.js";
51
+ import { fullCorpusHeapPressure, type HeapLimitStatistics } from "./full-corpus-heap-guard.js";
35
52
 
36
53
  type InjectedStorage = NonNullable<RebuildMemoryProjectionOptions["storage"]>;
37
54
 
@@ -45,20 +62,250 @@ export interface ProjectionRebuildScheduleState {
45
62
  lastFailureAtMs: number;
46
63
  }
47
64
 
65
+ export interface ProjectionRebuildForkRequest {
66
+ memoryDir: string;
67
+ defaultNamespace: string;
68
+ now: Date;
69
+ }
70
+
71
+ export interface ProjectionRebuildForkResult {
72
+ currentRows: number;
73
+ timelineRows: number;
74
+ entityMentionRows: number;
75
+ }
76
+
48
77
  /** Bounded retry cadence after a failure — short enough to self-heal promptly
49
78
  * once a transient cause clears, long enough to keep a persistently-failing
50
79
  * rebuild off every maintenance tick. */
51
80
  const FAILURE_RETRY_BACKOFF_MS = 5 * 60 * 1000;
52
81
 
82
+ /** Floor for a hung child. A short interval must not make this tighter:
83
+ * a large corpus can legitimately run longer than 30 minutes. When the
84
+ * configured interval is longer, the child may use that whole interval. */
85
+ const FORK_TIMEOUT_MS = 30 * 60 * 1000;
86
+
87
+ /** Hang cap for one scheduled fork. At least 30 minutes, otherwise the interval,
88
+ * and never above Node's 32-bit setTimeout limit. A larger delay overflows
89
+ * and fires in 1ms, which would kill every rebuild. */
90
+ const MAX_SETTIMEOUT_MS = 2_147_483_647;
91
+
92
+ export function projectionRebuildForkTimeoutMs(intervalMs: number): number {
93
+ const timeout = !Number.isFinite(intervalMs) || intervalMs < FORK_TIMEOUT_MS
94
+ ? FORK_TIMEOUT_MS
95
+ : intervalMs;
96
+ return Math.min(timeout, MAX_SETTIMEOUT_MS);
97
+ }
98
+
99
+ const projectionRebuildChildren = new Map<ProjectionRebuildScheduleState | undefined, Set<ChildProcess>>();
100
+ let parentExitHookInstalled = false;
101
+
102
+ function rememberProjectionRebuildChild(
103
+ child: ChildProcess,
104
+ owner: ProjectionRebuildScheduleState | undefined,
105
+ ): void {
106
+ let children = projectionRebuildChildren.get(owner);
107
+ if (!children) {
108
+ children = new Set();
109
+ projectionRebuildChildren.set(owner, children);
110
+ }
111
+ children.add(child);
112
+ const forget = () => {
113
+ children.delete(child);
114
+ if (children.size === 0) projectionRebuildChildren.delete(owner);
115
+ };
116
+ child.once("exit", forget);
117
+ child.once("error", forget);
118
+ if (!parentExitHookInstalled) {
119
+ parentExitHookInstalled = true;
120
+ // The exit listener is invoked with the exit code. Ignore that argument
121
+ // so a non-zero code is not treated as a scheduler owner.
122
+ process.on("exit", () => {
123
+ terminateScheduledProjectionRebuilds();
124
+ });
125
+ }
126
+ }
127
+
128
+ /**
129
+ * SIGKILL scheduled rebuild children. A scheduler dispose passes its own
130
+ * state so another instance's child keeps running. Process exit passes no
131
+ * owner and kills every child.
132
+ */
133
+ export function terminateScheduledProjectionRebuilds(
134
+ owner?: ProjectionRebuildScheduleState,
135
+ ): void {
136
+ const groups = owner
137
+ ? [projectionRebuildChildren.get(owner)]
138
+ : [...projectionRebuildChildren.values()];
139
+ for (const children of groups) {
140
+ if (!children) continue;
141
+ for (const child of children) child.kill("SIGKILL");
142
+ }
143
+ }
144
+
145
+ const CHILD_ENV_ALLOWLIST = [
146
+ "PATH",
147
+ "NODE_OPTIONS",
148
+ "HOME",
149
+ "USERPROFILE",
150
+ "TMPDIR",
151
+ "TMP",
152
+ "TEMP",
153
+ "LANG",
154
+ "LC_ALL",
155
+ "LC_CTYPE",
156
+ "TZ",
157
+ "SystemRoot",
158
+ "windir",
159
+ "PATHEXT",
160
+ "COMSPEC",
161
+ "NODE_PATH",
162
+ ] as const;
163
+
53
164
  export function createProjectionRebuildScheduleState(): ProjectionRebuildScheduleState {
54
165
  return { inFlight: false, lastRebuildAtMs: 0, lastFailureAtMs: 0 };
55
166
  }
56
167
 
168
+ /**
169
+ * Environment for the rebuild child. Only runtime locators are copied.
170
+ * API keys, tokens, and secure-store unlock material are not passed.
171
+ */
172
+ export function projectionRebuildChildEnv(parent: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
173
+ const env: NodeJS.ProcessEnv = {};
174
+ for (const key of CHILD_ENV_ALLOWLIST) {
175
+ const value = parent[key];
176
+ if (value !== undefined) env[key] = value;
177
+ }
178
+ return env;
179
+ }
180
+
181
+ function projectionRebuildRunnerPath(): string {
182
+ const here = fileURLToPath(import.meta.url);
183
+ const dir = path.dirname(here);
184
+ const candidates = [
185
+ path.join(dir, "..", "maintenance", "rebuild-memory-projection-runner.ts"),
186
+ path.join(dir, "..", "maintenance", "rebuild-memory-projection-runner.js"),
187
+ path.join(dir, "maintenance", "rebuild-memory-projection-runner.js"),
188
+ path.join(dir, "rebuild-memory-projection-runner.js"),
189
+ ];
190
+ for (const candidate of candidates) {
191
+ if (existsSync(candidate)) return candidate;
192
+ }
193
+ throw new Error("projection rebuild runner was not found next to the maintenance bundle");
194
+ }
195
+
196
+ function runnerExecArgv(runnerPath: string): string[] {
197
+ const argv: string[] = [];
198
+ const source = process.execArgv;
199
+ for (let index = 0; index < source.length; index += 1) {
200
+ const arg = source[index] ?? "";
201
+ if (arg === "--inspect" || arg === "--inspect-brk" || arg === "--inspect-port") {
202
+ if (arg === "--inspect-port") index += 1;
203
+ continue;
204
+ }
205
+ if (arg.startsWith("--inspect=") || arg.startsWith("--inspect-brk=") || arg.startsWith("--inspect-port=")) {
206
+ continue;
207
+ }
208
+ argv.push(arg);
209
+ }
210
+ if (runnerPath.endsWith(".ts") && !argv.some((arg) => arg === "tsx" || arg.includes(`${path.sep}tsx`))) {
211
+ argv.unshift("--import", "tsx");
212
+ }
213
+ return argv;
214
+ }
215
+
216
+ function isRunnerSuccess(message: unknown): message is ProjectionRebuildForkResult & { ok: true } {
217
+ if (!message || typeof message !== "object") return false;
218
+ const row = message as Record<string, unknown>;
219
+ return row.ok === true
220
+ && typeof row.currentRows === "number"
221
+ && typeof row.timelineRows === "number"
222
+ && typeof row.entityMentionRows === "number";
223
+ }
224
+
225
+ /** Fork the projection rebuild. Arguments are path, namespace, and timestamp only. */
226
+ export async function forkProjectionRebuild(
227
+ request: ProjectionRebuildForkRequest,
228
+ options?: {
229
+ timeoutMs?: number;
230
+ spawnChild?: () => ChildProcess;
231
+ /** Scheduler that owns this child. Dispose kills only that owner's child. */
232
+ owner?: ProjectionRebuildScheduleState;
233
+ /** Invoked after exit listeners are attached. Tests use this to disconnect. */
234
+ onChild?: (child: ChildProcess) => void;
235
+ },
236
+ ): Promise<ProjectionRebuildForkResult> {
237
+ const timeoutMs = Math.min(options?.timeoutMs ?? FORK_TIMEOUT_MS, MAX_SETTIMEOUT_MS);
238
+ const child = options?.spawnChild
239
+ ? options.spawnChild()
240
+ : spawnProjectionRebuildChild(request);
241
+ rememberProjectionRebuildChild(child, options?.owner);
242
+ return await new Promise((resolve, reject) => {
243
+ let settled = false;
244
+ let timer: ReturnType<typeof setTimeout> | undefined;
245
+ const finish = (err?: Error, result?: ProjectionRebuildForkResult) => {
246
+ if (settled) return;
247
+ settled = true;
248
+ if (timer) clearTimeout(timer);
249
+ if (err) reject(err);
250
+ else if (result) resolve(result);
251
+ else reject(new Error("projection rebuild runner returned no result"));
252
+ };
253
+ timer = setTimeout(() => {
254
+ child.kill("SIGKILL");
255
+ finish(new Error(`projection rebuild runner timed out after ${timeoutMs}ms`));
256
+ }, timeoutMs);
257
+ timer.unref?.();
258
+ child.on("message", (message: unknown) => {
259
+ if (isRunnerSuccess(message)) {
260
+ finish(undefined, message);
261
+ return;
262
+ }
263
+ const error = message && typeof message === "object" && "error" in message
264
+ ? String((message as { error?: unknown }).error ?? "projection rebuild runner failed")
265
+ : "projection rebuild runner failed";
266
+ finish(new Error(error));
267
+ });
268
+ child.on("error", (err) => finish(err));
269
+ child.on("exit", (code) => {
270
+ if (!settled) {
271
+ finish(new Error(`projection rebuild runner exited ${code ?? "null"}`));
272
+ }
273
+ });
274
+ options?.onChild?.(child);
275
+ });
276
+ }
277
+
278
+ function spawnProjectionRebuildChild(request: ProjectionRebuildForkRequest): ChildProcess {
279
+ const runnerPath = projectionRebuildRunnerPath();
280
+ const nowIso = request.now.toISOString();
281
+ return fork(
282
+ runnerPath,
283
+ [PROJECTION_REBUILD_RUNNER_FLAG, request.memoryDir, request.defaultNamespace, nowIso],
284
+ {
285
+ execArgv: runnerExecArgv(runnerPath),
286
+ env: projectionRebuildChildEnv(process.env),
287
+ stdio: ["ignore", "inherit", "inherit", "ipc"],
288
+ },
289
+ );
290
+ }
291
+
292
+ function storageIsUnlocked(storage: InjectedStorage | undefined): boolean {
293
+ if (!storage || typeof storage.isSecureStoreUnlocked !== "function") return false;
294
+ return storage.isSecureStoreUnlocked();
295
+ }
296
+
57
297
  export async function maybeRebuildMemoryProjectionScheduled(opts: {
58
298
  config: PluginConfig;
59
299
  /** The daemon's live root storage, when available (secure-store unlock). */
60
300
  getStorage?: () => InjectedStorage | undefined;
61
301
  state: ProjectionRebuildScheduleState;
302
+ /** Test seam. Production forks {@link forkProjectionRebuild}. */
303
+ forkRebuild?: (
304
+ request: ProjectionRebuildForkRequest,
305
+ options?: { timeoutMs?: number; owner?: ProjectionRebuildScheduleState },
306
+ ) => Promise<ProjectionRebuildForkResult>;
307
+ /** Test seam. Production reads `v8.getHeapStatistics()`. */
308
+ heapStatistics?: () => HeapLimitStatistics;
62
309
  }): Promise<void> {
63
310
  const { config, state } = opts;
64
311
  if (!resolveMemoryLifecycleCapabilities(config).projectionRebuild) return;
@@ -81,17 +328,41 @@ export async function maybeRebuildMemoryProjectionScheduled(opts: {
81
328
  return;
82
329
  }
83
330
 
331
+ const heapLimit = config.projectionRebuildHeapUsageLimit ?? DEFAULT_PROJECTION_REBUILD_HEAP_USAGE_LIMIT;
332
+ const heapStats = (opts.heapStatistics ?? (() => v8.getHeapStatistics()))();
333
+ const pressure = fullCorpusHeapPressure(heapStats, heapLimit);
334
+ if (pressure.postpone) {
335
+ state.lastFailureAtMs = Date.now();
336
+ log.warn(
337
+ `memory projection scheduled rebuild postponed for ${memoryDir}: `
338
+ + `heap used ${heapStats.used_heap_size} of limit ${heapStats.heap_size_limit} `
339
+ + `(ratio ${pressure.ratio.toFixed(3)}) exceeds projectionRebuildHeapUsageLimit ${heapLimit}`,
340
+ );
341
+ return;
342
+ }
343
+
344
+ const forkRebuild = opts.forkRebuild ?? forkProjectionRebuild;
345
+ const unlocked = storageIsUnlocked(rootStorage);
84
346
  state.inFlight = true;
85
347
  try {
86
- const result = await rebuildMemoryProjection({
87
- memoryDir,
88
- // Reuse the daemon's live storage so secure-store deployments rebuild
89
- // through the unlocked instance instead of a fresh locked one.
90
- ...(rootStorage ? { storage: rootStorage } : {}),
91
- defaultNamespace: config.defaultNamespace,
92
- dryRun: false,
93
- now: new Date(now),
94
- });
348
+ const result = unlocked
349
+ ? await rebuildMemoryProjection({
350
+ memoryDir,
351
+ // Reuse the daemon's live storage so secure-store deployments rebuild
352
+ // through the unlocked instance instead of a fresh locked one.
353
+ ...(rootStorage ? { storage: rootStorage } : {}),
354
+ defaultNamespace: config.defaultNamespace,
355
+ dryRun: false,
356
+ now: new Date(now),
357
+ })
358
+ : await forkRebuild({
359
+ memoryDir,
360
+ defaultNamespace: config.defaultNamespace || "default",
361
+ now: new Date(now),
362
+ }, {
363
+ timeoutMs: projectionRebuildForkTimeoutMs(intervalMs),
364
+ owner: state,
365
+ });
95
366
  state.lastRebuildAtMs = Date.now();
96
367
  const lag = Number.isFinite(rebuiltAtMs)
97
368
  ? `${Math.max(0, Math.round((now - rebuiltAtMs) / 60_000))}m stale`
@@ -632,21 +632,6 @@ export class SessionContextCoordinator {
632
632
  const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
633
633
  return canWriteNamespace(principal, req.namespace, this.deps.config);
634
634
  },
635
- llmComplete: async ({ system, user }) => {
636
- const llmResult = await this.deps.localLlm.chatCompletion(
637
- [
638
- { role: "system", content: system },
639
- { role: "user", content: user },
640
- ],
641
- { operation: "correction-classify", priority: "background" },
642
- );
643
- if (!llmResult) {
644
- throw new Error(
645
- "passive correction classify+draft: local LLM unavailable (disabled or in cooldown)",
646
- );
647
- }
648
- return llmResult.content;
649
- },
650
635
  });
651
636
  return this.deps._passiveCorrectionService;
652
637
  }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Scheduled projection-rebuild knobs (issue #2119, heap guard).
3
+ *
4
+ * Extracted from `config.ts` / `types.ts` so those god-file ceilings do not
5
+ * grow. `PluginConfig` extends the interface and `parseConfig` spreads
6
+ * {@link parseProjectionRebuildScheduleConfig}.
7
+ */
8
+
9
+ import { coerceBooleanLike, coerceNumber } from "./connectors/coerce.js";
10
+
11
+ /** Knobs for the maintenance-scheduled memory-projection rebuild. */
12
+ export interface ProjectionRebuildScheduleConfig {
13
+ /**
14
+ * Enable the maintenance-scheduled rebuild of `state/memory-projection.sqlite`.
15
+ * The projection is otherwise rebuild-only (manual CLI / tests), so it rots as
16
+ * the lifecycle ledger grows and timeline/browse consumers silently regress to
17
+ * full-corpus fallback scans. Default true — mirrors lifecycle-ledger
18
+ * auto-compaction, which is likewise enabled-by-default to keep a state file
19
+ * healthy. Set false to disable (operators can still cron the CLI rebuild).
20
+ */
21
+ projectionRebuildEnabled: boolean;
22
+ /**
23
+ * Minimum interval between scheduled projection rebuilds. A rebuild is skipped
24
+ * when the projection's `rebuiltAt` meta is younger than this, so a burst of
25
+ * maintenance requests cannot fan into back-to-back rebuilds. Floored at 60s.
26
+ * Default 6h (matches memoryLifecycleLedgerCompactMinIntervalMs).
27
+ */
28
+ projectionRebuildIntervalMs: number;
29
+ /**
30
+ * Postpone a scheduled full-corpus projection rebuild when
31
+ * `v8.getHeapStatistics().used_heap_size / heap_size_limit` exceeds this
32
+ * ratio. Finite number in `(0, 1]`. Default `0.6`. `1` disables the guard
33
+ * (usage cannot exceed the limit). A postponed rebuild uses the failure
34
+ * backoff and does not start the multi-GB allocation.
35
+ */
36
+ projectionRebuildHeapUsageLimit: number;
37
+ }
38
+
39
+ /** Integer coercion contract shared with `config.ts` (`parseIntegerAtLeast`). */
40
+ type IntegerParser = (value: unknown, fallback: number, min: number, keyName: string) => number;
41
+
42
+ /** Default heap-usage ratio above which a scheduled full-corpus rebuild waits. */
43
+ export const DEFAULT_PROJECTION_REBUILD_HEAP_USAGE_LIMIT = 0.6;
44
+
45
+ /**
46
+ * Parse `projectionRebuildHeapUsageLimit`. Absent values take the default.
47
+ * A present value must be a finite number in `(0, 1]` (numeric strings
48
+ * coerced). `0` is rejected: it would postpone every rebuild.
49
+ */
50
+ export function parseProjectionRebuildHeapUsageLimit(value: unknown): number {
51
+ if (value === undefined || value === null) return DEFAULT_PROJECTION_REBUILD_HEAP_USAGE_LIMIT;
52
+ const coerced = coerceNumber(value);
53
+ if (coerced === undefined || !Number.isFinite(coerced) || coerced <= 0 || coerced > 1) {
54
+ throw new Error(
55
+ `projectionRebuildHeapUsageLimit must be a finite number in (0, 1]; got ${JSON.stringify(value)}`,
56
+ );
57
+ }
58
+ return coerced;
59
+ }
60
+
61
+ /**
62
+ * Parse the scheduled projection-rebuild knobs. Boolean coercion follows
63
+ * gotcha #36 (`"false"` is false). The interval uses the shared integer
64
+ * parser (strings coerced, non-integers and sub-60s values rejected).
65
+ */
66
+ export function parseProjectionRebuildScheduleConfig(
67
+ cfg: Record<string, unknown>,
68
+ parseIntegerAtLeast: IntegerParser,
69
+ ): ProjectionRebuildScheduleConfig {
70
+ return {
71
+ projectionRebuildEnabled: coerceBooleanLike(cfg.projectionRebuildEnabled) ?? true,
72
+ projectionRebuildIntervalMs: parseIntegerAtLeast(
73
+ cfg.projectionRebuildIntervalMs,
74
+ 6 * 60 * 60 * 1000,
75
+ 60_000,
76
+ "projectionRebuildIntervalMs",
77
+ ),
78
+ projectionRebuildHeapUsageLimit: parseProjectionRebuildHeapUsageLimit(
79
+ cfg.projectionRebuildHeapUsageLimit,
80
+ ),
81
+ };
82
+ }
@@ -397,6 +397,30 @@ test("correctionPlan: a handle in targetIds is resolved before planning; an unkn
397
397
  }
398
398
  });
399
399
 
400
+ test("correctionPlan: a handle in duplicateOf is resolved before planning", async () => {
401
+ const { service, memoryDir } = await makeHarness({
402
+ recallMemoryHandles: true,
403
+ correctionEnabled: true,
404
+ });
405
+ try {
406
+ await assert.rejects(
407
+ () =>
408
+ service.correctionPlan({
409
+ text: "that memory is a duplicate",
410
+ targetIds: ["fact-loser"],
411
+ duplicateOf: "[m:dead]",
412
+ sessionKey: SESSION,
413
+ }),
414
+ (err: unknown) =>
415
+ err instanceof EngramAccessInputError &&
416
+ /not found/i.test((err as Error).message) &&
417
+ (err as Error).message.includes("[m:dead]"),
418
+ );
419
+ } finally {
420
+ await rm(memoryDir, { recursive: true, force: true });
421
+ }
422
+ });
423
+
400
424
  test("correctionPlan: a resolved handle targetIds set reaches the planner as concrete ids (round-trip)", async () => {
401
425
  const { orchestrator, service, memoryDir } = await makeHarness({
402
426
  recallMemoryHandles: true,
@@ -46,33 +46,41 @@ export type LedgerSecureReader = (filePath: string) => Promise<string>;
46
46
  export type LedgerSecureBufferReader = (filePath: string) => Promise<Buffer>;
47
47
 
48
48
  /**
49
- * Parse + canonically sort lifecycle rows from a line source. Permissive
50
- * validation (any `eventType` string is admitted) — matches the historical
51
- * `readAllMemoryLifecycleEvents` contract that projection rebuild depends on.
52
- * Fail-open on malformed rows.
49
+ * Parse one ledger line. Permissive validation (any `eventType` string is
50
+ * admitted) — matches the historical `readAllMemoryLifecycleEvents` contract
51
+ * that projection rebuild depends on. Fail-open on malformed rows.
52
+ */
53
+ function parseLifecycleLedgerLine(line: string): MemoryLifecycleEvent | null {
54
+ const row = line.trim();
55
+ if (!row) return null;
56
+ try {
57
+ const parsed = JSON.parse(row) as Partial<MemoryLifecycleEvent>;
58
+ if (
59
+ typeof parsed.eventId === "string" &&
60
+ typeof parsed.memoryId === "string" &&
61
+ typeof parsed.eventType === "string" &&
62
+ typeof parsed.timestamp === "string" &&
63
+ typeof parsed.actor === "string" &&
64
+ typeof parsed.ruleVersion === "string"
65
+ ) {
66
+ return parsed as MemoryLifecycleEvent;
67
+ }
68
+ } catch {
69
+ // Ignore malformed rows (fail-open).
70
+ }
71
+ return null;
72
+ }
73
+
74
+ /**
75
+ * Parse + canonically sort lifecycle rows from a line source.
53
76
  */
54
77
  async function collectLifecycleEvents(
55
78
  lines: AsyncIterable<string>,
56
79
  ): Promise<MemoryLifecycleEvent[]> {
57
80
  const out: MemoryLifecycleEvent[] = [];
58
81
  for await (const line of lines) {
59
- const row = line.trim();
60
- if (!row) continue;
61
- try {
62
- const parsed = JSON.parse(row) as Partial<MemoryLifecycleEvent>;
63
- if (
64
- typeof parsed.eventId === "string" &&
65
- typeof parsed.memoryId === "string" &&
66
- typeof parsed.eventType === "string" &&
67
- typeof parsed.timestamp === "string" &&
68
- typeof parsed.actor === "string" &&
69
- typeof parsed.ruleVersion === "string"
70
- ) {
71
- out.push(parsed as MemoryLifecycleEvent);
72
- }
73
- } catch {
74
- // Ignore malformed rows (fail-open).
75
- }
82
+ const parsed = parseLifecycleLedgerLine(line);
83
+ if (parsed) out.push(parsed);
76
84
  }
77
85
  return sortMemoryLifecycleEvents(out);
78
86
  }
@@ -116,27 +124,47 @@ async function* linesFromBuffer(
116
124
  }
117
125
 
118
126
  /**
119
- * Every valid ledger row in canonical order, read through the string-capped
120
- * secure line source (refuses an encrypted body over the whole-file decrypt
121
- * limit). General readers use this; compaction uses the uncapped buffer variant.
127
+ * Yield each valid ledger row in file order. Unlike
128
+ * {@link readAllLifecycleEventsFromLedger}, this does not accumulate or sort
129
+ * the ledger first. ENOENT yields nothing; a locked secure store rethrows.
130
+ * Malformed rows are skipped.
122
131
  */
123
- export async function readAllLifecycleEventsFromLedger(
132
+ export async function* iterateLifecycleEventsFromLedger(
124
133
  ledgerPath: string,
125
134
  readSecureFile: LedgerSecureReader,
126
- ): Promise<MemoryLifecycleEvent[]> {
135
+ ): AsyncGenerator<MemoryLifecycleEvent> {
136
+ let lines: AsyncGenerator<string>;
127
137
  try {
128
- return await collectLifecycleEvents(
129
- readMaybeEncryptedLines(
130
- ledgerPath,
131
- () => readSecureFile(ledgerPath),
132
- STATE_FILE_MAX_DECRYPT_BYTES,
133
- ),
138
+ lines = readMaybeEncryptedLines(
139
+ ledgerPath,
140
+ () => readSecureFile(ledgerPath),
141
+ STATE_FILE_MAX_DECRYPT_BYTES,
134
142
  );
135
143
  } catch (err) {
136
144
  if (err instanceof SecureStoreLockedError) throw err;
137
145
  if (!isErrnoCode(err, "ENOENT")) throw err;
138
- return [];
146
+ return;
139
147
  }
148
+ try {
149
+ for await (const line of lines) {
150
+ const parsed = parseLifecycleLedgerLine(line);
151
+ if (parsed) yield parsed;
152
+ }
153
+ } catch (err) {
154
+ if (err instanceof SecureStoreLockedError) throw err;
155
+ if (!isErrnoCode(err, "ENOENT")) throw err;
156
+ }
157
+ }
158
+
159
+ export async function readAllLifecycleEventsFromLedger(
160
+ ledgerPath: string,
161
+ readSecureFile: LedgerSecureReader,
162
+ ): Promise<MemoryLifecycleEvent[]> {
163
+ const out: MemoryLifecycleEvent[] = [];
164
+ for await (const event of iterateLifecycleEventsFromLedger(ledgerPath, readSecureFile)) {
165
+ out.push(event);
166
+ }
167
+ return sortMemoryLifecycleEvents(out);
140
168
  }
141
169
 
142
170
  /**
@@ -69,6 +69,7 @@ export interface MemoryReadStoreDeps {
69
69
  readParsedMemoriesFromPaths(
70
70
  filePaths: string[],
71
71
  batchSize?: number,
72
+ options?: CorpusReadOptions,
72
73
  ): Promise<MemoryFile[]>;
73
74
  readStorageSecureFile(filePath: string): Promise<string>;
74
75
  readWindowBoundedBatch(
@@ -466,7 +467,9 @@ export class MemoryReadStore {
466
467
  * covers any hot→cold demotion that changes cold-tier contents) and
467
468
  * expires after COLD_SCAN_CACHE_TTL_MS as a safety net.
468
469
  */
469
- async readAllColdMemories(): Promise<MemoryFile[]> {
470
+ async readAllColdMemories(options?: CorpusReadOptions): Promise<MemoryFile[]> {
471
+ checkCorpusReadAbort(options);
472
+ const retainRaw = options?.retainRaw !== false;
470
473
  const coldRoot = this.deps.resolveTierRootDir("cold");
471
474
 
472
475
  // Read the on-disk cold-version sentinel BEFORE checking the cache so that
@@ -480,7 +483,7 @@ export class MemoryReadStore {
480
483
  // decrypts per this manager's key, so a differently-keyed manager must not
481
484
  // read a cold corpus another instance decrypted for the same coldRoot.
482
485
  const keyId = this.deps.hotCacheKeyId();
483
- const cached = this.deps.storageManagerClass.coldMemoriesCache.get(coldRoot);
486
+ const cached = retainRaw ? this.deps.storageManagerClass.coldMemoriesCache.get(coldRoot) : undefined;
484
487
  if (
485
488
  cached &&
486
489
  cached.keyId === keyId &&
@@ -518,11 +521,14 @@ export class MemoryReadStore {
518
521
  // and ensures that any memory with structuredAttributes is found regardless
519
522
  // of which category it was written with.
520
523
  await collectPaths(coldRoot);
521
- const memories = await this.deps.readParsedMemoriesFromPaths(filePaths, 50);
524
+ const memories = await this.deps.readParsedMemoriesFromPaths(filePaths, 50, options);
522
525
 
523
526
  // Store in cache with the sentinel version captured above so that any
524
527
  // subsequent cold-version bump (by this or another process) invalidates it.
525
- this.deps.storageManagerClass.coldMemoriesCache.set(coldRoot, { memories, loadedAt: Date.now(), coldVersion: currentColdVersion, keyId });
528
+ // A raw-free read stays out of the cache so it cannot evict the raw copy.
529
+ if (retainRaw) {
530
+ this.deps.storageManagerClass.coldMemoriesCache.set(coldRoot, { memories, loadedAt: Date.now(), coldVersion: currentColdVersion, keyId });
531
+ }
526
532
  return memories;
527
533
  }
528
534