@remnic/core 9.27.0 → 9.29.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 (515) hide show
  1. package/dist/access-admin-ops-surface.d.ts +13 -10
  2. package/dist/access-admin-ops-surface.js +46 -41
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +13 -10
  5. package/dist/access-authorization-probe.js +47 -42
  6. package/dist/access-boundary.d.ts +13 -10
  7. package/dist/access-boundary.js +46 -41
  8. package/dist/access-cli.js +105 -96
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-health-types.d.ts +10 -1
  11. package/dist/access-http-lcm-compaction.d.ts +13 -10
  12. package/dist/access-http.d.ts +13 -10
  13. package/dist/access-http.js +56 -51
  14. package/dist/access-identity-continuity-surface.d.ts +9 -8
  15. package/dist/access-identity-continuity-surface.js +46 -41
  16. package/dist/access-lcm-surface.d.ts +13 -10
  17. package/dist/access-lcm-surface.js +46 -41
  18. package/dist/access-mcp.d.ts +13 -10
  19. package/dist/access-mcp.js +51 -46
  20. package/dist/access-memory-search-fanout.d.ts +2 -2
  21. package/dist/access-memory-search-fanout.js +3 -3
  22. package/dist/{access-namespace-preflight-wRSZEO5V.d.ts → access-namespace-preflight-DCXBkDp0.d.ts} +1 -1
  23. package/dist/access-namespace-preflight.d.ts +3 -3
  24. package/dist/access-namespace-preflight.js +46 -41
  25. package/dist/access-observe-write-surface.d.ts +13 -10
  26. package/dist/access-observe-write-surface.js +46 -41
  27. package/dist/access-operations-batch.js +48 -43
  28. package/dist/access-operations.d.ts +16 -13
  29. package/dist/access-operations.js +50 -45
  30. package/dist/access-recall-concurrency.d.ts +13 -10
  31. package/dist/access-recall-concurrency.js +46 -41
  32. package/dist/access-recall-response.d.ts +13 -10
  33. package/dist/access-recall-response.js +46 -41
  34. package/dist/access-recall-surface.d.ts +13 -10
  35. package/dist/access-recall-surface.js +46 -41
  36. package/dist/access-schema.d.ts +80 -80
  37. package/dist/access-schema.js +3 -3
  38. package/dist/{access-service-B4-Fu9x2.d.ts → access-service-DvPW_M5j.d.ts} +12 -8
  39. package/dist/access-service.d.ts +13 -10
  40. package/dist/access-service.js +46 -41
  41. package/dist/access-surface-catalog.d.ts +13 -10
  42. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  43. package/dist/action-confidence.d.ts +1 -1
  44. package/dist/active-memory-bridge.d.ts +1 -1
  45. package/dist/active-memory-bridge.js +3 -3
  46. package/dist/active-recall.d.ts +1 -1
  47. package/dist/active-recall.js +4 -2
  48. package/dist/active-recall.js.map +1 -1
  49. package/dist/adapters/index.js +4 -4
  50. package/dist/adapters/registry.js +2 -2
  51. package/dist/behavior-learner.d.ts +1 -1
  52. package/dist/behavior-signals.d.ts +1 -1
  53. package/dist/bootstrap.d.ts +9 -8
  54. package/dist/briefing.d.ts +3 -2
  55. package/dist/briefing.js +14 -12
  56. package/dist/buffer-surprise-report.d.ts +1 -1
  57. package/dist/buffer.d.ts +3 -2
  58. package/dist/buffer.js +2 -2
  59. package/dist/bulk-import/index.d.ts +3 -3
  60. package/dist/calibration.d.ts +1 -1
  61. package/dist/capabilities.d.ts +3 -2
  62. package/dist/capabilities.js +1 -1
  63. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  64. package/dist/{catalog-BLLxZ5L5.d.ts → catalog-BIVgftWu.d.ts} +1 -1
  65. package/dist/causal-behavior.d.ts +1 -1
  66. package/dist/causal-consolidation.d.ts +1 -1
  67. package/dist/causal-consolidation.js +15 -13
  68. package/dist/causal-consolidation.js.map +1 -1
  69. package/dist/causal-trajectory-graph.d.ts +1 -1
  70. package/dist/{chunk-CI26JDZA.js → chunk-2HNUMF5V.js} +6 -4
  71. package/dist/{chunk-CI26JDZA.js.map → chunk-2HNUMF5V.js.map} +1 -1
  72. package/dist/{chunk-NUWMZIYZ.js → chunk-2XC73SHY.js} +61 -43
  73. package/dist/chunk-2XC73SHY.js.map +1 -0
  74. package/dist/{chunk-RDQGLJRR.js → chunk-2XRE6FLM.js} +2 -1
  75. package/dist/{chunk-RDQGLJRR.js.map → chunk-2XRE6FLM.js.map} +1 -1
  76. package/dist/{chunk-2H7OEVPO.js → chunk-3GD2HFR6.js} +2 -2
  77. package/dist/{chunk-4TFIRMTE.js → chunk-4A6YGWQN.js} +2 -2
  78. package/dist/{chunk-JDOJZTFF.js → chunk-4PBVXX7L.js} +2 -2
  79. package/dist/{chunk-IKMAO55B.js → chunk-55MDBZLC.js} +2 -2
  80. package/dist/{chunk-VDX2J7OX.js → chunk-5W7CTZ2E.js} +4 -4
  81. package/dist/{chunk-B7GROTXD.js → chunk-6LKEUCEM.js} +2 -2
  82. package/dist/{chunk-2AJ72VVS.js → chunk-7BZOBA5J.js} +3 -3
  83. package/dist/{chunk-44DUJETW.js → chunk-7HXCF4RE.js} +2 -2
  84. package/dist/{chunk-X3SQYAPP.js → chunk-ACXPX4AG.js} +2 -2
  85. package/dist/{chunk-AJ7QCSIS.js → chunk-ALSGMEJR.js} +5 -5
  86. package/dist/{chunk-JGUXPJUQ.js → chunk-AS7YMSL6.js} +2 -2
  87. package/dist/{chunk-77CNV7DY.js → chunk-BLAKS3CP.js} +4 -4
  88. package/dist/{chunk-5BRT4Z2I.js → chunk-CMRQ34J5.js} +2 -2
  89. package/dist/{chunk-HEXSNYJD.js → chunk-CSMCNOPH.js} +8 -8
  90. package/dist/chunk-CVILPI77.js +432 -0
  91. package/dist/chunk-CVILPI77.js.map +1 -0
  92. package/dist/{chunk-SK3EYPKC.js → chunk-D2ANTDGO.js} +3 -3
  93. package/dist/{chunk-JCVQV6QX.js → chunk-D3LMYTBV.js} +7 -7
  94. package/dist/{chunk-GJJBPI6I.js → chunk-DRBXHRXE.js} +7 -3
  95. package/dist/chunk-DRBXHRXE.js.map +1 -0
  96. package/dist/{chunk-XY7QPJDA.js → chunk-E6EE5B67.js} +2 -2
  97. package/dist/{chunk-LLISELSY.js → chunk-EP5BVCRI.js} +2 -2
  98. package/dist/{chunk-PTN6UAUA.js → chunk-ES36HTSC.js} +4 -4
  99. package/dist/{chunk-WEAO45M4.js → chunk-ESBQWC3U.js} +4 -4
  100. package/dist/{chunk-EUSLKI4X.js → chunk-EVX44I7C.js} +5 -5
  101. package/dist/{chunk-CIQXI47W.js → chunk-FCDWWCLX.js} +1195 -271
  102. package/dist/chunk-FCDWWCLX.js.map +1 -0
  103. package/dist/{chunk-X6ROIHFE.js → chunk-G5R3D5UP.js} +2 -2
  104. package/dist/{chunk-MG6MNSP4.js → chunk-G6LBWZRF.js} +7 -7
  105. package/dist/{chunk-TKBDJTXG.js → chunk-GBJ4RDFR.js} +94 -20
  106. package/dist/chunk-GBJ4RDFR.js.map +1 -0
  107. package/dist/{chunk-FRVTCCGD.js → chunk-GGUBDXRR.js} +2 -2
  108. package/dist/{chunk-QH6CS6XJ.js → chunk-H24WNPA2.js} +2 -2
  109. package/dist/{chunk-V25OWXAC.js → chunk-HUHX2OCX.js} +1 -1
  110. package/dist/chunk-HUHX2OCX.js.map +1 -0
  111. package/dist/{chunk-TGQ2NTWH.js → chunk-IJ6WHMFB.js} +16 -2
  112. package/dist/{chunk-TGQ2NTWH.js.map → chunk-IJ6WHMFB.js.map} +1 -1
  113. package/dist/{chunk-EOLC6EXV.js → chunk-IMA2EWLV.js} +24 -3
  114. package/dist/chunk-IMA2EWLV.js.map +1 -0
  115. package/dist/{chunk-MQVINOJQ.js → chunk-IYZ5K7MU.js} +3 -3
  116. package/dist/{chunk-RPA2RX5P.js → chunk-JDZRYH2N.js} +2 -2
  117. package/dist/{chunk-M5EPMNS4.js → chunk-K5GB36ME.js} +2 -2
  118. package/dist/{chunk-UT3OQPFA.js → chunk-KUJQHXPH.js} +2 -2
  119. package/dist/{chunk-7RZJWZ46.js → chunk-LEPOP46W.js} +5 -5
  120. package/dist/{chunk-EYJSW2RV.js → chunk-NBDCZWP4.js} +4 -4
  121. package/dist/{chunk-XKGPIWGI.js → chunk-OFHFH655.js} +6 -6
  122. package/dist/{chunk-FGBJBYWP.js → chunk-OVRQLAYR.js} +3 -3
  123. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  124. package/dist/chunk-P2BM76KT.js +528 -0
  125. package/dist/chunk-P2BM76KT.js.map +1 -0
  126. package/dist/{chunk-U3TH5Q2Q.js → chunk-P3MH72CI.js} +2 -2
  127. package/dist/{chunk-P2OZKKYP.js → chunk-PHWUFPCO.js} +2 -2
  128. package/dist/{chunk-KGTD2KZJ.js → chunk-PKRIQL3V.js} +2 -2
  129. package/dist/{chunk-BNGPHGVZ.js → chunk-Q6VFVAKZ.js} +13 -6
  130. package/dist/{chunk-BNGPHGVZ.js.map → chunk-Q6VFVAKZ.js.map} +1 -1
  131. package/dist/{chunk-4MJZTF42.js → chunk-QAOGGNE3.js} +3 -3
  132. package/dist/{chunk-RGJBM7Z3.js → chunk-QMBNMPQM.js} +84 -84
  133. package/dist/{chunk-RGJBM7Z3.js.map → chunk-QMBNMPQM.js.map} +1 -1
  134. package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
  135. package/dist/chunk-RMMVQQA6.js +70 -0
  136. package/dist/chunk-RMMVQQA6.js.map +1 -0
  137. package/dist/{chunk-FCCMFVS6.js → chunk-RPSYDM6C.js} +2 -2
  138. package/dist/chunk-RPW2NOU6.js +33 -0
  139. package/dist/chunk-RPW2NOU6.js.map +1 -0
  140. package/dist/{chunk-RYHWZ52A.js → chunk-S2BBISHU.js} +4 -4
  141. package/dist/{chunk-RSYJV25N.js → chunk-SG265CVF.js} +10 -10
  142. package/dist/{chunk-UGH6VPPO.js → chunk-SH6YO3LT.js} +3 -3
  143. package/dist/{chunk-2RAC4JIG.js → chunk-T3GCXULH.js} +16 -16
  144. package/dist/chunk-T3GCXULH.js.map +1 -0
  145. package/dist/{chunk-FMLKOL2Z.js → chunk-TC3VNKGX.js} +4 -4
  146. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  147. package/dist/{chunk-BJJAX3IZ.js → chunk-UTRO5UJU.js} +2 -2
  148. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  149. package/dist/chunk-VNA7W7QF.js +134 -0
  150. package/dist/chunk-VNA7W7QF.js.map +1 -0
  151. package/dist/{chunk-BHLN7L7M.js → chunk-VVIW3PTA.js} +17 -17
  152. package/dist/chunk-WNIUPHWV.js +152 -0
  153. package/dist/chunk-WNIUPHWV.js.map +1 -0
  154. package/dist/chunk-WOCNN776.js +742 -0
  155. package/dist/chunk-WOCNN776.js.map +1 -0
  156. package/dist/{chunk-XQ4EH6DI.js → chunk-WONS4RZ2.js} +3 -3
  157. package/dist/chunk-WRJVB3C2.js +118 -0
  158. package/dist/chunk-WRJVB3C2.js.map +1 -0
  159. package/dist/{chunk-HORJVJ6K.js → chunk-WZ7UB7XQ.js} +42 -37
  160. package/dist/chunk-WZ7UB7XQ.js.map +1 -0
  161. package/dist/{chunk-MEBQFQ26.js → chunk-XEQ7OT7U.js} +8 -6
  162. package/dist/chunk-XEQ7OT7U.js.map +1 -0
  163. package/dist/{chunk-CSXHRAJJ.js → chunk-XOZ4ALGB.js} +3 -3
  164. package/dist/{chunk-XKO7BM2C.js → chunk-YGHMSDLK.js} +187 -26
  165. package/dist/chunk-YGHMSDLK.js.map +1 -0
  166. package/dist/chunk-YXZG5TVN.js +40 -0
  167. package/dist/chunk-YXZG5TVN.js.map +1 -0
  168. package/dist/{chunk-6NNNURLK.js → chunk-Z54EM5YZ.js} +4 -4
  169. package/dist/{chunk-YSGBD3QN.js → chunk-ZGOQTOYA.js} +3 -3
  170. package/dist/{chunk-4DJQYKMN.js → chunk-ZIKENA2C.js} +2 -2
  171. package/dist/chunk-ZIKENA2C.js.map +1 -0
  172. package/dist/{chunk-RNY3BO35.js → chunk-ZXAGJFHJ.js} +4 -4
  173. package/dist/{cli-Bz7X7dGx.d.ts → cli-CxoSOiG0.d.ts} +5 -5
  174. package/dist/cli.d.ts +14 -12
  175. package/dist/cli.js +73 -68
  176. package/dist/compounding/engine.d.ts +3 -2
  177. package/dist/compounding/engine.js +15 -13
  178. package/dist/compounding/preference-consolidator.d.ts +1 -1
  179. package/dist/compression-optimizer.d.ts +1 -1
  180. package/dist/config.d.ts +1 -1
  181. package/dist/config.js +4 -2
  182. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  183. package/dist/connectors/codex-materialize-runner.js +14 -12
  184. package/dist/connectors/codex-materialize.d.ts +1 -1
  185. package/dist/connectors/index.d.ts +1 -1
  186. package/dist/connectors/index.js +15 -13
  187. package/dist/consolidation-provenance-check.d.ts +3 -2
  188. package/dist/consolidation-undo.d.ts +3 -2
  189. package/dist/contradiction/index.d.ts +3 -2
  190. package/dist/contradiction/index.js +6 -6
  191. package/dist/{contradiction-scan-HMF7CNKD.js → contradiction-scan-HYLIRMJ2.js} +3 -3
  192. package/dist/conversation-index/backend.d.ts +1 -1
  193. package/dist/conversation-index/backend.js +2 -2
  194. package/dist/conversation-index/chunker.d.ts +1 -1
  195. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  196. package/dist/conversation-index/indexer.d.ts +1 -1
  197. package/dist/conversation-index/search.d.ts +1 -1
  198. package/dist/corpus-watermark.d.ts +15 -2
  199. package/dist/corpus-watermark.js +27 -23
  200. package/dist/day-summary.d.ts +1 -1
  201. package/dist/day-summary.js +2 -2
  202. package/dist/delinearize.d.ts +1 -1
  203. package/dist/direct-answer-wiring.d.ts +1 -1
  204. package/dist/direct-answer.d.ts +1 -1
  205. package/dist/embedding-fallback.d.ts +1 -1
  206. package/dist/embedding-fallback.js +2 -2
  207. package/dist/enrichment/index.d.ts +1 -1
  208. package/dist/entity-id-normalization.d.ts +4 -0
  209. package/dist/entity-id-normalization.js +10 -0
  210. package/dist/entity-id-normalization.js.map +1 -0
  211. package/dist/entity-retrieval-boundaries.d.ts +3 -0
  212. package/dist/entity-retrieval-boundaries.js +8 -0
  213. package/dist/entity-retrieval-boundaries.js.map +1 -0
  214. package/dist/entity-retrieval.d.ts +3 -2
  215. package/dist/entity-retrieval.js +15 -12
  216. package/dist/entity-schema.d.ts +1 -1
  217. package/dist/entity-schema.js +1 -1
  218. package/dist/explicit-capture.d.ts +9 -8
  219. package/dist/explicit-capture.js +2 -2
  220. package/dist/extraction-error-classification.d.ts +1 -1
  221. package/dist/extraction-faithfulness.d.ts +1 -1
  222. package/dist/extraction-judge-telemetry.d.ts +1 -1
  223. package/dist/extraction-judge-training.d.ts +1 -1
  224. package/dist/extraction-judge.d.ts +1 -1
  225. package/dist/extraction-liveness.d.ts +1 -1
  226. package/dist/extraction-source-grounding-helpers.d.ts +34 -0
  227. package/dist/extraction-source-grounding-helpers.js +62 -0
  228. package/dist/extraction-source-grounding-helpers.js.map +1 -0
  229. package/dist/extraction-source-grounding-rules.d.ts +18 -0
  230. package/dist/extraction-source-grounding-rules.js +12 -0
  231. package/dist/extraction-source-grounding-rules.js.map +1 -0
  232. package/dist/extraction-source-grounding.d.ts +11 -0
  233. package/dist/extraction-source-grounding.js +13 -0
  234. package/dist/extraction-source-grounding.js.map +1 -0
  235. package/dist/extraction.d.ts +3 -1
  236. package/dist/extraction.js +7 -4
  237. package/dist/fallback-llm.d.ts +1 -1
  238. package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-F2QJD66E.js} +2 -2
  239. package/dist/graph-dashboard-diff.d.ts +1 -1
  240. package/dist/graph-dashboard-key.d.ts +1 -1
  241. package/dist/graph-dashboard-parser.d.ts +1 -1
  242. package/dist/graph-edge-reinforcement.d.ts +1 -1
  243. package/dist/graph-snapshot.d.ts +1 -1
  244. package/dist/graph.d.ts +1 -1
  245. package/dist/importance.d.ts +1 -1
  246. package/dist/importers/index.d.ts +1 -1
  247. package/dist/in-flight-reads.d.ts +1 -1
  248. package/dist/index.d.ts +407 -405
  249. package/dist/index.js +154 -145
  250. package/dist/intent.d.ts +1 -1
  251. package/dist/lcm/engine.d.ts +1 -1
  252. package/dist/lcm/engine.js +2 -2
  253. package/dist/lcm/index.d.ts +1 -1
  254. package/dist/lcm/index.js +2 -2
  255. package/dist/lcm/tools.d.ts +1 -1
  256. package/dist/lifecycle.d.ts +1 -1
  257. package/dist/live-connectors-runner.d.ts +1 -1
  258. package/dist/local-llm.d.ts +1 -1
  259. package/dist/local-llm.js +2 -2
  260. package/dist/local-model-endpoint.d.ts +1 -1
  261. package/dist/maintenance/memory-governance.d.ts +1 -1
  262. package/dist/maintenance/memory-governance.js +14 -12
  263. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  264. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -12
  265. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  266. package/dist/maintenance/rebuild-memory-projection.js +15 -13
  267. package/dist/{maintenance-DgnD2z8S.d.ts → maintenance-Cb-PjxQd.d.ts} +3 -3
  268. package/dist/mcp-memory-inspector-app.d.ts +13 -10
  269. package/dist/memory-action-policy.d.ts +1 -1
  270. package/dist/memory-cache.d.ts +1 -1
  271. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  272. package/dist/memory-projection-mutations.d.ts +4 -0
  273. package/dist/memory-projection-mutations.js +15 -0
  274. package/dist/memory-projection-mutations.js.map +1 -0
  275. package/dist/memory-projection-store.d.ts +1 -1
  276. package/dist/memory-provenance.d.ts +1 -1
  277. package/dist/memory-worth-outcomes.d.ts +3 -2
  278. package/dist/models-json.d.ts +1 -1
  279. package/dist/namespaces/migrate.d.ts +4 -3
  280. package/dist/namespaces/migrate.js +24 -22
  281. package/dist/namespaces/principal.d.ts +1 -1
  282. package/dist/namespaces/principal.js +2 -2
  283. package/dist/namespaces/search.d.ts +1 -1
  284. package/dist/namespaces/search.js +10 -10
  285. package/dist/namespaces/storage.d.ts +4 -3
  286. package/dist/namespaces/storage.js +14 -12
  287. package/dist/native-knowledge.d.ts +1 -1
  288. package/dist/offline-sync-impression-drain.d.ts +1 -1
  289. package/dist/offline-sync-impression-drain.js +7 -7
  290. package/dist/operator-doctor-corpus.d.ts +22 -3
  291. package/dist/operator-doctor-corpus.js +34 -24
  292. package/dist/operator-doctor-replica.d.ts +52 -0
  293. package/dist/operator-doctor-replica.js +15 -0
  294. package/dist/operator-doctor-replica.js.map +1 -0
  295. package/dist/operator-toolkit.d.ts +7 -3
  296. package/dist/operator-toolkit.js +37 -31
  297. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  298. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  299. package/dist/orchestration/maintenance.d.ts +5 -4
  300. package/dist/orchestration/maintenance.js +21 -19
  301. package/dist/{orchestrator-rIHmHpv1.d.ts → orchestrator-5GKqb_HL.d.ts} +7 -7
  302. package/dist/orchestrator.d.ts +9 -8
  303. package/dist/orchestrator.js +105 -96
  304. package/dist/patterns-cli.d.ts +1 -1
  305. package/dist/{pipeline-Bq5zU6Bp.d.ts → pipeline-3Qi1TpRo.d.ts} +1 -1
  306. package/dist/policy-runtime.d.ts +1 -1
  307. package/dist/proactive-contention.d.ts +1 -1
  308. package/dist/provenance.d.ts +1 -1
  309. package/dist/{qmd-3ILJkC70.d.ts → qmd-D9JqzzRX.d.ts} +1 -1
  310. package/dist/qmd-preflight.d.ts +2 -2
  311. package/dist/qmd-recall-cache.d.ts +1 -1
  312. package/dist/qmd.d.ts +2 -2
  313. package/dist/recall-concurrency-config.d.ts +1 -1
  314. package/dist/recall-disclosure-escalation.d.ts +1 -1
  315. package/dist/recall-explain-renderer.d.ts +1 -1
  316. package/dist/recall-explain-renderer.js +3 -3
  317. package/dist/recall-memory-map.d.ts +1 -1
  318. package/dist/recall-planner-llm.d.ts +1 -1
  319. package/dist/recall-state.d.ts +1 -1
  320. package/dist/recall-state.js +2 -2
  321. package/dist/recall-tag-filter.d.ts +1 -1
  322. package/dist/recall-timings.d.ts +1 -1
  323. package/dist/recall-xray-cli.d.ts +1 -1
  324. package/dist/recall-xray-cli.js +4 -4
  325. package/dist/recall-xray-renderer.d.ts +1 -1
  326. package/dist/recall-xray-renderer.js +3 -3
  327. package/dist/recall-xray.d.ts +1 -1
  328. package/dist/recall-xray.js +2 -2
  329. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  330. package/dist/replay/normalizers/claude.d.ts +1 -1
  331. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  332. package/dist/replay/normalizers/shared.d.ts +1 -1
  333. package/dist/replay/runner.d.ts +1 -1
  334. package/dist/replay/types.d.ts +1 -1
  335. package/dist/replica-divergence.d.ts +279 -0
  336. package/dist/replica-divergence.js +28 -0
  337. package/dist/replica-divergence.js.map +1 -0
  338. package/dist/replica-peers-config.d.ts +5 -0
  339. package/dist/replica-peers-config.js +13 -0
  340. package/dist/replica-peers-config.js.map +1 -0
  341. package/dist/resolve-auth-token.d.ts +21 -2
  342. package/dist/resolve-auth-token.js +5 -1
  343. package/dist/resume-bundles.js +5 -3
  344. package/dist/retrieval-agents.d.ts +2 -2
  345. package/dist/retrieval-tiers.d.ts +1 -1
  346. package/dist/routing/engine.d.ts +1 -1
  347. package/dist/routing/store.d.ts +1 -1
  348. package/dist/salvage-envelope.d.ts +1 -1
  349. package/dist/schemas.d.ts +54 -54
  350. package/dist/{scope-profiles-D0-ff4xT.d.ts → scope-profiles-C4g6_UdP.d.ts} +1 -1
  351. package/dist/search/embed-helper.d.ts +1 -1
  352. package/dist/search/embed-helper.js +2 -2
  353. package/dist/search/factory.d.ts +1 -1
  354. package/dist/search/factory.js +9 -9
  355. package/dist/search/index.d.ts +1 -1
  356. package/dist/search/index.js +9 -9
  357. package/dist/search/lancedb-backend.d.ts +1 -1
  358. package/dist/search/lancedb-backend.js +2 -2
  359. package/dist/search/meilisearch-backend.d.ts +1 -1
  360. package/dist/search/meilisearch-backend.js +2 -2
  361. package/dist/search/noop-backend.d.ts +1 -1
  362. package/dist/search/orama-backend.d.ts +1 -1
  363. package/dist/search/orama-backend.js +2 -2
  364. package/dist/search/port.d.ts +1 -1
  365. package/dist/search/remote-backend.d.ts +1 -1
  366. package/dist/{semantic-consolidation-4Tfh7c1g.d.ts → semantic-consolidation-BrxqnzTW.d.ts} +1 -1
  367. package/dist/semantic-consolidation.d.ts +2 -2
  368. package/dist/semantic-consolidation.js +15 -13
  369. package/dist/semantic-rule-promotion.js +14 -12
  370. package/dist/semantic-rule-verifier.d.ts +1 -1
  371. package/dist/semantic-rule-verifier.js +14 -12
  372. package/dist/{service-cTvil7D_.d.ts → service-Bi1JgxdP.d.ts} +2 -2
  373. package/dist/session-observer-bands.d.ts +1 -1
  374. package/dist/session-observer-state.d.ts +1 -1
  375. package/dist/shared-context/manager.d.ts +9 -9
  376. package/dist/shared-context/manager.js +2 -2
  377. package/dist/signal.d.ts +1 -1
  378. package/dist/{storage-C9ibpTme.d.ts → storage-CcH6yPk2.d.ts} +13 -19
  379. package/dist/storage.d.ts +3 -2
  380. package/dist/storage.js +15 -12
  381. package/dist/summarizer.d.ts +1 -1
  382. package/dist/summarizer.js +3 -3
  383. package/dist/summary-snapshot.d.ts +1 -1
  384. package/dist/temporal-supersession.d.ts +3 -2
  385. package/dist/temporal-timeline-recall.d.ts +1 -1
  386. package/dist/temporal-validity.d.ts +1 -1
  387. package/dist/threading.d.ts +1 -1
  388. package/dist/tier-migration.d.ts +3 -2
  389. package/dist/tier-routing.d.ts +1 -1
  390. package/dist/{tier-stats-XKD7SXYY.js → tier-stats-OPTSBNRH.js} +2 -2
  391. package/dist/topics.d.ts +1 -1
  392. package/dist/transcript.d.ts +1 -1
  393. package/dist/transfer/backup.js +2 -2
  394. package/dist/transfer/capsule-export.js +2 -2
  395. package/dist/transfer/capsule-import.js +2 -2
  396. package/dist/transfer/types.d.ts +66 -66
  397. package/dist/trust-score-stage.d.ts +1 -1
  398. package/dist/trust-score.d.ts +1 -1
  399. package/dist/{types-DHBxIF0s.d.ts → types-Dg0w9ADr.d.ts} +54 -4
  400. package/dist/types.d.ts +1 -1
  401. package/dist/types.js +1 -1
  402. package/dist/utility-runtime.d.ts +1 -1
  403. package/dist/verified-recall.js +14 -12
  404. package/dist/write-envelope.d.ts +1 -1
  405. package/package.json +2 -2
  406. package/src/access-health-types.ts +8 -0
  407. package/src/access-http.test.ts +4 -0
  408. package/src/access-service-health.test.ts +23 -0
  409. package/src/access-service.ts +27 -4
  410. package/src/capabilities.test.ts +1 -0
  411. package/src/capabilities.ts +7 -7
  412. package/src/cli.ts +9 -7
  413. package/src/config.test.ts +5 -0
  414. package/src/config.ts +3 -2
  415. package/src/corpus-watermark.test.ts +21 -0
  416. package/src/corpus-watermark.ts +25 -3
  417. package/src/entity-id-normalization.ts +55 -0
  418. package/src/entity-retrieval-boundaries.ts +134 -0
  419. package/src/entity-retrieval.ts +253 -27
  420. package/src/entity-schema.ts +2 -1
  421. package/src/extraction-source-grounding-helpers.ts +603 -0
  422. package/src/extraction-source-grounding-rules.ts +1031 -0
  423. package/src/extraction-source-grounding.test.ts +2337 -0
  424. package/src/extraction-source-grounding.ts +50 -0
  425. package/src/extraction.ts +120 -15
  426. package/src/memory-projection-mutations.ts +132 -0
  427. package/src/namespaces/storage.ts +5 -3
  428. package/src/operator-doctor-corpus.ts +41 -0
  429. package/src/operator-doctor-replica.test.ts +261 -0
  430. package/src/operator-doctor-replica.ts +129 -0
  431. package/src/operator-toolkit.ts +5 -4
  432. package/src/orchestration/orchestrator-init.ts +2 -2
  433. package/src/replica-divergence.test.ts +1475 -0
  434. package/src/replica-divergence.ts +910 -0
  435. package/src/replica-peers-config.ts +250 -0
  436. package/src/resolve-auth-token.ts +38 -0
  437. package/src/storage/entity-canonical-id-migration-adapter.ts +72 -0
  438. package/src/storage/entity-canonical-id-migration-runner.ts +68 -0
  439. package/src/storage/entity-canonical-id-migration.ts +904 -0
  440. package/src/storage/entity-store.ts +44 -0
  441. package/src/storage/memory-frontmatter-metadata.ts +17 -0
  442. package/src/storage/memory-migration-serialization.ts +37 -0
  443. package/src/storage/memory-read-store.ts +3 -2
  444. package/src/storage/profile-header.ts +8 -7
  445. package/src/storage-profile-timestamp.test.ts +68 -0
  446. package/src/storage.ts +68 -69
  447. package/src/types.ts +5 -5
  448. package/dist/chunk-2RAC4JIG.js.map +0 -1
  449. package/dist/chunk-4DJQYKMN.js.map +0 -1
  450. package/dist/chunk-CIQXI47W.js.map +0 -1
  451. package/dist/chunk-EOLC6EXV.js.map +0 -1
  452. package/dist/chunk-GJJBPI6I.js.map +0 -1
  453. package/dist/chunk-HORJVJ6K.js.map +0 -1
  454. package/dist/chunk-MEBQFQ26.js.map +0 -1
  455. package/dist/chunk-NUWMZIYZ.js.map +0 -1
  456. package/dist/chunk-TKBDJTXG.js.map +0 -1
  457. package/dist/chunk-V25OWXAC.js.map +0 -1
  458. package/dist/chunk-XKO7BM2C.js.map +0 -1
  459. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  460. /package/dist/{chunk-2H7OEVPO.js.map → chunk-3GD2HFR6.js.map} +0 -0
  461. /package/dist/{chunk-4TFIRMTE.js.map → chunk-4A6YGWQN.js.map} +0 -0
  462. /package/dist/{chunk-JDOJZTFF.js.map → chunk-4PBVXX7L.js.map} +0 -0
  463. /package/dist/{chunk-IKMAO55B.js.map → chunk-55MDBZLC.js.map} +0 -0
  464. /package/dist/{chunk-VDX2J7OX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  465. /package/dist/{chunk-B7GROTXD.js.map → chunk-6LKEUCEM.js.map} +0 -0
  466. /package/dist/{chunk-2AJ72VVS.js.map → chunk-7BZOBA5J.js.map} +0 -0
  467. /package/dist/{chunk-44DUJETW.js.map → chunk-7HXCF4RE.js.map} +0 -0
  468. /package/dist/{chunk-X3SQYAPP.js.map → chunk-ACXPX4AG.js.map} +0 -0
  469. /package/dist/{chunk-AJ7QCSIS.js.map → chunk-ALSGMEJR.js.map} +0 -0
  470. /package/dist/{chunk-JGUXPJUQ.js.map → chunk-AS7YMSL6.js.map} +0 -0
  471. /package/dist/{chunk-77CNV7DY.js.map → chunk-BLAKS3CP.js.map} +0 -0
  472. /package/dist/{chunk-5BRT4Z2I.js.map → chunk-CMRQ34J5.js.map} +0 -0
  473. /package/dist/{chunk-HEXSNYJD.js.map → chunk-CSMCNOPH.js.map} +0 -0
  474. /package/dist/{chunk-SK3EYPKC.js.map → chunk-D2ANTDGO.js.map} +0 -0
  475. /package/dist/{chunk-JCVQV6QX.js.map → chunk-D3LMYTBV.js.map} +0 -0
  476. /package/dist/{chunk-XY7QPJDA.js.map → chunk-E6EE5B67.js.map} +0 -0
  477. /package/dist/{chunk-LLISELSY.js.map → chunk-EP5BVCRI.js.map} +0 -0
  478. /package/dist/{chunk-PTN6UAUA.js.map → chunk-ES36HTSC.js.map} +0 -0
  479. /package/dist/{chunk-WEAO45M4.js.map → chunk-ESBQWC3U.js.map} +0 -0
  480. /package/dist/{chunk-EUSLKI4X.js.map → chunk-EVX44I7C.js.map} +0 -0
  481. /package/dist/{chunk-X6ROIHFE.js.map → chunk-G5R3D5UP.js.map} +0 -0
  482. /package/dist/{chunk-MG6MNSP4.js.map → chunk-G6LBWZRF.js.map} +0 -0
  483. /package/dist/{chunk-FRVTCCGD.js.map → chunk-GGUBDXRR.js.map} +0 -0
  484. /package/dist/{chunk-QH6CS6XJ.js.map → chunk-H24WNPA2.js.map} +0 -0
  485. /package/dist/{chunk-MQVINOJQ.js.map → chunk-IYZ5K7MU.js.map} +0 -0
  486. /package/dist/{chunk-RPA2RX5P.js.map → chunk-JDZRYH2N.js.map} +0 -0
  487. /package/dist/{chunk-M5EPMNS4.js.map → chunk-K5GB36ME.js.map} +0 -0
  488. /package/dist/{chunk-UT3OQPFA.js.map → chunk-KUJQHXPH.js.map} +0 -0
  489. /package/dist/{chunk-7RZJWZ46.js.map → chunk-LEPOP46W.js.map} +0 -0
  490. /package/dist/{chunk-EYJSW2RV.js.map → chunk-NBDCZWP4.js.map} +0 -0
  491. /package/dist/{chunk-XKGPIWGI.js.map → chunk-OFHFH655.js.map} +0 -0
  492. /package/dist/{chunk-FGBJBYWP.js.map → chunk-OVRQLAYR.js.map} +0 -0
  493. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  494. /package/dist/{chunk-U3TH5Q2Q.js.map → chunk-P3MH72CI.js.map} +0 -0
  495. /package/dist/{chunk-P2OZKKYP.js.map → chunk-PHWUFPCO.js.map} +0 -0
  496. /package/dist/{chunk-KGTD2KZJ.js.map → chunk-PKRIQL3V.js.map} +0 -0
  497. /package/dist/{chunk-4MJZTF42.js.map → chunk-QAOGGNE3.js.map} +0 -0
  498. /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
  499. /package/dist/{chunk-FCCMFVS6.js.map → chunk-RPSYDM6C.js.map} +0 -0
  500. /package/dist/{chunk-RYHWZ52A.js.map → chunk-S2BBISHU.js.map} +0 -0
  501. /package/dist/{chunk-RSYJV25N.js.map → chunk-SG265CVF.js.map} +0 -0
  502. /package/dist/{chunk-UGH6VPPO.js.map → chunk-SH6YO3LT.js.map} +0 -0
  503. /package/dist/{chunk-FMLKOL2Z.js.map → chunk-TC3VNKGX.js.map} +0 -0
  504. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  505. /package/dist/{chunk-BJJAX3IZ.js.map → chunk-UTRO5UJU.js.map} +0 -0
  506. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  507. /package/dist/{chunk-BHLN7L7M.js.map → chunk-VVIW3PTA.js.map} +0 -0
  508. /package/dist/{chunk-XQ4EH6DI.js.map → chunk-WONS4RZ2.js.map} +0 -0
  509. /package/dist/{chunk-CSXHRAJJ.js.map → chunk-XOZ4ALGB.js.map} +0 -0
  510. /package/dist/{chunk-6NNNURLK.js.map → chunk-Z54EM5YZ.js.map} +0 -0
  511. /package/dist/{chunk-YSGBD3QN.js.map → chunk-ZGOQTOYA.js.map} +0 -0
  512. /package/dist/{chunk-RNY3BO35.js.map → chunk-ZXAGJFHJ.js.map} +0 -0
  513. /package/dist/{contradiction-scan-HMF7CNKD.js.map → contradiction-scan-HYLIRMJ2.js.map} +0 -0
  514. /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-F2QJD66E.js.map} +0 -0
  515. /package/dist/{tier-stats-XKD7SXYY.js.map → tier-stats-OPTSBNRH.js.map} +0 -0
@@ -0,0 +1,261 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { createServer, type RequestListener } from "node:http";
4
+ import type { AddressInfo, Socket } from "node:net";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import test from "node:test";
8
+ /**
9
+ * Replica-divergence doctor check (issue #2149).
10
+ *
11
+ * Verifies `summarizeReplicaDivergence` is ok when disabled / peerless /
12
+ * converged, warns (never ok) when a peer diverges or cannot be polled, surfaces
13
+ * concrete deltas, never leaks a token, and is wired into `runOperatorDoctor`.
14
+ * The check takes a pre-computed local watermark set (kept DTS-light); a real
15
+ * ephemeral 127.0.0.1 server stands in for the peer daemon.
16
+ */
17
+ import { parseConfig } from "./config.js";
18
+ import type { CorpusWatermark } from "./corpus-watermark.js";
19
+ import { summarizeReplicaDivergence } from "./operator-doctor-replica.js";
20
+ import { type OperatorToolkitOrchestrator, runOperatorDoctor } from "./operator-toolkit.js";
21
+ import type { ReplicaDivergenceStatus } from "./replica-divergence.js";
22
+ import { type ReplicaPeersConfig, parseReplicaPeersConfig } from "./replica-peers-config.js";
23
+ import { StorageManager } from "./storage.js";
24
+ import type { PluginConfig } from "./types.js";
25
+
26
+ function watermark(namespace: string, overrides: Partial<CorpusWatermark> = {}): CorpusWatermark {
27
+ return {
28
+ namespace,
29
+ memoryFileCount: 10,
30
+ newestPartition: "2026-03-08",
31
+ newestWriteAt: "2026-03-08T00:00:00.000Z",
32
+ digest: `digest-${namespace}`,
33
+ computedAt: new Date().toISOString(),
34
+ ...overrides,
35
+ };
36
+ }
37
+
38
+ function replicaConfig(block: Record<string, unknown>): ReplicaPeersConfig {
39
+ return parseReplicaPeersConfig({ replicaPeers: block });
40
+ }
41
+
42
+ interface Peer {
43
+ url: string;
44
+ requests: { authorization: string | undefined }[];
45
+ close: () => Promise<void>;
46
+ }
47
+
48
+ async function startPeer(handler: RequestListener): Promise<Peer> {
49
+ const requests: Peer["requests"] = [];
50
+ const sockets = new Set<Socket>();
51
+ const server = createServer((req, res) => {
52
+ requests.push({ authorization: req.headers.authorization });
53
+ handler(req, res);
54
+ });
55
+ server.on("connection", (socket) => {
56
+ sockets.add(socket);
57
+ socket.on("close", () => sockets.delete(socket));
58
+ });
59
+ const listening = Promise.withResolvers<void>();
60
+ server.once("error", listening.reject);
61
+ server.listen(0, "127.0.0.1", listening.resolve);
62
+ await listening.promise;
63
+ const address = server.address() as AddressInfo;
64
+ return {
65
+ url: `http://127.0.0.1:${address.port}`,
66
+ requests,
67
+ close: async () => {
68
+ for (const socket of sockets) socket.destroy();
69
+ await new Promise<void>((resolve) => server.close(() => resolve()));
70
+ },
71
+ };
72
+ }
73
+
74
+ function healthHandler(corpus: CorpusWatermark[]): RequestListener {
75
+ return (req, res) => {
76
+ if (new URL(req.url ?? "/", "http://127.0.0.1").pathname === "/engram/v1/health") {
77
+ res.writeHead(200, { "content-type": "application/json" });
78
+ res.end(JSON.stringify({ ok: true, corpus }));
79
+ return;
80
+ }
81
+ res.writeHead(404, { "content-type": "application/json" });
82
+ res.end(JSON.stringify({ error: "not_found" }));
83
+ };
84
+ }
85
+
86
+ test("summarizeReplicaDivergence: disabled resolves ok and performs no network I/O", async () => {
87
+ const peer = await startPeer(healthHandler([]));
88
+ try {
89
+ const check = await summarizeReplicaDivergence(
90
+ replicaConfig({ enabled: false, peers: [{ url: peer.url }] }),
91
+ [watermark("global")],
92
+ );
93
+ assert.equal(check.key, "replica_divergence");
94
+ assert.equal(check.status, "ok");
95
+ assert.match(check.summary, /disabled/i);
96
+ assert.equal(peer.requests.length, 0, "a disabled check must not poll");
97
+ } finally {
98
+ await peer.close();
99
+ }
100
+ });
101
+
102
+ test("summarizeReplicaDivergence: enabled with no peers resolves ok", async () => {
103
+ const check = await summarizeReplicaDivergence(replicaConfig({ enabled: true, peers: [] }), [watermark("global")]);
104
+ assert.equal(check.status, "ok");
105
+ assert.match(check.summary, /no peers/i);
106
+ });
107
+
108
+ test("summarizeReplicaDivergence: a converged peer resolves ok", async () => {
109
+ const local = [watermark("global")];
110
+ const peer = await startPeer(healthHandler(local));
111
+ try {
112
+ const check = await summarizeReplicaDivergence(replicaConfig({ enabled: true, peers: [{ url: peer.url }] }), local);
113
+ assert.equal(check.status, "ok");
114
+ assert.match(check.summary, /converged/i);
115
+ } finally {
116
+ await peer.close();
117
+ }
118
+ });
119
+
120
+ test("summarizeReplicaDivergence: an incomplete local census downgrades a converged peer AND warns (round 6)", async () => {
121
+ // /health downgrades a would-be-converged peer to unknown/local_census_incomplete
122
+ // when the local census is partial; the doctor must derive the SAME peer state
123
+ // through the shared gate, not render `peer: converged` with converged details.
124
+ const local = [watermark("global")];
125
+ const peer = await startPeer(healthHandler(local));
126
+ try {
127
+ const check = await summarizeReplicaDivergence(
128
+ replicaConfig({ enabled: true, peers: [{ url: peer.url }] }),
129
+ local,
130
+ { localCensusComplete: false },
131
+ );
132
+ assert.equal(check.status, "warn", "an incomplete local census cannot certify convergence");
133
+ assert.match(check.summary, /local census incomplete/i);
134
+ const report = check.details as ReplicaDivergenceStatus;
135
+ assert.equal(report.censusComplete, false);
136
+ assert.equal(report.peers[0]?.state, "unknown", "the peer detail is downgraded, not left converged");
137
+ assert.equal(report.peers[0]?.reason, "local_census_incomplete");
138
+ assert.notEqual(report.peers[0]?.state, "converged");
139
+ } finally {
140
+ await peer.close();
141
+ }
142
+ });
143
+
144
+ test("summarizeReplicaDivergence: a diverged peer warns with the concrete delta", async () => {
145
+ const peer = await startPeer(healthHandler([watermark("global", { memoryFileCount: 340_000, digest: "peer" })]));
146
+ try {
147
+ const check = await summarizeReplicaDivergence(
148
+ replicaConfig({ enabled: true, peers: [{ url: peer.url }] }),
149
+ [watermark("global", { memoryFileCount: 190_000, digest: "local" })],
150
+ );
151
+ assert.equal(check.status, "warn", "a divergence must warn, never ok");
152
+ assert.match(check.summary, /diverged/);
153
+ assert.match(check.summary, /file_count_delta=150000/, "the operator sees the concrete delta");
154
+ } finally {
155
+ await peer.close();
156
+ }
157
+ });
158
+
159
+ test("summarizeReplicaDivergence: an unreachable peer warns and is not conflated with ok (§22)", async () => {
160
+ const peer = await startPeer((_req, res) => {
161
+ res.writeHead(500);
162
+ res.end("boom");
163
+ });
164
+ try {
165
+ const check = await summarizeReplicaDivergence(
166
+ replicaConfig({ enabled: true, peers: [{ url: peer.url }] }),
167
+ [watermark("global")],
168
+ );
169
+ assert.equal(check.status, "warn");
170
+ assert.match(check.summary, /unreachable/);
171
+ assert.match(check.summary, /http_500/);
172
+ } finally {
173
+ await peer.close();
174
+ }
175
+ });
176
+
177
+ test("summarizeReplicaDivergence: the peer token never appears in the doctor check output", async () => {
178
+ const secret = "DOCTOR-SECRET-TOKEN";
179
+ const peer = await startPeer(healthHandler([watermark("global", { memoryFileCount: 999_999, digest: "x" })]));
180
+ try {
181
+ const check = await summarizeReplicaDivergence(
182
+ replicaConfig({ enabled: true, peers: [{ url: peer.url, token: secret }] }),
183
+ [watermark("global")],
184
+ );
185
+ assert.ok(peer.requests.some((request) => request.authorization === `Bearer ${secret}`), "token IS used (non-vacuous)");
186
+ assert.ok(!JSON.stringify(check).includes(secret), "token must never appear in the doctor output");
187
+ } finally {
188
+ await peer.close();
189
+ }
190
+ });
191
+
192
+ async function writeMemory(memoryDir: string, rel: string): Promise<void> {
193
+ const full = path.join(memoryDir, rel);
194
+ await mkdir(path.dirname(full), { recursive: true });
195
+ await writeFile(full, `---\nid: ${path.basename(rel, ".md")}\n---\n\nbody\n`, "utf-8");
196
+ }
197
+
198
+ async function makeFixture(): Promise<{
199
+ root: string;
200
+ memoryDir: string;
201
+ configPath: string;
202
+ orchestrator: OperatorToolkitOrchestrator;
203
+ }> {
204
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-replica-doctor-"));
205
+ const memoryDir = path.join(root, "memory");
206
+ await mkdir(memoryDir, { recursive: true });
207
+ const rawConfig = {
208
+ openaiApiKey: "sk-test",
209
+ memoryDir,
210
+ qmdEnabled: false,
211
+ namespacesEnabled: false,
212
+ defaultNamespace: "global",
213
+ };
214
+ const config: PluginConfig = parseConfig(rawConfig);
215
+ const configPath = path.join(root, "openclaw.json");
216
+ await writeFile(
217
+ configPath,
218
+ JSON.stringify({ plugins: { entries: { "openclaw-remnic": { config: rawConfig } } } }, null, 2),
219
+ "utf-8",
220
+ );
221
+ const orchestrator: OperatorToolkitOrchestrator = {
222
+ config,
223
+ storage: new StorageManager(memoryDir),
224
+ qmd: {
225
+ async probe() {
226
+ return false;
227
+ },
228
+ isAvailable() {
229
+ return false;
230
+ },
231
+ async ensureCollection() {
232
+ return "skipped";
233
+ },
234
+ debugStatus() {
235
+ return "disabled";
236
+ },
237
+ },
238
+ conversationIndexCoordinator: {
239
+ async getHealth() {
240
+ return { enabled: false, backend: "qmd" as const, status: "disabled" as const, chunkDocCount: 0, lastUpdateAt: null };
241
+ },
242
+ async rebuild() {
243
+ return { chunks: 0, skipped: true, reason: "disabled", embedded: false, rebuilt: false };
244
+ },
245
+ },
246
+ };
247
+ return { root, memoryDir, configPath, orchestrator };
248
+ }
249
+
250
+ test("runOperatorDoctor: includes the replica_divergence check (disabled -> ok)", async () => {
251
+ const { root, memoryDir, configPath, orchestrator } = await makeFixture();
252
+ try {
253
+ await writeMemory(memoryDir, "facts/2026-03-08/a.md");
254
+ const report = await runOperatorDoctor({ configPath, orchestrator });
255
+ const check = report.checks.find((entry) => entry.key === "replica_divergence");
256
+ assert.ok(check, "expected a replica_divergence check");
257
+ assert.equal(check?.status, "ok");
258
+ } finally {
259
+ await rm(root, { recursive: true, force: true });
260
+ }
261
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Replica-divergence doctor check (issue #2149).
3
+ *
4
+ * Kept deliberately LIGHT: it takes the ALREADY-computed local corpus watermark
5
+ * set (the same array the `corpus_watermark` check produces) instead of importing
6
+ * the corpus census helpers or `PluginConfig`. That keeps this new tsup DTS entry
7
+ * from pulling the heavy `PluginConfig` type graph into its `.d.ts` — two sibling
8
+ * PRs OOMed the default-heap DTS worker exactly that way (the issue #1562 heap
9
+ * cliff). `runOperatorDoctor` computes the local watermarks once for the corpus
10
+ * check and hands them here via `corpusWatermarksFromCheck`, so there is also no
11
+ * second corpus scan.
12
+ *
13
+ * Status: `ok` when disabled, peerless, or every peer converged; `warn` when any
14
+ * peer diverged beyond threshold, could not be polled (unreachable/unknown), or
15
+ * the local corpus census was incomplete — a scan that cannot ask a peer, or
16
+ * cannot fully read its OWN corpus, must never read as agreement (AGENTS.md §22).
17
+ * The summary carries concrete deltas so an operator sees numbers, not a verdict.
18
+ * Peer tokens are never resolved into, logged from, or printed by this check; a
19
+ * peer is identified only by its redacted host:port. The CLI forwards the host
20
+ * SecretRef resolver (when one is configured) so a SecretRef peer token
21
+ * authenticates here too; without a resolver such a token degrades to a per-peer
22
+ * `token_error` (never a throw). The always-on `/health` surface remains the
23
+ * primary reporting path. Reconciliation is issue #2150.
24
+ */
25
+
26
+ import type { CorpusWatermark } from "./corpus-watermark.js";
27
+ import type { OperatorDoctorCheck } from "./operator-doctor-types.js";
28
+ import { type FetchLike, type ReplicaPeerReport, gateReportByCensus, pollReplicaPeers } from "./replica-divergence.js";
29
+ import { resolveReplicaPeersConfig, type ReplicaPeersConfig } from "./replica-peers-config.js";
30
+ import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
31
+
32
+ export interface SummarizeReplicaDivergenceOptions {
33
+ now?: Date;
34
+ resolveSecretRef?: ResolveSecretRefFn | null;
35
+ /** Injectable for tests; production polls with global fetch. */
36
+ fetchImpl?: FetchLike;
37
+ /**
38
+ * Whether the LOCAL corpus census that produced `localWatermarks` was complete
39
+ * (the `corpus_watermark` check was `ok`). When false, a would-be-converged
40
+ * result is downgraded to `warn`: a namespace missing from an incomplete local
41
+ * scan must never let the replica check certify convergence (cursor finding).
42
+ */
43
+ localCensusComplete?: boolean;
44
+ }
45
+
46
+ function formatPeerLine(peer: ReplicaPeerReport): string {
47
+ if (peer.state === "unreachable" || peer.state === "unknown") {
48
+ return `${peer.peer}: ${peer.state} (${peer.reason ?? "unknown"})`;
49
+ }
50
+ if (peer.state === "converged") return `${peer.peer}: converged`;
51
+ const divergedNamespaces = peer.namespaces
52
+ .filter((delta) => delta.diverged)
53
+ .map((delta) => `${delta.namespace}: ${delta.reasons.join("+")}`);
54
+ return `${peer.peer}: diverged [${divergedNamespaces.join(", ")}]`;
55
+ }
56
+
57
+ export async function summarizeReplicaDivergence(
58
+ rawConfig: ReplicaPeersConfig | undefined,
59
+ localWatermarks: readonly CorpusWatermark[],
60
+ options: SummarizeReplicaDivergenceOptions = {},
61
+ ): Promise<OperatorDoctorCheck> {
62
+ // A host adapter or hand-built PluginConfig can omit the block entirely;
63
+ // normalize through the same read-boundary resolver /health uses so doctor
64
+ // degrades to disabled instead of aborting the whole run (round 5, codex P2).
65
+ const replicaConfig = resolveReplicaPeersConfig(rawConfig);
66
+ if (!replicaConfig.enabled) {
67
+ return {
68
+ key: "replica_divergence",
69
+ status: "ok",
70
+ summary: "Replica divergence detection is disabled.",
71
+ details: { enabled: false, pending: false, polledAt: null, peers: [] },
72
+ };
73
+ }
74
+ if (replicaConfig.peers.length === 0) {
75
+ return {
76
+ key: "replica_divergence",
77
+ status: "ok",
78
+ summary: "Replica divergence detection is enabled, but no peers are configured.",
79
+ details: { enabled: true, pending: false, polledAt: null, peers: [] },
80
+ };
81
+ }
82
+
83
+ const report = await pollReplicaPeers({
84
+ config: replicaConfig,
85
+ localWatermarks,
86
+ now: options.now,
87
+ resolveSecretRef: options.resolveSecretRef,
88
+ fetchImpl: options.fetchImpl,
89
+ });
90
+ // Apply the SAME census gate /health uses (round 6): otherwise the doctor
91
+ // renders `peer: converged` lines and converged `details` while /health
92
+ // downgrades those same peers to `unknown`/`local_census_incomplete`, so a
93
+ // machine reading doctor JSON sees agreement /health denies. Gating here
94
+ // turns every would-be-converged peer into `unknown` when the local census
95
+ // was incomplete, so both surfaces derive peer state from one function.
96
+ const gated = gateReportByCensus(report, options.localCensusComplete !== false);
97
+ const diverged = gated.peers.filter((peer) => peer.state === "diverged");
98
+ const unreachable = gated.peers.filter((peer) => peer.state === "unreachable" || peer.state === "unknown");
99
+ const lines = gated.peers.map(formatPeerLine);
100
+ const censusIncomplete = gated.censusComplete === false;
101
+
102
+ if (diverged.length > 0 || unreachable.length > 0 || censusIncomplete) {
103
+ const counts = [`${diverged.length} diverged`, `${unreachable.length} unreachable/unknown`];
104
+ if (censusIncomplete) counts.push("local census incomplete");
105
+ return {
106
+ key: "replica_divergence",
107
+ status: "warn",
108
+ summary:
109
+ `Replica divergence across ${gated.peers.length} peer(s): ` +
110
+ `${counts.join(", ")}. ${lines.join("; ")}`,
111
+ remediation:
112
+ (censusIncomplete
113
+ ? "The local corpus census was incomplete (see the corpus_watermark check), so convergence cannot be " +
114
+ "certified — resolve that first. "
115
+ : "") +
116
+ "Investigate the flagged peer(s): a diverged peer's corpus differs beyond the configured threshold " +
117
+ "(a possible split-brain — the pair's recall will differ across failover); an unreachable/unknown peer " +
118
+ "could not be polled or compared. Detection only; reconciliation is tracked in issue #2150.",
119
+ details: gated,
120
+ };
121
+ }
122
+
123
+ return {
124
+ key: "replica_divergence",
125
+ status: "ok",
126
+ summary: `All ${gated.peers.length} replica peer(s) converged. ${lines.join("; ")}`,
127
+ details: gated,
128
+ };
129
+ }
@@ -57,7 +57,8 @@ import type {
57
57
  } from "./types.js";
58
58
  import { reportBufferSurpriseDistribution } from "./buffer-surprise-report.js";
59
59
  import { readJudgeVerdictStats } from "./extraction-judge-telemetry.js";
60
- import { summarizeCorpusWatermark } from "./operator-doctor-corpus.js";
60
+ import { summarizeCorpusAndReplica } from "./operator-doctor-corpus.js";
61
+ import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
61
62
 
62
63
  const OPENCLAW_REMNIC_PLUGIN_IDS = ["openclaw-remnic", "openclaw-engram"] as const;
63
64
 
@@ -384,6 +385,8 @@ export interface OperatorDoctorOptions {
384
385
  orchestrator: OperatorToolkitOrchestrator;
385
386
  configPath?: string;
386
387
  now?: Date;
388
+ /** Host SecretRef resolver so a SecretRef peer token authenticates during doctor replica polling (#2149). */
389
+ resolveSecretRef?: ResolveSecretRefFn | null;
387
390
  }
388
391
 
389
392
  export interface OperatorConfigReviewOptions {
@@ -1496,11 +1499,9 @@ export async function runOperatorDoctor(options: OperatorDoctorOptions): Promise
1496
1499
  // Shows hot/cold counts, per-status breakdown, and forgotten-memory count.
1497
1500
  // Informational only — never errors, never blocks doctor from returning ok.
1498
1501
  checks.push(await summarizeTierDistribution(options.orchestrator.storage));
1499
-
1500
1502
  checks.push(await summarizeDreamsPhases(config, storage));
1501
1503
  checks.push(await summarizeExtractionLiveness(config, storage, options.orchestrator.buffer));
1502
- checks.push(await summarizeCorpusWatermark(config, (dir) => new StorageManager(dir))); // corpus watermark #2149
1503
-
1504
+ checks.push(...(await summarizeCorpusAndReplica(config, (d) => new StorageManager(d), options.resolveSecretRef)));
1504
1505
  // Security mitigation status (issue #565).
1505
1506
  // Reports whether the cross-namespace budget and anomaly detection
1506
1507
  // mitigations are enabled and surfaces config values for operator review.
@@ -116,8 +116,8 @@ export class OrchestratorInitCoordinator {
116
116
  quiet: true,
117
117
  logger: (message) => log.info(message),
118
118
  });
119
- await this.deps.storage.ensureDirectories();
120
119
  await this.deps.storage.loadAliases();
120
+ await this.deps.storage.ensureDirectories();
121
121
  if (resolveNamespaceCapabilities(this.deps.config).namespaces) {
122
122
  const namespaces = new Set<string>([
123
123
  this.deps.config.defaultNamespace,
@@ -126,8 +126,8 @@ export class OrchestratorInitCoordinator {
126
126
  ]);
127
127
  for (const ns of namespaces) {
128
128
  const sm = await this.deps.storageRouter.storageFor(ns);
129
- await sm.ensureDirectories();
130
129
  await sm.loadAliases().catch(() => undefined);
130
+ await sm.ensureDirectories();
131
131
  }
132
132
  // Explicitly seed the catalog with all configured namespaces at startup
133
133
  // (round 6, cursor Medium — NBLlR). The storageFor loop above fires the