@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
@@ -1,32 +1,34 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-UT3OQPFA.js";
4
+ } from "./chunk-KUJQHXPH.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-CIQXI47W.js";
6
+ import "./chunk-FCDWWCLX.js";
7
7
  import "./chunk-UHVXE24Y.js";
8
8
  import "./chunk-2QMKMVHH.js";
9
9
  import "./chunk-DEBHXHJR.js";
10
10
  import "./chunk-DNHVPZOD.js";
11
11
  import "./chunk-6CIAGZ6X.js";
12
- import "./chunk-HKF5VASQ.js";
13
12
  import "./chunk-J6A3CX5N.js";
14
- import "./chunk-V25OWXAC.js";
15
- import "./chunk-XKGPIWGI.js";
13
+ import "./chunk-HKF5VASQ.js";
14
+ import "./chunk-HUHX2OCX.js";
15
+ import "./chunk-OFHFH655.js";
16
16
  import "./chunk-EGGE52UU.js";
17
- import "./chunk-GCASGYIO.js";
18
17
  import "./chunk-WL5EBRDH.js";
19
- import "./chunk-ILGC6JH6.js";
20
- import "./chunk-SCU65EZI.js";
18
+ import "./chunk-WRJVB3C2.js";
19
+ import "./chunk-GCASGYIO.js";
21
20
  import "./chunk-3CSX3ETE.js";
22
21
  import "./chunk-RL6NEVXT.js";
22
+ import "./chunk-ILGC6JH6.js";
23
+ import "./chunk-SCU65EZI.js";
23
24
  import "./chunk-DM2T26WE.js";
24
25
  import "./chunk-LDXUBPMO.js";
26
+ import "./chunk-JYIJNNN3.js";
27
+ import "./chunk-AAD2ZS6P.js";
25
28
  import "./chunk-CGASUJVP.js";
26
29
  import "./chunk-R3DJVOSM.js";
27
30
  import "./chunk-BT7NVCML.js";
28
- import "./chunk-JYIJNNN3.js";
29
- import "./chunk-AAD2ZS6P.js";
31
+ import "./chunk-YXZG5TVN.js";
30
32
  import "./chunk-5VQJBH2G.js";
31
33
  import "./chunk-AITCS2RC.js";
32
34
  import "./chunk-XMMESCPD.js";
@@ -41,8 +43,8 @@ import "./chunk-45GF7Y3V.js";
41
43
  import "./chunk-RGMVMVMF.js";
42
44
  import "./chunk-N7RWREIQ.js";
43
45
  import "./chunk-5I4M26Q7.js";
46
+ import "./chunk-ZIKENA2C.js";
44
47
  import "./chunk-5GKPFL3S.js";
45
- import "./chunk-4DJQYKMN.js";
46
48
  import "./chunk-PQVCH2AE.js";
47
49
  import "./chunk-EYIEWJNI.js";
48
50
  import "./chunk-JUC24CTX.js";
@@ -53,7 +55,7 @@ import "./chunk-BJMBJZ2Y.js";
53
55
  import "./chunk-UKJAGEXH.js";
54
56
  import "./chunk-FP2373TW.js";
55
57
  import "./chunk-P7FMDTKL.js";
56
- import "./chunk-RDQGLJRR.js";
58
+ import "./chunk-2XRE6FLM.js";
57
59
  import "./chunk-FF4KLI5W.js";
58
60
  import "./chunk-AIK5W3IW.js";
59
61
  import "./chunk-A6XUJE5D.js";
@@ -1,4 +1,4 @@
1
- import { t as MemoryCategory } from './types-DHBxIF0s.js';
1
+ import { v as MemoryCategory } from './types-Dg0w9ADr.js';
2
2
  import './message-parts/index.js';
3
3
  import './bounded-jsonl-state.js';
4
4
  import './operator-doctor-types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.27.0",
3
+ "version": "9.29.0",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3076,7 +3076,7 @@
3076
3076
  "core"
3077
3077
  ],
3078
3078
  "peerDependencies": {
3079
- "@remnic/coding-graph": "^9.27.0"
3079
+ "@remnic/coding-graph": "^9.29.0"
3080
3080
  },
3081
3081
  "peerDependenciesMeta": {
3082
3082
  "@remnic/coding-graph": {
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import type { ExtractionLivenessStatus } from "./extraction-liveness.js";
12
12
  import type { CorpusWatermark } from "./corpus-watermark.js";
13
+ import type { ReplicaDivergenceStatus } from "./replica-divergence.js";
13
14
 
14
15
  export interface EngramAccessHealthResponse {
15
16
  ok: true;
@@ -23,6 +24,13 @@ export interface EngramAccessHealthResponse {
23
24
  projectionAvailable: boolean;
24
25
  extraction: ExtractionLivenessStatus;
25
26
  corpus: CorpusWatermark[];
27
+ /**
28
+ * Whether `corpus` above is the COMPLETE census for this responder, from the
29
+ * same call that produced it. A polling peer must refuse to certify
30
+ * convergence against a partial array (issue #2149).
31
+ */
32
+ corpusComplete: boolean;
33
+ replica: ReplicaDivergenceStatus;
26
34
  }
27
35
 
28
36
  export type EngramAccessQmdCollectionState =
@@ -1870,6 +1870,8 @@ test("HTTP externalRequestHandler runs pre-auth, can end responses, and falls th
1870
1870
  watermarkScope: "root-store",
1871
1871
  },
1872
1872
  corpus: [],
1873
+ corpusComplete: true,
1874
+ replica: { enabled: false, pending: false, polledAt: null, peers: [] },
1873
1875
  }),
1874
1876
  } satisfies Pick<EngramAccessService, "health">;
1875
1877
  const service = healthStub as unknown as EngramAccessService;
@@ -1995,6 +1997,8 @@ test("HTTP authTokenEntriesGetter is authoritative: scope policy binds connector
1995
1997
  watermarkScope: "root-store",
1996
1998
  },
1997
1999
  corpus: [],
2000
+ corpusComplete: true,
2001
+ replica: { enabled: false, pending: false, polledAt: null, peers: [] },
1998
2002
  }),
1999
2003
  } satisfies Pick<EngramAccessService, "health">;
2000
2004
  const entries = [
@@ -108,6 +108,29 @@ test("health reports active QMD version and collection state", async () => {
108
108
  }
109
109
  });
110
110
 
111
+ test("health reports replica divergence disabled by default (no peers -> behaves as today)", async () => {
112
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-replica-"));
113
+ try {
114
+ const config = parseConfig({ memoryDir });
115
+ const service = new EngramAccessService({
116
+ config,
117
+ qmd: makeQmd({}),
118
+ async getStorage() {
119
+ return { dir: memoryDir };
120
+ },
121
+ } as unknown as Orchestrator);
122
+
123
+ const health = await service.health();
124
+
125
+ assert.equal(health.replica.enabled, false);
126
+ assert.equal(health.replica.pending, false);
127
+ assert.equal(health.replica.polledAt, null);
128
+ assert.equal(health.replica.peers.length, 0);
129
+ } finally {
130
+ await rm(memoryDir, { recursive: true, force: true });
131
+ }
132
+ });
133
+
111
134
  test("health treats qmdEmbeddingBacklogThreshold 0 as backlog degradation disabled", async () => {
112
135
  const config = parseConfig({ qmdEnabled: true, qmdEmbeddingBacklogThreshold: 0 });
113
136
  const qmd = makeQmd({
@@ -19,7 +19,9 @@ import { resolveNamespaceCapabilities,
19
19
  resolveMemoryLifecycleCapabilities,
20
20
  resolveQmdCapabilities,
21
21
  resolveSecurityCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities, resolveRecallAuxiliaryCapabilities } from "./capabilities.js";
22
- import { CorpusWatermarkCache, computeServiceCorpusWatermarks } from "./corpus-watermark.js";
22
+ import { CorpusWatermarkCache, computeServiceCorpusCensus } from "./corpus-watermark.js";
23
+ import { ReplicaDivergenceMonitor } from "./replica-divergence.js";
24
+ import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
23
25
  import type {
24
26
  EngramAccessHealthResponse,
25
27
  EngramAccessQmdCollectionState,
@@ -1277,6 +1279,7 @@ export class EngramAccessService {
1277
1279
  private readonly budget: CrossNamespaceBudget;
1278
1280
  private readonly auditAdapter: AccessAuditAdapter | null;
1279
1281
  private readonly corpusWatermarkCache = new CorpusWatermarkCache();
1282
+ private readonly replicaDivergenceMonitor: ReplicaDivergenceMonitor;
1280
1283
 
1281
1284
  /** AccessObserveWriteSurface (access-service decomposition). Lazy; selfDeps live wiring. */
1282
1285
  private _accessObserveWriteSurface: AccessObserveWriteSurface | undefined;
@@ -1339,8 +1342,13 @@ export class EngramAccessService {
1339
1342
  }
1340
1343
  private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
1341
1344
 
1342
- constructor(private readonly orchestrator: Orchestrator) {
1345
+ constructor(private readonly orchestrator: Orchestrator, options: { resolveSecretRef?: ResolveSecretRefFn | null } = {}) {
1343
1346
  this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
1347
+ // Peer SecretRef tokens resolve at poll time through the host resolver, the
1348
+ // same indirection as agentAccessHttp.authToken (review round 1). Absent a
1349
+ // resolver, string/${ENV} tokens still work and a SecretRef degrades to a
1350
+ // per-peer `unreachable` (never a throw).
1351
+ this.replicaDivergenceMonitor = new ReplicaDivergenceMonitor({ resolveSecretRef: options.resolveSecretRef });
1344
1352
  const accessCaps = resolveAccessSetupCapabilities(orchestrator.config); // #1566 Cluster B
1345
1353
  this.budget = new CrossNamespaceBudget({
1346
1354
  enabled: accessCaps.recallCrossNamespaceBudget,
@@ -2432,6 +2440,11 @@ export class EngramAccessService {
2432
2440
  const searchBackend = this.orchestrator.config.searchBackend ?? "qmd";
2433
2441
  const qmdEnabled = resolveQmdCapabilities(this.orchestrator.config).qmd === true;
2434
2442
  const extraction = await computeExtractionLivenessStatus(this.orchestrator, this.extractionLivenessWarn);
2443
+ // ONE call: the corpus array and the flag describing it must not come from
2444
+ // two independently-cached scans (round 8, codex P1).
2445
+ const caps = tokenCapabilityStore.getStore();
2446
+ const corpusCensus = await computeServiceCorpusCensus(this.orchestrator, {
2447
+ cache: this.corpusWatermarkCache, caps });
2435
2448
  let projectionAvailable = false;
2436
2449
  try {
2437
2450
  await stat(getMemoryProjectionPath(storage.dir));
@@ -2456,8 +2469,18 @@ export class EngramAccessService {
2456
2469
  nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
2457
2470
  projectionAvailable,
2458
2471
  extraction,
2459
- corpus: await computeServiceCorpusWatermarks(this.orchestrator, {
2460
- cache: this.corpusWatermarkCache, caps: tokenCapabilityStore.getStore() }),
2472
+ corpus: corpusCensus.watermarks,
2473
+ // Describes THIS response's array (round 8): a separate scan could report
2474
+ // complete while the shipped corpus was partial, and peers trust it.
2475
+ corpusComplete: corpusCensus.complete,
2476
+ replica: this.replicaDivergenceMonitor.getReport({
2477
+ config: this.orchestrator.config.replicaPeers,
2478
+ // Capability-INDEPENDENT: this poll is cached instance-wide, so a
2479
+ // restricted caller's filtered census must never seed it (round 9).
2480
+ computeLocalWatermarks: () => computeServiceCorpusCensus(this.orchestrator, {}),
2481
+ caps,
2482
+ localCensusComplete: corpusCensus.complete,
2483
+ }),
2461
2484
  };
2462
2485
  }
2463
2486
 
@@ -1246,6 +1246,7 @@ const PIPELINE_FIELD_TO_FLAG: Record<keyof PipelineProcessingCapabilitySet, stri
1246
1246
  lcm: "lcmEnabled",
1247
1247
  localLlmFast: "localLlmFastEnabled",
1248
1248
  proactiveExtraction: "proactiveExtractionEnabled",
1249
+ sourceGrounding: "extractionSourceGroundingEnabled",
1249
1250
  delinearize: "delinearizeEnabled",
1250
1251
  slowLog: "slowLogEnabled",
1251
1252
  hostEmbeddingProvider: "hostEmbeddingProviderEnabled",
@@ -1132,13 +1132,10 @@ export function resolveRecallEnhancementCapabilities(config: RecallEnhancementCo
1132
1132
  }
1133
1133
 
1134
1134
  // ---------------------------------------------------------------------------
1135
- // PipelineProcessing capability set (issue #1523 batch 9).
1136
- //
1137
- // These 22 flags gate the extraction/chunking/summarization pipeline and LLM
1138
- // infrastructure. Read sites span orchestrator, extraction, summarizer,
1139
- // embedding-fallback, local-llm, search, day-summary, and semantic-consolidation.
1140
- // All flags are non-optional booleans on PluginConfig (defaults resolved at
1141
- // the parse boundary), so the projection is a pure pass-through.
1135
+ // PipelineProcessing capability set (issue #1523 batch 9). These 23 flags gate
1136
+ // extraction/chunking/summarization and LLM infrastructure across orchestrator,
1137
+ // extraction, summarizer, embedding-fallback, local-llm, search, day-summary, and
1138
+ // semantic-consolidation. Defaults resolve at parse boundary, so pure pass-through.
1142
1139
  // ---------------------------------------------------------------------------
1143
1140
 
1144
1141
  /**
@@ -1161,6 +1158,7 @@ export interface PipelineProcessingCapabilitySet {
1161
1158
  readonly lcm: boolean;
1162
1159
  readonly localLlmFast: boolean;
1163
1160
  readonly proactiveExtraction: boolean;
1161
+ readonly sourceGrounding: boolean;
1164
1162
  readonly delinearize: boolean;
1165
1163
  readonly slowLog: boolean;
1166
1164
  readonly hostEmbeddingProvider: boolean;
@@ -1189,6 +1187,7 @@ export type PipelineProcessingConfigProjection = Pick<
1189
1187
  | "lcmEnabled"
1190
1188
  | "localLlmFastEnabled"
1191
1189
  | "proactiveExtractionEnabled"
1190
+ | "extractionSourceGroundingEnabled"
1192
1191
  | "delinearizeEnabled"
1193
1192
  | "slowLogEnabled"
1194
1193
  | "hostEmbeddingProviderEnabled"
@@ -1217,6 +1216,7 @@ export function resolvePipelineProcessingCapabilities(config: PipelineProcessing
1217
1216
  lcm: config.lcmEnabled,
1218
1217
  localLlmFast: config.localLlmFastEnabled,
1219
1218
  proactiveExtraction: config.proactiveExtractionEnabled,
1219
+ sourceGrounding: config.extractionSourceGroundingEnabled,
1220
1220
  delinearize: config.delinearizeEnabled,
1221
1221
  slowLog: config.slowLogEnabled,
1222
1222
  hostEmbeddingProvider: config.hostEmbeddingProviderEnabled,
package/src/cli.ts CHANGED
@@ -115,6 +115,8 @@ import {
115
115
  renderActionConfidenceText,
116
116
  } from "./action-confidence.js";
117
117
  import {
118
+ hostSecretRefResolver,
119
+ loadHostSecretRefResolver,
118
120
  resolveAgentAccessAuthToken,
119
121
  type ResolveSecretRefFn,
120
122
  } from "./resolve-auth-token.js";
@@ -3797,7 +3799,8 @@ export function registerCli(
3797
3799
  .option("--json", "Emit machine-readable JSON only")
3798
3800
  .action(async (...args: unknown[]) => {
3799
3801
  const options = (args[0] ?? {}) as Record<string, unknown>;
3800
- const report = await runOperatorDoctor({ orchestrator });
3802
+ const resolveSecretRef = await loadHostSecretRefResolver(registerOptions);
3803
+ const report = await runOperatorDoctor({ orchestrator, resolveSecretRef });
3801
3804
  if (reportHasMachineReadableOutput(options)) {
3802
3805
  console.log(JSON.stringify(report, null, 2));
3803
3806
  } else {
@@ -6767,7 +6770,10 @@ export function registerCli(
6767
6770
  console.log("OK");
6768
6771
  });
6769
6772
 
6770
- const accessService = new EngramAccessService(orchestrator);
6773
+ // /health's replica monitor resolves peer-token SecretRefs at poll time (#2149).
6774
+ const accessService = new EngramAccessService(orchestrator, {
6775
+ resolveSecretRef: hostSecretRefResolver(registerOptions),
6776
+ });
6771
6777
  const accessCmd = cmd
6772
6778
  .command("access")
6773
6779
  .description("Manage Engram HTTP and MCP access surfaces");
@@ -6796,11 +6802,7 @@ export function registerCli(
6796
6802
  typeof options.token === "string" && options.token.trim().length > 0
6797
6803
  ? options.token
6798
6804
  : undefined;
6799
- const resolveSecretRef =
6800
- registerOptions.resolveSecretRef ??
6801
- (registerOptions.loadResolveSecretRef
6802
- ? await registerOptions.loadResolveSecretRef()
6803
- : null);
6805
+ const resolveSecretRef = await loadHostSecretRefResolver(registerOptions);
6804
6806
  const resolvedConfigAuthToken = cliTokenOverride
6805
6807
  ? undefined
6806
6808
  : await resolveAgentAccessAuthToken(
@@ -907,6 +907,11 @@ test("parseConfig validates localLlmMaxContext as a usable context window", () =
907
907
  );
908
908
  }
909
909
  });
910
+ test("parseConfig extractionSourceGroundingEnabled defaults on and accepts string false", () => {
911
+ assert.equal(parseConfig({}).extractionSourceGroundingEnabled, true);
912
+ assert.equal(parseConfig({ extractionSourceGroundingEnabled: "false" }).extractionSourceGroundingEnabled, false);
913
+ });
914
+
910
915
  test("parseConfig extractionTelemetryPrefilterEnabled defaults on and accepts string false", () => {
911
916
  assert.equal(parseConfig({}).extractionTelemetryPrefilterEnabled, true);
912
917
  assert.equal(parseConfig({ extractionTelemetryPrefilterEnabled: "false" }).extractionTelemetryPrefilterEnabled, false);
package/src/config.ts CHANGED
@@ -38,6 +38,7 @@ import { expandTildePath } from "./utils/path.js";
38
38
  import { coerceBool, coerceBooleanLike, coerceInstallExtension, coerceNumber } from "./connectors/coerce.js";
39
39
  import { parseRecallConcurrencyConfig } from "./recall-concurrency-config.js";
40
40
  import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
41
+ import { parseReplicaPeersConfig } from "./replica-peers-config.js";
41
42
  import { hasLegacyConnectorEntries } from "./connectors/paths.js";
42
43
  import {
43
44
  parseQmdChunkStrategy,
@@ -72,7 +73,6 @@ const DEFAULT_MEMORY_DIR = path.join(
72
73
  "memory",
73
74
  "local",
74
75
  );
75
-
76
76
  const DEFAULT_WORKSPACE_DIR = path.join(
77
77
  resolveHomeDir(),
78
78
  ".openclaw",
@@ -2335,6 +2335,7 @@ export function parseConfig(
2335
2335
  dreamsPhases,
2336
2336
  procedural,
2337
2337
  extractionLiveness: parseExtractionLivenessConfig(cfg),
2338
+ replicaPeers: parseReplicaPeersConfig(cfg),
2338
2339
  wearables,
2339
2340
  meetings,
2340
2341
  activity,
@@ -2349,7 +2350,6 @@ export function parseConfig(
2349
2350
  codexCompat,
2350
2351
  codingKnowledge: parseCodingKnowledgeConfig(cfg.codingKnowledge),
2351
2352
  chat: parseChatConfig(cfg.chat),
2352
- // Hourly summaries
2353
2353
  hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true
2354
2354
  daySummaryEnabled: cfg.daySummaryEnabled !== false, // default: true
2355
2355
  hourlySummaryCronAutoRegister: cfg.hourlySummaryCronAutoRegister === true,
@@ -2734,6 +2734,7 @@ export function parseConfig(
2734
2734
  : 100,
2735
2735
  // Extraction stability guards (P0/P1)
2736
2736
  extractionDedupeEnabled: cfg.extractionDedupeEnabled !== false,
2737
+ extractionSourceGroundingEnabled: coerceBool(cfg.extractionSourceGroundingEnabled) !== false,
2737
2738
  extractionDedupeWindowMs:
2738
2739
  typeof cfg.extractionDedupeWindowMs === "number" ? cfg.extractionDedupeWindowMs : 5 * 60_000,
2739
2740
  extractionMinChars:
@@ -25,6 +25,7 @@ import {
25
25
  buildPartitionCensus,
26
26
  computeCorpusWatermark,
27
27
  computeCorpusWatermarks,
28
+ computeServiceCorpusCensus,
28
29
  computeServiceCorpusWatermarks,
29
30
  digestPartitionCensus,
30
31
  resolveCorpusNamespaceRoots,
@@ -838,3 +839,23 @@ test("finding round-10: a non-directory category root fails a strict census (nam
838
839
  await rm(memoryDir, { recursive: true, force: true });
839
840
  }
840
841
  });
842
+
843
+ test("round 6 (coderabbit): a failed namespace enumeration is an INCOMPLETE census, not an empty corpus", async () => {
844
+ // computeServiceCorpusCensus wraps resolveCorpusNamespaceRoots: when enumeration
845
+ // throws, the census must report complete:false (so a peer is never certified
846
+ // converged against it) rather than an empty set that reads as an empty deployment.
847
+ const throwingConfig = new Proxy({} as PluginConfig, {
848
+ get() {
849
+ throw new Error("namespace enumeration unavailable");
850
+ },
851
+ });
852
+ const host = {
853
+ config: throwingConfig,
854
+ getStorage: () => {
855
+ throw new Error("getStorage must not be reached once enumeration fails");
856
+ },
857
+ };
858
+ const census = await computeServiceCorpusCensus(host);
859
+ assert.equal(census.complete, false, "an enumeration failure is incomplete, never a certified empty census");
860
+ assert.deepEqual(census.watermarks, [], "and it yields no watermarks");
861
+ });
@@ -500,6 +500,22 @@ export async function computeServiceCorpusWatermarks(
500
500
  host: CorpusWatermarkHost,
501
501
  options: ServiceCorpusWatermarkOptions = {},
502
502
  ): Promise<CorpusWatermark[]> {
503
+ return (await computeServiceCorpusCensus(host, options)).watermarks;
504
+ }
505
+
506
+ /**
507
+ * Watermarks PLUS whether every configured namespace made it into the set.
508
+ *
509
+ * Completeness is returned ATOMICALLY with the data rather than stashed in a
510
+ * side channel: every early exit here (enumeration threw, roots still warming,
511
+ * a per-namespace scan failed, a cache entry not yet populated) yields an
512
+ * incomplete set, and a caller that certifies convergence against a partial
513
+ * census would hide the divergence of whatever was dropped (issue #2149).
514
+ */
515
+ export async function computeServiceCorpusCensus(
516
+ host: CorpusWatermarkHost,
517
+ options: ServiceCorpusWatermarkOptions = {},
518
+ ): Promise<{ watermarks: CorpusWatermark[]; complete: boolean }> {
503
519
  let roots: CorpusNamespaceRoot[] | undefined;
504
520
  if (options.cache) {
505
521
  roots = options.cache.getResolvedRoots(() => resolveCorpusNamespaceRoots({ config: host.config }));
@@ -507,25 +523,31 @@ export async function computeServiceCorpusWatermarks(
507
523
  try {
508
524
  roots = await resolveCorpusNamespaceRoots({ config: host.config });
509
525
  } catch {
510
- return [];
526
+ return { watermarks: [], complete: false }; // never enumerated — not an empty corpus
511
527
  }
512
528
  }
513
- if (!roots) return []; // enumeration still warming (cold) served on a later probe
529
+ // Enumeration still warming (cold): served on a later probe, and NOT complete.
530
+ if (!roots) return { watermarks: [], complete: false };
514
531
  const visible = roots.filter((root) => root.namespaces.some((ns) => capabilityAllowsNamespace(options.caps, ns)));
515
532
  const watermarks: CorpusWatermark[] = [];
533
+ let complete = true;
516
534
  for (const { namespace } of visible) {
517
535
  const compute = async (): Promise<CorpusWatermark> =>
518
536
  computeNamespaceWatermark(namespace, await host.getStorage(namespace), options.now);
519
537
  if (options.cache) {
520
538
  const cached = options.cache.get(namespace, compute);
521
539
  if (cached) watermarks.push(cached);
540
+ else complete = false; // still warming — the set is not the full census yet
522
541
  } else {
523
542
  try {
524
543
  watermarks.push(await compute());
525
544
  } catch {
526
545
  // One tenant's storage/scan failed — omit just that namespace.
546
+ complete = false;
527
547
  }
528
548
  }
529
549
  }
530
- return watermarks;
550
+ return { watermarks, complete };
531
551
  }
552
+
553
+
@@ -0,0 +1,55 @@
1
+ const BUILTIN_ALIASES: Record<string, string> = {
2
+ openclaw: "openclaw",
3
+ "open-claw": "openclaw",
4
+ };
5
+
6
+ function normalizeEntityNameWithPattern(
7
+ raw: string,
8
+ type: string,
9
+ aliases: Readonly<Record<string, string>> | undefined,
10
+ pattern: RegExp,
11
+ normalizeUnicode: boolean
12
+ ): string {
13
+ const rawStr = typeof raw === "string" ? raw : "";
14
+ const typeStr = typeof type === "string" && type.trim().length > 0 ? type : "entity";
15
+ const typePrefix = `${typeStr.toLowerCase()}-`;
16
+ let name = normalizeUnicode ? rawStr.normalize("NFC").toLowerCase().trim() : rawStr.toLowerCase().trim();
17
+ if (name.startsWith(typePrefix)) name = name.slice(typePrefix.length);
18
+
19
+ let normalized = name.replace(pattern, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
20
+ let legacyNormalized: string | undefined;
21
+ if (normalizeUnicode) {
22
+ let legacyName = rawStr.toLowerCase().trim();
23
+ if (legacyName.startsWith(typePrefix)) legacyName = legacyName.slice(typePrefix.length);
24
+ legacyNormalized = legacyName.replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
25
+ }
26
+ const unicodeAlias = aliases !== undefined && Object.hasOwn(aliases, normalized) ? aliases[normalized] : undefined;
27
+ const legacyAlias =
28
+ legacyNormalized !== undefined && legacyNormalized !== normalized && aliases !== undefined &&
29
+ Object.hasOwn(aliases, legacyNormalized)
30
+ ? aliases[legacyNormalized]
31
+ : undefined;
32
+ const userAlias =
33
+ typeof unicodeAlias === "string" && unicodeAlias.length > 0
34
+ ? unicodeAlias
35
+ : legacyAlias;
36
+ if (typeof userAlias === "string" && userAlias.length > 0) {
37
+ normalized = userAlias;
38
+ } else if (Object.hasOwn(BUILTIN_ALIASES, normalized)) {
39
+ normalized = BUILTIN_ALIASES[normalized];
40
+ }
41
+
42
+ return `${typeStr.toLowerCase()}-${normalized}`;
43
+ }
44
+
45
+ export function normalizeEntityName(raw: string, type: string, aliases?: Readonly<Record<string, string>>): string {
46
+ return normalizeEntityNameWithPattern(raw, type, aliases, /[^\p{L}\p{M}\p{N}]+/gu, true);
47
+ }
48
+
49
+ export function normalizeLegacyEntityName(
50
+ raw: string,
51
+ type: string,
52
+ aliases?: Readonly<Record<string, string>>
53
+ ): string {
54
+ return normalizeEntityNameWithPattern(raw, type, aliases, /[^a-z0-9]+/g, false);
55
+ }
@@ -0,0 +1,134 @@
1
+ const UNICODE_WORD_OR_NUMBER_RE = /[\p{L}\p{M}\p{N}]/u;
2
+
3
+ function firstUnicodeCharacter(value: string): string {
4
+ const codePoint = value.codePointAt(0);
5
+ return codePoint === undefined ? "" : String.fromCodePoint(codePoint);
6
+ }
7
+
8
+ function lastUnicodeCharacter(value: string): string {
9
+ const codePoint = [...value].at(-1);
10
+ return codePoint ?? "";
11
+ }
12
+
13
+ const JAPANESE_PARTICLE_RE = /^[のはがをにへともやかでだ]$/u;
14
+ const JAPANESE_MULTI_CHARACTER_PARTICLES = [
15
+ "について",
16
+ "にとって",
17
+ "によって",
18
+ "に関して",
19
+ "に対して",
20
+ "とは",
21
+ "では",
22
+ "には",
23
+ "にも",
24
+ "って",
25
+ ] as const;
26
+ const KOREAN_PARTICLES = [
27
+ "에서", "에게", "한테", "으로", "까지", "부터", "보다", "처럼", "같이",
28
+ "이나", "라도", "밖에", "마다", "조차", "이랑", "하고", "은", "는",
29
+ "이", "가", "을", "를", "의", "께", "와", "과", "도", "만", "든",
30
+ "에", "로", "나", "랑",
31
+ ] as const;
32
+ const KOREAN_UNSPACED_QUESTION_PARTICLES = ["은", "는", "이", "가"] as const;
33
+ const KOREAN_INTERROGATIVE_PREFIXES = [
34
+ "어디", "무엇", "뭐", "왜", "어떻게", "언제", "누구", "어느", "몇", "얼마",
35
+ ] as const;
36
+
37
+ const HANGUL_RUN_RE = /^[\p{Script=Hangul}]+/u;
38
+
39
+ const UNICODE_WORD_SEGMENTER =
40
+ typeof Intl.Segmenter === "function" ? new Intl.Segmenter(undefined, { granularity: "word" }) : null;
41
+ const KOREAN_WORD_SEGMENTER =
42
+ typeof Intl.Segmenter === "function" ? new Intl.Segmenter("ko", { granularity: "word" }) : null;
43
+
44
+ const JAPANESE_WORD_SEGMENTER =
45
+ typeof Intl.Segmenter === "function" ? new Intl.Segmenter("ja", { granularity: "word" }) : null;
46
+ const JAPANESE_KANA_RE = /[\p{Script=Hiragana}\p{Script=Katakana}]/u;
47
+
48
+ function isJapaneseParticleBoundary(suffix: string): boolean {
49
+ const firstSegment = JAPANESE_WORD_SEGMENTER?.segment(suffix).containing(0)?.segment;
50
+ if (firstSegment !== undefined) {
51
+ if (JAPANESE_MULTI_CHARACTER_PARTICLES.some((particle) => particle === firstSegment)) return true;
52
+ return JAPANESE_PARTICLE_RE.test(firstSegment);
53
+ }
54
+ const firstCharacter = firstUnicodeCharacter(suffix);
55
+ return (
56
+ JAPANESE_MULTI_CHARACTER_PARTICLES.some((particle) => suffix.startsWith(particle)) ||
57
+ (JAPANESE_PARTICLE_RE.test(firstCharacter) &&
58
+ !UNICODE_WORD_OR_NUMBER_RE.test(firstUnicodeCharacter(suffix.slice(firstCharacter.length))))
59
+ );
60
+ }
61
+
62
+ function isIntlWordBoundary(source: string, index: number): boolean {
63
+ if (index <= 0 || index >= source.length) return true;
64
+ return UNICODE_WORD_SEGMENTER?.segment(source).containing(index)?.index === index;
65
+ }
66
+
67
+ function isKoreanUnspacedQuestionBoundary(suffix: string): boolean {
68
+ return KOREAN_UNSPACED_QUESTION_PARTICLES.some((particle) =>
69
+ suffix.startsWith(particle) &&
70
+ KOREAN_INTERROGATIVE_PREFIXES.some((prefix) => suffix.startsWith(prefix, particle.length)),
71
+ );
72
+ }
73
+
74
+ function isKoreanParticleBoundary(suffix: string): boolean {
75
+ if (isKoreanUnspacedQuestionBoundary(suffix)) return true;
76
+ const firstSegment = KOREAN_WORD_SEGMENTER?.segment(suffix).containing(0)?.segment;
77
+ if (firstSegment !== undefined) {
78
+ return KOREAN_PARTICLES.some((particle) => particle === firstSegment);
79
+ }
80
+ const particleRun = suffix.match(HANGUL_RUN_RE)?.[0] ?? "";
81
+ const nextCharacter = firstUnicodeCharacter(suffix.slice(particleRun.length));
82
+ return (
83
+ KOREAN_PARTICLES.some((particle) => particle === particleRun) &&
84
+ (nextCharacter.length === 0 || !UNICODE_WORD_OR_NUMBER_RE.test(nextCharacter))
85
+ );
86
+ }
87
+
88
+ function isUnicodePhraseBoundary(
89
+ character: string,
90
+ suffix: string = "",
91
+ source: string = "",
92
+ boundaryIndex: number = -1,
93
+ strictUnicode = false,
94
+ allowLeadingParticle = false,
95
+ ): boolean {
96
+ return (
97
+ character.length === 0
98
+ || !UNICODE_WORD_OR_NUMBER_RE.test(character)
99
+ || (allowLeadingParticle && isJapaneseParticleBoundary(character))
100
+ || isJapaneseParticleBoundary(suffix)
101
+ || (!strictUnicode &&
102
+ boundaryIndex >= 0 &&
103
+ !JAPANESE_KANA_RE.test(suffix) &&
104
+ isIntlWordBoundary(source, boundaryIndex))
105
+ || (allowLeadingParticle && isKoreanParticleBoundary(character))
106
+ || isKoreanParticleBoundary(suffix)
107
+ );
108
+ }
109
+
110
+ export function containsPhrase(haystack: string, needle: string): boolean {
111
+ if (!needle) return false;
112
+ const caseInsensitive = /^[a-z0-9 ]+$/i.test(needle);
113
+ const searchHaystack = caseInsensitive ? haystack.toLowerCase() : haystack;
114
+ const searchNeedle = caseInsensitive ? needle.toLowerCase() : needle;
115
+ let offset = searchHaystack.indexOf(searchNeedle);
116
+ while (offset >= 0) {
117
+ const before = lastUnicodeCharacter(searchHaystack.slice(0, offset));
118
+ const after = searchHaystack.slice(offset + searchNeedle.length);
119
+ if (
120
+ isUnicodePhraseBoundary(before, "", searchHaystack, offset, caseInsensitive, true)
121
+ && isUnicodePhraseBoundary(
122
+ firstUnicodeCharacter(after),
123
+ after,
124
+ searchHaystack,
125
+ offset + searchNeedle.length,
126
+ caseInsensitive,
127
+ )
128
+ ) {
129
+ return true;
130
+ }
131
+ offset = searchHaystack.indexOf(searchNeedle, offset + searchNeedle.length);
132
+ }
133
+ return false;
134
+ }