@remnic/core 9.23.4 → 9.25.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 (412) hide show
  1. package/dist/access-admin-ops-surface.d.ts +12 -10
  2. package/dist/access-admin-ops-surface.js +40 -39
  3. package/dist/access-authorization-probe.d.ts +122 -0
  4. package/dist/access-authorization-probe.js +154 -0
  5. package/dist/access-boundary.d.ts +12 -10
  6. package/dist/access-boundary.js +40 -39
  7. package/dist/access-cli.js +119 -117
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-health-types.d.ts +54 -0
  10. package/dist/access-health-types.js +1 -0
  11. package/dist/access-http.d.ts +12 -10
  12. package/dist/access-http.js +51 -49
  13. package/dist/access-identity-continuity-surface.d.ts +9 -8
  14. package/dist/access-identity-continuity-surface.js +40 -39
  15. package/dist/access-lcm-surface.d.ts +12 -10
  16. package/dist/access-lcm-surface.js +40 -39
  17. package/dist/access-mcp.d.ts +12 -10
  18. package/dist/access-mcp.js +46 -45
  19. package/dist/access-memory-search-fanout.d.ts +3 -2
  20. package/dist/{access-namespace-preflight-CmErR03h.d.ts → access-namespace-preflight-wRSZEO5V.d.ts} +1 -1
  21. package/dist/access-namespace-preflight.d.ts +4 -3
  22. package/dist/access-namespace-preflight.js +40 -39
  23. package/dist/access-observe-write-surface.d.ts +13 -11
  24. package/dist/access-observe-write-surface.js +40 -39
  25. package/dist/access-operations-batch.js +42 -41
  26. package/dist/access-operations.d.ts +13 -11
  27. package/dist/access-operations.js +44 -43
  28. package/dist/access-recall-concurrency.d.ts +12 -10
  29. package/dist/access-recall-concurrency.js +40 -39
  30. package/dist/access-recall-response.d.ts +12 -10
  31. package/dist/access-recall-response.js +40 -39
  32. package/dist/access-recall-surface.d.ts +12 -10
  33. package/dist/access-recall-surface.js +40 -39
  34. package/dist/access-schema.d.ts +10 -10
  35. package/dist/access-schema.js +8 -8
  36. package/dist/{access-service-Pl-h7x4p.d.ts → access-service-BlNKWBC9.d.ts} +10 -40
  37. package/dist/access-service.d.ts +13 -11
  38. package/dist/access-service.js +40 -39
  39. package/dist/access-surface-catalog.d.ts +12 -10
  40. package/dist/access-token-capabilities.d.ts +15 -1
  41. package/dist/access-token-capabilities.js +3 -1
  42. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  43. package/dist/action-confidence.d.ts +2 -1
  44. package/dist/active-memory-bridge.d.ts +2 -1
  45. package/dist/active-recall.d.ts +2 -1
  46. package/dist/active-recall.js +7 -6
  47. package/dist/active-recall.js.map +1 -1
  48. package/dist/adapters/index.js +4 -4
  49. package/dist/adapters/registry.js +2 -2
  50. package/dist/auto-sync-5OE5QOZB.js +1 -1
  51. package/dist/behavior-learner.d.ts +2 -1
  52. package/dist/behavior-signals.d.ts +2 -1
  53. package/dist/bootstrap.d.ts +9 -8
  54. package/dist/briefing.d.ts +3 -2
  55. package/dist/briefing.js +9 -9
  56. package/dist/buffer-surprise-report.d.ts +2 -1
  57. package/dist/buffer.d.ts +6 -2
  58. package/dist/buffer.js +1 -1
  59. package/dist/bulk-import/index.d.ts +4 -3
  60. package/dist/calibration.d.ts +2 -1
  61. package/dist/capabilities.d.ts +2 -1
  62. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  63. package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
  64. package/dist/{catalog-BFTVo2Ez.d.ts → catalog-BLLxZ5L5.d.ts} +1 -1
  65. package/dist/causal-behavior.d.ts +2 -1
  66. package/dist/causal-behavior.js +2 -2
  67. package/dist/causal-chain.js +2 -2
  68. package/dist/causal-consolidation.d.ts +2 -1
  69. package/dist/causal-consolidation.js +12 -12
  70. package/dist/causal-retrieval.js +2 -2
  71. package/dist/causal-trajectory-graph.d.ts +2 -1
  72. package/dist/causal-trajectory-graph.js +2 -2
  73. package/dist/causal-trajectory.js +1 -1
  74. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  75. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  76. package/dist/{chunk-34RC5RT7.js → chunk-2SA56WMI.js} +4 -4
  77. package/dist/{chunk-POHSSW2T.js → chunk-3CDMIR3C.js} +2 -2
  78. package/dist/{chunk-EXH5AK46.js → chunk-3I35RLJW.js} +27 -15
  79. package/dist/chunk-3I35RLJW.js.map +1 -0
  80. package/dist/{chunk-JRQBPN63.js → chunk-3UOSVTFR.js} +8 -8
  81. package/dist/chunk-443XCR34.js +213 -0
  82. package/dist/chunk-443XCR34.js.map +1 -0
  83. package/dist/{chunk-354T54RR.js → chunk-4TFIRMTE.js} +28 -1
  84. package/dist/chunk-4TFIRMTE.js.map +1 -0
  85. package/dist/{chunk-CNUZ2PN2.js → chunk-5ZGWA4AG.js} +14 -10
  86. package/dist/chunk-5ZGWA4AG.js.map +1 -0
  87. package/dist/{chunk-AT7XL2JJ.js → chunk-6LRTGCRV.js} +10 -10
  88. package/dist/{chunk-AJ7QCSIS.js → chunk-7CPOZH6Y.js} +2 -2
  89. package/dist/{chunk-EHOTE26K.js → chunk-AGR7MGUX.js} +2 -2
  90. package/dist/{chunk-D5ILARSD.js → chunk-AL4TZWI3.js} +2 -2
  91. package/dist/{chunk-RPOSRICW.js → chunk-AT6DNUCM.js} +2 -2
  92. package/dist/{chunk-KNB7IBBU.js → chunk-CKMO4RDY.js} +5 -5
  93. package/dist/{chunk-5CPI2QWG.js → chunk-CSXHRAJJ.js} +3 -3
  94. package/dist/{chunk-5XMJ2P62.js → chunk-DPYYSG6F.js} +7 -7
  95. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  96. package/dist/{chunk-K3C6CJOF.js → chunk-FIGDB2HR.js} +2 -2
  97. package/dist/{chunk-Z54EM5YZ.js → chunk-GF22HWS2.js} +4 -4
  98. package/dist/{chunk-ZYU7ZFLT.js → chunk-GJJBPI6I.js} +5 -1
  99. package/dist/chunk-GJJBPI6I.js.map +1 -0
  100. package/dist/{chunk-UZ7HGRHK.js → chunk-GNFZFJBJ.js} +2 -2
  101. package/dist/{chunk-W6ROK2KU.js → chunk-HNZKVLAN.js} +2 -2
  102. package/dist/{chunk-HVYOZAQ7.js → chunk-IE4HB6O5.js} +3 -3
  103. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  104. package/dist/chunk-JMDZDT24.js +38 -0
  105. package/dist/chunk-JMDZDT24.js.map +1 -0
  106. package/dist/{chunk-UZGJFIIG.js → chunk-JYIFGGEM.js} +2 -2
  107. package/dist/{chunk-VDX2J7OX.js → chunk-KQAFEZQX.js} +2 -2
  108. package/dist/{chunk-3SHB4YAW.js → chunk-L2DPF4DF.js} +4 -4
  109. package/dist/{chunk-SPWOLGXT.js → chunk-LARPWF3S.js} +3 -3
  110. package/dist/{chunk-NSRTLSBX.js → chunk-LFHMUWA2.js} +131 -131
  111. package/dist/{chunk-AYAROCWD.js → chunk-LLISELSY.js} +2 -2
  112. package/dist/{chunk-W3BKLKG6.js → chunk-LXKJNUND.js} +2 -2
  113. package/dist/{chunk-MMTG3SCJ.js → chunk-M5EPMNS4.js} +2 -2
  114. package/dist/{chunk-KYP5FSPG.js → chunk-MNLZGCM2.js} +10 -10
  115. package/dist/{chunk-TMX4MBSK.js → chunk-MPDX5QMH.js} +2 -2
  116. package/dist/{chunk-PO5LSKQO.js → chunk-MU7ZHSZE.js} +2 -2
  117. package/dist/{chunk-7AMFUATK.js → chunk-MZWSOLMT.js} +14 -1
  118. package/dist/chunk-MZWSOLMT.js.map +1 -0
  119. package/dist/{chunk-JVOA5VDZ.js → chunk-NMGO2HAZ.js} +3 -3
  120. package/dist/{chunk-CAGPP5NB.js → chunk-NRV4Y3PM.js} +1 -1
  121. package/dist/{chunk-H2M4YA6K.js → chunk-NVYCTASB.js} +2 -2
  122. package/dist/{chunk-M2PG7OTI.js → chunk-P25IPRXP.js} +7 -7
  123. package/dist/{chunk-6MFMTNY4.js → chunk-RROMWDDC.js} +50 -54
  124. package/dist/chunk-RROMWDDC.js.map +1 -0
  125. package/dist/{chunk-FPJWQZ35.js → chunk-SZN6XVFC.js} +2 -2
  126. package/dist/{chunk-ZLDMAGCB.js → chunk-TG2DJFH7.js} +80 -80
  127. package/dist/chunk-TG2DJFH7.js.map +1 -0
  128. package/dist/{chunk-4E3DWNTJ.js → chunk-THHPDPMS.js} +2 -2
  129. package/dist/{chunk-XPLTZEJU.js → chunk-U37RGPJT.js} +2 -2
  130. package/dist/{chunk-SCOT5DTA.js → chunk-V25OWXAC.js} +1 -1
  131. package/dist/chunk-V25OWXAC.js.map +1 -0
  132. package/dist/{chunk-3UD5ZAUA.js → chunk-VY6SDKWZ.js} +2 -2
  133. package/dist/{chunk-XJTYLU6J.js → chunk-W4ZDTHWZ.js} +3 -3
  134. package/dist/{chunk-3NAHZQU3.js → chunk-X3SQYAPP.js} +2 -2
  135. package/dist/{chunk-WMLHJ5UW.js → chunk-X6ROIHFE.js} +2 -2
  136. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  137. package/dist/{chunk-GCQIMJFH.js → chunk-XTAAG4SQ.js} +8 -8
  138. package/dist/{chunk-RSLXMGFP.js → chunk-ZN4UZWMT.js} +2 -2
  139. package/dist/{cli-DuMB83Mw.d.ts → cli-Zc6UclD1.d.ts} +5 -5
  140. package/dist/cli.d.ts +14 -12
  141. package/dist/cli.js +82 -80
  142. package/dist/compounding/engine.d.ts +3 -2
  143. package/dist/compounding/engine.js +9 -9
  144. package/dist/compounding/preference-consolidator.d.ts +2 -1
  145. package/dist/compression-optimizer.d.ts +2 -1
  146. package/dist/config.d.ts +2 -1
  147. package/dist/config.js +4 -3
  148. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  149. package/dist/connectors/codex-materialize-runner.js +9 -9
  150. package/dist/connectors/codex-materialize.d.ts +2 -1
  151. package/dist/connectors/index.d.ts +2 -1
  152. package/dist/connectors/index.js +12 -12
  153. package/dist/consolidation-provenance-check.d.ts +3 -2
  154. package/dist/consolidation-provenance-check.js +2 -2
  155. package/dist/consolidation-undo.d.ts +3 -2
  156. package/dist/contradiction/index.d.ts +3 -2
  157. package/dist/contradiction/index.js +1 -1
  158. package/dist/conversation-index/backend.d.ts +2 -1
  159. package/dist/conversation-index/backend.js +2 -2
  160. package/dist/conversation-index/chunker.d.ts +2 -1
  161. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  162. package/dist/conversation-index/indexer.d.ts +2 -1
  163. package/dist/conversation-index/search.d.ts +2 -1
  164. package/dist/corpus-watermark.d.ts +2 -1
  165. package/dist/corpus-watermark.js +18 -18
  166. package/dist/dashboard-runtime.js +2 -2
  167. package/dist/day-summary.d.ts +2 -1
  168. package/dist/delinearize.d.ts +2 -1
  169. package/dist/direct-answer-wiring.d.ts +2 -1
  170. package/dist/direct-answer.d.ts +2 -1
  171. package/dist/embedding-fallback.d.ts +2 -1
  172. package/dist/enrichment/index.d.ts +2 -1
  173. package/dist/entity-retrieval.d.ts +3 -2
  174. package/dist/entity-retrieval.js +9 -9
  175. package/dist/entity-schema.d.ts +2 -1
  176. package/dist/explicit-capture.d.ts +9 -8
  177. package/dist/explicit-capture.js +1 -1
  178. package/dist/extraction-error-classification.d.ts +2 -1
  179. package/dist/extraction-faithfulness.d.ts +2 -1
  180. package/dist/extraction-judge-telemetry.d.ts +2 -1
  181. package/dist/extraction-judge-training.d.ts +2 -1
  182. package/dist/extraction-judge.d.ts +2 -1
  183. package/dist/extraction-liveness.d.ts +5 -0
  184. package/dist/extraction-liveness.js +26 -0
  185. package/dist/extraction-liveness.js.map +1 -0
  186. package/dist/extraction.d.ts +2 -1
  187. package/dist/extraction.js +1 -1
  188. package/dist/fallback-llm.d.ts +2 -1
  189. package/dist/graph-dashboard-diff.d.ts +2 -1
  190. package/dist/graph-dashboard-key.d.ts +2 -1
  191. package/dist/graph-dashboard-parser.d.ts +2 -1
  192. package/dist/{graph-edge-decay-GF3ZSGSP.js → graph-edge-decay-Z6ENALU2.js} +4 -4
  193. package/dist/graph-edge-decay-Z6ENALU2.js.map +1 -0
  194. package/dist/graph-edge-reinforcement.d.ts +2 -1
  195. package/dist/graph-snapshot.d.ts +2 -1
  196. package/dist/graph-snapshot.js +3 -3
  197. package/dist/graph.d.ts +2 -1
  198. package/dist/graph.js +2 -2
  199. package/dist/importance.d.ts +2 -1
  200. package/dist/importers/index.d.ts +2 -1
  201. package/dist/in-flight-reads.d.ts +2 -1
  202. package/dist/index.d.ts +53 -51
  203. package/dist/index.js +229 -227
  204. package/dist/intent.d.ts +2 -1
  205. package/dist/lcm/engine.d.ts +2 -1
  206. package/dist/lcm/engine.js +2 -2
  207. package/dist/lcm/index.d.ts +2 -1
  208. package/dist/lcm/index.js +4 -4
  209. package/dist/lcm/tools.d.ts +2 -1
  210. package/dist/lifecycle.d.ts +2 -1
  211. package/dist/live-connectors-runner.d.ts +2 -1
  212. package/dist/local-llm.d.ts +2 -1
  213. package/dist/local-model-endpoint.d.ts +2 -1
  214. package/dist/maintenance/memory-governance.d.ts +2 -1
  215. package/dist/maintenance/memory-governance.js +9 -9
  216. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  217. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
  218. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  219. package/dist/maintenance/rebuild-memory-projection.js +10 -10
  220. package/dist/{maintenance-DGvDB1xF.d.ts → maintenance-DD22oIx9.d.ts} +3 -3
  221. package/dist/mcp-memory-inspector-app.d.ts +12 -10
  222. package/dist/memory-action-policy.d.ts +2 -1
  223. package/dist/memory-cache.d.ts +2 -1
  224. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  225. package/dist/memory-projection-store.d.ts +2 -1
  226. package/dist/memory-provenance.d.ts +2 -1
  227. package/dist/memory-worth-outcomes.d.ts +3 -2
  228. package/dist/models-json.d.ts +2 -1
  229. package/dist/namespaces/migrate.d.ts +4 -3
  230. package/dist/namespaces/migrate.js +16 -16
  231. package/dist/namespaces/principal.d.ts +2 -1
  232. package/dist/namespaces/search.d.ts +2 -1
  233. package/dist/namespaces/search.js +6 -6
  234. package/dist/namespaces/storage.d.ts +4 -3
  235. package/dist/namespaces/storage.js +9 -9
  236. package/dist/native-knowledge.d.ts +2 -1
  237. package/dist/offline-sync-impression-drain.d.ts +2 -1
  238. package/dist/offline-sync-impression-drain.js +1 -1
  239. package/dist/operator-doctor-corpus.d.ts +2 -15
  240. package/dist/operator-doctor-corpus.js +19 -19
  241. package/dist/operator-doctor-types.d.ts +22 -0
  242. package/dist/operator-doctor-types.js +1 -0
  243. package/dist/operator-doctor-types.js.map +1 -0
  244. package/dist/operator-toolkit.d.ts +10 -13
  245. package/dist/operator-toolkit.js +32 -28
  246. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  247. package/dist/orchestration/maintenance.d.ts +5 -4
  248. package/dist/orchestration/maintenance.js +15 -15
  249. package/dist/{orchestrator-RXHefhAy.d.ts → orchestrator-BTGgoKli.d.ts} +7 -7
  250. package/dist/orchestrator.d.ts +9 -8
  251. package/dist/orchestrator.js +120 -118
  252. package/dist/patterns-cli.d.ts +2 -1
  253. package/dist/{pipeline-id_-sqYm.d.ts → pipeline-Bq5zU6Bp.d.ts} +1 -1
  254. package/dist/policy-runtime.d.ts +2 -1
  255. package/dist/proactive-contention.d.ts +2 -1
  256. package/dist/provenance.d.ts +2 -1
  257. package/dist/{qmd-R6XaQOZK.d.ts → qmd-3ILJkC70.d.ts} +1 -1
  258. package/dist/qmd-preflight.d.ts +3 -2
  259. package/dist/qmd-recall-cache.d.ts +2 -1
  260. package/dist/qmd.d.ts +3 -2
  261. package/dist/recall-concurrency-config.d.ts +2 -1
  262. package/dist/recall-disclosure-escalation.d.ts +2 -1
  263. package/dist/recall-explain-renderer.d.ts +2 -1
  264. package/dist/recall-explain-renderer.js +3 -3
  265. package/dist/recall-memory-map.d.ts +2 -1
  266. package/dist/recall-planner-llm.d.ts +2 -1
  267. package/dist/recall-state.d.ts +2 -1
  268. package/dist/recall-tag-filter.d.ts +2 -1
  269. package/dist/recall-timings.d.ts +2 -1
  270. package/dist/recall-xray-cli.d.ts +2 -1
  271. package/dist/recall-xray-cli.js +4 -4
  272. package/dist/recall-xray-renderer.d.ts +2 -1
  273. package/dist/recall-xray-renderer.js +3 -3
  274. package/dist/recall-xray.d.ts +2 -1
  275. package/dist/recall-xray.js +2 -2
  276. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  277. package/dist/replay/normalizers/claude.d.ts +2 -1
  278. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  279. package/dist/replay/normalizers/shared.d.ts +2 -1
  280. package/dist/replay/runner.d.ts +2 -1
  281. package/dist/replay/types.d.ts +2 -1
  282. package/dist/resolution-3K27T4VO.js +1 -1
  283. package/dist/resolve-auth-token.d.ts +2 -1
  284. package/dist/resume-bundles.js +6 -5
  285. package/dist/retrieval-agents.d.ts +3 -2
  286. package/dist/retrieval-tiers.d.ts +2 -1
  287. package/dist/routing/engine.d.ts +2 -1
  288. package/dist/routing/store.d.ts +2 -1
  289. package/dist/salvage-envelope.d.ts +2 -1
  290. package/dist/salvage-envelope.js +1 -1
  291. package/dist/{scope-profiles-EhyuAKkd.d.ts → scope-profiles-D0-ff4xT.d.ts} +1 -1
  292. package/dist/search/embed-helper.d.ts +2 -1
  293. package/dist/search/factory.d.ts +2 -1
  294. package/dist/search/factory.js +5 -5
  295. package/dist/search/index.d.ts +2 -1
  296. package/dist/search/index.js +9 -9
  297. package/dist/search/lancedb-backend.d.ts +2 -1
  298. package/dist/search/meilisearch-backend.d.ts +2 -1
  299. package/dist/search/noop-backend.d.ts +2 -1
  300. package/dist/search/orama-backend.d.ts +2 -1
  301. package/dist/search/port.d.ts +2 -1
  302. package/dist/search/remote-backend.d.ts +2 -1
  303. package/dist/{semantic-consolidation-B2xo26UQ.d.ts → semantic-consolidation-4Tfh7c1g.d.ts} +1 -1
  304. package/dist/semantic-consolidation.d.ts +3 -2
  305. package/dist/semantic-consolidation.js +14 -14
  306. package/dist/semantic-rule-promotion.js +9 -9
  307. package/dist/semantic-rule-verifier.d.ts +2 -1
  308. package/dist/semantic-rule-verifier.js +9 -9
  309. package/dist/{service-BrWqlsZ4.d.ts → service-Z8uzoAST.d.ts} +2 -2
  310. package/dist/session-observer-bands.d.ts +2 -1
  311. package/dist/session-observer-state.d.ts +2 -1
  312. package/dist/shared-context/manager.d.ts +2 -1
  313. package/dist/signal.d.ts +2 -1
  314. package/dist/{storage-DgNVexXm.d.ts → storage-BZVMn8yJ.d.ts} +1 -1
  315. package/dist/storage.d.ts +3 -2
  316. package/dist/storage.js +8 -8
  317. package/dist/summarizer.d.ts +2 -1
  318. package/dist/summary-snapshot.d.ts +2 -1
  319. package/dist/temporal-supersession.d.ts +3 -2
  320. package/dist/temporal-timeline-recall.d.ts +2 -1
  321. package/dist/temporal-validity.d.ts +2 -1
  322. package/dist/threading.d.ts +2 -1
  323. package/dist/tier-migration.d.ts +3 -2
  324. package/dist/tier-routing.d.ts +2 -1
  325. package/dist/tokens.js +2 -2
  326. package/dist/topics.d.ts +2 -1
  327. package/dist/transcript.d.ts +2 -1
  328. package/dist/transfer/backup.js +4 -4
  329. package/dist/transfer/capsule-export.js +4 -4
  330. package/dist/transfer/capsule-import.js +3 -3
  331. package/dist/trust-score-stage.d.ts +2 -1
  332. package/dist/trust-score.d.ts +2 -1
  333. package/dist/{types-Bbs0qz6b.d.ts → types-DHBxIF0s.d.ts} +181 -5
  334. package/dist/types.d.ts +2 -1
  335. package/dist/types.js +1 -1
  336. package/dist/utility-runtime.d.ts +2 -1
  337. package/dist/verified-recall.js +9 -9
  338. package/dist/write-envelope.d.ts +2 -1
  339. package/dist/write-envelope.js +1 -1
  340. package/package.json +2 -2
  341. package/src/access-authorization-probe.ts +43 -0
  342. package/src/access-boundary.ts +2 -31
  343. package/src/access-health-types.ts +51 -0
  344. package/src/access-http.test.ts +94 -0
  345. package/src/access-http.ts +11 -0
  346. package/src/access-service-health.test.ts +212 -0
  347. package/src/access-service.ts +11 -39
  348. package/src/access-surface-catalog.test.ts +4 -3
  349. package/src/access-token-capabilities.ts +31 -0
  350. package/src/buffer.ts +30 -0
  351. package/src/cli.ts +2 -4
  352. package/src/config.ts +4 -4
  353. package/src/extraction-liveness.test.ts +461 -0
  354. package/src/extraction-liveness.ts +462 -0
  355. package/src/operator-doctor-types.ts +20 -0
  356. package/src/operator-toolkit.ts +9 -10
  357. package/src/types.ts +4 -4
  358. package/dist/chunk-354T54RR.js.map +0 -1
  359. package/dist/chunk-6MFMTNY4.js.map +0 -1
  360. package/dist/chunk-7AMFUATK.js.map +0 -1
  361. package/dist/chunk-CNUZ2PN2.js.map +0 -1
  362. package/dist/chunk-EXH5AK46.js.map +0 -1
  363. package/dist/chunk-SCOT5DTA.js.map +0 -1
  364. package/dist/chunk-ZLDMAGCB.js.map +0 -1
  365. package/dist/chunk-ZYU7ZFLT.js.map +0 -1
  366. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-authorization-probe.js.map} +0 -0
  367. /package/dist/{graph-edge-decay-GF3ZSGSP.js.map → access-health-types.js.map} +0 -0
  368. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  369. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  370. /package/dist/{chunk-34RC5RT7.js.map → chunk-2SA56WMI.js.map} +0 -0
  371. /package/dist/{chunk-POHSSW2T.js.map → chunk-3CDMIR3C.js.map} +0 -0
  372. /package/dist/{chunk-JRQBPN63.js.map → chunk-3UOSVTFR.js.map} +0 -0
  373. /package/dist/{chunk-AT7XL2JJ.js.map → chunk-6LRTGCRV.js.map} +0 -0
  374. /package/dist/{chunk-AJ7QCSIS.js.map → chunk-7CPOZH6Y.js.map} +0 -0
  375. /package/dist/{chunk-EHOTE26K.js.map → chunk-AGR7MGUX.js.map} +0 -0
  376. /package/dist/{chunk-D5ILARSD.js.map → chunk-AL4TZWI3.js.map} +0 -0
  377. /package/dist/{chunk-RPOSRICW.js.map → chunk-AT6DNUCM.js.map} +0 -0
  378. /package/dist/{chunk-KNB7IBBU.js.map → chunk-CKMO4RDY.js.map} +0 -0
  379. /package/dist/{chunk-5CPI2QWG.js.map → chunk-CSXHRAJJ.js.map} +0 -0
  380. /package/dist/{chunk-5XMJ2P62.js.map → chunk-DPYYSG6F.js.map} +0 -0
  381. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  382. /package/dist/{chunk-K3C6CJOF.js.map → chunk-FIGDB2HR.js.map} +0 -0
  383. /package/dist/{chunk-Z54EM5YZ.js.map → chunk-GF22HWS2.js.map} +0 -0
  384. /package/dist/{chunk-UZ7HGRHK.js.map → chunk-GNFZFJBJ.js.map} +0 -0
  385. /package/dist/{chunk-W6ROK2KU.js.map → chunk-HNZKVLAN.js.map} +0 -0
  386. /package/dist/{chunk-HVYOZAQ7.js.map → chunk-IE4HB6O5.js.map} +0 -0
  387. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  388. /package/dist/{chunk-UZGJFIIG.js.map → chunk-JYIFGGEM.js.map} +0 -0
  389. /package/dist/{chunk-VDX2J7OX.js.map → chunk-KQAFEZQX.js.map} +0 -0
  390. /package/dist/{chunk-3SHB4YAW.js.map → chunk-L2DPF4DF.js.map} +0 -0
  391. /package/dist/{chunk-SPWOLGXT.js.map → chunk-LARPWF3S.js.map} +0 -0
  392. /package/dist/{chunk-NSRTLSBX.js.map → chunk-LFHMUWA2.js.map} +0 -0
  393. /package/dist/{chunk-AYAROCWD.js.map → chunk-LLISELSY.js.map} +0 -0
  394. /package/dist/{chunk-W3BKLKG6.js.map → chunk-LXKJNUND.js.map} +0 -0
  395. /package/dist/{chunk-MMTG3SCJ.js.map → chunk-M5EPMNS4.js.map} +0 -0
  396. /package/dist/{chunk-KYP5FSPG.js.map → chunk-MNLZGCM2.js.map} +0 -0
  397. /package/dist/{chunk-TMX4MBSK.js.map → chunk-MPDX5QMH.js.map} +0 -0
  398. /package/dist/{chunk-PO5LSKQO.js.map → chunk-MU7ZHSZE.js.map} +0 -0
  399. /package/dist/{chunk-JVOA5VDZ.js.map → chunk-NMGO2HAZ.js.map} +0 -0
  400. /package/dist/{chunk-CAGPP5NB.js.map → chunk-NRV4Y3PM.js.map} +0 -0
  401. /package/dist/{chunk-H2M4YA6K.js.map → chunk-NVYCTASB.js.map} +0 -0
  402. /package/dist/{chunk-M2PG7OTI.js.map → chunk-P25IPRXP.js.map} +0 -0
  403. /package/dist/{chunk-FPJWQZ35.js.map → chunk-SZN6XVFC.js.map} +0 -0
  404. /package/dist/{chunk-4E3DWNTJ.js.map → chunk-THHPDPMS.js.map} +0 -0
  405. /package/dist/{chunk-XPLTZEJU.js.map → chunk-U37RGPJT.js.map} +0 -0
  406. /package/dist/{chunk-3UD5ZAUA.js.map → chunk-VY6SDKWZ.js.map} +0 -0
  407. /package/dist/{chunk-XJTYLU6J.js.map → chunk-W4ZDTHWZ.js.map} +0 -0
  408. /package/dist/{chunk-3NAHZQU3.js.map → chunk-X3SQYAPP.js.map} +0 -0
  409. /package/dist/{chunk-WMLHJ5UW.js.map → chunk-X6ROIHFE.js.map} +0 -0
  410. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  411. /package/dist/{chunk-GCQIMJFH.js.map → chunk-XTAAG4SQ.js.map} +0 -0
  412. /package/dist/{chunk-RSLXMGFP.js.map → chunk-ZN4UZWMT.js.map} +0 -0
@@ -1642,6 +1642,15 @@ test("HTTP externalRequestHandler runs pre-auth, can end responses, and falls th
1642
1642
  },
1643
1643
  nativeKnowledgeEnabled: false,
1644
1644
  projectionAvailable: false,
1645
+ extraction: {
1646
+ lastExtractionAt: null,
1647
+ bufferedSessionCount: 0,
1648
+ pendingTurnCount: 0,
1649
+ oldestBufferedTurnAgeMs: null,
1650
+ degraded: false,
1651
+ degradedReason: null,
1652
+ watermarkScope: "root-store",
1653
+ },
1645
1654
  corpus: [],
1646
1655
  }),
1647
1656
  } satisfies Pick<EngramAccessService, "health">;
@@ -1758,6 +1767,15 @@ test("HTTP authTokenEntriesGetter is authoritative: scope policy binds connector
1758
1767
  },
1759
1768
  nativeKnowledgeEnabled: false,
1760
1769
  projectionAvailable: false,
1770
+ extraction: {
1771
+ lastExtractionAt: null,
1772
+ bufferedSessionCount: 0,
1773
+ pendingTurnCount: 0,
1774
+ oldestBufferedTurnAgeMs: null,
1775
+ degraded: false,
1776
+ degradedReason: null,
1777
+ watermarkScope: "root-store",
1778
+ },
1761
1779
  corpus: [],
1762
1780
  }),
1763
1781
  } satisfies Pick<EngramAccessService, "health">;
@@ -2960,3 +2978,79 @@ test("HTTP meetings get returns 400 (not 500) for a malformed percent-encoded id
2960
2978
  await server.stop();
2961
2979
  }
2962
2980
  });
2981
+
2982
+ test("HTTP authorization probe verifies requested operation grants without invoking operations (issue #2129)", async () => {
2983
+ const service = {
2984
+ configRef: parseConfig({ memoryDir: "/tmp/remnic-http-authorization-probe", defaultNamespace: "default" }),
2985
+ } as unknown as EngramAccessService;
2986
+ const server = new EngramAccessHttpServer({
2987
+ service,
2988
+ port: 0,
2989
+ authTokenEntriesGetter: () => [
2990
+ {
2991
+ token: "delegate-token",
2992
+ capabilities: { version: 1, ops: ["recall", "observe", "lcm_compaction_flush"] },
2993
+ },
2994
+ { token: "recall-only-token", capabilities: { version: 1, ops: ["recall"] } },
2995
+ { token: "observe-only-token", capabilities: { version: 1, ops: ["observe"] } },
2996
+ {
2997
+ token: "fleet-scoped-token",
2998
+ capabilities: {
2999
+ version: 1,
3000
+ ops: ["continuity_audit_generate"],
3001
+ namespaces: ["default"],
3002
+ },
3003
+ },
3004
+ ],
3005
+ adminConsoleEnabled: false,
3006
+ });
3007
+ const status = await server.start();
3008
+ const probe = (token: string, operations: string[]) => {
3009
+ const query = new URLSearchParams();
3010
+ for (const operation of operations) query.append("op", operation);
3011
+ return fetch(`http://127.0.0.1:${status.port}/engram/v1/authorization?${query}`, {
3012
+ headers: { authorization: `Bearer ${token}` },
3013
+ });
3014
+ };
3015
+ const delegateOperations = ["recall", "observe", "lcm_compaction_flush"];
3016
+ try {
3017
+ const authorized = await probe("delegate-token", [...delegateOperations, "recall"]);
3018
+ assert.equal(authorized.status, 200);
3019
+ assert.equal(authorized.headers.get("cache-control"), "no-store");
3020
+ assert.deepEqual(await authorized.json(), { authorized: true, operations: delegateOperations });
3021
+
3022
+ const alternateGrant = await probe("observe-only-token", ["namespace_writable"]);
3023
+ assert.equal(alternateGrant.status, 200);
3024
+ await alternateGrant.text();
3025
+
3026
+ const fleetWide = await probe("fleet-scoped-token", ["continuity_audit_generate"]);
3027
+ assert.equal(fleetWide.status, 403);
3028
+ assert.equal(fleetWide.headers.get("cache-control"), "no-store");
3029
+ await fleetWide.text();
3030
+
3031
+ const denied = await probe("recall-only-token", delegateOperations);
3032
+ assert.equal(
3033
+ denied.status,
3034
+ 403,
3035
+ "a token missing any requested operation is rejected without running it",
3036
+ );
3037
+ assert.equal(denied.headers.get("cache-control"), "no-store");
3038
+ await denied.text();
3039
+
3040
+ const wrongToken = await probe("wrong-token", delegateOperations);
3041
+ assert.equal(wrongToken.status, 401);
3042
+ await wrongToken.text();
3043
+
3044
+ const empty = await probe("delegate-token", []);
3045
+ assert.equal(empty.status, 400);
3046
+ assert.equal(empty.headers.get("cache-control"), "no-store");
3047
+ await empty.text();
3048
+
3049
+ const unknown = await probe("delegate-token", ["not_an_operation"]);
3050
+ assert.equal(unknown.status, 400);
3051
+ assert.equal(unknown.headers.get("cache-control"), "no-store");
3052
+ await unknown.text();
3053
+ } finally {
3054
+ await server.stop();
3055
+ }
3056
+ });
@@ -38,6 +38,7 @@ import {
38
38
  import { expandTildePath } from "./utils/path.js";
39
39
  import { projectTagProjectId } from "./coding/coding-namespace.js";
40
40
  import { getOperation, type OperationName } from "./access-boundary.js";
41
+ import { probeOperationAuthorization } from "./access-authorization-probe.js";
41
42
  import { resolveQueryNamespaceWritablePreflight } from "./access-namespace-preflight.js";
42
43
  import {
43
44
  assertOperationAllowed,
@@ -889,6 +890,16 @@ export class EngramAccessHttpServer {
889
890
  return;
890
891
  }
891
892
 
893
+ if (req.method === "GET" && pathname === "/engram/v1/authorization") {
894
+ res.setHeader("cache-control", "no-store");
895
+ this.respondJson(
896
+ res,
897
+ 200,
898
+ probeOperationAuthorization(tokenCapabilityStore.getStore(), parsed.searchParams.getAll("op")),
899
+ );
900
+ return;
901
+ }
902
+
892
903
  if (req.method === "GET" && pathname === "/engram/v1/adapters") {
893
904
  // Issue #1850 round 5 (finding 1): adapter metadata is served after
894
905
  // auth but was NOT op-gated, so a deny-all or narrow-ops token reached
@@ -449,3 +449,215 @@ test("health keeps namespace QMD failures scoped to the namespace", async () =>
449
449
  await rm(rootDir, { recursive: true, force: true });
450
450
  }
451
451
  });
452
+
453
+ test("health surfaces extraction liveness as degraded when the buffer is non-empty and the watermark is stale", async () => {
454
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-"));
455
+ try {
456
+ const oldTs = new Date(Date.now() - 10_000).toISOString();
457
+ const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 1000 } });
458
+ const service = new EngramAccessService({
459
+ config,
460
+ qmd: makeQmd({}),
461
+ buffer: {
462
+ getBufferSnapshot: async () => ({ bufferedSessionCount: 3, pendingTurnCount: 12, oldestTurnTimestamp: oldTs }),
463
+ },
464
+ // The extraction watermark is read from the daemon-global root store,
465
+ // not the per-namespace store (issue #2151).
466
+ storage: {
467
+ loadMeta: async () => ({
468
+ lastExtractionAt: oldTs,
469
+ extractionCount: 4,
470
+ lastConsolidationAt: null,
471
+ totalMemories: 0,
472
+ totalEntities: 0,
473
+ }),
474
+ },
475
+ async getStorage() {
476
+ return { dir: memoryDir };
477
+ },
478
+ } as unknown as Orchestrator);
479
+
480
+ const health = await service.health();
481
+ assert.equal(health.extraction.degraded, true);
482
+ assert.equal(health.extraction.bufferedSessionCount, 3);
483
+ assert.equal(health.extraction.pendingTurnCount, 12);
484
+ assert.equal(health.extraction.lastExtractionAt, oldTs);
485
+ const oldestAge = health.extraction.oldestBufferedTurnAgeMs ?? -1;
486
+ assert.ok(
487
+ oldestAge >= 10_000 && oldestAge < 60_000,
488
+ `oldest buffered turn age reflects the ~10s offset, not merely non-negative (got ${oldestAge}ms)`,
489
+ );
490
+ assert.ok(
491
+ health.extraction.degradedReason !== null && health.extraction.degradedReason.length > 0,
492
+ "degraded reason is populated",
493
+ );
494
+ } finally {
495
+ await rm(memoryDir, { recursive: true, force: true });
496
+ }
497
+ });
498
+
499
+ test("health reports extraction liveness ok when the buffer is empty (nothing to extract)", async () => {
500
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-ok-"));
501
+ try {
502
+ const oldTs = new Date(Date.now() - 10_000).toISOString();
503
+ const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 1000 } });
504
+ const service = new EngramAccessService({
505
+ config,
506
+ qmd: makeQmd({}),
507
+ buffer: {
508
+ getBufferSnapshot: async () => ({ bufferedSessionCount: 0, pendingTurnCount: 0, oldestTurnTimestamp: null }),
509
+ },
510
+ storage: {
511
+ loadMeta: async () => ({
512
+ lastExtractionAt: oldTs,
513
+ extractionCount: 4,
514
+ lastConsolidationAt: null,
515
+ totalMemories: 0,
516
+ totalEntities: 0,
517
+ }),
518
+ },
519
+ async getStorage() {
520
+ return { dir: memoryDir };
521
+ },
522
+ } as unknown as Orchestrator);
523
+
524
+ const health = await service.health();
525
+ assert.equal(health.extraction.degraded, false);
526
+ assert.equal(health.extraction.bufferedSessionCount, 0);
527
+ assert.equal(health.extraction.lastExtractionAt, oldTs);
528
+ } finally {
529
+ await rm(memoryDir, { recursive: true, force: true });
530
+ }
531
+ });
532
+
533
+ test("health returns the same daemon-global extraction verdict for every namespace (issue #2151)", async () => {
534
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-ns-"));
535
+ try {
536
+ const rootTs = new Date().toISOString(); // fresh daemon-global watermark
537
+ const staleTs = new Date(Date.now() - 7_200_000).toISOString(); // 2h old
538
+ const config = parseConfig({
539
+ memoryDir,
540
+ qmdEnabled: false,
541
+ namespacesEnabled: true,
542
+ defaultNamespace: "default",
543
+ extractionLiveness: { staleWindowMs: 3_600_000 },
544
+ });
545
+ // Per-namespace stores return DIVERGING watermarks (fresh vs 2h stale vs
546
+ // never), but the global buffer is shared and the watermark must be sourced
547
+ // from the root store. Pre-fix, the extraction verdict tracked the
548
+ // namespace argument; post-fix it is identical for every namespace.
549
+ const perNamespaceMeta: Record<string, string | null> = { fresh: rootTs, stale: staleTs };
550
+ const service = new EngramAccessService({
551
+ config,
552
+ qmd: makeQmd({}),
553
+ buffer: {
554
+ getBufferSnapshot: async () => ({ bufferedSessionCount: 3, pendingTurnCount: 12, oldestTurnTimestamp: staleTs }),
555
+ },
556
+ storage: {
557
+ loadMeta: async () => ({
558
+ lastExtractionAt: rootTs,
559
+ extractionCount: 4,
560
+ lastConsolidationAt: null,
561
+ totalMemories: 0,
562
+ totalEntities: 0,
563
+ }),
564
+ },
565
+ async getStorage(namespace?: string) {
566
+ return {
567
+ dir: memoryDir,
568
+ loadMeta: async () => ({
569
+ lastExtractionAt: namespace ? perNamespaceMeta[namespace] ?? null : staleTs,
570
+ extractionCount: 4,
571
+ lastConsolidationAt: null,
572
+ totalMemories: 0,
573
+ totalEntities: 0,
574
+ }),
575
+ };
576
+ },
577
+ } as unknown as Orchestrator);
578
+
579
+ const fresh = (await service.health("fresh")).extraction;
580
+ const stale = (await service.health("stale")).extraction;
581
+ const def = (await service.health()).extraction;
582
+ // The namespace-governed fields must not vary with the namespace argument
583
+ // (oldestBufferedTurnAgeMs is time-derived and intentionally excluded).
584
+ assert.equal(stale.degraded, fresh.degraded, "degraded must not vary by namespace");
585
+ assert.equal(def.degraded, fresh.degraded, "default health matches namespaced health");
586
+ assert.equal(stale.lastExtractionAt, fresh.lastExtractionAt, "watermark must not vary by namespace");
587
+ assert.equal(def.lastExtractionAt, fresh.lastExtractionAt);
588
+ assert.equal(stale.degradedReason, fresh.degradedReason);
589
+ // Sourced from the fresh root watermark → healthy despite stale per-namespace stores.
590
+ assert.equal(fresh.degraded, false);
591
+ assert.equal(fresh.lastExtractionAt, rootTs);
592
+ } finally {
593
+ await rm(memoryDir, { recursive: true, force: true });
594
+ }
595
+ });
596
+
597
+ test("health reports extraction liveness degraded when the buffer read fails (§22)", async () => {
598
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-readfail-"));
599
+ try {
600
+ const freshTs = new Date().toISOString();
601
+ const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 3_600_000 } });
602
+ const service = new EngramAccessService({
603
+ config,
604
+ qmd: makeQmd({}),
605
+ buffer: {
606
+ getBufferSnapshot: async () => {
607
+ throw new Error("buffer file corrupt");
608
+ },
609
+ },
610
+ // Fresh watermark → the ONLY fault is the unreadable buffer, proving the
611
+ // read failure (not staleness) drives the degradation.
612
+ storage: {
613
+ loadMeta: async () => ({
614
+ lastExtractionAt: freshTs,
615
+ extractionCount: 4,
616
+ lastConsolidationAt: null,
617
+ totalMemories: 0,
618
+ totalEntities: 0,
619
+ }),
620
+ },
621
+ async getStorage() {
622
+ return { dir: memoryDir };
623
+ },
624
+ } as unknown as Orchestrator);
625
+
626
+ const health = await service.health();
627
+ assert.equal(health.extraction.degraded, true, "an unreadable buffer must not report a healthy pipeline");
628
+ assert.match(health.extraction.degradedReason ?? "", /unreadable/);
629
+ assert.match(health.extraction.degradedReason ?? "", /buffer file corrupt/);
630
+ } finally {
631
+ await rm(memoryDir, { recursive: true, force: true });
632
+ }
633
+ });
634
+
635
+ test("health reports extraction liveness degraded when the watermark (meta) read fails (§22)", async () => {
636
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-metafail-"));
637
+ try {
638
+ const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 3_600_000 } });
639
+ const service = new EngramAccessService({
640
+ config,
641
+ qmd: makeQmd({}),
642
+ // Empty buffer: proves the meta-read failure alone drives the degradation.
643
+ buffer: {
644
+ getBufferSnapshot: async () => ({ bufferedSessionCount: 0, pendingTurnCount: 0, oldestTurnTimestamp: null }),
645
+ },
646
+ storage: {
647
+ loadMeta: async () => {
648
+ throw new Error("meta.json unreadable");
649
+ },
650
+ },
651
+ async getStorage() {
652
+ return { dir: memoryDir };
653
+ },
654
+ } as unknown as Orchestrator);
655
+
656
+ const health = await service.health();
657
+ assert.equal(health.extraction.degraded, true, "an unreadable watermark must not report a healthy pipeline");
658
+ assert.match(health.extraction.degradedReason ?? "", /watermark unreadable/);
659
+ assert.match(health.extraction.degradedReason ?? "", /meta\.json unreadable/);
660
+ } finally {
661
+ await rm(memoryDir, { recursive: true, force: true });
662
+ }
663
+ });
@@ -6,6 +6,7 @@ import { readdirSync, unlinkSync } from "node:fs";
6
6
  import { createHash } from "node:crypto";
7
7
  import { ZodError } from "zod";
8
8
  import { AccessIdempotencyStore, hashAccessIdempotencyPayload } from "./access-idempotency.js";
9
+ import { computeExtractionLivenessStatus, ExtractionLivenessWarnThrottle } from "./extraction-liveness.js";
9
10
  import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
10
11
  import {
11
12
  recordCitationUsage as recordCitationUsageForAccess,
@@ -18,7 +19,13 @@ import { resolveNamespaceCapabilities,
18
19
  resolveMemoryLifecycleCapabilities,
19
20
  resolveQmdCapabilities,
20
21
  resolveSecurityCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities, resolveRecallAuxiliaryCapabilities } from "./capabilities.js";
21
- import { CorpusWatermarkCache, computeServiceCorpusWatermarks, type CorpusWatermark } from "./corpus-watermark.js";
22
+ import { CorpusWatermarkCache, computeServiceCorpusWatermarks } from "./corpus-watermark.js";
23
+ import type {
24
+ EngramAccessHealthResponse,
25
+ EngramAccessQmdCollectionState,
26
+ EngramAccessQmdHealthResponse,
27
+ } from "./access-health-types.js";
28
+ export type { EngramAccessHealthResponse, EngramAccessQmdCollectionState, EngramAccessQmdHealthResponse };
22
29
  import { AccessAuditAdapter, type AccessAuditConfig, type AccessAuditResult } from "./access-audit.js";
23
30
  import type { AnomalyDetectorResult } from "./recall-audit-anomaly.js";
24
31
  import { resolveGitContext } from "./coding/git-context.js";
@@ -342,44 +349,6 @@ function normalizeTrustZoneInputError(error: unknown): EngramAccessInputError |
342
349
 
343
350
  export const ENGRAM_ACCESS_WRITE_SCHEMA_VERSION = 1;
344
351
 
345
- export interface EngramAccessHealthResponse {
346
- ok: true;
347
- memoryDir: string;
348
- namespacesEnabled: boolean;
349
- defaultNamespace: string;
350
- searchBackend: string;
351
- qmdEnabled: boolean;
352
- qmd: EngramAccessQmdHealthResponse;
353
- nativeKnowledgeEnabled: boolean;
354
- projectionAvailable: boolean;
355
- corpus: CorpusWatermark[];
356
- }
357
-
358
- export type EngramAccessQmdCollectionState =
359
- | "present"
360
- | "missing"
361
- | "unknown"
362
- | "skipped";
363
-
364
- export interface EngramAccessQmdHealthResponse {
365
- enabled: boolean;
366
- active: boolean;
367
- degraded: boolean;
368
- mode: "cli" | "daemon" | "fallback" | "disabled" | "not-selected";
369
- collection: string;
370
- collectionState: EngramAccessQmdCollectionState;
371
- installedVersion: string | null;
372
- supportedVersion: string | null;
373
- supported: boolean | null;
374
- upgradeAvailable: boolean | null;
375
- doctorAvailable: boolean | null;
376
- debugStatus: string;
377
- pendingEmbeddings: number | null;
378
- oldestPendingAgeMs: number | null;
379
- embeddingBacklogThreshold: number;
380
- degradedReason?: string;
381
- }
382
-
383
352
  export interface EngramAccessRecallRequest {
384
353
  query: string;
385
354
  sessionKey?: string;
@@ -1365,6 +1334,7 @@ export class EngramAccessService {
1365
1334
  }
1366
1335
  return this._accessIdentityContinuitySurface;
1367
1336
  }
1337
+ private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
1368
1338
 
1369
1339
  constructor(private readonly orchestrator: Orchestrator) {
1370
1340
  this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
@@ -2458,6 +2428,7 @@ export class EngramAccessService {
2458
2428
  const storage = await this.orchestrator.getStorage(resolvedNamespace);
2459
2429
  const searchBackend = this.orchestrator.config.searchBackend ?? "qmd";
2460
2430
  const qmdEnabled = resolveQmdCapabilities(this.orchestrator.config).qmd === true;
2431
+ const extraction = await computeExtractionLivenessStatus(this.orchestrator, this.extractionLivenessWarn);
2461
2432
  let projectionAvailable = false;
2462
2433
  try {
2463
2434
  await stat(getMemoryProjectionPath(storage.dir));
@@ -2481,6 +2452,7 @@ export class EngramAccessService {
2481
2452
  ),
2482
2453
  nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
2483
2454
  projectionAvailable,
2455
+ extraction,
2484
2456
  corpus: await computeServiceCorpusWatermarks(this.orchestrator, {
2485
2457
  cache: this.corpusWatermarkCache, caps: tokenCapabilityStore.getStore() }),
2486
2458
  };
@@ -493,9 +493,9 @@ test("MCP tools/list matches the catalog exactly (no untracked handlers)", async
493
493
  * patterns from the source and compares against HTTP_ROUTES so a new
494
494
  * service-invoking route cannot land without a catalog entry.
495
495
  *
496
- * Infrastructure routes (health, admin console, UI assets, MCP delegate) are
497
- * excluded — they carry no user-validated request envelope. (Adapters was
498
- * migrated into the catalog in issue #1850 round 5.)
496
+ * Infrastructure routes (health, auth capability probes, admin console, UI
497
+ * assets, MCP delegate) are excluded — they do not invoke an access-service
498
+ * method. (Adapters was migrated into the catalog in issue #1850 round 5.)
499
499
  */
500
500
  test("HTTP handler source routes match the catalog (static completeness)", () => {
501
501
  const httpSource = readFileSync(
@@ -534,6 +534,7 @@ test("HTTP handler source routes match the catalog (static completeness)", () =>
534
534
 
535
535
  const INFRA = [
536
536
  /^\/engram\/v1\/health$/,
537
+ /^\/engram\/v1\/authorization$/,
537
538
  /^\/engram\/v1\/admin\//,
538
539
  /^\/engram\/ui/,
539
540
  /^\/mcp$/,
@@ -249,6 +249,37 @@ export function capabilityAllowsOp(caps: TokenCapabilities | undefined | null, o
249
249
  return caps.ops.includes(op);
250
250
  }
251
251
 
252
+ /**
253
+ * The operation policy that all access surfaces use to decide whether a token
254
+ * can invoke an operation.
255
+ */
256
+ export interface OperationAuthorizationPolicy {
257
+ readonly name: string;
258
+ readonly allowedByOps?: readonly string[];
259
+ readonly fleetWide?: boolean;
260
+ }
261
+
262
+ /**
263
+ * Apply an operation's alternate grant and fleet-wide restrictions without
264
+ * invoking its handler.
265
+ */
266
+ export function assertOperationAuthorizationAllowed(
267
+ caps: TokenCapabilities | undefined | null,
268
+ operation: OperationAuthorizationPolicy,
269
+ ): void {
270
+ if (operation.allowedByOps && operation.allowedByOps.length > 0) {
271
+ if (!operation.allowedByOps.some((allowedOperation) => capabilityAllowsOp(caps, allowedOperation))) {
272
+ throw new EngramAccessForbiddenError(`token is not permitted to call operation: ${operation.name}`);
273
+ }
274
+ } else {
275
+ assertOperationAllowed(caps, operation.name);
276
+ }
277
+
278
+ if (operation.fleetWide) {
279
+ assertFleetWideOperationAllowed(caps);
280
+ }
281
+ }
282
+
252
283
  /**
253
284
  * True when `caps` permits `namespace`.
254
285
  * - record ABSENT / namespaces axis ABSENT ⇒ unrestricted (true).
package/src/buffer.ts CHANGED
@@ -10,6 +10,7 @@ import type {
10
10
  SignalLevel,
11
11
  } from "./types.js";
12
12
  import { resolvePresentationCapabilities } from "./capabilities.js";
13
+ import type { ExtractionBufferSnapshot } from "./extraction-liveness.js";
13
14
 
14
15
  export type TriggerDecision = "extract_now" | "extract_batch" | "keep_buffering";
15
16
 
@@ -306,6 +307,35 @@ export class SmartBuffer {
306
307
  await this.enqueueMutation(async () => this.loadUnlocked());
307
308
  }
308
309
 
310
+ /** Snapshot of buffered, not-yet-extracted work across sessions (#2151): session count,
311
+ * pending-turn total, oldest buffered turn. Counts retained (#562) + active turns per entry. */
312
+ async getBufferSnapshot(): Promise<ExtractionBufferSnapshot> {
313
+ await this.load();
314
+ let bufferedSessionCount = 0;
315
+ let pendingTurnCount = 0;
316
+ let oldestMs = Number.POSITIVE_INFINITY;
317
+ let oldestTurnTimestamp: string | null = null;
318
+ const consider = (turns: BufferTurn[] | undefined): void => {
319
+ if (!Array.isArray(turns) || turns.length === 0) return;
320
+ bufferedSessionCount += 1;
321
+ pendingTurnCount += turns.length;
322
+ const first = turns[0]?.timestamp;
323
+ const parsed = typeof first === "string" ? Date.parse(first) : Number.NaN;
324
+ if (Number.isFinite(parsed) && parsed < oldestMs) {
325
+ oldestMs = parsed;
326
+ oldestTurnTimestamp = first ?? null;
327
+ }
328
+ };
329
+ const entries = this.state.entries;
330
+ if (entries) {
331
+ // Retained turns (deferred #562) are pending too - count with active (oldest-first), like getTurns().
332
+ for (const entry of Object.values(entries)) consider([...(entry?.retainedTurns ?? []), ...(entry?.turns ?? [])]);
333
+ } else {
334
+ consider(this.state.turns);
335
+ }
336
+ return { bufferedSessionCount, pendingTurnCount, oldestTurnTimestamp };
337
+ }
338
+
309
339
  /**
310
340
  * Reset the buffer to an empty, usable state.
311
341
  * Called when the persisted buffer file is corrupt and load() fails,
package/src/cli.ts CHANGED
@@ -30,6 +30,7 @@ import { isRecallDisclosure, RECALL_DISCLOSURE_LEVELS } from "./types.js";
30
30
  import { chunkContent } from "./chunking.js";
31
31
  import { rescoreMemoryImportance } from "./importance.js";
32
32
  import { renderQmdBacklogStatus } from "./qmd-status.js";
33
+ import { renderExtractionLivenessStats } from "./extraction-liveness.js";
33
34
  import { exportJsonBundle } from "./transfer/export-json.js";
34
35
  import { exportMarkdownBundle } from "./transfer/export-md.js";
35
36
  import { backupMemoryDir } from "./transfer/backup.js";
@@ -3653,7 +3654,6 @@ export function registerCli(
3653
3654
  // Ensure QMD is probed before checking availability
3654
3655
  await orchestrator.qmd.probe();
3655
3656
 
3656
- const meta = await orchestrator.storage.loadMeta();
3657
3657
  const memories = await orchestrator.storage.readAllMemories();
3658
3658
  const entities = await orchestrator.storage.readEntities();
3659
3659
  const profile = await orchestrator.storage.readProfile();
@@ -3662,9 +3662,7 @@ export function registerCli(
3662
3662
  console.log(`Total memories: ${memories.length}`);
3663
3663
  console.log(`Total entities: ${entities.length}`);
3664
3664
  console.log(`Profile size: ${profile.length} chars`);
3665
- console.log(`Extractions: ${meta.extractionCount}`);
3666
- console.log(`Last extraction: ${meta.lastExtractionAt ?? "never"}`);
3667
- console.log(`Last consolidation: ${meta.lastConsolidationAt ?? "never"}`);
3665
+ for (const line of await renderExtractionLivenessStats(orchestrator)) console.log(line);
3668
3666
  console.log(`QMD: ${orchestrator.qmd.isAvailable() ? "available" : "not available"}`);
3669
3667
  for (const line of await renderQmdBacklogStatus(orchestrator.qmd, orchestrator.config.qmdEmbeddingBacklogThreshold)) console.log(line);
3670
3668
 
package/src/config.ts CHANGED
@@ -37,6 +37,7 @@ import { expandTildePath } from "./utils/path.js";
37
37
  // config.ts → connectors/index.ts nor the reverse circular import arises.
38
38
  import { coerceBool, coerceBooleanLike, coerceInstallExtension, coerceNumber } from "./connectors/coerce.js";
39
39
  import { parseRecallConcurrencyConfig } from "./recall-concurrency-config.js";
40
+ import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
40
41
  import { hasLegacyConnectorEntries } from "./connectors/paths.js";
41
42
  import {
42
43
  parseQmdChunkStrategy,
@@ -2326,15 +2327,14 @@ export function parseConfig(
2326
2327
  typeof cfg.activeRecallEntityGraphDepth === "number"
2327
2328
  ? Math.min(3, Math.max(0, Math.floor(cfg.activeRecallEntityGraphDepth)))
2328
2329
  : 1,
2329
- activeRecallIncludeCausalTrajectories:
2330
- cfg.activeRecallIncludeCausalTrajectories === true,
2330
+ activeRecallIncludeCausalTrajectories: cfg.activeRecallIncludeCausalTrajectories === true,
2331
2331
  activeRecallIncludeDaySummary: cfg.activeRecallIncludeDaySummary === true,
2332
2332
  activeRecallAttachRecallExplain: cfg.activeRecallAttachRecallExplain === true,
2333
- activeRecallAllowChainedActiveMemory:
2334
- cfg.activeRecallAllowChainedActiveMemory === true,
2333
+ activeRecallAllowChainedActiveMemory: cfg.activeRecallAllowChainedActiveMemory === true,
2335
2334
  dreaming,
2336
2335
  dreamsPhases,
2337
2336
  procedural,
2337
+ extractionLiveness: parseExtractionLivenessConfig(cfg),
2338
2338
  wearables,
2339
2339
  meetings,
2340
2340
  activity,