@remnic/core 9.39.0 → 9.41.0

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 (347) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -10
  2. package/dist/access-admin-ops-surface.js +13 -12
  3. package/dist/access-authorization-probe.d.ts +10 -10
  4. package/dist/access-authorization-probe.js +14 -13
  5. package/dist/access-boundary.d.ts +10 -10
  6. package/dist/access-boundary.js +13 -12
  7. package/dist/access-cli.js +35 -34
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +10 -10
  10. package/dist/access-extraction-force-flush.js +13 -12
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +10 -10
  13. package/dist/access-http-lifecycle-flush.d.ts +10 -10
  14. package/dist/access-http.d.ts +10 -10
  15. package/dist/access-http.js +18 -17
  16. package/dist/access-identity-continuity-surface.d.ts +8 -8
  17. package/dist/access-identity-continuity-surface.js +13 -12
  18. package/dist/access-lcm-surface.d.ts +10 -10
  19. package/dist/access-lcm-surface.js +13 -12
  20. package/dist/access-mcp.d.ts +10 -10
  21. package/dist/access-mcp.js +16 -15
  22. package/dist/access-memory-search-fanout.d.ts +2 -2
  23. package/dist/{access-namespace-preflight-CWyL4Zai.d.ts → access-namespace-preflight-47dOyty9.d.ts} +1 -1
  24. package/dist/access-namespace-preflight.d.ts +3 -3
  25. package/dist/access-namespace-preflight.js +13 -12
  26. package/dist/access-observe-write-surface.d.ts +10 -10
  27. package/dist/access-observe-write-surface.js +13 -12
  28. package/dist/access-operations-batch.js +14 -13
  29. package/dist/access-operations.d.ts +13 -13
  30. package/dist/access-operations.js +15 -14
  31. package/dist/access-recall-concurrency.d.ts +10 -10
  32. package/dist/access-recall-concurrency.js +13 -12
  33. package/dist/access-recall-response.d.ts +10 -10
  34. package/dist/access-recall-response.js +13 -12
  35. package/dist/access-recall-surface.d.ts +10 -10
  36. package/dist/access-recall-surface.js +13 -12
  37. package/dist/access-schema.d.ts +84 -84
  38. package/dist/{access-service-C6QuKBCG.d.ts → access-service-D1BkxwSf.d.ts} +7 -7
  39. package/dist/access-service-helpers.d.ts +10 -10
  40. package/dist/access-service.d.ts +10 -10
  41. package/dist/access-service.js +13 -12
  42. package/dist/access-surface-catalog.d.ts +10 -10
  43. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  44. package/dist/action-confidence.d.ts +1 -1
  45. package/dist/active-memory-bridge.d.ts +1 -1
  46. package/dist/active-recall.d.ts +1 -1
  47. package/dist/active-recall.js +2 -2
  48. package/dist/behavior-learner.d.ts +1 -1
  49. package/dist/behavior-signals.d.ts +1 -1
  50. package/dist/bootstrap.d.ts +8 -8
  51. package/dist/briefing.d.ts +2 -2
  52. package/dist/briefing.js +3 -3
  53. package/dist/buffer-surprise-report.d.ts +1 -1
  54. package/dist/buffer-turn-helpers.d.ts +1 -1
  55. package/dist/buffer.d.ts +2 -2
  56. package/dist/bulk-import/index.d.ts +3 -3
  57. package/dist/calibration.d.ts +1 -1
  58. package/dist/capabilities.d.ts +1 -1
  59. package/dist/{catalog-Du4bpZWM.d.ts → catalog-DPQynQZG.d.ts} +1 -1
  60. package/dist/causal-behavior.d.ts +1 -1
  61. package/dist/causal-consolidation.d.ts +1 -1
  62. package/dist/causal-consolidation.js +4 -4
  63. package/dist/causal-trajectory-graph.d.ts +1 -1
  64. package/dist/{chunk-AVGTOOYP.js → chunk-3C2TGBDB.js} +2 -2
  65. package/dist/{chunk-443XCR34.js → chunk-3SG4FGDV.js} +53 -41
  66. package/dist/chunk-3SG4FGDV.js.map +1 -0
  67. package/dist/{chunk-MHCRASVK.js → chunk-5N26WBPQ.js} +2 -2
  68. package/dist/{chunk-CMFUYOYB.js → chunk-5TOV3D6U.js} +2 -2
  69. package/dist/{chunk-SHTPVI47.js → chunk-6GIMMNVK.js} +3 -3
  70. package/dist/{chunk-5JUYBWJD.js → chunk-6I2C3EOH.js} +18 -18
  71. package/dist/chunk-7VIB7PAE.js +142 -0
  72. package/dist/chunk-7VIB7PAE.js.map +1 -0
  73. package/dist/{chunk-CNZLKQEL.js → chunk-AXUU7SG3.js} +2 -2
  74. package/dist/{chunk-7ERHAARG.js → chunk-BI6RE2ZS.js} +2 -2
  75. package/dist/{chunk-GYGXKATH.js → chunk-CQ5MR2HQ.js} +16 -12
  76. package/dist/chunk-CQ5MR2HQ.js.map +1 -0
  77. package/dist/{chunk-CYM2PHLB.js → chunk-CWPDM66T.js} +8 -7
  78. package/dist/chunk-CWPDM66T.js.map +1 -0
  79. package/dist/{chunk-UGAZILZG.js → chunk-F2KMAFEB.js} +2 -2
  80. package/dist/{chunk-G57BGHQ2.js → chunk-FHEJ22B7.js} +11 -5
  81. package/dist/chunk-FHEJ22B7.js.map +1 -0
  82. package/dist/{chunk-DMT2RGAZ.js → chunk-FXGLFGIG.js} +3 -3
  83. package/dist/{chunk-6BNE62PM.js → chunk-GDC4INBF.js} +2 -2
  84. package/dist/{chunk-HXDWZFNP.js → chunk-GSL47NPM.js} +1 -1
  85. package/dist/chunk-GSL47NPM.js.map +1 -0
  86. package/dist/{chunk-DJH35IVS.js → chunk-JDXDA5OO.js} +2 -2
  87. package/dist/{chunk-ZBDORYWM.js → chunk-KPJQTSRJ.js} +2 -2
  88. package/dist/{chunk-CPD6C6K6.js → chunk-KXGN6G2Y.js} +3 -3
  89. package/dist/chunk-KXGN6G2Y.js.map +1 -0
  90. package/dist/{chunk-F5EVTFQK.js → chunk-MSXWUXFE.js} +2 -2
  91. package/dist/{chunk-XSPD6KQL.js → chunk-MVW234LO.js} +2 -2
  92. package/dist/{chunk-5TRIAPT4.js → chunk-NHRNYJPJ.js} +4 -4
  93. package/dist/{chunk-VGK33D3K.js → chunk-OEXKYYVH.js} +2 -2
  94. package/dist/{chunk-VK33JSBR.js → chunk-OYFDEJZB.js} +23 -6
  95. package/dist/chunk-OYFDEJZB.js.map +1 -0
  96. package/dist/{chunk-JKTHT4KX.js → chunk-PWKZV4A3.js} +3 -3
  97. package/dist/{chunk-BVJIAIB3.js → chunk-Q4XL7LJW.js} +32 -11
  98. package/dist/chunk-Q4XL7LJW.js.map +1 -0
  99. package/dist/{chunk-AL73FWSS.js → chunk-QY66HJ4X.js} +2 -2
  100. package/dist/{chunk-KWU6MAD4.js → chunk-R4Q7CQGZ.js} +2 -2
  101. package/dist/{chunk-IB26HVAJ.js → chunk-TM72UOX2.js} +3 -3
  102. package/dist/chunk-TM72UOX2.js.map +1 -0
  103. package/dist/{chunk-MYXWPG5O.js → chunk-TXBU7YDV.js} +2 -2
  104. package/dist/{chunk-KJP2R5MJ.js → chunk-UGCUVLOL.js} +25 -21
  105. package/dist/chunk-UGCUVLOL.js.map +1 -0
  106. package/dist/{chunk-7OCTH7AJ.js → chunk-UQVGDEAJ.js} +2 -2
  107. package/dist/{chunk-VQTRSX4R.js → chunk-WGCTFGLW.js} +2 -2
  108. package/dist/{chunk-4CSTEPFA.js → chunk-XRWVXPEM.js} +2 -2
  109. package/dist/{chunk-ENLZOWYK.js → chunk-ZERSIPFC.js} +2 -2
  110. package/dist/{cli-ClXRCu08.d.ts → cli-IUhV-lmk.d.ts} +5 -5
  111. package/dist/cli.d.ts +12 -12
  112. package/dist/cli.js +30 -29
  113. package/dist/compounding/engine.d.ts +2 -2
  114. package/dist/compounding/engine.js +3 -3
  115. package/dist/compounding/preference-consolidator.d.ts +1 -1
  116. package/dist/compression-optimizer.d.ts +1 -1
  117. package/dist/config.d.ts +1 -1
  118. package/dist/config.js +2 -2
  119. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  120. package/dist/connectors/codex-materialize-runner.js +3 -3
  121. package/dist/connectors/codex-materialize.d.ts +1 -1
  122. package/dist/connectors/index.d.ts +1 -1
  123. package/dist/connectors/index.js +3 -3
  124. package/dist/consolidation-provenance-check.d.ts +2 -2
  125. package/dist/consolidation-undo.d.ts +2 -2
  126. package/dist/contradiction/index.d.ts +2 -2
  127. package/dist/conversation-index/backend.d.ts +1 -1
  128. package/dist/conversation-index/chunker.d.ts +1 -1
  129. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  130. package/dist/conversation-index/indexer.d.ts +1 -1
  131. package/dist/conversation-index/search.d.ts +1 -1
  132. package/dist/corpus-watermark.d.ts +7 -1
  133. package/dist/corpus-watermark.js +5 -5
  134. package/dist/day-summary.d.ts +1 -1
  135. package/dist/delinearize.d.ts +1 -1
  136. package/dist/direct-answer-wiring.d.ts +1 -1
  137. package/dist/direct-answer.d.ts +1 -1
  138. package/dist/embedding-fallback.d.ts +1 -1
  139. package/dist/enrichment/index.d.ts +1 -1
  140. package/dist/entity-retrieval.d.ts +2 -2
  141. package/dist/entity-retrieval.js +3 -3
  142. package/dist/entity-schema.d.ts +1 -1
  143. package/dist/explicit-capture.d.ts +8 -8
  144. package/dist/extraction-error-classification.d.ts +1 -1
  145. package/dist/extraction-faithfulness.d.ts +1 -1
  146. package/dist/extraction-judge-telemetry.d.ts +1 -1
  147. package/dist/extraction-judge-training.d.ts +1 -1
  148. package/dist/extraction-judge.d.ts +1 -1
  149. package/dist/extraction-liveness.d.ts +1 -1
  150. package/dist/extraction-liveness.js +3 -1
  151. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  152. package/dist/extraction-source-grounding.d.ts +1 -1
  153. package/dist/extraction.d.ts +1 -1
  154. package/dist/extraction.js +3 -3
  155. package/dist/fallback-llm.d.ts +1 -1
  156. package/dist/graph-dashboard-diff.d.ts +1 -1
  157. package/dist/graph-dashboard-key.d.ts +1 -1
  158. package/dist/graph-dashboard-parser.d.ts +1 -1
  159. package/dist/graph-edge-reinforcement.d.ts +1 -1
  160. package/dist/graph-snapshot.d.ts +1 -1
  161. package/dist/graph.d.ts +1 -1
  162. package/dist/importance.d.ts +1 -1
  163. package/dist/importers/index.d.ts +1 -1
  164. package/dist/in-flight-reads.d.ts +1 -1
  165. package/dist/index.d.ts +407 -407
  166. package/dist/index.js +35 -34
  167. package/dist/intent.d.ts +1 -1
  168. package/dist/lcm/engine.d.ts +1 -1
  169. package/dist/lcm/index.d.ts +1 -1
  170. package/dist/lcm/tools.d.ts +1 -1
  171. package/dist/lifecycle.d.ts +1 -1
  172. package/dist/live-connectors-runner.d.ts +1 -1
  173. package/dist/local-llm.d.ts +1 -1
  174. package/dist/local-model-endpoint.d.ts +1 -1
  175. package/dist/maintenance/memory-governance.d.ts +1 -1
  176. package/dist/maintenance/memory-governance.js +3 -3
  177. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  178. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  179. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  180. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  181. package/dist/{maintenance-Dsvprbod.d.ts → maintenance-DVBLXkFw.d.ts} +3 -3
  182. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  183. package/dist/memory-action-policy.d.ts +1 -1
  184. package/dist/memory-cache.d.ts +1 -1
  185. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  186. package/dist/memory-projection-store.d.ts +1 -1
  187. package/dist/memory-provenance.d.ts +1 -1
  188. package/dist/memory-worth-outcomes.d.ts +2 -2
  189. package/dist/models-json.d.ts +1 -1
  190. package/dist/namespaces/migrate.d.ts +4 -3
  191. package/dist/namespaces/migrate.js +4 -4
  192. package/dist/namespaces/principal.d.ts +1 -1
  193. package/dist/namespaces/search.d.ts +1 -1
  194. package/dist/namespaces/storage.d.ts +3 -3
  195. package/dist/namespaces/storage.js +3 -3
  196. package/dist/native-knowledge.d.ts +1 -1
  197. package/dist/offline-sync-impression-drain.d.ts +1 -1
  198. package/dist/operator-doctor-corpus.d.ts +1 -1
  199. package/dist/operator-doctor-corpus.js +6 -6
  200. package/dist/operator-doctor-replica.d.ts +1 -1
  201. package/dist/operator-toolkit.d.ts +5 -4
  202. package/dist/operator-toolkit.js +12 -11
  203. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  204. package/dist/orchestration/maintenance.d.ts +4 -4
  205. package/dist/orchestration/maintenance.js +8 -8
  206. package/dist/{orchestrator-CEhod0MJ.d.ts → orchestrator-fYTncnLy.d.ts} +7 -7
  207. package/dist/orchestrator.d.ts +8 -8
  208. package/dist/orchestrator.js +35 -34
  209. package/dist/patterns-cli.d.ts +1 -1
  210. package/dist/{pipeline-DSLWFeHz.d.ts → pipeline-Cs76XC-p.d.ts} +1 -1
  211. package/dist/policy-runtime.d.ts +1 -1
  212. package/dist/proactive-contention.d.ts +1 -1
  213. package/dist/provenance.d.ts +1 -1
  214. package/dist/{qmd-BSDGyr0H.d.ts → qmd-WJwvBgiF.d.ts} +1 -1
  215. package/dist/qmd-preflight.d.ts +2 -2
  216. package/dist/qmd-recall-cache.d.ts +1 -1
  217. package/dist/qmd.d.ts +2 -2
  218. package/dist/recall-concurrency-config.d.ts +1 -1
  219. package/dist/recall-disclosure-escalation.d.ts +1 -1
  220. package/dist/recall-explain-renderer.d.ts +1 -1
  221. package/dist/recall-explain-renderer.js +3 -3
  222. package/dist/recall-memory-map.d.ts +1 -1
  223. package/dist/recall-planner-llm.d.ts +1 -1
  224. package/dist/recall-state.d.ts +1 -1
  225. package/dist/recall-tag-filter.d.ts +1 -1
  226. package/dist/recall-timings.d.ts +1 -1
  227. package/dist/recall-xray-cli.d.ts +1 -1
  228. package/dist/recall-xray-cli.js +4 -4
  229. package/dist/recall-xray-renderer.d.ts +1 -1
  230. package/dist/recall-xray-renderer.js +3 -3
  231. package/dist/recall-xray.d.ts +1 -1
  232. package/dist/recall-xray.js +2 -2
  233. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  234. package/dist/replay/normalizers/claude.d.ts +1 -1
  235. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  236. package/dist/replay/normalizers/shared.d.ts +1 -1
  237. package/dist/replay/runner.d.ts +1 -1
  238. package/dist/replay/types.d.ts +1 -1
  239. package/dist/replica-divergence.d.ts +1 -1
  240. package/dist/replica-peers-config.d.ts +1 -1
  241. package/dist/resolve-auth-token.d.ts +1 -1
  242. package/dist/resume-bundles.js +3 -3
  243. package/dist/retrieval-agents.d.ts +2 -2
  244. package/dist/retrieval-tiers.d.ts +1 -1
  245. package/dist/routing/engine.d.ts +1 -1
  246. package/dist/routing/store.d.ts +1 -1
  247. package/dist/salvage-envelope.d.ts +1 -1
  248. package/dist/schemas.d.ts +76 -76
  249. package/dist/{scope-profiles-C4zY-a2K.d.ts → scope-profiles-CQ0NAleS.d.ts} +1 -1
  250. package/dist/search/embed-helper.d.ts +1 -1
  251. package/dist/search/factory.d.ts +1 -1
  252. package/dist/search/index.d.ts +1 -1
  253. package/dist/search/lancedb-backend.d.ts +1 -1
  254. package/dist/search/meilisearch-backend.d.ts +1 -1
  255. package/dist/search/noop-backend.d.ts +1 -1
  256. package/dist/search/orama-backend.d.ts +1 -1
  257. package/dist/search/port.d.ts +1 -1
  258. package/dist/search/remote-backend.d.ts +1 -1
  259. package/dist/{semantic-consolidation-ChKRYpRO.d.ts → semantic-consolidation-BWxOBMtz.d.ts} +1 -1
  260. package/dist/semantic-consolidation.d.ts +2 -2
  261. package/dist/semantic-consolidation.js +4 -4
  262. package/dist/semantic-rule-promotion.js +3 -3
  263. package/dist/semantic-rule-verifier.d.ts +1 -1
  264. package/dist/semantic-rule-verifier.js +3 -3
  265. package/dist/{service-BlOfGid8.d.ts → service-CLuMO-pa.d.ts} +2 -2
  266. package/dist/session-observer-bands.d.ts +1 -1
  267. package/dist/session-observer-state.d.ts +1 -1
  268. package/dist/shared-context/manager.d.ts +9 -9
  269. package/dist/signal.d.ts +1 -1
  270. package/dist/source-agent-qualifier.d.ts +1 -1
  271. package/dist/source-agent-qualifier.js +3 -3
  272. package/dist/{storage-CNKZocJF.d.ts → storage-Blr71GpS.d.ts} +1 -1
  273. package/dist/storage.d.ts +2 -2
  274. package/dist/storage.js +2 -2
  275. package/dist/summarizer.d.ts +1 -1
  276. package/dist/summary-snapshot.d.ts +1 -1
  277. package/dist/temporal-supersession.d.ts +2 -2
  278. package/dist/temporal-timeline-recall.d.ts +1 -1
  279. package/dist/temporal-validity.d.ts +1 -1
  280. package/dist/threading.d.ts +1 -1
  281. package/dist/tier-migration.d.ts +2 -2
  282. package/dist/tier-routing.d.ts +1 -1
  283. package/dist/topics.d.ts +1 -1
  284. package/dist/transcript.d.ts +1 -1
  285. package/dist/transfer/types.d.ts +66 -66
  286. package/dist/trust-score-stage.d.ts +1 -1
  287. package/dist/trust-score.d.ts +1 -1
  288. package/dist/{types-5398p7Zm.d.ts → types-CqWwMPr_.d.ts} +42 -66
  289. package/dist/types.d.ts +1 -1
  290. package/dist/types.js +1 -1
  291. package/dist/utility-runtime.d.ts +1 -1
  292. package/dist/verified-recall.js +3 -3
  293. package/dist/write-envelope.d.ts +1 -1
  294. package/package.json +2 -2
  295. package/src/access-http.test.ts +62 -2
  296. package/src/access-http.ts +2 -1
  297. package/src/access-service-health.test.ts +39 -17
  298. package/src/access-service.ts +25 -3
  299. package/src/access-surface-catalog.test.ts +1 -0
  300. package/src/cli.ts +3 -3
  301. package/src/config.test.ts +4 -0
  302. package/src/config.ts +1 -5
  303. package/src/corpus-watermark.test.ts +16 -0
  304. package/src/corpus-watermark.ts +28 -5
  305. package/src/extraction-liveness.test.ts +81 -19
  306. package/src/extraction-liveness.ts +96 -98
  307. package/src/extraction-watermark.test.ts +290 -0
  308. package/src/namespaces/migrate.ts +10 -2
  309. package/src/operator-doctor-corpus.test.ts +7 -0
  310. package/src/operator-doctor-corpus.ts +1 -1
  311. package/src/operator-toolkit.ts +8 -8
  312. package/src/orchestration/extraction-watermark.ts +188 -0
  313. package/src/types.ts +1 -7
  314. package/dist/chunk-443XCR34.js.map +0 -1
  315. package/dist/chunk-BVJIAIB3.js.map +0 -1
  316. package/dist/chunk-CPD6C6K6.js.map +0 -1
  317. package/dist/chunk-CYM2PHLB.js.map +0 -1
  318. package/dist/chunk-G57BGHQ2.js.map +0 -1
  319. package/dist/chunk-GYGXKATH.js.map +0 -1
  320. package/dist/chunk-HXDWZFNP.js.map +0 -1
  321. package/dist/chunk-IB26HVAJ.js.map +0 -1
  322. package/dist/chunk-KJP2R5MJ.js.map +0 -1
  323. package/dist/chunk-VK33JSBR.js.map +0 -1
  324. /package/dist/{chunk-AVGTOOYP.js.map → chunk-3C2TGBDB.js.map} +0 -0
  325. /package/dist/{chunk-MHCRASVK.js.map → chunk-5N26WBPQ.js.map} +0 -0
  326. /package/dist/{chunk-CMFUYOYB.js.map → chunk-5TOV3D6U.js.map} +0 -0
  327. /package/dist/{chunk-SHTPVI47.js.map → chunk-6GIMMNVK.js.map} +0 -0
  328. /package/dist/{chunk-5JUYBWJD.js.map → chunk-6I2C3EOH.js.map} +0 -0
  329. /package/dist/{chunk-CNZLKQEL.js.map → chunk-AXUU7SG3.js.map} +0 -0
  330. /package/dist/{chunk-7ERHAARG.js.map → chunk-BI6RE2ZS.js.map} +0 -0
  331. /package/dist/{chunk-UGAZILZG.js.map → chunk-F2KMAFEB.js.map} +0 -0
  332. /package/dist/{chunk-DMT2RGAZ.js.map → chunk-FXGLFGIG.js.map} +0 -0
  333. /package/dist/{chunk-6BNE62PM.js.map → chunk-GDC4INBF.js.map} +0 -0
  334. /package/dist/{chunk-DJH35IVS.js.map → chunk-JDXDA5OO.js.map} +0 -0
  335. /package/dist/{chunk-ZBDORYWM.js.map → chunk-KPJQTSRJ.js.map} +0 -0
  336. /package/dist/{chunk-F5EVTFQK.js.map → chunk-MSXWUXFE.js.map} +0 -0
  337. /package/dist/{chunk-XSPD6KQL.js.map → chunk-MVW234LO.js.map} +0 -0
  338. /package/dist/{chunk-5TRIAPT4.js.map → chunk-NHRNYJPJ.js.map} +0 -0
  339. /package/dist/{chunk-VGK33D3K.js.map → chunk-OEXKYYVH.js.map} +0 -0
  340. /package/dist/{chunk-JKTHT4KX.js.map → chunk-PWKZV4A3.js.map} +0 -0
  341. /package/dist/{chunk-AL73FWSS.js.map → chunk-QY66HJ4X.js.map} +0 -0
  342. /package/dist/{chunk-KWU6MAD4.js.map → chunk-R4Q7CQGZ.js.map} +0 -0
  343. /package/dist/{chunk-MYXWPG5O.js.map → chunk-TXBU7YDV.js.map} +0 -0
  344. /package/dist/{chunk-7OCTH7AJ.js.map → chunk-UQVGDEAJ.js.map} +0 -0
  345. /package/dist/{chunk-VQTRSX4R.js.map → chunk-WGCTFGLW.js.map} +0 -0
  346. /package/dist/{chunk-4CSTEPFA.js.map → chunk-XRWVXPEM.js.map} +0 -0
  347. /package/dist/{chunk-ENLZOWYK.js.map → chunk-ZERSIPFC.js.map} +0 -0
@@ -0,0 +1,290 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { TOKEN_CAPABILITIES_VERSION } from "./access-token-capabilities.js";
8
+ import { parseConfig } from "./config.js";
9
+ import { CorpusWatermarkCache } from "./corpus-watermark.js";
10
+ import { readAggregateExtractionWatermark } from "./orchestration/extraction-watermark.js";
11
+ import type { PluginConfig } from "./types.js";
12
+
13
+ interface FakeWatermarkStorage {
14
+ readonly dir: string;
15
+ loadMeta(): Promise<{ lastExtractionAt: string | null }>;
16
+ }
17
+
18
+ function storage(dir: string, read: () => Promise<string | null>): FakeWatermarkStorage {
19
+ return {
20
+ dir,
21
+ loadMeta: async () => ({ lastExtractionAt: await read() }),
22
+ };
23
+ }
24
+
25
+ async function namespacedFixture(): Promise<{
26
+ memoryDir: string;
27
+ config: PluginConfig;
28
+ namespaceDirs: Record<string, string>;
29
+ }> {
30
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-extraction-watermark-"));
31
+ const namespaceDirs = {
32
+ "team-a": path.join(memoryDir, "namespaces", "team-a"),
33
+ "team-b": path.join(memoryDir, "namespaces", "team-b"),
34
+ };
35
+ await Promise.all(Object.values(namespaceDirs).map((dir) => mkdir(dir, { recursive: true })));
36
+ return {
37
+ memoryDir,
38
+ config: parseConfig({ memoryDir, namespacesEnabled: true, defaultNamespace: "default" }),
39
+ namespaceDirs,
40
+ };
41
+ }
42
+
43
+ test("aggregate watermark selects the most recent extraction across distinct namespace stores", async () => {
44
+ const fixture = await namespacedFixture();
45
+ try {
46
+ const timestamps = {
47
+ default: "2026-07-20T12:00:00.000Z",
48
+ "team-a": "2026-07-21T12:00:00.000Z",
49
+ "team-b": "2026-07-22T12:00:00.000Z",
50
+ };
51
+ const result = await readAggregateExtractionWatermark({
52
+ config: fixture.config,
53
+ rootStorage: storage(fixture.memoryDir, async () => timestamps.default),
54
+ storageForNamespace: async (namespace) =>
55
+ storage(fixture.namespaceDirs[namespace], async () => timestamps[namespace as keyof typeof timestamps]),
56
+ });
57
+
58
+ assert.deepEqual(result, {
59
+ lastExtractionAt: timestamps["team-b"],
60
+ readFailed: false,
61
+ });
62
+ } finally {
63
+ await rm(fixture.memoryDir, { recursive: true, force: true });
64
+ }
65
+ });
66
+
67
+ test("a namespace-isolated extraction advances the daemon aggregate watermark", async () => {
68
+ const fixture = await namespacedFixture();
69
+ try {
70
+ const rootTimestamp = "2026-07-20T12:00:00.000Z";
71
+ let teamTimestamp = "2026-07-19T12:00:00.000Z";
72
+ const options = {
73
+ config: fixture.config,
74
+ rootStorage: storage(fixture.memoryDir, async () => rootTimestamp),
75
+ storageForNamespace: async (namespace: string) =>
76
+ storage(fixture.namespaceDirs[namespace], async () => (namespace === "team-a" ? teamTimestamp : null)),
77
+ };
78
+
79
+ assert.equal((await readAggregateExtractionWatermark(options)).lastExtractionAt, rootTimestamp);
80
+ teamTimestamp = "2026-07-23T12:00:00.000Z";
81
+ assert.equal((await readAggregateExtractionWatermark(options)).lastExtractionAt, teamTimestamp);
82
+ } finally {
83
+ await rm(fixture.memoryDir, { recursive: true, force: true });
84
+ }
85
+ });
86
+
87
+ test("a partial namespace read returns readFailed instead of a survivor's fresh watermark", async () => {
88
+ const fixture = await namespacedFixture();
89
+ try {
90
+ const result = await readAggregateExtractionWatermark({
91
+ config: fixture.config,
92
+ rootStorage: storage(fixture.memoryDir, async () => "2026-07-23T12:00:00.000Z"),
93
+ storageForNamespace: async (namespace) =>
94
+ storage(fixture.namespaceDirs[namespace], async () => {
95
+ if (namespace === "team-b") throw new Error("meta store unavailable");
96
+ return "2026-07-22T12:00:00.000Z";
97
+ }),
98
+ });
99
+
100
+ assert.equal(result.lastExtractionAt, null, "a surviving timestamp must not be reported as complete");
101
+ assert.equal(result.readFailed, true);
102
+ assert.match(result.readError ?? "", /namespace watermark unreadable/);
103
+ assert.match(result.readError ?? "", /meta store unavailable/);
104
+ } finally {
105
+ await rm(fixture.memoryDir, { recursive: true, force: true });
106
+ }
107
+ });
108
+ test("scoped capabilities filter candidate namespaces during aggregate read", async () => {
109
+ const fixture = await namespacedFixture();
110
+ try {
111
+ let scannedTeamB = false;
112
+ const result = await readAggregateExtractionWatermark({
113
+ config: fixture.config,
114
+ rootStorage: storage(fixture.memoryDir, async () => "2026-07-20T12:00:00.000Z"),
115
+ storageForNamespace: async (namespace) => {
116
+ if (namespace === "team-b") scannedTeamB = true;
117
+ return storage(fixture.namespaceDirs[namespace], async () => "2026-07-25T12:00:00.000Z");
118
+ },
119
+ caps: { version: TOKEN_CAPABILITIES_VERSION, namespaces: ["team-a"] },
120
+ });
121
+
122
+ assert.equal(scannedTeamB, false, "team-b should be skipped when token is restricted to team-a");
123
+ assert.equal(result.readFailed, false);
124
+ } finally {
125
+ await rm(fixture.memoryDir, { recursive: true, force: true });
126
+ }
127
+ });
128
+
129
+ test("default root capability check uses normalized aliases for migrated storage", async () => {
130
+ const fixture = await namespacedFixture();
131
+ try {
132
+ const migratedDefaultDir = path.join(fixture.memoryDir, "namespaces", "default");
133
+ await mkdir(migratedDefaultDir, { recursive: true });
134
+ const result = await readAggregateExtractionWatermark({
135
+ config: { ...fixture.config, defaultNamespace: " default " },
136
+ rootStorage: storage(fixture.memoryDir, async () => {
137
+ throw new Error("inactive legacy root is unreadable");
138
+ }),
139
+ storageForNamespace: async (_namespace, rootDir) =>
140
+ storage(rootDir, async () =>
141
+ path.resolve(rootDir) === path.resolve(migratedDefaultDir)
142
+ ? "2026-07-26T12:00:00.000Z"
143
+ : "2026-07-24T12:00:00.000Z",
144
+ ),
145
+ caps: { version: TOKEN_CAPABILITIES_VERSION, namespaces: ["default"] },
146
+ });
147
+
148
+ assert.equal(result.lastExtractionAt, "2026-07-26T12:00:00.000Z");
149
+ assert.equal(result.readFailed, false);
150
+ } finally {
151
+ await rm(fixture.memoryDir, { recursive: true, force: true });
152
+ }
153
+ });
154
+ test("unparsable non-null timestamp in namespace store fails the aggregate read", async () => {
155
+ const fixture = await namespacedFixture();
156
+ try {
157
+ const result = await readAggregateExtractionWatermark({
158
+ config: fixture.config,
159
+ rootStorage: storage(fixture.memoryDir, async () => "2026-07-20T12:00:00.000Z"),
160
+ storageForNamespace: async (namespace) =>
161
+ storage(fixture.namespaceDirs[namespace], async () => (namespace === "team-a" ? "invalid-date-string" : "2026-07-25T12:00:00.000Z")),
162
+ });
163
+
164
+ assert.equal(result.lastExtractionAt, null);
165
+ assert.equal(result.readFailed, true);
166
+ assert.match(result.readError ?? "", /watermark timestamp invalid/);
167
+ } finally {
168
+ await rm(fixture.memoryDir, { recursive: true, force: true });
169
+ }
170
+ });
171
+
172
+ test("namespace discovery I/O failure is an explicit incomplete read", async () => {
173
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-extraction-watermark-enumeration-"));
174
+ try {
175
+ await writeFile(path.join(memoryDir, "namespaces"), "not a directory", "utf8");
176
+ const config = parseConfig({ memoryDir, namespacesEnabled: true });
177
+ const result = await readAggregateExtractionWatermark({
178
+ config,
179
+ rootStorage: storage(memoryDir, async () => "2026-07-23T12:00:00.000Z"),
180
+ storageForNamespace: async (_namespace, rootDir) => storage(rootDir, async () => null),
181
+ });
182
+
183
+ assert.equal(result.lastExtractionAt, null);
184
+ assert.equal(result.readFailed, true);
185
+ assert.match(result.readError ?? "", /namespace watermark enumeration failed/);
186
+ assert.match(result.readError ?? "", /ENOTDIR/);
187
+ } finally {
188
+ await rm(memoryDir, { recursive: true, force: true });
189
+ }
190
+ });
191
+
192
+ test("a failed stale-cache refresh makes later reads incomplete", async () => {
193
+ const fixture = await namespacedFixture();
194
+ try {
195
+ let now = 1;
196
+ const cache = new CorpusWatermarkCache({ ttlMs: 1, clock: () => now });
197
+ const options = {
198
+ config: fixture.config,
199
+ rootStorage: storage(fixture.memoryDir, async () => "2026-07-20T12:00:00.000Z"),
200
+ storageForNamespace: async (namespace: string) =>
201
+ storage(fixture.namespaceDirs[namespace], async () => "2026-07-21T12:00:00.000Z"),
202
+ rootsCache: cache,
203
+ };
204
+
205
+ const coldRead = await readAggregateExtractionWatermark(options);
206
+ assert.equal(coldRead.readFailed, false);
207
+ assert.equal(coldRead.pending, true);
208
+ await cache.whenIdle();
209
+ assert.equal((await readAggregateExtractionWatermark(options)).readFailed, false);
210
+
211
+ await rm(path.join(fixture.memoryDir, "namespaces"), { recursive: true, force: true });
212
+ await writeFile(path.join(fixture.memoryDir, "namespaces"), "not a directory", "utf8");
213
+ now += 2;
214
+ assert.equal(
215
+ (await readAggregateExtractionWatermark(options)).readFailed,
216
+ false,
217
+ "the stale value may be served while refresh is still in flight",
218
+ );
219
+ await cache.whenIdle();
220
+ const failedRefresh = await readAggregateExtractionWatermark(options);
221
+ assert.equal(failedRefresh.lastExtractionAt, null);
222
+ assert.equal(failedRefresh.readFailed, true);
223
+ assert.match(failedRefresh.readError ?? "", /namespace watermark enumeration failed/);
224
+ } finally {
225
+ await rm(fixture.memoryDir, { recursive: true, force: true });
226
+ }
227
+ });
228
+
229
+ test("a cold namespace-root cache is pending, not a failed read", async () => {
230
+ const fixture = await namespacedFixture();
231
+ try {
232
+ let rootReads = 0;
233
+ const result = await readAggregateExtractionWatermark({
234
+ config: fixture.config,
235
+ rootStorage: storage(fixture.memoryDir, async () => {
236
+ rootReads += 1;
237
+ return "2026-07-23T12:00:00.000Z";
238
+ }),
239
+ storageForNamespace: async (namespace) => storage(fixture.namespaceDirs[namespace], async () => null),
240
+ rootsCache: {
241
+ getResolvedRootsStatus: () => ({ roots: undefined, refreshError: undefined }),
242
+ },
243
+ });
244
+
245
+ assert.equal(result.lastExtractionAt, null);
246
+ assert.equal(result.readFailed, false);
247
+ assert.equal(result.pending, true);
248
+ assert.equal(rootReads, 0, "a root survivor is not read or published before enumeration completes");
249
+ } finally {
250
+ await rm(fixture.memoryDir, { recursive: true, force: true });
251
+ }
252
+ });
253
+
254
+ test("namespaces disabled performs exactly one root metadata read", async () => {
255
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-extraction-watermark-single-"));
256
+ try {
257
+ const config = parseConfig({ memoryDir, namespacesEnabled: false });
258
+ let rootReads = 0;
259
+ let namespaceResolutions = 0;
260
+ const timestamp = "2026-07-23T12:00:00.000Z";
261
+ const result = await readAggregateExtractionWatermark({
262
+ config,
263
+ rootStorage: {
264
+ dir: memoryDir,
265
+ loadMeta: async () => {
266
+ rootReads += 1;
267
+ return {
268
+ lastExtractionAt: timestamp,
269
+ extractionCount: 9,
270
+ lastConsolidationAt: null,
271
+ };
272
+ },
273
+ },
274
+ storageForNamespace: async () => {
275
+ namespaceResolutions += 1;
276
+ throw new Error("disabled path must not resolve namespace storage");
277
+ },
278
+ });
279
+
280
+ assert.deepEqual(result, {
281
+ lastExtractionAt: timestamp,
282
+ readFailed: false,
283
+ rootStats: { extractionCount: 9, lastConsolidationAt: null },
284
+ });
285
+ assert.equal(rootReads, 1);
286
+ assert.equal(namespaceResolutions, 0);
287
+ } finally {
288
+ await rm(memoryDir, { recursive: true, force: true });
289
+ }
290
+ });
@@ -65,6 +65,7 @@ async function hasAnyLegacyData(rootDir: string): Promise<boolean> {
65
65
 
66
66
  async function discoverConfiguredNamespaces(
67
67
  config: PluginConfig,
68
+ propagateDiscoveryErrors: boolean,
68
69
  ): Promise<string[]> {
69
70
  const discovered = new Set<string>([
70
71
  config.defaultNamespace,
@@ -85,7 +86,10 @@ async function discoverConfiguredNamespaces(
85
86
  discovered.add(namespace);
86
87
  }
87
88
  }
88
- } catch {
89
+ } catch (error) {
90
+ if (propagateDiscoveryErrors && (error as NodeJS.ErrnoException).code !== "ENOENT") {
91
+ throw error;
92
+ }
89
93
  // No namespace directory yet.
90
94
  }
91
95
 
@@ -95,9 +99,13 @@ async function discoverConfiguredNamespaces(
95
99
  export async function listNamespaces(options: {
96
100
  config: PluginConfig;
97
101
  storageRouter?: NamespaceStorageRouter;
102
+ propagateDiscoveryErrors?: boolean;
98
103
  }): Promise<NamespaceInventoryEntry[]> {
99
104
  const storageRouter = options.storageRouter ?? new NamespaceStorageRouter(options.config);
100
- const namespaces = await discoverConfiguredNamespaces(options.config);
105
+ const namespaces = await discoverConfiguredNamespaces(
106
+ options.config,
107
+ options.propagateDiscoveryErrors ?? false,
108
+ );
101
109
  const items = await Promise.all(
102
110
  namespaces.map(async (namespace) => {
103
111
  const storage = await storageRouter.storageFor(namespace);
@@ -143,11 +143,18 @@ test("runOperatorDoctor: includes the corpus_watermark check", async () => {
143
143
  const { root, memoryDir, configPath, orchestrator } = await makeFixture();
144
144
  try {
145
145
  await writeMemory(memoryDir, "facts/2026-03-08/a.md");
146
+ let metadataReads = 0;
147
+ const loadMeta = orchestrator.storage.loadMeta.bind(orchestrator.storage);
148
+ orchestrator.storage.loadMeta = async () => {
149
+ metadataReads += 1;
150
+ return loadMeta();
151
+ };
146
152
  const report = await runOperatorDoctor({ configPath, orchestrator });
147
153
  const check = report.checks.find((c) => c.key === "corpus_watermark");
148
154
  assert.ok(check, "expected a corpus_watermark check");
149
155
  assert.equal(check?.status, "ok");
150
156
  assert.equal(corpusOf(check)[0]?.memoryFileCount, 1);
157
+ assert.equal(metadataReads, 1, "doctor reuses the root metadata read for extraction liveness");
151
158
  } finally {
152
159
  await rm(root, { recursive: true, force: true });
153
160
  }
@@ -42,7 +42,7 @@ export async function summarizeCorpusWatermark(
42
42
  // The doctor orchestrator has no live namespace catalog, so config-driven
43
43
  // enumeration (deduped by root inside the shared helper) is the whole set.
44
44
  const rootByNamespace = new Map<string, string>();
45
- for (const root of await resolveCorpusNamespaceRoots({ config })) {
45
+ for (const root of await resolveCorpusNamespaceRoots({ config, propagateDiscoveryErrors: true })) {
46
46
  rootByNamespace.set(root.namespace, root.rootDir);
47
47
  }
48
48
  resolved = [...rootByNamespace.keys()];
@@ -4,6 +4,7 @@ import { access, mkdir, readFile, readdir, stat, unlink, writeFile } from "node:
4
4
  import { lintWorkspaceFiles } from "./hygiene.js";
5
5
  import { parseConfig } from "./config.js";
6
6
  import { summarizeExtractionLiveness, type ExtractionBufferSource } from "./extraction-liveness.js";
7
+ import { readAggregateExtractionWatermark } from "./orchestration/extraction-watermark.js";
7
8
  import type { OperatorDoctorCheck } from "./operator-doctor-types.js";
8
9
  import { readEnvVar, resolveHomeDir } from "./runtime/env.js";
9
10
  import { resolvePluginEntry } from "./plugin-entry-resolver.js";
@@ -53,6 +54,7 @@ import type {
53
54
  DreamsPhasesConfig,
54
55
  FileHygieneConfig,
55
56
  MemoryFile,
57
+ MetaState,
56
58
  PluginConfig,
57
59
  } from "./types.js";
58
60
  import { reportBufferSurpriseDistribution } from "./buffer-surprise-report.js";
@@ -155,12 +157,12 @@ interface ConversationIndexLike {
155
157
  }>;
156
158
  };
157
159
  }
158
-
159
160
  export interface OperatorToolkitOrchestrator extends ConversationIndexLike {
160
161
  config: PluginConfig;
161
162
  storage: StorageManager;
162
163
  qmd: QmdRuntimeLike;
163
164
  buffer?: ExtractionBufferSource;
165
+ getStorage?(namespace: string): Promise<StorageManager>;
164
166
  }
165
167
 
166
168
  export interface OperatorConfigLoadResult {
@@ -1496,11 +1498,10 @@ export async function runOperatorDoctor(options: OperatorDoctorOptions): Promise
1496
1498
  checks.push(await summarizeGraphEdgeDecayStatus(config));
1497
1499
 
1498
1500
  // Tier distribution (issue #686 retention-completion).
1499
- // Shows hot/cold counts, per-status breakdown, and forgotten-memory count.
1500
- // Informational only — never errors, never blocks doctor from returning ok.
1501
1501
  checks.push(await summarizeTierDistribution(options.orchestrator.storage));
1502
- checks.push(await summarizeDreamsPhases(config, storage));
1503
- checks.push(await summarizeExtractionLiveness(config, storage, options.orchestrator.buffer));
1502
+ checks.push(await summarizeDreamsPhases(config, storage, meta));
1503
+ const extractionWatermark = await readAggregateExtractionWatermark({ config, rootStorage: storage, rootMeta: meta, storageForNamespace: (ns, rootDir) => options.orchestrator.getStorage?.(ns) ?? new StorageManager(rootDir) });
1504
+ checks.push(await summarizeExtractionLiveness(config, extractionWatermark, options.orchestrator.buffer));
1504
1505
  checks.push(...(await summarizeCorpusAndReplica(config, (d) => new StorageManager(d), options.resolveSecretRef)));
1505
1506
  // Security mitigation status (issue #565).
1506
1507
  // Reports whether the cross-namespace budget and anomaly detection
@@ -1898,11 +1899,10 @@ export async function summarizeTierDistribution(
1898
1899
  export async function summarizeDreamsPhases(
1899
1900
  config: Pick<PluginConfig, "memoryDir" | "dreamsPhases">,
1900
1901
  storage: StorageManager = new StorageManager(config.memoryDir),
1902
+ loadedMeta?: MetaState,
1901
1903
  ): Promise<OperatorDoctorCheck> {
1902
1904
  const phases: DreamsPhasesConfig = config.dreamsPhases;
1903
-
1904
- // Load meta.json for best-available last-run timestamps.
1905
- const meta = await storage.loadMeta();
1905
+ const meta = loadedMeta ?? (await storage.loadMeta());
1906
1906
 
1907
1907
  let deepSleepLastRun: string | null = null;
1908
1908
  let deepSleepLastRunWarning: string | null = null;
@@ -0,0 +1,188 @@
1
+ import path from "node:path";
2
+
3
+ import { capabilityAllowsNamespace, type TokenCapabilities } from "../access-token-capabilities.js";
4
+ import { resolveNamespaceCapabilities } from "../capabilities.js";
5
+ import { resolveCorpusNamespaceRoots, type CorpusNamespaceRoot } from "../corpus-watermark.js";
6
+ import { normalizeNamespaceIdentity } from "../namespaces/identity.js";
7
+ import type { ExtractionRootStats, ExtractionWatermarkRead } from "../extraction-liveness.js";
8
+ import type { MetaState, PluginConfig } from "../types.js";
9
+
10
+ export interface ExtractionWatermarkMeta extends Pick<MetaState, "lastExtractionAt"> {
11
+ extractionCount?: number;
12
+ lastConsolidationAt?: string | null;
13
+ }
14
+
15
+ export interface ExtractionWatermarkStorage {
16
+ readonly dir: string;
17
+ loadMeta(): Promise<ExtractionWatermarkMeta>;
18
+ }
19
+
20
+ export interface ExtractionNamespaceRootCache {
21
+ getResolvedRootsStatus(compute: () => Promise<CorpusNamespaceRoot[]>): {
22
+ roots: CorpusNamespaceRoot[] | undefined;
23
+ refreshError: unknown;
24
+ };
25
+ }
26
+
27
+ export interface AggregateExtractionWatermarkOptions {
28
+ config: PluginConfig;
29
+ rootStorage: ExtractionWatermarkStorage;
30
+ rootMeta?: ExtractionWatermarkMeta;
31
+ storageForNamespace(
32
+ namespace: string,
33
+ rootDir: string
34
+ ): ExtractionWatermarkStorage | Promise<ExtractionWatermarkStorage>;
35
+ rootsCache?: ExtractionNamespaceRootCache;
36
+ caps?: TokenCapabilities;
37
+ }
38
+
39
+ function readFailure(reason: string, rootStats?: ExtractionRootStats): ExtractionWatermarkRead {
40
+ return {
41
+ lastExtractionAt: null,
42
+ readFailed: true,
43
+ readError: reason,
44
+ ...(rootStats ? { rootStats } : {}),
45
+ };
46
+ }
47
+
48
+ function errorMessage(error: unknown): string {
49
+ return error instanceof Error ? error.message : String(error);
50
+ }
51
+
52
+ function watermarkFromMeta(meta: ExtractionWatermarkMeta, name: string): ExtractionWatermarkRead {
53
+ if (meta.lastExtractionAt !== null && meta.lastExtractionAt !== undefined) {
54
+ const parsed = Date.parse(meta.lastExtractionAt);
55
+ if (!Number.isFinite(parsed)) {
56
+ return readFailure(`${name} watermark timestamp invalid`);
57
+ }
58
+ }
59
+ const hasRootStats = meta.extractionCount !== undefined || meta.lastConsolidationAt !== undefined;
60
+ return {
61
+ lastExtractionAt: meta.lastExtractionAt ?? null,
62
+ readFailed: false,
63
+ ...(hasRootStats
64
+ ? {
65
+ rootStats: {
66
+ extractionCount: meta.extractionCount,
67
+ lastConsolidationAt: meta.lastConsolidationAt,
68
+ },
69
+ }
70
+ : {}),
71
+ };
72
+ }
73
+
74
+ async function readWatermark(storage: ExtractionWatermarkStorage, name: string): Promise<ExtractionWatermarkRead> {
75
+ try {
76
+ return watermarkFromMeta(await storage.loadMeta(), name);
77
+ } catch (error) {
78
+ return readFailure(`${name} watermark unreadable: ${errorMessage(error)}`);
79
+ }
80
+ }
81
+
82
+ async function resolveRoots(
83
+ options: AggregateExtractionWatermarkOptions
84
+ ): Promise<CorpusNamespaceRoot[] | ExtractionWatermarkRead> {
85
+ const compute = () =>
86
+ resolveCorpusNamespaceRoots({
87
+ config: options.config,
88
+ propagateDiscoveryErrors: true,
89
+ });
90
+ if (options.rootsCache) {
91
+ const { roots, refreshError } = options.rootsCache.getResolvedRootsStatus(compute);
92
+ if (refreshError !== undefined) {
93
+ return readFailure(`namespace watermark enumeration failed: ${errorMessage(refreshError)}`);
94
+ }
95
+ return roots ?? { lastExtractionAt: null, readFailed: false, pending: true };
96
+ }
97
+ try {
98
+ return await compute();
99
+ } catch (error) {
100
+ return readFailure(`namespace watermark enumeration failed: ${errorMessage(error)}`);
101
+ }
102
+ }
103
+
104
+ function isReadFailure(value: CorpusNamespaceRoot[] | ExtractionWatermarkRead): value is ExtractionWatermarkRead {
105
+ return !Array.isArray(value);
106
+ }
107
+
108
+ function newerWatermark(current: string | null, candidate: string | null): string | null {
109
+ if (candidate === null) return current;
110
+ const candidateMs = Date.parse(candidate);
111
+ if (!Number.isFinite(candidateMs)) return current;
112
+ if (current === null) return candidate;
113
+ const currentMs = Date.parse(current);
114
+ return !Number.isFinite(currentMs) || candidateMs > currentMs ? candidate : current;
115
+ }
116
+
117
+ export async function readAggregateExtractionWatermark(
118
+ options: AggregateExtractionWatermarkOptions
119
+ ): Promise<ExtractionWatermarkRead> {
120
+ if (!resolveNamespaceCapabilities(options.config).namespaces) {
121
+ return options.rootMeta
122
+ ? watermarkFromMeta(options.rootMeta, "root store")
123
+ : readWatermark(options.rootStorage, "root store");
124
+ }
125
+
126
+ const resolved = await resolveRoots(options);
127
+ if (isReadFailure(resolved)) return resolved;
128
+
129
+ const rootDir = path.resolve(options.rootStorage.dir);
130
+ const seenDirs = new Set<string>([rootDir]);
131
+ const targets: CorpusNamespaceRoot[] = [];
132
+ for (const root of resolved) {
133
+ if (
134
+ options.caps &&
135
+ !root.namespaces.some((ns) =>
136
+ capabilityAllowsNamespace(options.caps, normalizeNamespaceIdentity(ns)),
137
+ )
138
+ ) {
139
+ continue;
140
+ }
141
+ const resolvedDir = path.resolve(root.rootDir);
142
+ if (seenDirs.has(resolvedDir)) continue;
143
+ seenDirs.add(resolvedDir);
144
+ targets.push(root);
145
+ }
146
+
147
+ const defaultNamespace = normalizeNamespaceIdentity(options.config.defaultNamespace);
148
+ const hasMigratedDefault = resolved.some(
149
+ (root) =>
150
+ path.resolve(root.rootDir) !== rootDir &&
151
+ root.namespaces.some((namespace) => normalizeNamespaceIdentity(namespace) === defaultNamespace),
152
+ );
153
+ const canAccessRoot =
154
+ !hasMigratedDefault &&
155
+ (!options.caps || capabilityAllowsNamespace(options.caps, defaultNamespace));
156
+ let rootRead: ExtractionWatermarkRead = { lastExtractionAt: null, readFailed: false };
157
+ if (canAccessRoot) {
158
+ rootRead = await readWatermark(options.rootStorage, "root store");
159
+ if (rootRead.readFailed) return rootRead;
160
+ }
161
+ let lastExtractionAt = rootRead.lastExtractionAt;
162
+
163
+ const reads = await Promise.all(
164
+ targets.map(async (target) => {
165
+ try {
166
+ const storage = await options.storageForNamespace(target.namespace, target.rootDir);
167
+ return await readWatermark(storage, "namespace");
168
+ } catch (error) {
169
+ return readFailure(`namespace watermark storage unavailable: ${errorMessage(error)}`);
170
+ }
171
+ })
172
+ );
173
+
174
+ for (const read of reads) {
175
+ if (read.readFailed) {
176
+ return readFailure(
177
+ read.readError ?? "namespace watermark unreadable",
178
+ rootRead.rootStats
179
+ );
180
+ }
181
+ lastExtractionAt = newerWatermark(lastExtractionAt, read.lastExtractionAt);
182
+ }
183
+ return {
184
+ lastExtractionAt,
185
+ readFailed: false,
186
+ ...(rootRead.rootStats ? { rootStats: rootRead.rootStats } : {}),
187
+ };
188
+ }
package/src/types.ts CHANGED
@@ -1249,13 +1249,7 @@ export interface PluginConfig extends BoundedJsonlStateConfig {
1249
1249
  /** OpenClaw bridge mode (#2120): `"embedded"` (default) or `"delegate"`. */
1250
1250
  bridgeMode: string;
1251
1251
  codexCompat: CodexCompatConfig;
1252
- /**
1253
- * When true (default), the extraction prompt instructs the LLM to classify
1254
- * each fact as `"project"` or `"global"` scope. Global-scoped facts are
1255
- * promoted to the shared namespace so they are visible across all projects.
1256
- * When false, all facts go to whatever namespace the session is in (pre-
1257
- * scope-classification behavior). Rule 30: configuration gate.
1258
- */
1252
+ /** When true (default), LLM classifies facts as `"project"` or `"global"` scope for promotion across projects. */
1259
1253
  extractionScopeClassificationEnabled: boolean;
1260
1254
  // Extraction judge (issue #376)
1261
1255
  /** Enable the LLM-as-judge fact-worthiness gate on extracted facts. Default false (opt-in). */