@remnic/core 9.27.0 → 9.28.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 (439) hide show
  1. package/dist/access-admin-ops-surface.d.ts +13 -10
  2. package/dist/access-admin-ops-surface.js +43 -38
  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 +44 -39
  6. package/dist/access-boundary.d.ts +13 -10
  7. package/dist/access-boundary.js +43 -38
  8. package/dist/access-cli.js +100 -94
  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 +53 -48
  14. package/dist/access-identity-continuity-surface.d.ts +9 -8
  15. package/dist/access-identity-continuity-surface.js +43 -38
  16. package/dist/access-lcm-surface.d.ts +13 -10
  17. package/dist/access-lcm-surface.js +43 -38
  18. package/dist/access-mcp.d.ts +13 -10
  19. package/dist/access-mcp.js +48 -43
  20. package/dist/access-memory-search-fanout.d.ts +2 -2
  21. package/dist/{access-namespace-preflight-wRSZEO5V.d.ts → access-namespace-preflight-BiQ_-iUJ.d.ts} +1 -1
  22. package/dist/access-namespace-preflight.d.ts +3 -3
  23. package/dist/access-namespace-preflight.js +43 -38
  24. package/dist/access-observe-write-surface.d.ts +13 -10
  25. package/dist/access-observe-write-surface.js +43 -38
  26. package/dist/access-operations-batch.js +45 -40
  27. package/dist/access-operations.d.ts +16 -13
  28. package/dist/access-operations.js +47 -42
  29. package/dist/access-recall-concurrency.d.ts +13 -10
  30. package/dist/access-recall-concurrency.js +43 -38
  31. package/dist/access-recall-response.d.ts +13 -10
  32. package/dist/access-recall-response.js +43 -38
  33. package/dist/access-recall-surface.d.ts +13 -10
  34. package/dist/access-recall-surface.js +43 -38
  35. package/dist/access-schema.d.ts +80 -80
  36. package/dist/access-schema.js +4 -4
  37. package/dist/{access-service-B4-Fu9x2.d.ts → access-service-CXkIgcGh.d.ts} +12 -8
  38. package/dist/access-service.d.ts +13 -10
  39. package/dist/access-service.js +43 -38
  40. package/dist/access-surface-catalog.d.ts +13 -10
  41. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  42. package/dist/action-confidence.d.ts +1 -1
  43. package/dist/active-memory-bridge.d.ts +1 -1
  44. package/dist/active-recall.d.ts +1 -1
  45. package/dist/active-recall.js +4 -2
  46. package/dist/active-recall.js.map +1 -1
  47. package/dist/adapters/index.js +7 -7
  48. package/dist/adapters/registry.js +3 -3
  49. package/dist/behavior-learner.d.ts +1 -1
  50. package/dist/behavior-signals.d.ts +1 -1
  51. package/dist/bootstrap.d.ts +9 -8
  52. package/dist/briefing.d.ts +3 -2
  53. package/dist/briefing.js +12 -10
  54. package/dist/buffer-surprise-report.d.ts +1 -1
  55. package/dist/buffer.d.ts +3 -2
  56. package/dist/bulk-import/index.d.ts +3 -3
  57. package/dist/calibration.d.ts +1 -1
  58. package/dist/capabilities.d.ts +1 -1
  59. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  60. package/dist/{catalog-BLLxZ5L5.d.ts → catalog-Bouj8Gfg.d.ts} +1 -1
  61. package/dist/causal-behavior.d.ts +1 -1
  62. package/dist/causal-consolidation.d.ts +1 -1
  63. package/dist/causal-consolidation.js +13 -11
  64. package/dist/causal-consolidation.js.map +1 -1
  65. package/dist/causal-trajectory-graph.d.ts +1 -1
  66. package/dist/{chunk-7RZJWZ46.js → chunk-227UFSEQ.js} +5 -5
  67. package/dist/{chunk-UT3OQPFA.js → chunk-2BEJ4XCF.js} +2 -2
  68. package/dist/{chunk-EOLC6EXV.js → chunk-2FYNLDKJ.js} +24 -3
  69. package/dist/chunk-2FYNLDKJ.js.map +1 -0
  70. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  71. package/dist/{chunk-6NNNURLK.js → chunk-2PHX3I5C.js} +8 -8
  72. package/dist/{chunk-HORJVJ6K.js → chunk-2TQ2UFKH.js} +65 -60
  73. package/dist/chunk-2TQ2UFKH.js.map +1 -0
  74. package/dist/{chunk-RPA2RX5P.js → chunk-3BSJBIZ3.js} +2 -2
  75. package/dist/{chunk-JCVQV6QX.js → chunk-3UOSVTFR.js} +11 -11
  76. package/dist/{chunk-AJ7QCSIS.js → chunk-7CPOZH6Y.js} +2 -2
  77. package/dist/{chunk-MEBQFQ26.js → chunk-AHFZXUZM.js} +7 -5
  78. package/dist/chunk-AHFZXUZM.js.map +1 -0
  79. package/dist/{chunk-U3TH5Q2Q.js → chunk-ALTP3MFS.js} +2 -2
  80. package/dist/{chunk-77CNV7DY.js → chunk-BLAKS3CP.js} +4 -4
  81. package/dist/{chunk-XQ4EH6DI.js → chunk-BR4UFMLO.js} +2 -2
  82. package/dist/chunk-CVILPI77.js +432 -0
  83. package/dist/chunk-CVILPI77.js.map +1 -0
  84. package/dist/{chunk-WEAO45M4.js → chunk-DKQM5Q6Q.js} +2 -2
  85. package/dist/{chunk-CSXHRAJJ.js → chunk-EG64LXKL.js} +3 -3
  86. package/dist/{chunk-PTN6UAUA.js → chunk-ES36HTSC.js} +4 -4
  87. package/dist/{chunk-5BRT4Z2I.js → chunk-EZWWCN7I.js} +2 -2
  88. package/dist/{chunk-XKGPIWGI.js → chunk-FBZTWUK5.js} +5 -5
  89. package/dist/{chunk-GJJBPI6I.js → chunk-FOCEI3TN.js} +6 -3
  90. package/dist/chunk-FOCEI3TN.js.map +1 -0
  91. package/dist/{chunk-FRVTCCGD.js → chunk-GJPCP5CA.js} +2 -2
  92. package/dist/{chunk-CI26JDZA.js → chunk-GQSMYXKL.js} +6 -4
  93. package/dist/{chunk-CI26JDZA.js.map → chunk-GQSMYXKL.js.map} +1 -1
  94. package/dist/{chunk-TGQ2NTWH.js → chunk-IJ6WHMFB.js} +16 -2
  95. package/dist/{chunk-TGQ2NTWH.js.map → chunk-IJ6WHMFB.js.map} +1 -1
  96. package/dist/{chunk-VDX2J7OX.js → chunk-IPLYGWQF.js} +6 -6
  97. package/dist/{chunk-YSGBD3QN.js → chunk-IYT632D5.js} +3 -3
  98. package/dist/{chunk-2QSZNTDO.js → chunk-JBPKEARU.js} +7 -7
  99. package/dist/{chunk-RSYJV25N.js → chunk-JIF3VRKQ.js} +8 -8
  100. package/dist/{chunk-V25OWXAC.js → chunk-JQ7T5VDC.js} +1 -1
  101. package/dist/chunk-JQ7T5VDC.js.map +1 -0
  102. package/dist/{chunk-EUSLKI4X.js → chunk-KKBTBUVT.js} +2 -2
  103. package/dist/{chunk-RNY3BO35.js → chunk-LIHC3T43.js} +2 -2
  104. package/dist/{chunk-RGJBM7Z3.js → chunk-MJPV4LBH.js} +79 -79
  105. package/dist/{chunk-RGJBM7Z3.js.map → chunk-MJPV4LBH.js.map} +1 -1
  106. package/dist/{chunk-UGH6VPPO.js → chunk-MWTMTW2T.js} +2 -2
  107. package/dist/{chunk-MG6MNSP4.js → chunk-MXJ3VP6S.js} +6 -6
  108. package/dist/{chunk-XKO7BM2C.js → chunk-NBNDVNJ2.js} +186 -25
  109. package/dist/chunk-NBNDVNJ2.js.map +1 -0
  110. package/dist/{chunk-M5EPMNS4.js → chunk-P2CLYN6H.js} +2 -2
  111. package/dist/{chunk-BNGPHGVZ.js → chunk-PXQM2HOG.js} +13 -6
  112. package/dist/{chunk-BNGPHGVZ.js.map → chunk-PXQM2HOG.js.map} +1 -1
  113. package/dist/{chunk-CIQXI47W.js → chunk-Q5VJUNXA.js} +1192 -268
  114. package/dist/chunk-Q5VJUNXA.js.map +1 -0
  115. package/dist/{chunk-KGTD2KZJ.js → chunk-Q6YJW6KE.js} +2 -2
  116. package/dist/{chunk-X3SQYAPP.js → chunk-R372P2EH.js} +2 -2
  117. package/dist/{chunk-4MJZTF42.js → chunk-RKXZ7P4V.js} +3 -3
  118. package/dist/chunk-RMMVQQA6.js +70 -0
  119. package/dist/chunk-RMMVQQA6.js.map +1 -0
  120. package/dist/{chunk-2RAC4JIG.js → chunk-S24E4MBQ.js} +14 -14
  121. package/dist/chunk-S24E4MBQ.js.map +1 -0
  122. package/dist/{chunk-RYHWZ52A.js → chunk-S2BBISHU.js} +4 -4
  123. package/dist/{chunk-LLISELSY.js → chunk-TBMRQZDY.js} +2 -2
  124. package/dist/{chunk-FMLKOL2Z.js → chunk-TC3VNKGX.js} +4 -4
  125. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  126. package/dist/{chunk-NUWMZIYZ.js → chunk-UR5SIN7H.js} +53 -35
  127. package/dist/chunk-UR5SIN7H.js.map +1 -0
  128. package/dist/{chunk-JDOJZTFF.js → chunk-VFNI3RPT.js} +2 -2
  129. package/dist/chunk-VNA7W7QF.js +134 -0
  130. package/dist/chunk-VNA7W7QF.js.map +1 -0
  131. package/dist/{chunk-EYJSW2RV.js → chunk-VYYNBJXH.js} +5 -5
  132. package/dist/chunk-WNIUPHWV.js +152 -0
  133. package/dist/chunk-WNIUPHWV.js.map +1 -0
  134. package/dist/chunk-WRJVB3C2.js +118 -0
  135. package/dist/chunk-WRJVB3C2.js.map +1 -0
  136. package/dist/{chunk-BHLN7L7M.js → chunk-WVVK2RFM.js} +6 -6
  137. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  138. package/dist/{chunk-HEXSNYJD.js → chunk-YOBNCD3Z.js} +6 -6
  139. package/dist/chunk-YXZG5TVN.js +40 -0
  140. package/dist/chunk-YXZG5TVN.js.map +1 -0
  141. package/dist/{chunk-4DJQYKMN.js → chunk-ZIKENA2C.js} +2 -2
  142. package/dist/chunk-ZIKENA2C.js.map +1 -0
  143. package/dist/{chunk-SK3EYPKC.js → chunk-ZN4UZWMT.js} +2 -2
  144. package/dist/{cli-Bz7X7dGx.d.ts → cli-DJbkaZBU.d.ts} +5 -5
  145. package/dist/cli.d.ts +14 -12
  146. package/dist/cli.js +79 -74
  147. package/dist/compounding/engine.d.ts +3 -2
  148. package/dist/compounding/engine.js +12 -10
  149. package/dist/compounding/preference-consolidator.d.ts +1 -1
  150. package/dist/compression-optimizer.d.ts +1 -1
  151. package/dist/config.d.ts +1 -1
  152. package/dist/config.js +4 -2
  153. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  154. package/dist/connectors/codex-materialize-runner.js +12 -10
  155. package/dist/connectors/codex-materialize.d.ts +1 -1
  156. package/dist/connectors/index.d.ts +1 -1
  157. package/dist/connectors/index.js +12 -10
  158. package/dist/consolidation-provenance-check.d.ts +3 -2
  159. package/dist/consolidation-undo.d.ts +3 -2
  160. package/dist/contradiction/index.d.ts +3 -2
  161. package/dist/conversation-index/backend.d.ts +1 -1
  162. package/dist/conversation-index/backend.js +2 -2
  163. package/dist/conversation-index/chunker.d.ts +1 -1
  164. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  165. package/dist/conversation-index/indexer.d.ts +1 -1
  166. package/dist/conversation-index/search.d.ts +1 -1
  167. package/dist/corpus-watermark.d.ts +15 -2
  168. package/dist/corpus-watermark.js +25 -21
  169. package/dist/day-summary.d.ts +1 -1
  170. package/dist/delinearize.d.ts +1 -1
  171. package/dist/direct-answer-wiring.d.ts +1 -1
  172. package/dist/direct-answer.d.ts +1 -1
  173. package/dist/embedding-fallback.d.ts +1 -1
  174. package/dist/enrichment/index.d.ts +1 -1
  175. package/dist/entity-id-normalization.d.ts +4 -0
  176. package/dist/entity-id-normalization.js +10 -0
  177. package/dist/entity-id-normalization.js.map +1 -0
  178. package/dist/entity-retrieval-boundaries.d.ts +3 -0
  179. package/dist/entity-retrieval-boundaries.js +8 -0
  180. package/dist/entity-retrieval-boundaries.js.map +1 -0
  181. package/dist/entity-retrieval.d.ts +3 -2
  182. package/dist/entity-retrieval.js +13 -10
  183. package/dist/entity-schema.d.ts +1 -1
  184. package/dist/entity-schema.js +1 -1
  185. package/dist/explicit-capture.d.ts +9 -8
  186. package/dist/extraction-error-classification.d.ts +1 -1
  187. package/dist/extraction-faithfulness.d.ts +1 -1
  188. package/dist/extraction-judge-telemetry.d.ts +1 -1
  189. package/dist/extraction-judge-training.d.ts +1 -1
  190. package/dist/extraction-judge.d.ts +1 -1
  191. package/dist/extraction-liveness.d.ts +1 -1
  192. package/dist/extraction.d.ts +1 -1
  193. package/dist/fallback-llm.d.ts +1 -1
  194. package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
  195. package/dist/graph-dashboard-diff.d.ts +1 -1
  196. package/dist/graph-dashboard-key.d.ts +1 -1
  197. package/dist/graph-dashboard-parser.d.ts +1 -1
  198. package/dist/graph-edge-reinforcement.d.ts +1 -1
  199. package/dist/graph-snapshot.d.ts +1 -1
  200. package/dist/graph.d.ts +1 -1
  201. package/dist/importance.d.ts +1 -1
  202. package/dist/importers/index.d.ts +1 -1
  203. package/dist/in-flight-reads.d.ts +1 -1
  204. package/dist/index.d.ts +409 -407
  205. package/dist/index.js +147 -141
  206. package/dist/intent.d.ts +1 -1
  207. package/dist/lcm/engine.d.ts +1 -1
  208. package/dist/lcm/engine.js +3 -3
  209. package/dist/lcm/index.d.ts +1 -1
  210. package/dist/lcm/index.js +9 -9
  211. package/dist/lcm/tools.d.ts +1 -1
  212. package/dist/lifecycle.d.ts +1 -1
  213. package/dist/live-connectors-runner.d.ts +1 -1
  214. package/dist/local-llm.d.ts +1 -1
  215. package/dist/local-model-endpoint.d.ts +1 -1
  216. package/dist/maintenance/memory-governance.d.ts +1 -1
  217. package/dist/maintenance/memory-governance.js +12 -10
  218. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  219. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -10
  220. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  221. package/dist/maintenance/rebuild-memory-projection.js +13 -11
  222. package/dist/{maintenance-DgnD2z8S.d.ts → maintenance-DveW6azo.d.ts} +3 -3
  223. package/dist/mcp-memory-inspector-app.d.ts +13 -10
  224. package/dist/memory-action-policy.d.ts +1 -1
  225. package/dist/memory-cache.d.ts +1 -1
  226. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  227. package/dist/memory-projection-mutations.d.ts +4 -0
  228. package/dist/memory-projection-mutations.js +15 -0
  229. package/dist/memory-projection-mutations.js.map +1 -0
  230. package/dist/memory-projection-store.d.ts +1 -1
  231. package/dist/memory-provenance.d.ts +1 -1
  232. package/dist/memory-worth-outcomes.d.ts +3 -2
  233. package/dist/models-json.d.ts +1 -1
  234. package/dist/namespaces/migrate.d.ts +4 -3
  235. package/dist/namespaces/migrate.js +22 -20
  236. package/dist/namespaces/principal.d.ts +1 -1
  237. package/dist/namespaces/search.d.ts +1 -1
  238. package/dist/namespaces/search.js +9 -9
  239. package/dist/namespaces/storage.d.ts +4 -3
  240. package/dist/namespaces/storage.js +12 -10
  241. package/dist/native-knowledge.d.ts +1 -1
  242. package/dist/offline-sync-impression-drain.d.ts +1 -1
  243. package/dist/offline-sync-impression-drain.js +3 -3
  244. package/dist/operator-doctor-corpus.d.ts +22 -3
  245. package/dist/operator-doctor-corpus.js +32 -22
  246. package/dist/operator-doctor-replica.d.ts +52 -0
  247. package/dist/operator-doctor-replica.js +15 -0
  248. package/dist/operator-doctor-replica.js.map +1 -0
  249. package/dist/operator-toolkit.d.ts +7 -3
  250. package/dist/operator-toolkit.js +33 -27
  251. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  252. package/dist/orchestration/maintenance.d.ts +5 -4
  253. package/dist/orchestration/maintenance.js +17 -15
  254. package/dist/{orchestrator-rIHmHpv1.d.ts → orchestrator-Cvlgpe6I.d.ts} +7 -7
  255. package/dist/orchestrator.d.ts +9 -8
  256. package/dist/orchestrator.js +99 -93
  257. package/dist/patterns-cli.d.ts +1 -1
  258. package/dist/{pipeline-Bq5zU6Bp.d.ts → pipeline-BveYVaz7.d.ts} +1 -1
  259. package/dist/policy-runtime.d.ts +1 -1
  260. package/dist/proactive-contention.d.ts +1 -1
  261. package/dist/provenance.d.ts +1 -1
  262. package/dist/{qmd-3ILJkC70.d.ts → qmd-CLWDsbYR.d.ts} +1 -1
  263. package/dist/qmd-preflight.d.ts +2 -2
  264. package/dist/qmd-recall-cache.d.ts +1 -1
  265. package/dist/qmd.d.ts +2 -2
  266. package/dist/recall-concurrency-config.d.ts +1 -1
  267. package/dist/recall-disclosure-escalation.d.ts +1 -1
  268. package/dist/recall-explain-renderer.d.ts +1 -1
  269. package/dist/recall-explain-renderer.js +3 -3
  270. package/dist/recall-memory-map.d.ts +1 -1
  271. package/dist/recall-planner-llm.d.ts +1 -1
  272. package/dist/recall-state.d.ts +1 -1
  273. package/dist/recall-state.js +2 -2
  274. package/dist/recall-tag-filter.d.ts +1 -1
  275. package/dist/recall-timings.d.ts +1 -1
  276. package/dist/recall-xray-cli.d.ts +1 -1
  277. package/dist/recall-xray-cli.js +4 -4
  278. package/dist/recall-xray-renderer.d.ts +1 -1
  279. package/dist/recall-xray-renderer.js +3 -3
  280. package/dist/recall-xray.d.ts +1 -1
  281. package/dist/recall-xray.js +2 -2
  282. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  283. package/dist/replay/normalizers/claude.d.ts +1 -1
  284. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  285. package/dist/replay/normalizers/shared.d.ts +1 -1
  286. package/dist/replay/runner.d.ts +1 -1
  287. package/dist/replay/types.d.ts +1 -1
  288. package/dist/replica-divergence.d.ts +279 -0
  289. package/dist/replica-divergence.js +28 -0
  290. package/dist/replica-divergence.js.map +1 -0
  291. package/dist/replica-peers-config.d.ts +5 -0
  292. package/dist/replica-peers-config.js +13 -0
  293. package/dist/replica-peers-config.js.map +1 -0
  294. package/dist/resolve-auth-token.d.ts +21 -2
  295. package/dist/resolve-auth-token.js +5 -1
  296. package/dist/resume-bundles.js +5 -3
  297. package/dist/retrieval-agents.d.ts +2 -2
  298. package/dist/retrieval-tiers.d.ts +1 -1
  299. package/dist/routing/engine.d.ts +1 -1
  300. package/dist/routing/store.d.ts +1 -1
  301. package/dist/salvage-envelope.d.ts +1 -1
  302. package/dist/schemas.d.ts +76 -76
  303. package/dist/{scope-profiles-D0-ff4xT.d.ts → scope-profiles-BVf3DZ7z.d.ts} +1 -1
  304. package/dist/search/embed-helper.d.ts +1 -1
  305. package/dist/search/factory.d.ts +1 -1
  306. package/dist/search/factory.js +8 -8
  307. package/dist/search/index.d.ts +1 -1
  308. package/dist/search/index.js +13 -13
  309. package/dist/search/lancedb-backend.d.ts +1 -1
  310. package/dist/search/lancedb-backend.js +2 -2
  311. package/dist/search/meilisearch-backend.d.ts +1 -1
  312. package/dist/search/meilisearch-backend.js +2 -2
  313. package/dist/search/noop-backend.d.ts +1 -1
  314. package/dist/search/orama-backend.d.ts +1 -1
  315. package/dist/search/orama-backend.js +2 -2
  316. package/dist/search/port.d.ts +1 -1
  317. package/dist/search/remote-backend.d.ts +1 -1
  318. package/dist/{semantic-consolidation-4Tfh7c1g.d.ts → semantic-consolidation-DXLV47y2.d.ts} +1 -1
  319. package/dist/semantic-consolidation.d.ts +2 -2
  320. package/dist/semantic-consolidation.js +13 -11
  321. package/dist/semantic-rule-promotion.js +12 -10
  322. package/dist/semantic-rule-verifier.d.ts +1 -1
  323. package/dist/semantic-rule-verifier.js +12 -10
  324. package/dist/{service-cTvil7D_.d.ts → service-DbgPTeMJ.d.ts} +2 -2
  325. package/dist/session-observer-bands.d.ts +1 -1
  326. package/dist/session-observer-state.d.ts +1 -1
  327. package/dist/shared-context/manager.d.ts +9 -9
  328. package/dist/signal.d.ts +1 -1
  329. package/dist/{storage-C9ibpTme.d.ts → storage-DOzTm8wG.d.ts} +13 -19
  330. package/dist/storage.d.ts +3 -2
  331. package/dist/storage.js +13 -10
  332. package/dist/summarizer.d.ts +1 -1
  333. package/dist/summary-snapshot.d.ts +1 -1
  334. package/dist/temporal-supersession.d.ts +3 -2
  335. package/dist/temporal-timeline-recall.d.ts +1 -1
  336. package/dist/temporal-validity.d.ts +1 -1
  337. package/dist/threading.d.ts +1 -1
  338. package/dist/tier-migration.d.ts +3 -2
  339. package/dist/tier-routing.d.ts +1 -1
  340. package/dist/topics.d.ts +1 -1
  341. package/dist/transcript.d.ts +1 -1
  342. package/dist/transfer/autodetect.js +1 -1
  343. package/dist/transfer/backup.js +2 -2
  344. package/dist/transfer/capsule-export.js +3 -3
  345. package/dist/transfer/capsule-import.js +2 -2
  346. package/dist/transfer/types.d.ts +66 -66
  347. package/dist/trust-score-stage.d.ts +1 -1
  348. package/dist/trust-score.d.ts +1 -1
  349. package/dist/{types-DHBxIF0s.d.ts → types-BA7W-_xy.d.ts} +53 -4
  350. package/dist/types.d.ts +1 -1
  351. package/dist/types.js +1 -1
  352. package/dist/utility-runtime.d.ts +1 -1
  353. package/dist/verified-recall.js +12 -10
  354. package/dist/write-envelope.d.ts +1 -1
  355. package/package.json +2 -2
  356. package/src/access-health-types.ts +8 -0
  357. package/src/access-http.test.ts +4 -0
  358. package/src/access-service-health.test.ts +23 -0
  359. package/src/access-service.ts +27 -4
  360. package/src/cli.ts +9 -7
  361. package/src/config.ts +2 -1
  362. package/src/corpus-watermark.test.ts +21 -0
  363. package/src/corpus-watermark.ts +25 -3
  364. package/src/entity-id-normalization.ts +55 -0
  365. package/src/entity-retrieval-boundaries.ts +134 -0
  366. package/src/entity-retrieval.ts +253 -27
  367. package/src/entity-schema.ts +2 -1
  368. package/src/memory-projection-mutations.ts +132 -0
  369. package/src/namespaces/storage.ts +5 -3
  370. package/src/operator-doctor-corpus.ts +41 -0
  371. package/src/operator-doctor-replica.test.ts +261 -0
  372. package/src/operator-doctor-replica.ts +129 -0
  373. package/src/operator-toolkit.ts +5 -4
  374. package/src/orchestration/orchestrator-init.ts +2 -2
  375. package/src/replica-divergence.test.ts +1475 -0
  376. package/src/replica-divergence.ts +910 -0
  377. package/src/replica-peers-config.ts +250 -0
  378. package/src/resolve-auth-token.ts +38 -0
  379. package/src/storage/entity-canonical-id-migration-adapter.ts +72 -0
  380. package/src/storage/entity-canonical-id-migration-runner.ts +68 -0
  381. package/src/storage/entity-canonical-id-migration.ts +904 -0
  382. package/src/storage/entity-store.ts +44 -0
  383. package/src/storage/memory-frontmatter-metadata.ts +17 -0
  384. package/src/storage/memory-migration-serialization.ts +37 -0
  385. package/src/storage/memory-read-store.ts +3 -2
  386. package/src/storage/profile-header.ts +8 -7
  387. package/src/storage-profile-timestamp.test.ts +68 -0
  388. package/src/storage.ts +68 -69
  389. package/src/types.ts +3 -3
  390. package/dist/chunk-2RAC4JIG.js.map +0 -1
  391. package/dist/chunk-4DJQYKMN.js.map +0 -1
  392. package/dist/chunk-CIQXI47W.js.map +0 -1
  393. package/dist/chunk-EOLC6EXV.js.map +0 -1
  394. package/dist/chunk-GJJBPI6I.js.map +0 -1
  395. package/dist/chunk-HORJVJ6K.js.map +0 -1
  396. package/dist/chunk-MEBQFQ26.js.map +0 -1
  397. package/dist/chunk-NUWMZIYZ.js.map +0 -1
  398. package/dist/chunk-V25OWXAC.js.map +0 -1
  399. package/dist/chunk-XKO7BM2C.js.map +0 -1
  400. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  401. /package/dist/{chunk-7RZJWZ46.js.map → chunk-227UFSEQ.js.map} +0 -0
  402. /package/dist/{chunk-UT3OQPFA.js.map → chunk-2BEJ4XCF.js.map} +0 -0
  403. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  404. /package/dist/{chunk-6NNNURLK.js.map → chunk-2PHX3I5C.js.map} +0 -0
  405. /package/dist/{chunk-RPA2RX5P.js.map → chunk-3BSJBIZ3.js.map} +0 -0
  406. /package/dist/{chunk-JCVQV6QX.js.map → chunk-3UOSVTFR.js.map} +0 -0
  407. /package/dist/{chunk-AJ7QCSIS.js.map → chunk-7CPOZH6Y.js.map} +0 -0
  408. /package/dist/{chunk-U3TH5Q2Q.js.map → chunk-ALTP3MFS.js.map} +0 -0
  409. /package/dist/{chunk-77CNV7DY.js.map → chunk-BLAKS3CP.js.map} +0 -0
  410. /package/dist/{chunk-XQ4EH6DI.js.map → chunk-BR4UFMLO.js.map} +0 -0
  411. /package/dist/{chunk-WEAO45M4.js.map → chunk-DKQM5Q6Q.js.map} +0 -0
  412. /package/dist/{chunk-CSXHRAJJ.js.map → chunk-EG64LXKL.js.map} +0 -0
  413. /package/dist/{chunk-PTN6UAUA.js.map → chunk-ES36HTSC.js.map} +0 -0
  414. /package/dist/{chunk-5BRT4Z2I.js.map → chunk-EZWWCN7I.js.map} +0 -0
  415. /package/dist/{chunk-XKGPIWGI.js.map → chunk-FBZTWUK5.js.map} +0 -0
  416. /package/dist/{chunk-FRVTCCGD.js.map → chunk-GJPCP5CA.js.map} +0 -0
  417. /package/dist/{chunk-VDX2J7OX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  418. /package/dist/{chunk-YSGBD3QN.js.map → chunk-IYT632D5.js.map} +0 -0
  419. /package/dist/{chunk-2QSZNTDO.js.map → chunk-JBPKEARU.js.map} +0 -0
  420. /package/dist/{chunk-RSYJV25N.js.map → chunk-JIF3VRKQ.js.map} +0 -0
  421. /package/dist/{chunk-EUSLKI4X.js.map → chunk-KKBTBUVT.js.map} +0 -0
  422. /package/dist/{chunk-RNY3BO35.js.map → chunk-LIHC3T43.js.map} +0 -0
  423. /package/dist/{chunk-UGH6VPPO.js.map → chunk-MWTMTW2T.js.map} +0 -0
  424. /package/dist/{chunk-MG6MNSP4.js.map → chunk-MXJ3VP6S.js.map} +0 -0
  425. /package/dist/{chunk-M5EPMNS4.js.map → chunk-P2CLYN6H.js.map} +0 -0
  426. /package/dist/{chunk-KGTD2KZJ.js.map → chunk-Q6YJW6KE.js.map} +0 -0
  427. /package/dist/{chunk-X3SQYAPP.js.map → chunk-R372P2EH.js.map} +0 -0
  428. /package/dist/{chunk-4MJZTF42.js.map → chunk-RKXZ7P4V.js.map} +0 -0
  429. /package/dist/{chunk-RYHWZ52A.js.map → chunk-S2BBISHU.js.map} +0 -0
  430. /package/dist/{chunk-LLISELSY.js.map → chunk-TBMRQZDY.js.map} +0 -0
  431. /package/dist/{chunk-FMLKOL2Z.js.map → chunk-TC3VNKGX.js.map} +0 -0
  432. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  433. /package/dist/{chunk-JDOJZTFF.js.map → chunk-VFNI3RPT.js.map} +0 -0
  434. /package/dist/{chunk-EYJSW2RV.js.map → chunk-VYYNBJXH.js.map} +0 -0
  435. /package/dist/{chunk-BHLN7L7M.js.map → chunk-WVVK2RFM.js.map} +0 -0
  436. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  437. /package/dist/{chunk-HEXSNYJD.js.map → chunk-YOBNCD3Z.js.map} +0 -0
  438. /package/dist/{chunk-SK3EYPKC.js.map → chunk-ZN4UZWMT.js.map} +0 -0
  439. /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
@@ -0,0 +1,250 @@
1
+ /**
2
+ * `replicaPeers` config surface (issue #2149) — types + parser.
3
+ *
4
+ * Deliberately split out of replica-divergence.ts as a LIGHT module: it imports
5
+ * no heavy modules (no corpus-watermark, no access-token-capabilities). PluginConfig
6
+ * carries `replicaPeers: ReplicaPeersConfig`, so types.ts imports ReplicaPeersConfig
7
+ * from HERE. If that type instead lived in replica-divergence.ts (which pulls in the
8
+ * corpus census graph), then types.ts -> replica-divergence.ts -> corpus-watermark.ts
9
+ * -> types.ts would form a heavy import cycle that rollup-plugin-dts re-expands across
10
+ * every PluginConfig-inlining entry, OOMing the default-heap DTS worker (the issue
11
+ * #1562 heap cliff). Keeping the config surface corpus-free severs that cycle.
12
+ */
13
+
14
+ import { coerceBool, coerceNumber } from "./connectors/coerce.js";
15
+ import { isAgentAccessSecretRef } from "./resolve-auth-token.js";
16
+ import type { AgentAccessAuthToken } from "./types.js";
17
+
18
+ const DEFAULT_POLL_INTERVAL_MS = 300_000; // 5 min
19
+ const DEFAULT_REQUEST_TIMEOUT_MS = 10_000;
20
+ const DEFAULT_MAX_FILE_COUNT_DELTA = 100;
21
+ const DEFAULT_MAX_WATERMARK_AGE_DELTA_MS = 900_000; // 15 min
22
+ /** Node clamps a `setTimeout`/`AbortSignal.timeout` delay above 2^31-1 ms to 1ms,
23
+ * which would make `withDeadline` fire immediately and mark every peer unreachable. */
24
+ const MAX_TIMER_DELAY_MS = 2_147_483_647;
25
+
26
+ export interface ReplicaPeerConfig {
27
+ /** Base URL of the peer's agent-access HTTP server (http/https). */
28
+ url: string;
29
+ /**
30
+ * Bearer token for the peer's authenticated `/health`. A literal string
31
+ * (env-expanded) or an unresolved SecretRef preserved verbatim and resolved
32
+ * at poll time — mirrors `agentAccessHttp.authToken` exactly.
33
+ */
34
+ token?: AgentAccessAuthToken;
35
+ }
36
+
37
+ export interface ReplicaPeersConfig {
38
+ /** Master gate. Default false — a daemon with no peers behaves exactly as before. */
39
+ enabled: boolean;
40
+ /** Peers to poll. Default []. */
41
+ peers: ReplicaPeerConfig[];
42
+ /** How often a peer is re-polled (SWR TTL), ms. Default 5 min. */
43
+ pollIntervalMs: number;
44
+ /** Per-peer request timeout, ms. Default 10s. */
45
+ requestTimeoutMs: number;
46
+ /** File-count delta (per namespace) beyond which a peer is flagged diverged. Default 100. */
47
+ maxFileCountDelta: number;
48
+ /** Newest-write timestamp gap (per namespace) beyond which a peer is flagged diverged, ms. Default 15 min. */
49
+ maxWatermarkAgeDeltaMs: number;
50
+ }
51
+
52
+ /**
53
+ * Expand `${ENV_VAR}` placeholders in a config string, matching config.ts's
54
+ * `resolveEnvVars` semantics (throw on unset var / malformed placeholder).
55
+ * Inlined rather than imported because config.ts imports THIS module for
56
+ * `parseReplicaPeersConfig`, so importing back would be circular — the same
57
+ * reason extraction-liveness.ts inlines its numeric validation.
58
+ */
59
+ function expandEnvValue(value: string): string {
60
+ const resolved = value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, name: string) => {
61
+ const envValue = process.env[name];
62
+ if (envValue === undefined || envValue === "") {
63
+ throw new Error(`replicaPeers: environment variable ${name} is not set`);
64
+ }
65
+ return envValue;
66
+ });
67
+ // An UNTERMINATED `${NAME` matches neither the replacement regex nor the
68
+ // balanced leftover check below, so the literal typo would be sent as the
69
+ // bearer token and surface as a misleading `http_401` (round 8, codex P2).
70
+ const unterminated = resolved.match(/\$\{[^}]*$/);
71
+ if (unterminated) {
72
+ throw new Error(`replicaPeers: unterminated environment variable placeholder: ${unterminated[0]}`);
73
+ }
74
+ const remaining = resolved.match(/\$\{[^}]*\}/);
75
+ if (remaining) {
76
+ throw new Error(`replicaPeers: malformed environment variable placeholder: ${remaining[0]}`);
77
+ }
78
+ return resolved;
79
+ }
80
+
81
+ /**
82
+ * An absent key falls back to the default; any PRESENT value (including an
83
+ * explicit `null`) must coerce to an integer `>= min`, else THROW. A fractional
84
+ * or out-of-range value is rejected, never floored/reinterpreted (§1/§17/§39).
85
+ */
86
+ function parseIntegerAtLeast(value: unknown, min: number, dflt: number, label: string, max = Number.MAX_SAFE_INTEGER): number {
87
+ if (value === undefined) return dflt;
88
+ const coerced = coerceNumber(value);
89
+ if (coerced === undefined || !Number.isFinite(coerced) || !Number.isInteger(coerced) || coerced < min) {
90
+ throw new Error(`${label} must be an integer greater than or equal to ${min}; got ${JSON.stringify(value)}`);
91
+ }
92
+ if (coerced > max) {
93
+ throw new Error(`${label} must be an integer no greater than ${max}; got ${JSON.stringify(value)}`);
94
+ }
95
+ return coerced;
96
+ }
97
+
98
+ function asRecord(value: unknown, label: string): Record<string, unknown> {
99
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
100
+ throw new Error(`${label} must be an object`);
101
+ }
102
+ return value as Record<string, unknown>;
103
+ }
104
+
105
+ function parseReplicaPeerToken(raw: unknown, index: number): AgentAccessAuthToken | undefined {
106
+ // Only an OMITTED token selects unauthenticated polling. A present `null` (round
107
+ // 4, codex P2) or an explicit empty/whitespace string (round 6, codex P2) is a
108
+ // present-but-invalid credential: silently dropping it polls without the token
109
+ // and surfaces a healthy peer as `http_401`, hiding the real config error.
110
+ if (raw === undefined) return undefined;
111
+ if (typeof raw === "string") {
112
+ const trimmed = raw.trim();
113
+ if (trimmed.length === 0) {
114
+ throw new Error(`replicaPeers.peers[${index}].token must be a non-empty string or a SecretRef object`);
115
+ }
116
+ // Re-validate AFTER expansion: `${PEER_TOKEN}` pointing at a whitespace-only
117
+ // env value clears the check above, then resolveAgentAccessAuthToken
118
+ // normalizes it to undefined — silently downgrading an explicitly
119
+ // authenticated peer to an unauthenticated poll read as http_401 (round 9).
120
+ const expanded = expandEnvValue(trimmed);
121
+ if (expanded.trim().length === 0) {
122
+ throw new Error(`replicaPeers.peers[${index}].token expanded to an empty value`);
123
+ }
124
+ return expanded;
125
+ }
126
+ if (isAgentAccessSecretRef(raw)) return raw;
127
+ throw new Error(`replicaPeers.peers[${index}].token must be a string or a SecretRef object`);
128
+ }
129
+
130
+ function parseReplicaPeer(value: unknown, index: number): ReplicaPeerConfig {
131
+ const record = asRecord(value, `replicaPeers.peers[${index}]`);
132
+ if (typeof record.url !== "string" || record.url.trim().length === 0) {
133
+ throw new Error(`replicaPeers.peers[${index}].url must be a non-empty string`);
134
+ }
135
+ const url = expandEnvValue(record.url.trim());
136
+ let parsed: URL;
137
+ try {
138
+ parsed = new URL(url);
139
+ } catch {
140
+ throw new Error(`replicaPeers.peers[${index}].url is not a valid URL`);
141
+ }
142
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
143
+ throw new Error(`replicaPeers.peers[${index}].url must be an http(s) URL (got ${parsed.protocol})`);
144
+ }
145
+ // The health path is appended to this base by string concatenation, so a query
146
+ // or fragment would corrupt the request URL (`https://h?x` + `/engram/v1/health`
147
+ // targets `/` with a mangled query; a fragment drops the path). Reject them at
148
+ // parse time — a peer URL must be a clean base (round 6, codex). Embedded
149
+ // credentials (`user:pass@host`) are rejected too: Node's fetch refuses to
150
+ // construct a request from a URL with credentials, so a healthy peer would
151
+ // falsely read as unreachable while redaction hid the config mistake.
152
+ if (parsed.search.length > 0 || parsed.hash.length > 0 || parsed.username.length > 0 || parsed.password.length > 0) {
153
+ throw new Error(`replicaPeers.peers[${index}].url must be a clean base URL (no query, fragment, or embedded credentials)`);
154
+ }
155
+ const token = parseReplicaPeerToken(record.token, index);
156
+ // Store the CANONICAL form: `new URL()` tolerates surrounding whitespace that
157
+ // the raw string keeps, and the health path is appended by concatenation - so
158
+ // " https://peer /engram/v1/health" reads as an unreachable healthy peer.
159
+ const canonical = parsed.toString().replace(/\/+$/, "");
160
+ return token === undefined ? { url: canonical } : { url: canonical, token };
161
+ }
162
+
163
+ /**
164
+ * Parse the `replicaPeers` config block. Mirrors the nested-block validation of
165
+ * the other config-block parsers; coerces string booleans (§24) and rejects
166
+ * invalid numbers/urls/shapes (§1/§39).
167
+ */
168
+ /**
169
+ * Strict boolean for the parse path: absent -> the default, present -> must be
170
+ * a recognized boolean token. A value like `1` must NOT silently reinterpret as
171
+ * `false`, which would leave monitoring off after an operator tried to enable
172
+ * it (round 3, codex P2). The lenient read-boundary resolver still defaults.
173
+ */
174
+ function parseStrictBool(value: unknown, fallback: boolean, label: string): boolean {
175
+ if (value === undefined) return fallback;
176
+ const coerced = coerceBool(value);
177
+ if (coerced === undefined) {
178
+ throw new Error(`${label} must be a boolean (got ${JSON.stringify(value)})`);
179
+ }
180
+ return coerced;
181
+ }
182
+
183
+ export function parseReplicaPeersConfig(cfg: Record<string, unknown>): ReplicaPeersConfig {
184
+ const raw = cfg.replicaPeers;
185
+ if (raw !== undefined && (raw === null || typeof raw !== "object" || Array.isArray(raw))) {
186
+ throw new Error(`replicaPeers must be a plain object (got ${JSON.stringify(raw)})`);
187
+ }
188
+ const block = (raw ?? {}) as Record<string, unknown>;
189
+ if (block.peers !== undefined && !Array.isArray(block.peers)) {
190
+ throw new Error(`replicaPeers.peers must be an array (got ${JSON.stringify(block.peers)})`);
191
+ }
192
+ const peers = (block.peers ?? []).map(parseReplicaPeer);
193
+ return {
194
+ enabled: parseStrictBool(block.enabled, false, "replicaPeers.enabled"),
195
+ peers,
196
+ pollIntervalMs: parseIntegerAtLeast(block.pollIntervalMs, 1, DEFAULT_POLL_INTERVAL_MS, "replicaPeers.pollIntervalMs"),
197
+ requestTimeoutMs: parseIntegerAtLeast(block.requestTimeoutMs, 1, DEFAULT_REQUEST_TIMEOUT_MS, "replicaPeers.requestTimeoutMs", MAX_TIMER_DELAY_MS),
198
+ maxFileCountDelta: parseIntegerAtLeast(block.maxFileCountDelta, 0, DEFAULT_MAX_FILE_COUNT_DELTA, "replicaPeers.maxFileCountDelta"),
199
+ maxWatermarkAgeDeltaMs: parseIntegerAtLeast(
200
+ block.maxWatermarkAgeDeltaMs,
201
+ 0,
202
+ DEFAULT_MAX_WATERMARK_AGE_DELTA_MS,
203
+ "replicaPeers.maxWatermarkAgeDeltaMs",
204
+ ),
205
+ };
206
+ }
207
+
208
+ /**
209
+ * READ-boundary resolver (mirrors `resolveExtractionLivenessConfig`, issue #2155).
210
+ * `parseConfig` always populates `replicaPeers`, but a host adapter, an older
211
+ * persisted config, or a hand-built `PluginConfig` can hand a READ surface
212
+ * (/health, doctor) an absent, partial, or loosely-typed block. Every replica
213
+ * surface must degrade to the documented default (disabled, no peers, no polling)
214
+ * rather than throw — `/health` must stay answerable. Unlike the strict parser, a
215
+ * present-but-invalid field falls back to its default here instead of throwing, and
216
+ * a malformed peer entry is dropped rather than aborting the whole block.
217
+ */
218
+ export function resolveReplicaPeersConfig(block: unknown): ReplicaPeersConfig {
219
+ const record =
220
+ block !== null && typeof block === "object" && !Array.isArray(block) ? (block as Record<string, unknown>) : {};
221
+ return {
222
+ enabled: coerceBool(record.enabled) ?? false,
223
+ peers: resolveReplicaPeers(record.peers),
224
+ pollIntervalMs: resolveIntegerAtLeast(record.pollIntervalMs, 1, DEFAULT_POLL_INTERVAL_MS),
225
+ requestTimeoutMs: resolveIntegerAtLeast(record.requestTimeoutMs, 1, DEFAULT_REQUEST_TIMEOUT_MS, MAX_TIMER_DELAY_MS),
226
+ maxFileCountDelta: resolveIntegerAtLeast(record.maxFileCountDelta, 0, DEFAULT_MAX_FILE_COUNT_DELTA),
227
+ maxWatermarkAgeDeltaMs: resolveIntegerAtLeast(record.maxWatermarkAgeDeltaMs, 0, DEFAULT_MAX_WATERMARK_AGE_DELTA_MS),
228
+ };
229
+ }
230
+
231
+ /** Lenient sibling of {@link parseIntegerAtLeast}: a present-but-invalid value falls back, never throws. */
232
+ function resolveIntegerAtLeast(value: unknown, min: number, dflt: number, max = Number.MAX_SAFE_INTEGER): number {
233
+ if (value === undefined) return dflt;
234
+ const coerced = coerceNumber(value);
235
+ return coerced !== undefined && Number.isFinite(coerced) && Number.isInteger(coerced) && coerced >= min && coerced <= max ? coerced : dflt;
236
+ }
237
+
238
+ /** Lenient peer list: a non-array is empty; a malformed entry is dropped, never thrown (read boundary). */
239
+ function resolveReplicaPeers(value: unknown): ReplicaPeerConfig[] {
240
+ if (!Array.isArray(value)) return [];
241
+ const peers: ReplicaPeerConfig[] = [];
242
+ value.forEach((entry, index) => {
243
+ try {
244
+ peers.push(parseReplicaPeer(entry, index));
245
+ } catch {
246
+ // Read surfaces never throw on a bad peer — parseConfig is the enforcing boundary.
247
+ }
248
+ });
249
+ return peers;
250
+ }
@@ -154,3 +154,41 @@ export function isAgentAccessSecretRef(value: unknown): value is SecretRef {
154
154
  export function clearAuthTokenSecretCache(): void {
155
155
  resolvedCache = new WeakMap<ResolveSecretRefFn, Map<string, string>>();
156
156
  }
157
+
158
+ /**
159
+ * Resolve a host SecretRef resolver, preferring an explicitly supplied one over
160
+ * the lazy loader.
161
+ *
162
+ * Shared by every CLI command that authenticates with a SecretRef — `access
163
+ * serve` and `doctor` (replica peer tokens, issue #2149) — so the two cannot
164
+ * drift. Structurally typed rather than importing the CLI's options type, which
165
+ * would invert the dependency.
166
+ */
167
+ export async function loadHostSecretRefResolver(options: {
168
+ resolveSecretRef?: ResolveSecretRefFn | null;
169
+ loadResolveSecretRef?: () =>
170
+ | Promise<ResolveSecretRefFn | null | undefined>
171
+ | ResolveSecretRefFn
172
+ | null
173
+ | undefined;
174
+ }): Promise<ResolveSecretRefFn | null | undefined> {
175
+ if (options.resolveSecretRef) return options.resolveSecretRef;
176
+ if (!options.loadResolveSecretRef) return null;
177
+ try {
178
+ return await options.loadResolveSecretRef();
179
+ } catch {
180
+ // A host whose lazy loader throws means "no resolver available" — not
181
+ // "abort the caller". `doctor` must still run its unrelated checks and let
182
+ // the replica check report token_error per affected peer (round 9, codex).
183
+ return null;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Adapt a host's lazily-loaded SecretRef resolver into the eager
189
+ * `ResolveSecretRefFn` that `EngramAccessService` expects, so replica peer
190
+ * tokens resolve at poll time (issue #2149).
191
+ */
192
+ export function hostSecretRefResolver(options: Parameters<typeof loadHostSecretRefResolver>[0]): ResolveSecretRefFn {
193
+ return (ref, context) => loadHostSecretRefResolver(options).then((resolve) => resolve?.(ref, context));
194
+ }
@@ -0,0 +1,72 @@
1
+ import type { EntityFile, MemoryFile } from "../types.js";
2
+ import {
3
+ getFingerprint,
4
+ migrateLegacyEntityCanonicalIds,
5
+ validateRoots,
6
+ type EntityCanonicalIdMigrationDependencies,
7
+ } from "./entity-canonical-id-migration.js";
8
+ import {
9
+ rewriteProjectedEntityReferences,
10
+ rewriteProjectedMemoryEntityReference,
11
+ } from "../memory-projection-mutations.js";
12
+
13
+ export interface EntityCanonicalIdMigrationHost {
14
+ readonly baseDir: string;
15
+ readonly entitiesDir: string;
16
+ readonly stateDir: string;
17
+ readonly archiveDir: string;
18
+ normalizeEntityName(raw: string, type: string): string;
19
+ resolveEntityFilePath(id: string): string | null;
20
+ readStorageSecureFile(filePath: string): Promise<string>;
21
+ writeStorageSecureFile(filePath: string, content: string, forceEncrypt?: boolean): Promise<void>;
22
+ isEncryptedFileHeader(filePath: string): Promise<boolean>;
23
+ snapshotBeforeWrite(filePath: string, trigger: "write"): Promise<void>;
24
+ readMemoryByPath(filePath: string): Promise<MemoryFile | null>;
25
+ readAllMemories(): Promise<MemoryFile[]>;
26
+ readAllColdMemories(): Promise<MemoryFile[]>;
27
+ readArchivedMemories(): Promise<MemoryFile[]>;
28
+ invalidateKnowledgeIndexCache(): void;
29
+ invalidateAllMemoriesCache(): void;
30
+ invalidateColdMemoriesCache(): void;
31
+ bumpMemoryStatusVersion(): void;
32
+ getCorpusScanVersion(): string;
33
+ }
34
+
35
+ export async function runLegacyEntityCanonicalIdMigration(
36
+ host: EntityCanonicalIdMigrationHost,
37
+ parseEntityFile: (content: string) => EntityFile,
38
+ serializeEntityFile: (entity: EntityFile) => string,
39
+ serializeMemoryWithEntityRef: (memory: MemoryFile, entityRef: string) => string,
40
+ ): Promise<string> {
41
+ const readMigrationFingerprint = () =>
42
+ getFingerprint(host.baseDir, host.entitiesDir, () => host.getCorpusScanVersion());
43
+ const completionFingerprint = await migrateLegacyEntityCanonicalIds({
44
+ stateDir: host.stateDir,
45
+ entitiesDir: host.entitiesDir,
46
+ normalizeEntityName: host.normalizeEntityName.bind(host),
47
+ resolveEntityFilePath: host.resolveEntityFilePath.bind(host),
48
+ readStorageSecureFile: host.readStorageSecureFile.bind(host),
49
+ writeStorageSecureFile: host.writeStorageSecureFile.bind(host),
50
+ isEncryptedStorageFile: host.isEncryptedFileHeader.bind(host),
51
+ snapshotBeforeWrite: host.snapshotBeforeWrite.bind(host),
52
+ parseEntityFile,
53
+ serializeEntityFile,
54
+ serializeMemoryWithEntityRef,
55
+ readMemoryByPath: host.readMemoryByPath.bind(host),
56
+ readAllMemories: host.readAllMemories.bind(host),
57
+ readAllColdMemories: host.readAllColdMemories.bind(host),
58
+ readArchivedMemories: host.readArchivedMemories.bind(host),
59
+ validateMemoryScanRoots: () =>
60
+ validateRoots(host.baseDir, host.entitiesDir, host.stateDir, host.archiveDir),
61
+ rewriteProjectedEntityReferences: (mappings) =>
62
+ rewriteProjectedEntityReferences(host.baseDir, mappings),
63
+ rewriteProjectedMemoryEntityReference: (memoryId, previousEntityRef, nextEntityRef) =>
64
+ rewriteProjectedMemoryEntityReference(host.baseDir, memoryId, previousEntityRef, nextEntityRef),
65
+ invalidateKnowledgeIndexCache: host.invalidateKnowledgeIndexCache.bind(host),
66
+ invalidateAllMemoriesCache: host.invalidateAllMemoriesCache.bind(host),
67
+ invalidateColdMemoriesCache: host.invalidateColdMemoriesCache.bind(host),
68
+ bumpMemoryStatusVersion: host.bumpMemoryStatusVersion.bind(host),
69
+ readMigrationFingerprint,
70
+ } satisfies EntityCanonicalIdMigrationDependencies);
71
+ return completionFingerprint ?? readMigrationFingerprint();
72
+ }
@@ -0,0 +1,68 @@
1
+ export class EntityCanonicalIdMigrationRunner {
2
+ private inFlight: Promise<void> | null = null;
3
+ private directoriesInitialized = false;
4
+ private migrationComplete = false;
5
+ private completedFingerprint: string | null = null;
6
+
7
+ public constructor(
8
+ private readonly canRun: () => boolean,
9
+ private readonly runMigration: () => Promise<string | void>,
10
+ private readonly readFingerprint: () => Promise<string> = async () => "static",
11
+ ) {}
12
+
13
+ public async markDirectoriesInitialized(): Promise<void> {
14
+ this.directoriesInitialized = true;
15
+ await this.ensure();
16
+ }
17
+
18
+ public ensure(): Promise<void> {
19
+ if (!this.canRun()) return Promise.resolve();
20
+ if (this.inFlight) return this.inFlight;
21
+ const migration = this.runOrReuse();
22
+ this.inFlight = migration;
23
+ void migration.then(
24
+ () => this.clearInFlight(migration),
25
+ () => this.clearInFlight(migration),
26
+ );
27
+ return migration;
28
+ }
29
+
30
+ public triggerAfterUnlock(): Promise<void> {
31
+ if (!this.directoriesInitialized) return Promise.resolve();
32
+ return this.ensure();
33
+ }
34
+
35
+ private async runOrReuse(): Promise<void> {
36
+ let fingerprintAtStart = await this.readFingerprint();
37
+ if (this.migrationComplete && fingerprintAtStart === this.completedFingerprint) return;
38
+
39
+ for (let attempt = 0; attempt < 3; attempt += 1) {
40
+ const completionFingerprint = await this.runMigration();
41
+ const fingerprintAfterMigration = await this.readFingerprint();
42
+ const fingerprintAfterStabilityRead = await this.readFingerprint();
43
+ const returnedFingerprint =
44
+ typeof completionFingerprint === "string" ? completionFingerprint : fingerprintAfterMigration;
45
+ if (
46
+ returnedFingerprint === fingerprintAfterMigration
47
+ && fingerprintAfterMigration === fingerprintAfterStabilityRead
48
+ && (
49
+ typeof completionFingerprint === "string"
50
+ || fingerprintAfterMigration === fingerprintAtStart
51
+ )
52
+ ) {
53
+ this.migrationComplete = true;
54
+ this.completedFingerprint = fingerprintAfterStabilityRead;
55
+ return;
56
+ }
57
+ fingerprintAtStart = fingerprintAfterStabilityRead;
58
+ }
59
+
60
+ this.migrationComplete = false;
61
+ this.completedFingerprint = null;
62
+ throw new Error("Entity canonical-id migration fingerprint changed while migration was completing; retry migration.");
63
+ }
64
+
65
+ private clearInFlight(migration: Promise<void>): void {
66
+ if (this.inFlight === migration) this.inFlight = null;
67
+ }
68
+ }