@remnic/core 9.62.1 → 9.63.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 (484) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +26 -26
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +11 -11
  5. package/dist/access-authorization-probe.js +27 -27
  6. package/dist/access-boundary.d.ts +11 -11
  7. package/dist/access-boundary.js +26 -26
  8. package/dist/access-cli.js +88 -86
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-coding-context-resolution.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.d.ts +11 -11
  12. package/dist/access-extraction-force-flush.js +26 -26
  13. package/dist/access-health-types.d.ts +1 -1
  14. package/dist/access-http-lcm-compaction.d.ts +11 -11
  15. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  16. package/dist/access-http-offline-stream.d.ts +11 -11
  17. package/dist/access-http-query.js +26 -26
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +36 -36
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +26 -26
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +26 -26
  24. package/dist/access-mcp.d.ts +11 -11
  25. package/dist/access-mcp.js +31 -31
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-EMvicnrb.d.ts → access-namespace-preflight-yO4LMGFH.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +26 -26
  30. package/dist/access-observe-write-surface.d.ts +11 -11
  31. package/dist/access-observe-write-surface.js +26 -26
  32. package/dist/access-offline-manifest.d.ts +9 -9
  33. package/dist/access-offline-manifest.js +2 -2
  34. package/dist/access-operations-batch.js +27 -27
  35. package/dist/access-operations.d.ts +11 -11
  36. package/dist/access-operations.js +30 -30
  37. package/dist/access-recall-concurrency.d.ts +11 -11
  38. package/dist/access-recall-concurrency.js +26 -26
  39. package/dist/access-recall-response.d.ts +11 -11
  40. package/dist/access-recall-response.js +26 -26
  41. package/dist/access-recall-surface.d.ts +11 -11
  42. package/dist/access-recall-surface.js +26 -26
  43. package/dist/{access-service-BeDYQQ62.d.ts → access-service-M4LgO141.d.ts} +7 -7
  44. package/dist/access-service-helpers.d.ts +11 -11
  45. package/dist/access-service.d.ts +11 -11
  46. package/dist/access-service.js +26 -26
  47. package/dist/access-surface-catalog.d.ts +11 -11
  48. package/dist/access-surface-catalog.js +28 -28
  49. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  50. package/dist/action-confidence.d.ts +1 -1
  51. package/dist/active-memory-bridge.d.ts +1 -1
  52. package/dist/active-recall.d.ts +1 -1
  53. package/dist/active-recall.js +1 -1
  54. package/dist/ambient-provenance.d.ts +1 -1
  55. package/dist/artifact-search.d.ts +1 -1
  56. package/dist/{auto-sync-FMWQQB3J.js → auto-sync-Z52VWMNC.js} +3 -3
  57. package/dist/behavior-learner.d.ts +1 -1
  58. package/dist/behavior-learner.js +2 -2
  59. package/dist/behavior-signals.d.ts +1 -1
  60. package/dist/bootstrap.d.ts +9 -9
  61. package/dist/briefing-window.d.ts +2 -2
  62. package/dist/briefing.d.ts +2 -2
  63. package/dist/briefing.js +11 -10
  64. package/dist/buffer-surprise-report.d.ts +1 -1
  65. package/dist/buffer-turn-helpers.d.ts +1 -1
  66. package/dist/buffer.d.ts +2 -2
  67. package/dist/bulk-import/index.d.ts +3 -3
  68. package/dist/calibration.d.ts +1 -1
  69. package/dist/capabilities.d.ts +1 -1
  70. package/dist/{catalog-B2SxZ6LU.d.ts → catalog-CyYTf_ok.d.ts} +1 -1
  71. package/dist/causal-behavior.d.ts +1 -1
  72. package/dist/causal-behavior.js +3 -3
  73. package/dist/causal-chain.js +3 -3
  74. package/dist/causal-consolidation.d.ts +1 -1
  75. package/dist/causal-consolidation.js +14 -14
  76. package/dist/causal-retrieval.js +3 -3
  77. package/dist/causal-trajectory-graph.d.ts +1 -1
  78. package/dist/causal-trajectory.js +2 -2
  79. package/dist/{chunk-B2QHVLJO.js → chunk-256FBCVX.js} +22 -10
  80. package/dist/chunk-256FBCVX.js.map +1 -0
  81. package/dist/{chunk-QP2IZTUR.js → chunk-2TYIAKU5.js} +2 -2
  82. package/dist/{chunk-QNMNNFKD.js → chunk-347ZR6D4.js} +2 -2
  83. package/dist/{chunk-76YNCJ5H.js → chunk-3F3CVVDS.js} +2 -2
  84. package/dist/{chunk-KCFZOSR6.js → chunk-3MA7JVXN.js} +4 -4
  85. package/dist/{chunk-KHQ57QLJ.js → chunk-46WM6JX2.js} +7 -3
  86. package/dist/chunk-46WM6JX2.js.map +1 -0
  87. package/dist/chunk-47DU4SGJ.js +92 -0
  88. package/dist/chunk-47DU4SGJ.js.map +1 -0
  89. package/dist/{chunk-HKYNBEL4.js → chunk-4FFROSFG.js} +37 -14
  90. package/dist/{chunk-HKYNBEL4.js.map → chunk-4FFROSFG.js.map} +1 -1
  91. package/dist/{chunk-TLUSSS2F.js → chunk-4HO3542O.js} +2 -2
  92. package/dist/{chunk-4E67XCT2.js → chunk-4IZ2IT7D.js} +3 -3
  93. package/dist/{chunk-33JBK2XP.js → chunk-5F6HMNMZ.js} +2 -2
  94. package/dist/{chunk-5WQMORU5.js → chunk-5PFGMO33.js} +2 -2
  95. package/dist/{chunk-6HEM6HTQ.js → chunk-6GGTATZF.js} +2 -2
  96. package/dist/{chunk-UIRU3MIJ.js → chunk-7BJYTX6Q.js} +2 -2
  97. package/dist/{chunk-2GRLJMKJ.js → chunk-7DRSWPUV.js} +3 -3
  98. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  99. package/dist/{chunk-HXXGZ4KV.js → chunk-ALNZEWGN.js} +2 -2
  100. package/dist/{chunk-5WVUO6QT.js → chunk-AR253JBM.js} +1 -1
  101. package/dist/chunk-AR253JBM.js.map +1 -0
  102. package/dist/{chunk-67MKNKJQ.js → chunk-AYIHDC5S.js} +2 -2
  103. package/dist/{chunk-IXJ5U6ZL.js → chunk-BBHFAVMP.js} +8 -8
  104. package/dist/{chunk-IIRK5V5Z.js → chunk-BHO6RHE5.js} +3 -3
  105. package/dist/{chunk-WANOCU3K.js → chunk-BP6WMYLP.js} +3 -3
  106. package/dist/{chunk-ZJKLGS76.js → chunk-CALURYWR.js} +283 -248
  107. package/dist/chunk-CALURYWR.js.map +1 -0
  108. package/dist/{chunk-JLMH5YMU.js → chunk-CH627RRV.js} +2 -2
  109. package/dist/{chunk-XIABRKF6.js → chunk-CLJ5QS6J.js} +239 -47
  110. package/dist/chunk-CLJ5QS6J.js.map +1 -0
  111. package/dist/{chunk-YLHM5BQQ.js → chunk-DCUMFQYM.js} +171 -8
  112. package/dist/chunk-DCUMFQYM.js.map +1 -0
  113. package/dist/{chunk-ZBJMUXZH.js → chunk-DJ7HMNSL.js} +15 -8
  114. package/dist/chunk-DJ7HMNSL.js.map +1 -0
  115. package/dist/{chunk-WTMG5GAK.js → chunk-DROAPP6N.js} +3 -3
  116. package/dist/{chunk-PBH2Z2NY.js → chunk-DTLF2SLZ.js} +2 -2
  117. package/dist/{chunk-7JAXC526.js → chunk-EFWHCTYJ.js} +2 -2
  118. package/dist/{chunk-3XG4QEA2.js → chunk-FF6E6HOT.js} +39 -39
  119. package/dist/{chunk-NP7FLVZW.js → chunk-G2FCSILA.js} +2 -2
  120. package/dist/{chunk-7PVTOZR4.js → chunk-H23GIXJC.js} +2 -2
  121. package/dist/{chunk-WT6UL3UA.js → chunk-H7PRHUBD.js} +2 -2
  122. package/dist/{chunk-ETCVSZLG.js → chunk-HSBQJRV2.js} +2 -2
  123. package/dist/{chunk-GZRDOVQN.js → chunk-HVKMJAEF.js} +2 -2
  124. package/dist/{chunk-CSOYVTRX.js → chunk-IIPJKCZB.js} +3 -3
  125. package/dist/{chunk-E57E5SCS.js → chunk-IRLH4NM2.js} +3 -3
  126. package/dist/{chunk-4G45LJJP.js → chunk-IZRNVNPV.js} +2 -2
  127. package/dist/{chunk-YSUSUZR4.js → chunk-JCJGYNIS.js} +3 -3
  128. package/dist/{chunk-EU74U4GT.js → chunk-JDI7G6EA.js} +2 -2
  129. package/dist/{chunk-QWPAQLYV.js → chunk-JFLKSD5V.js} +2 -2
  130. package/dist/{chunk-KQS72GCR.js → chunk-LJOIZPJH.js} +2 -2
  131. package/dist/{chunk-U27G4E5G.js → chunk-LLGDVG52.js} +3 -3
  132. package/dist/{chunk-7N7DB4L5.js → chunk-LTJTP5YQ.js} +10 -9
  133. package/dist/chunk-LTJTP5YQ.js.map +1 -0
  134. package/dist/{chunk-XL3TATMJ.js → chunk-OQIRBGUU.js} +21 -12
  135. package/dist/chunk-OQIRBGUU.js.map +1 -0
  136. package/dist/{chunk-JGW2EUCQ.js → chunk-PMRUMGK6.js} +2 -2
  137. package/dist/{chunk-3G6YU5YD.js → chunk-PSNN25DW.js} +2 -2
  138. package/dist/{chunk-LRGSLV7M.js → chunk-PYHOAXTI.js} +4 -4
  139. package/dist/{chunk-75U2FR7U.js → chunk-QCI73Z7C.js} +2 -2
  140. package/dist/{chunk-EHMMRZOZ.js → chunk-QICOU4RY.js} +2 -2
  141. package/dist/{chunk-K4WIUTNH.js → chunk-RFH7U5LT.js} +2 -2
  142. package/dist/{chunk-4SGDYYWV.js → chunk-RPKJHYVE.js} +2 -2
  143. package/dist/{chunk-BHO3IVAN.js → chunk-RYST72N5.js} +12 -1
  144. package/dist/chunk-RYST72N5.js.map +1 -0
  145. package/dist/chunk-T3GIETKV.js +152 -0
  146. package/dist/chunk-T3GIETKV.js.map +1 -0
  147. package/dist/{chunk-DYDACAK2.js → chunk-TGSMU3F2.js} +3 -3
  148. package/dist/{chunk-MJFDJTDC.js → chunk-TIRJV2LW.js} +2 -2
  149. package/dist/{chunk-QRA3XVJX.js → chunk-UDTME32W.js} +2 -2
  150. package/dist/{chunk-LAM6UDFV.js → chunk-WMOJIOIG.js} +2 -2
  151. package/dist/{chunk-LLLY5IBK.js → chunk-WR2YKUIW.js} +2 -2
  152. package/dist/{chunk-KYI3CM42.js → chunk-X6E7TT3A.js} +2 -2
  153. package/dist/{chunk-QN7XQEIT.js → chunk-YIIC5IDU.js} +2 -2
  154. package/dist/{chunk-JDJOAL4B.js → chunk-YSR3DXGC.js} +2 -2
  155. package/dist/{chunk-LBJBNWS2.js → chunk-YTHQHH5U.js} +2 -2
  156. package/dist/{chunk-JF6YSHJM.js → chunk-ZPGHA7EO.js} +12 -12
  157. package/dist/{chunk-VUDALPI5.js → chunk-ZQKXRKMR.js} +19 -5
  158. package/dist/chunk-ZQKXRKMR.js.map +1 -0
  159. package/dist/{chunk-YG56A6XY.js → chunk-ZS4JADYY.js} +3 -3
  160. package/dist/{cli-DB_uakTc.d.ts → cli-Bw9z-KqX.d.ts} +5 -5
  161. package/dist/cli.d.ts +13 -13
  162. package/dist/cli.js +60 -60
  163. package/dist/coding/pre-action-gate.d.ts +1 -1
  164. package/dist/coding/pre-action-gate.js +3 -3
  165. package/dist/compounding/engine.d.ts +2 -2
  166. package/dist/compounding/engine.js +11 -10
  167. package/dist/compounding/preference-consolidator.d.ts +1 -1
  168. package/dist/compression-optimizer.d.ts +1 -1
  169. package/dist/config.d.ts +1 -1
  170. package/dist/config.js +1 -1
  171. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  172. package/dist/connectors/codex-materialize-runner.js +11 -10
  173. package/dist/connectors/codex-materialize.d.ts +1 -1
  174. package/dist/connectors/index.d.ts +1 -1
  175. package/dist/connectors/index.js +11 -10
  176. package/dist/consolidation-provenance-check.d.ts +2 -2
  177. package/dist/consolidation-undo.d.ts +2 -2
  178. package/dist/contradiction/index.d.ts +2 -2
  179. package/dist/converge-config.d.ts +1 -1
  180. package/dist/convergence-refresh.d.ts +2 -2
  181. package/dist/convergence-refresh.js +13 -12
  182. package/dist/conversation-index/backend.d.ts +1 -1
  183. package/dist/conversation-index/chunker.d.ts +1 -1
  184. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  185. package/dist/conversation-index/indexer.d.ts +1 -1
  186. package/dist/conversation-index/search.d.ts +1 -1
  187. package/dist/corpus-watermark.d.ts +1 -1
  188. package/dist/corpus-watermark.js +13 -12
  189. package/dist/day-summary.d.ts +1 -1
  190. package/dist/delinearize.d.ts +1 -1
  191. package/dist/dependency-propagation-config.d.ts +1 -1
  192. package/dist/{dependency-propagation-delivery-DcOVpK3y.d.ts → dependency-propagation-delivery-BxhvAppj.d.ts} +1 -1
  193. package/dist/direct-answer-wiring.d.ts +1 -1
  194. package/dist/direct-answer-wiring.js +3 -3
  195. package/dist/direct-answer.d.ts +1 -1
  196. package/dist/direct-answer.js +2 -2
  197. package/dist/embedding-fallback.d.ts +1 -1
  198. package/dist/enrichment/index.d.ts +1 -1
  199. package/dist/entity-origin-fields.d.ts +1 -1
  200. package/dist/entity-retrieval.d.ts +2 -2
  201. package/dist/entity-retrieval.js +11 -10
  202. package/dist/entity-schema.d.ts +1 -1
  203. package/dist/episodic-context.d.ts +92 -0
  204. package/dist/episodic-context.js +16 -0
  205. package/dist/episodic-context.js.map +1 -0
  206. package/dist/explicit-capture.d.ts +9 -9
  207. package/dist/external-wiki-access.d.ts +11 -11
  208. package/dist/external-wiki-access.js +27 -27
  209. package/dist/external-wiki-collection-registration.d.ts +1 -1
  210. package/dist/external-wiki-collection.d.ts +1 -1
  211. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  212. package/dist/extraction-error-classification.d.ts +1 -1
  213. package/dist/extraction-faithfulness.d.ts +1 -1
  214. package/dist/extraction-judge-telemetry.d.ts +1 -1
  215. package/dist/extraction-judge-training.d.ts +1 -1
  216. package/dist/extraction-judge.d.ts +1 -1
  217. package/dist/extraction-liveness.d.ts +1 -1
  218. package/dist/extraction-normalization.d.ts +1 -1
  219. package/dist/extraction-normalization.js +2 -2
  220. package/dist/extraction-prompt.d.ts +1 -1
  221. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  222. package/dist/extraction-source-grounding.d.ts +1 -1
  223. package/dist/extraction.d.ts +1 -1
  224. package/dist/extraction.js +14 -14
  225. package/dist/fallback-llm.d.ts +1 -1
  226. package/dist/{forget-5TWK7CZT.js → forget-SZ2BXDGF.js} +2 -2
  227. package/dist/graph-dashboard-diff.d.ts +1 -1
  228. package/dist/graph-dashboard-key.d.ts +1 -1
  229. package/dist/graph-dashboard-parser.d.ts +1 -1
  230. package/dist/graph-edge-reinforcement.d.ts +1 -1
  231. package/dist/graph-path-reconstruction.d.ts +1 -1
  232. package/dist/graph-path-scoring.d.ts +1 -1
  233. package/dist/graph-snapshot.d.ts +1 -1
  234. package/dist/graph.d.ts +1 -1
  235. package/dist/harmonic-construction.js +2 -2
  236. package/dist/harmonic-retrieval.js +2 -2
  237. package/dist/importance.d.ts +1 -1
  238. package/dist/importers/index.d.ts +1 -1
  239. package/dist/in-flight-reads.d.ts +1 -1
  240. package/dist/index.d.ts +21 -21
  241. package/dist/index.js +100 -98
  242. package/dist/intent.d.ts +1 -1
  243. package/dist/lcm/engine.d.ts +8 -2
  244. package/dist/lcm/engine.js +4 -4
  245. package/dist/lcm/index.d.ts +1 -1
  246. package/dist/lcm/index.js +9 -9
  247. package/dist/lcm/tools.d.ts +1 -1
  248. package/dist/lifecycle.d.ts +1 -1
  249. package/dist/live-connectors-runner.d.ts +1 -1
  250. package/dist/local-llm.d.ts +1 -1
  251. package/dist/local-model-endpoint.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.d.ts +1 -1
  253. package/dist/maintenance/memory-governance.js +11 -10
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -10
  256. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  257. package/dist/maintenance/rebuild-memory-projection.js +12 -11
  258. package/dist/{maintenance-5c1olVtB.d.ts → maintenance-uJb74j64.d.ts} +3 -3
  259. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  260. package/dist/memory-action-policy.d.ts +1 -1
  261. package/dist/memory-cache.d.ts +1 -1
  262. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  263. package/dist/memory-projection-store.d.ts +1 -1
  264. package/dist/memory-provenance.d.ts +1 -1
  265. package/dist/memory-snapshot.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +12 -11
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +6 -5
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +11 -10
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-impression-drain.d.ts +1 -1
  277. package/dist/operator-doctor-corpus.d.ts +1 -1
  278. package/dist/operator-doctor-corpus.js +14 -13
  279. package/dist/operator-doctor-replica.d.ts +1 -1
  280. package/dist/operator-toolkit.d.ts +3 -3
  281. package/dist/operator-toolkit.js +19 -18
  282. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  283. package/dist/orchestration/maintenance.d.ts +4 -4
  284. package/dist/orchestration/maintenance.js +16 -15
  285. package/dist/{orchestrator-HPuY6I4i.d.ts → orchestrator-CFi-5JSR.d.ts} +23 -8
  286. package/dist/orchestrator.d.ts +9 -9
  287. package/dist/orchestrator.js +88 -86
  288. package/dist/patterns-cli.d.ts +1 -1
  289. package/dist/{pipeline-CvVe1Q2_.d.ts → pipeline-BdF3ferY.d.ts} +1 -1
  290. package/dist/policy-runtime.d.ts +1 -1
  291. package/dist/policy-runtime.js +3 -3
  292. package/dist/proactive-contention.d.ts +1 -1
  293. package/dist/provenance.d.ts +1 -1
  294. package/dist/{public-http-D0JKFkyf.d.ts → public-http-DK-QwaBu.d.ts} +1 -1
  295. package/dist/{qmd-Bd0Tp76_.d.ts → qmd-D_62bYNl.d.ts} +1 -1
  296. package/dist/qmd-preflight.d.ts +2 -2
  297. package/dist/qmd-recall-cache.d.ts +1 -1
  298. package/dist/qmd.d.ts +2 -2
  299. package/dist/recall-concurrency-config.d.ts +1 -1
  300. package/dist/recall-disclosure-escalation.d.ts +1 -1
  301. package/dist/recall-explain-renderer.d.ts +1 -1
  302. package/dist/recall-explain-renderer.js +3 -3
  303. package/dist/recall-memory-map.d.ts +1 -1
  304. package/dist/recall-planner-llm.d.ts +1 -1
  305. package/dist/recall-query-policy.js +2 -2
  306. package/dist/recall-state.d.ts +1 -1
  307. package/dist/recall-tag-filter.d.ts +1 -1
  308. package/dist/recall-timings.d.ts +1 -1
  309. package/dist/recall-tokenization.d.ts +3 -1
  310. package/dist/recall-tokenization.js +5 -1
  311. package/dist/recall-xray-cli.d.ts +1 -1
  312. package/dist/recall-xray-cli.js +4 -4
  313. package/dist/recall-xray-renderer.d.ts +1 -1
  314. package/dist/recall-xray-renderer.js +3 -3
  315. package/dist/recall-xray.d.ts +1 -1
  316. package/dist/recall-xray.js +2 -2
  317. package/dist/reconcile/cursor.d.ts +1 -1
  318. package/dist/reconcile/manifest.d.ts +10 -1
  319. package/dist/reconcile/manifest.js +1 -1
  320. package/dist/reconcile/plan.d.ts +1 -1
  321. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  322. package/dist/replay/normalizers/claude.d.ts +1 -1
  323. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  324. package/dist/replay/normalizers/shared.d.ts +1 -1
  325. package/dist/replay/runner.d.ts +1 -1
  326. package/dist/replay/types.d.ts +1 -1
  327. package/dist/replica-divergence.d.ts +1 -1
  328. package/dist/replica-peers-config.d.ts +1 -1
  329. package/dist/resolve-auth-token.d.ts +1 -1
  330. package/dist/resume-bundles.js +4 -4
  331. package/dist/retrieval-agents.d.ts +2 -2
  332. package/dist/retrieval-tiers.d.ts +1 -1
  333. package/dist/routing/engine.d.ts +1 -1
  334. package/dist/routing/store.d.ts +1 -1
  335. package/dist/salvage-envelope.d.ts +1 -1
  336. package/dist/{scope-profiles-ClLtm9gK.d.ts → scope-profiles-CeMv7pP0.d.ts} +1 -1
  337. package/dist/search/embed-helper.d.ts +1 -1
  338. package/dist/search/factory.d.ts +1 -1
  339. package/dist/search/factory.js +5 -4
  340. package/dist/search/index.d.ts +1 -1
  341. package/dist/search/index.js +9 -8
  342. package/dist/search/lancedb-backend.d.ts +14 -1
  343. package/dist/search/lancedb-backend.js +1 -1
  344. package/dist/search/meilisearch-backend.d.ts +1 -1
  345. package/dist/search/noop-backend.d.ts +1 -1
  346. package/dist/search/orama-backend.d.ts +22 -1
  347. package/dist/search/orama-backend.js +2 -1
  348. package/dist/search/port.d.ts +1 -1
  349. package/dist/search/remote-backend.d.ts +1 -1
  350. package/dist/{semantic-consolidation-B1EkeEDj.d.ts → semantic-consolidation-B-85brYj.d.ts} +1 -1
  351. package/dist/semantic-consolidation.d.ts +2 -2
  352. package/dist/semantic-consolidation.js +12 -12
  353. package/dist/semantic-rule-promotion.js +11 -10
  354. package/dist/semantic-rule-verifier.d.ts +1 -1
  355. package/dist/semantic-rule-verifier.js +11 -11
  356. package/dist/{service-Cf3ANQj9.d.ts → service-CoO0HA2E.d.ts} +2 -2
  357. package/dist/session-observer-bands.d.ts +1 -1
  358. package/dist/session-observer-state.d.ts +1 -1
  359. package/dist/shared-context/manager.d.ts +1 -1
  360. package/dist/signal.d.ts +1 -1
  361. package/dist/source-agent-qualifier.d.ts +1 -1
  362. package/dist/source-agent-qualifier.js +11 -10
  363. package/dist/{storage-DS2O_6Qt.d.ts → storage-BVAVitkO.d.ts} +1 -1
  364. package/dist/storage.d.ts +2 -2
  365. package/dist/storage.js +10 -9
  366. package/dist/summarizer.d.ts +1 -1
  367. package/dist/summary-snapshot.d.ts +1 -1
  368. package/dist/support-passport/index.d.ts +14 -14
  369. package/dist/support-passport/index.js +29 -29
  370. package/dist/temporal-supersession.d.ts +2 -2
  371. package/dist/temporal-timeline-recall.d.ts +1 -1
  372. package/dist/temporal-validity.d.ts +1 -1
  373. package/dist/threading.d.ts +1 -1
  374. package/dist/tier-migration.d.ts +2 -2
  375. package/dist/tier-routing.d.ts +1 -1
  376. package/dist/topics.d.ts +1 -1
  377. package/dist/transcript.d.ts +1 -1
  378. package/dist/transfer/import-sqlite.js +2 -2
  379. package/dist/trust-score-stage.d.ts +1 -1
  380. package/dist/trust-score.d.ts +1 -1
  381. package/dist/trust-zones.js +2 -2
  382. package/dist/{types-BOANGhCJ.d.ts → types-DWHOxlZP.d.ts} +3 -0
  383. package/dist/types.d.ts +1 -1
  384. package/dist/types.js +1 -1
  385. package/dist/user-message-cleaning.d.ts +23 -0
  386. package/dist/user-message-cleaning.js +10 -0
  387. package/dist/user-message-cleaning.js.map +1 -0
  388. package/dist/utility-runtime.d.ts +1 -1
  389. package/dist/verified-recall.js +11 -11
  390. package/dist/work-product-ledger.js +2 -2
  391. package/dist/write-envelope.d.ts +1 -1
  392. package/package.json +12 -2
  393. package/src/access-service-offline-file-content.test.ts +1 -0
  394. package/src/config.ts +11 -0
  395. package/src/episodic-context-recall.integration.test.ts +169 -0
  396. package/src/episodic-context.test.ts +266 -0
  397. package/src/episodic-context.ts +274 -0
  398. package/src/lcm/engine.ts +18 -1
  399. package/src/lifecycle/tombstones.test.ts +134 -0
  400. package/src/lifecycle/tombstones.ts +29 -2
  401. package/src/orchestration/episodic-context-section.ts +255 -0
  402. package/src/orchestration/recall-internal-deps.ts +2 -0
  403. package/src/orchestration/recall-internal.ts +40 -25
  404. package/src/orchestration/recall-result-formatter.ts +37 -0
  405. package/src/recall-tokenization.ts +14 -8
  406. package/src/reconcile/manifest.test.ts +133 -4
  407. package/src/reconcile/manifest.ts +43 -7
  408. package/src/search/factory.ts +1 -0
  409. package/src/search/lancedb-backend.ts +24 -16
  410. package/src/search/orama-backend.test.ts +208 -1
  411. package/src/search/orama-backend.ts +133 -18
  412. package/src/search/orama-cjk-tokenizer.test.ts +108 -0
  413. package/src/search/orama-cjk-tokenizer.ts +143 -0
  414. package/src/storage/tombstone-migration-sources.test.ts +116 -0
  415. package/src/storage/tombstone-migration-sources.ts +90 -0
  416. package/src/storage.ts +13 -34
  417. package/src/types.ts +3 -3
  418. package/src/user-message-cleaning.ts +139 -0
  419. package/dist/chunk-5WVUO6QT.js.map +0 -1
  420. package/dist/chunk-7N7DB4L5.js.map +0 -1
  421. package/dist/chunk-B2QHVLJO.js.map +0 -1
  422. package/dist/chunk-BHO3IVAN.js.map +0 -1
  423. package/dist/chunk-KHQ57QLJ.js.map +0 -1
  424. package/dist/chunk-VUDALPI5.js.map +0 -1
  425. package/dist/chunk-XIABRKF6.js.map +0 -1
  426. package/dist/chunk-XL3TATMJ.js.map +0 -1
  427. package/dist/chunk-YLHM5BQQ.js.map +0 -1
  428. package/dist/chunk-ZBJMUXZH.js.map +0 -1
  429. package/dist/chunk-ZJKLGS76.js.map +0 -1
  430. /package/dist/{auto-sync-FMWQQB3J.js.map → auto-sync-Z52VWMNC.js.map} +0 -0
  431. /package/dist/{chunk-QP2IZTUR.js.map → chunk-2TYIAKU5.js.map} +0 -0
  432. /package/dist/{chunk-QNMNNFKD.js.map → chunk-347ZR6D4.js.map} +0 -0
  433. /package/dist/{chunk-76YNCJ5H.js.map → chunk-3F3CVVDS.js.map} +0 -0
  434. /package/dist/{chunk-KCFZOSR6.js.map → chunk-3MA7JVXN.js.map} +0 -0
  435. /package/dist/{chunk-TLUSSS2F.js.map → chunk-4HO3542O.js.map} +0 -0
  436. /package/dist/{chunk-4E67XCT2.js.map → chunk-4IZ2IT7D.js.map} +0 -0
  437. /package/dist/{chunk-33JBK2XP.js.map → chunk-5F6HMNMZ.js.map} +0 -0
  438. /package/dist/{chunk-5WQMORU5.js.map → chunk-5PFGMO33.js.map} +0 -0
  439. /package/dist/{chunk-6HEM6HTQ.js.map → chunk-6GGTATZF.js.map} +0 -0
  440. /package/dist/{chunk-UIRU3MIJ.js.map → chunk-7BJYTX6Q.js.map} +0 -0
  441. /package/dist/{chunk-2GRLJMKJ.js.map → chunk-7DRSWPUV.js.map} +0 -0
  442. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  443. /package/dist/{chunk-HXXGZ4KV.js.map → chunk-ALNZEWGN.js.map} +0 -0
  444. /package/dist/{chunk-67MKNKJQ.js.map → chunk-AYIHDC5S.js.map} +0 -0
  445. /package/dist/{chunk-IXJ5U6ZL.js.map → chunk-BBHFAVMP.js.map} +0 -0
  446. /package/dist/{chunk-IIRK5V5Z.js.map → chunk-BHO6RHE5.js.map} +0 -0
  447. /package/dist/{chunk-WANOCU3K.js.map → chunk-BP6WMYLP.js.map} +0 -0
  448. /package/dist/{chunk-JLMH5YMU.js.map → chunk-CH627RRV.js.map} +0 -0
  449. /package/dist/{chunk-WTMG5GAK.js.map → chunk-DROAPP6N.js.map} +0 -0
  450. /package/dist/{chunk-PBH2Z2NY.js.map → chunk-DTLF2SLZ.js.map} +0 -0
  451. /package/dist/{chunk-7JAXC526.js.map → chunk-EFWHCTYJ.js.map} +0 -0
  452. /package/dist/{chunk-3XG4QEA2.js.map → chunk-FF6E6HOT.js.map} +0 -0
  453. /package/dist/{chunk-NP7FLVZW.js.map → chunk-G2FCSILA.js.map} +0 -0
  454. /package/dist/{chunk-7PVTOZR4.js.map → chunk-H23GIXJC.js.map} +0 -0
  455. /package/dist/{chunk-WT6UL3UA.js.map → chunk-H7PRHUBD.js.map} +0 -0
  456. /package/dist/{chunk-ETCVSZLG.js.map → chunk-HSBQJRV2.js.map} +0 -0
  457. /package/dist/{chunk-GZRDOVQN.js.map → chunk-HVKMJAEF.js.map} +0 -0
  458. /package/dist/{chunk-CSOYVTRX.js.map → chunk-IIPJKCZB.js.map} +0 -0
  459. /package/dist/{chunk-E57E5SCS.js.map → chunk-IRLH4NM2.js.map} +0 -0
  460. /package/dist/{chunk-4G45LJJP.js.map → chunk-IZRNVNPV.js.map} +0 -0
  461. /package/dist/{chunk-YSUSUZR4.js.map → chunk-JCJGYNIS.js.map} +0 -0
  462. /package/dist/{chunk-EU74U4GT.js.map → chunk-JDI7G6EA.js.map} +0 -0
  463. /package/dist/{chunk-QWPAQLYV.js.map → chunk-JFLKSD5V.js.map} +0 -0
  464. /package/dist/{chunk-KQS72GCR.js.map → chunk-LJOIZPJH.js.map} +0 -0
  465. /package/dist/{chunk-U27G4E5G.js.map → chunk-LLGDVG52.js.map} +0 -0
  466. /package/dist/{chunk-JGW2EUCQ.js.map → chunk-PMRUMGK6.js.map} +0 -0
  467. /package/dist/{chunk-3G6YU5YD.js.map → chunk-PSNN25DW.js.map} +0 -0
  468. /package/dist/{chunk-LRGSLV7M.js.map → chunk-PYHOAXTI.js.map} +0 -0
  469. /package/dist/{chunk-75U2FR7U.js.map → chunk-QCI73Z7C.js.map} +0 -0
  470. /package/dist/{chunk-EHMMRZOZ.js.map → chunk-QICOU4RY.js.map} +0 -0
  471. /package/dist/{chunk-K4WIUTNH.js.map → chunk-RFH7U5LT.js.map} +0 -0
  472. /package/dist/{chunk-4SGDYYWV.js.map → chunk-RPKJHYVE.js.map} +0 -0
  473. /package/dist/{chunk-DYDACAK2.js.map → chunk-TGSMU3F2.js.map} +0 -0
  474. /package/dist/{chunk-MJFDJTDC.js.map → chunk-TIRJV2LW.js.map} +0 -0
  475. /package/dist/{chunk-QRA3XVJX.js.map → chunk-UDTME32W.js.map} +0 -0
  476. /package/dist/{chunk-LAM6UDFV.js.map → chunk-WMOJIOIG.js.map} +0 -0
  477. /package/dist/{chunk-LLLY5IBK.js.map → chunk-WR2YKUIW.js.map} +0 -0
  478. /package/dist/{chunk-KYI3CM42.js.map → chunk-X6E7TT3A.js.map} +0 -0
  479. /package/dist/{chunk-QN7XQEIT.js.map → chunk-YIIC5IDU.js.map} +0 -0
  480. /package/dist/{chunk-JDJOAL4B.js.map → chunk-YSR3DXGC.js.map} +0 -0
  481. /package/dist/{chunk-LBJBNWS2.js.map → chunk-YTHQHH5U.js.map} +0 -0
  482. /package/dist/{chunk-JF6YSHJM.js.map → chunk-ZPGHA7EO.js.map} +0 -0
  483. /package/dist/{chunk-YG56A6XY.js.map → chunk-ZS4JADYY.js.map} +0 -0
  484. /package/dist/{forget-5TWK7CZT.js.map → forget-SZ2BXDGF.js.map} +0 -0
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Episodic-context recall section (issue #2331, harmonic-memory P3).
3
+ *
4
+ * Extracted sibling of `recallInternal`'s final assembly phase: resolves the
5
+ * structured `sources` provenance of the top recalled facts to LCM archive
6
+ * turn ranges, groups overlapping ranges into episodes, and appends the raw
7
+ * turns as a `## Source Episodes` section — pure lookup + formatting, no LLM
8
+ * calls, read-only archive access, inside the enrichment deadline.
9
+ *
10
+ * Opt-in: the registry entry is gated on `episodicContextEnabled === true`
11
+ * (default off), so flag-off returns before touching the archive and recall
12
+ * output stays byte-identical.
13
+ */
14
+
15
+ import { lcmSessionKeyForNamespace } from "../coding/coding-namespace.js";
16
+ import { type EpisodicFactInput, planEpisodeWindowsWithFallback } from "../episodic-context.js";
17
+ import type { LcmMessage } from "../lcm/archive.js";
18
+ import { log } from "../logger.js";
19
+ import {
20
+ type RecallSectionMetric,
21
+ resolveRecallCoreSectionDeadlineMs,
22
+ runRecallSectionWithinDeadline,
23
+ } from "../recall-qos.js";
24
+ import { cleanArchivedUserMessage } from "../user-message-cleaning.js";
25
+ import type { RecallSectionBuckets } from "./recall-section-coordinator.js";
26
+ import type { RecallInternalDeps } from "./recall-internal-deps.js";
27
+ import type { ScopePlan } from "../scopes/scope-plan.js";
28
+
29
+ /** Cap on recalled facts whose provenance is read per recall. */
30
+ const EPISODIC_FACT_SCAN_LIMIT = 8;
31
+ /** Per-turn character cap inside a Source Episodes block. */
32
+ const EPISODIC_TURN_CHAR_LIMIT = 300;
33
+
34
+ export async function appendEpisodicContextSection(
35
+ deps: RecallInternalDeps,
36
+ options: {
37
+ sectionBuckets: RecallSectionBuckets;
38
+ recalledMemoryPaths: string[];
39
+ recalledMemoryNamespaces: Array<string | undefined>;
40
+ scopePlan: ScopePlan;
41
+ namespacesEnabled: boolean;
42
+ enrichmentSectionDeadlineMs: number;
43
+ recallOuterTimeoutMs: number;
44
+ recallStart: number;
45
+ abortSignal?: AbortSignal;
46
+ recordMetric: (metric: RecallSectionMetric) => void;
47
+ },
48
+ ): Promise<void> {
49
+ const engine = deps.lcmEngine;
50
+ if (!engine?.enabled) return;
51
+ if (!deps.isRecallSectionEnabled("episodic-context", false)) return;
52
+ const maxEpisodes =
53
+ deps.getRecallSectionNumber("episodic-context", "maxResults") ?? 2;
54
+ const maxTurns = deps.getRecallSectionNumber("episodic-context", "maxTurns") ?? 8;
55
+ const skip = (timing: string) =>
56
+ options.recordMetric({
57
+ section: "episodicContext",
58
+ priority: "enrichment",
59
+ durationMs: 0,
60
+ deadlineMs: options.enrichmentSectionDeadlineMs,
61
+ source: "skip",
62
+ success: true,
63
+ timing,
64
+ });
65
+ if (maxEpisodes <= 0 || maxTurns <= 0) {
66
+ // Zero semantics (checklist item 33): disable before any archive query.
67
+ skip("skip(limit=0)");
68
+ return;
69
+ }
70
+ if (options.recalledMemoryPaths.length === 0) {
71
+ skip("skip(no-memories)");
72
+ return;
73
+ }
74
+
75
+ const outerDeadlineAtMs =
76
+ options.recallOuterTimeoutMs > 0
77
+ ? options.recallStart + options.recallOuterTimeoutMs
78
+ : null;
79
+ const remainingOuterMs =
80
+ outerDeadlineAtMs === null ? null : outerDeadlineAtMs - deps.recallAssemblyClockMs();
81
+ const deadlineMs = resolveRecallCoreSectionDeadlineMs({
82
+ configuredCoreDeadlineMs: options.enrichmentSectionDeadlineMs,
83
+ remainingOuterMs,
84
+ });
85
+
86
+ const outcome = await runRecallSectionWithinDeadline<string | null>({
87
+ deadlineMs,
88
+ fallback: null,
89
+ parentSignal: options.abortSignal,
90
+ run: async (signal) => {
91
+ // 1. Structured provenance from the top recalled facts. Facts whose
92
+ // frontmatter carries no `sources` array are silently skipped (no
93
+ // legacy scalar `source` parsing — issue non-goal).
94
+ const facts: EpisodicFactInput[] = [];
95
+ const scanLimit = Math.min(
96
+ options.recalledMemoryPaths.length,
97
+ EPISODIC_FACT_SCAN_LIMIT,
98
+ );
99
+ for (let index = 0; index < scanLimit; index += 1) {
100
+ const memoryPath = options.recalledMemoryPaths[index]!;
101
+ const namespace = options.recalledMemoryNamespaces[index];
102
+ try {
103
+ const storage = await deps.storageRouter.storageFor(
104
+ namespace ?? deps.config.defaultNamespace,
105
+ );
106
+ const memory = await storage.readMemoryByPath(memoryPath);
107
+ const sources = memory?.frontmatter?.sources;
108
+ if (memory && Array.isArray(sources) && sources.length > 0) {
109
+ facts.push({
110
+ memoryId: memory.frontmatter.id,
111
+ rank: index,
112
+ sources,
113
+ });
114
+ }
115
+ } catch (err) {
116
+ log.debug(
117
+ `episodic-context: provenance read failed for ${memoryPath}`,
118
+ err,
119
+ );
120
+ }
121
+ }
122
+ if (facts.length === 0) return null;
123
+
124
+ // 2. Authoritative LCM session ids for a provenance sessionKey
125
+ // (checklist item 30): only keys framed under the caller's authorized read
126
+ // namespaces. A foreign session's rows live under a foreign namespace
127
+ // frame and are unreachable through this mapping.
128
+ const readNamespaces = options.namespacesEnabled
129
+ ? options.scopePlan.lcmReadNamespaces
130
+ : [deps.config.defaultNamespace];
131
+ const candidateSessionIds = (sessionKey: string): string[] => {
132
+ const seen = new Set<string>();
133
+ const out: string[] = [];
134
+ for (const namespace of readNamespaces) {
135
+ const key =
136
+ lcmSessionKeyForNamespace(
137
+ namespace,
138
+ sessionKey,
139
+ deps.config.defaultNamespace,
140
+ ) ?? sessionKey;
141
+ if (!seen.has(key)) {
142
+ seen.add(key);
143
+ out.push(key);
144
+ }
145
+ }
146
+ return out;
147
+ };
148
+
149
+ // 3. Plan windows (pure) with the single documented quote fallback.
150
+ const windows = await planEpisodeWindowsWithFallback({
151
+ recalledFacts: facts,
152
+ maxEpisodes,
153
+ maxTurnsPerEpisode: maxTurns,
154
+ locateQuote: async (quote, sessionKey) => {
155
+ for (const sessionId of candidateSessionIds(sessionKey)) {
156
+ try {
157
+ const hits = await engine.searchContextFull(quote, 1, sessionId);
158
+ if (hits.length > 0) return hits[0]!.turn_index;
159
+ } catch (err) {
160
+ // One failing session read must not sink the fallback; try the
161
+ // next candidate (fail-open per candidate).
162
+ log.debug(
163
+ `episodic-context: quote search failed for session ${sessionId}`,
164
+ err,
165
+ );
166
+ }
167
+ }
168
+ return null;
169
+ },
170
+ });
171
+ if (windows.length === 0) return null;
172
+
173
+ // 4. Fetch + clean raw turns. `getMessages` bounds are inclusive, so
174
+ // the exclusive `toTurn` passes as `toTurn - 1`.
175
+ const episodes: Array<{
176
+ sessionKey: string;
177
+ fromTurn: number;
178
+ toTurn: number;
179
+ memoryIds: readonly string[];
180
+ turns: ReadonlyArray<{ role: string; content: string }>;
181
+ }> = [];
182
+ for (const window of windows) {
183
+ if (signal.aborted) break;
184
+ let rows: LcmMessage[] = [];
185
+ for (const sessionId of candidateSessionIds(window.sessionKey)) {
186
+ try {
187
+ const fetched = await engine.getTurnRange(
188
+ sessionId,
189
+ window.fromTurn,
190
+ window.toTurn - 1,
191
+ );
192
+ if (fetched.length > 0) {
193
+ rows = fetched;
194
+ break;
195
+ }
196
+ } catch (err) {
197
+ // A failing session read skips that candidate only; the window
198
+ // is dropped when every candidate fails (fail-open).
199
+ log.debug(
200
+ `episodic-context: turn-range read failed for session ${sessionId}`,
201
+ err,
202
+ );
203
+ }
204
+ }
205
+ if (rows.length === 0) continue;
206
+ const turns = rows
207
+ .filter((m) => m.role === "user" || m.role === "assistant")
208
+ .map((m) => ({
209
+ role: m.role,
210
+ content:
211
+ m.role === "user"
212
+ ? cleanArchivedUserMessage(m.content)
213
+ : m.content,
214
+ }))
215
+ .map((turn) => ({
216
+ ...turn,
217
+ content:
218
+ turn.content.length > EPISODIC_TURN_CHAR_LIMIT
219
+ ? `${turn.content.slice(0, EPISODIC_TURN_CHAR_LIMIT)}…`
220
+ : turn.content,
221
+ }));
222
+ if (turns.length === 0) continue;
223
+ episodes.push({
224
+ sessionKey: window.sessionKey,
225
+ fromTurn: window.fromTurn,
226
+ toTurn: window.toTurn,
227
+ memoryIds: window.memoryIds,
228
+ turns,
229
+ });
230
+ }
231
+ return episodes.length > 0
232
+ ? deps.recallResultFormatter.formatEpisodicContext(episodes)
233
+ : null;
234
+ },
235
+ });
236
+
237
+ options.recordMetric({
238
+ section: "episodicContext",
239
+ priority: "enrichment",
240
+ durationMs: outcome.durationMs,
241
+ deadlineMs,
242
+ source: outcome.timedOut ? "timeout" : "fresh",
243
+ success: true,
244
+ ...(outcome.timedOut
245
+ ? { timing: `timeout(${Math.max(0, Math.round(outcome.durationMs))}ms)` }
246
+ : {}),
247
+ });
248
+ if (outcome.value === null) return;
249
+ const maxChars = deps.getRecallSectionMaxChars("episodic-context");
250
+ const body =
251
+ typeof maxChars === "number"
252
+ ? deps.truncateRecallSectionToBudget(outcome.value, maxChars)
253
+ : outcome.value;
254
+ deps.appendRecallSection(options.sectionBuckets, "episodic-context", body);
255
+ }
@@ -13,6 +13,7 @@ import type { EvalShadowRecallRecord } from "../evals.js";
13
13
  import type { HarmonicRetrievalResult } from "../harmonic-retrieval.js";
14
14
  import type { StorageManager } from "../index.js";
15
15
  import type { LcmEngine } from "../lcm/index.js";
16
+ import type { RecallResultFormatter } from "./recall-result-formatter.js";
16
17
  import type { NamespaceCatalog } from "../namespaces/catalog.js";
17
18
  import type { NamespaceStorageRouter } from "../namespaces/storage.js";
18
19
  import type { ObjectiveStateSearchResult } from "../objective-state.js";
@@ -248,6 +249,7 @@ export interface RecallInternalDeps {
248
249
  formatHarmonicRetrievalResults(
249
250
  results: HarmonicRetrievalResult[],
250
251
  ): string;
252
+ readonly recallResultFormatter: RecallResultFormatter;
251
253
  formatObjectiveStateResults(
252
254
  results: ObjectiveStateSearchResult[],
253
255
  ): string;
@@ -70,9 +70,9 @@ import { isDisagreementPrompt } from "../signal.js";
70
70
  import { buildTargetedFactRecallSection, shouldRecallTargetedFactEvidence } from "../targeted-fact-recall.js";
71
71
  import { shouldFilterSupersededFromRecall } from "../temporal-supersession.js";
72
72
  import { queryTemporalTimelineAsync } from "../temporal-index.js";
73
- import { buildTemporalTimelineRecallSection, type TemporalTimelineRecallItem } from "../temporal-timeline-recall.js";
74
- import { isValidAsOf } from "../temporal-validity.js";
75
73
  import { type TrustStageResultItem, projectTrustForXray } from "../trust-score-stage.js";
74
+ import { isValidAsOf } from "../temporal-validity.js";
75
+ import { buildTemporalTimelineRecallSection, type TemporalTimelineRecallItem } from "../temporal-timeline-recall.js";
76
76
  import { searchTrustZoneRecords } from "../trust-zones.js";
77
77
  import type { IdentityInjectionMode, MemoryFile, QmdSearchResult, RecallPlanMode } from "../types.js";
78
78
  import { type VerifiedEpisodeResult, compareVerifiedEpisodeResults, searchVerifiedEpisodes } from "../verified-recall.js";
@@ -105,6 +105,7 @@ import {
105
105
  type RecallResultPartitionSink,
106
106
  } from "./recall-rerank-coordinator.js";
107
107
  import type { RecallInternalDeps } from "./recall-internal-deps.js";
108
+ import { appendEpisodicContextSection } from "./episodic-context-section.js";
108
109
  import { resolveCompositeProfileStorage } from "./recall-profile-storage.js";
109
110
 
110
111
  export class RecallInternalCoordinator {
@@ -469,29 +470,16 @@ export class RecallInternalCoordinator {
469
470
  scopeProfilePlan,
470
471
  lcmReadSessionIds,
471
472
  } = scopePlan;
472
- // Query an LCM-backed read across the ordered read key set and return the
473
- // FIRST non-empty result (#1505 fallback-namespace unification). The primary
474
- // overlay key is tried first; if a branch-scoped session has no rows under its
475
- // branch key, the project / root fallback keys are tried in order.
476
- //
477
- // #1505 codex P2 ("Merge LCM fallback reads instead of short-circuiting"): the
478
- // query-SCORED sections (explicit-cue, targeted-facts, focused-list,
479
- // response-guidance, event-order, structured message-parts) no longer use this
480
- // helper they MERGE candidates across EVERY authorized key under their single
481
- // budget (a weak primary-key hit must not mask stronger fallback evidence; the
482
- // section builders take `sessionIds`, structured-parts merges inline below).
483
- // This first-non-empty helper now serves ONLY the compressed-history section,
484
- // which is a per-session HOLISTIC DAG narrative with no per-item id to merge or
485
- // dedupe on — see its call site for the rationale.
486
- //
487
- // When the set is a single key (single-user / no-overlay / explicit-namespace),
488
- // this is exactly one call — unchanged. `lcmSessionId` is `string | undefined`:
489
- // a legacy SESSIONLESS recall yields the single `undefined` key so the read
490
- // runs ONE archive-wide read with no `session_id` filter (pre-#1505 behavior).
491
- // Hosted scope profiles are stricter: without a session key there is no
492
- // namespace-scoped LCM key to query, so the key set stays empty and LCM cannot
493
- // bypass the profile read stack via an archive-wide read. NEVER the literal
494
- // "default" session id (codex P2).
473
+ // `firstNonEmptyLcmRead`: query the ordered LCM read key set, return the
474
+ // FIRST non-empty result (#1505). The query-SCORED sections no longer use
475
+ // it they MERGE candidates across every authorized key (a weak primary
476
+ // hit must not mask stronger fallback evidence); this helper now serves
477
+ // only compressed-history, a holistic per-session DAG narrative with no
478
+ // per-item id to merge on. A single-key set is exactly one call. A legacy
479
+ // SESSIONLESS recall yields one `undefined` key: one archive-wide read,
480
+ // no `session_id` filter. Hosted scope profiles without a session key get
481
+ // an EMPTY key set, so LCM cannot bypass the profile read stack. NEVER
482
+ // the literal "default" session id (codex P2).
495
483
  const firstNonEmptyLcmRead = async <T>(
496
484
  read: (lcmSessionId: string | undefined) => Promise<T>,
497
485
  isEmpty: (value: T) => boolean,
@@ -4926,6 +4914,32 @@ export class RecallInternalCoordinator {
4926
4914
  recallPlan: timings.recallPlan,
4927
4915
  queryPolicy: timings.queryPolicy,
4928
4916
  });
4917
+ // Episodic context (#2331): opt-in raw-turn episodes for the top recalled
4918
+ // facts; flag off is a no-op so recall output stays byte-identical.
4919
+ // Namespaces must be index-aligned with recalledMemoryPaths here — every
4920
+ // recall branch populates xrayRecalledResults from the same array it
4921
+ // mapped paths from, so per-path namespaces derive from those results
4922
+ // (the assembly-time assignment below runs after this section).
4923
+ const episodicNamespaceByPath = new Map<string, string | undefined>();
4924
+ for (const result of xrayRecalledResults) {
4925
+ if (result.path) episodicNamespaceByPath.set(result.path, result.namespace);
4926
+ }
4927
+ const episodicMemoryNamespaces = recalledMemoryPaths.map((memoryPath) =>
4928
+ episodicNamespaceByPath.get(memoryPath),
4929
+ );
4930
+ // The section is advisory context: an archive error degrades the
4931
+ // section, never the recall (fail-open).
4932
+ try {
4933
+ await appendEpisodicContextSection(this.deps, {
4934
+ sectionBuckets, recalledMemoryPaths,
4935
+ recalledMemoryNamespaces: episodicMemoryNamespaces,
4936
+ scopePlan, namespacesEnabled,
4937
+ enrichmentSectionDeadlineMs, recallOuterTimeoutMs, recallStart,
4938
+ recordMetric: recordRecallSectionMetric, abortSignal: options.abortSignal,
4939
+ });
4940
+ } catch (err) {
4941
+ log.debug("episodic-context: section degraded after error", err);
4942
+ }
4929
4943
  const recallBudgetChars = this.deps.getRecallBudgetChars(options.budgetCharsOverride);
4930
4944
  const assembledRecall = this.deps.assembleRecallSections(
4931
4945
  sectionBuckets, contextBudgetForFooter(recallBudgetChars, curiosityFooter),
@@ -5326,4 +5340,5 @@ export class RecallInternalCoordinator {
5326
5340
  closeProfileTrace();
5327
5341
  }
5328
5342
  }
5343
+
5329
5344
  }
@@ -384,6 +384,43 @@ export class RecallResultFormatter {
384
384
  return `## Harmonic Retrieval\n\n${lines.join("\n\n")}`;
385
385
  }
386
386
 
387
+ /**
388
+ * Render grouped raw-turn episodes for the top recalled facts (issue #2331).
389
+ * Returns `null` for zero episodes so the section is omitted entirely —
390
+ * never an empty header.
391
+ */
392
+ formatEpisodicContext(
393
+ episodes: ReadonlyArray<{
394
+ sessionKey: string;
395
+ fromTurn: number;
396
+ toTurn: number;
397
+ memoryIds: readonly string[];
398
+ turns: ReadonlyArray<{ role: string; content: string }>;
399
+ }>,
400
+ ): string | null {
401
+ if (episodes.length === 0) return null;
402
+ const blocks = episodes.map((episode) => {
403
+ const shortKey =
404
+ episode.sessionKey.length > 8
405
+ ? `${episode.sessionKey.slice(0, 8)}…`
406
+ : episode.sessionKey;
407
+ const header =
408
+ `### Episode: ${shortKey} turns ${episode.fromTurn}-${episode.toTurn - 1} ` +
409
+ `(supports [${episode.memoryIds.join(", ")}])`;
410
+ const lines = episode.turns.map((turn) => {
411
+ // Archived conversation turns carry no origin: least-privilege
412
+ // fencing applies when origin authority is enabled (issue #2331).
413
+ const content = renderAuthorityBoundContent(turn.content, undefined, {
414
+ enabled: this.originAuthorityEnabled,
415
+ untrustedOrigins: this.config.untrustedOrigins,
416
+ });
417
+ return `${turn.role}: ${content}`;
418
+ });
419
+ return [header, ...lines].join("\n");
420
+ });
421
+ return `## Source Episodes\n\n${blocks.join("\n\n")}`;
422
+ }
423
+
387
424
  formatWorkProductResults(
388
425
  results: WorkProductLedgerSearchResult[],
389
426
  ): string {
@@ -4,7 +4,7 @@ export interface NormalizeRecallTokenOptions {
4
4
 
5
5
  const DEFAULT_RECALL_STOP_WORDS = ["the", "and", "for", "with", "from", "into", "that", "this", "why", "did"];
6
6
 
7
- function isUnsegmentableRecallChar(char: string): boolean {
7
+ export function isUnsegmentableRecallChar(char: string): boolean {
8
8
  if (char === "ー" || char === "ー") return true;
9
9
  return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(char);
10
10
  }
@@ -24,21 +24,27 @@ function shouldKeepRecallToken(token: string, minTokenLength: number, stopWords:
24
24
  return token.length >= 2 && hasNonAsciiCodepoint && /\p{L}/u.test(token);
25
25
  }
26
26
 
27
- function addUnsegmentableRecallSegment(tokens: Set<string>, segment: string, stopWords: Set<string>): void {
27
+ export function expandUnsegmentableRecallNGrams(segment: string): string[] {
28
28
  const chars = [...segment].filter((ch) => /[\p{L}\p{N}\p{M}]/u.test(ch) || isUnsegmentableRecallChar(ch));
29
+ const tokens: string[] = [];
29
30
  for (const ch of chars) {
30
- if (!stopWords.has(ch)) tokens.add(ch);
31
+ tokens.push(ch);
31
32
  }
32
33
  for (const size of [2, 3, 4]) {
33
34
  if (chars.length < size) continue;
34
35
  for (let index = 0; index <= chars.length - size; index += 1) {
35
- const token = chars.slice(index, index + size).join("");
36
- if (!stopWords.has(token)) tokens.add(token);
36
+ tokens.push(chars.slice(index, index + size).join(""));
37
37
  }
38
38
  }
39
- const whole = chars.join("");
40
- if (whole.length > 3 && !stopWords.has(whole)) {
41
- tokens.add(whole);
39
+ if (chars.length > 3) {
40
+ tokens.push(chars.join(""));
41
+ }
42
+ return tokens;
43
+ }
44
+
45
+ function addUnsegmentableRecallSegment(tokens: Set<string>, segment: string, stopWords: Set<string>): void {
46
+ for (const token of expandUnsegmentableRecallNGrams(segment)) {
47
+ if (!stopWords.has(token)) tokens.add(token);
42
48
  }
43
49
  }
44
50
 
@@ -50,6 +50,7 @@ test("reconcile manifest keeps file identity separate from canonical semantic id
50
50
  category: "fact",
51
51
  contentHash: semanticHash,
52
52
  normalizerVersion: 4,
53
+ identityResolutionVersion: 2,
53
54
  status: "active",
54
55
  });
55
56
  });
@@ -100,11 +101,52 @@ test("reconcile manifest reparses cached pre-version identities after Unicode mi
100
101
  });
101
102
 
102
103
  assert.equal(reads, 1);
104
+ // The café body is lossy under the legacy normalizer, so the persisted
105
+ // legacy hash stays primary and the recovered current identity rides along
106
+ // as an alias (issue #2367).
103
107
  assert.equal(
104
108
  manifest.files[0]?.memory?.contentHash,
105
- ContentHashIndex.computeHash(content),
109
+ legacyHash,
106
110
  );
107
- assert.equal("contentHashAliases" in (manifest.files[0]?.memory ?? {}), false);
111
+ assert.deepEqual(manifest.files[0]?.memory?.contentHashAliases, [
112
+ ContentHashIndex.computeHash(content),
113
+ ]);
114
+ });
115
+
116
+ test("reconcile manifest reparses cached identities lacking the identity-resolution version", async () => {
117
+ const content = "The user prefers café.";
118
+ const legacyHash = computeLegacyContentHash(content);
119
+ const serialized = memoryFile({ id: "legacy-identity-version", content, contentHash: legacyHash });
120
+ const file = { path: "facts/legacy-identity-version.md", sha256: fileHash(serialized) };
121
+ let reads = 0;
122
+
123
+ const manifest = await buildReconcileManifest({
124
+ files: [file],
125
+ parseMemory: parseFrontmatter,
126
+ readFile: async () => {
127
+ reads += 1;
128
+ return serialized;
129
+ },
130
+ // Same normalizerVersion, but written before identity-resolution
131
+ // versioning existed: the entry carries no aliases and must NOT be
132
+ // reused (issue #2367 review round 2).
133
+ cachedFiles: [{
134
+ ...file,
135
+ memory: {
136
+ id: "legacy-identity-version",
137
+ category: "fact",
138
+ contentHash: legacyHash,
139
+ normalizerVersion: 4,
140
+ status: "active",
141
+ },
142
+ }],
143
+ });
144
+
145
+ assert.equal(reads, 1);
146
+ assert.equal(manifest.files[0]?.memory?.identityResolutionVersion, 2);
147
+ assert.deepEqual(manifest.files[0]?.memory?.contentHashAliases, [
148
+ ContentHashIndex.computeHash(content),
149
+ ]);
108
150
  });
109
151
 
110
152
  test("reconcile manifest replaces a pure-CJK legacy identity with its current hash", async () => {
@@ -146,7 +188,10 @@ test("reconcile manifest recovers a raw hash source beneath citation and attribu
146
188
  readFile: async () => serialized,
147
189
  });
148
190
 
149
- assert.equal(manifest.files[0]?.memory?.contentHash, ContentHashIndex.computeHash(content));
191
+ assert.equal(manifest.files[0]?.memory?.contentHash, computeLegacyContentHash(content));
192
+ assert.deepEqual(manifest.files[0]?.memory?.contentHashAliases, [
193
+ ContentHashIndex.computeHash(content),
194
+ ]);
150
195
  });
151
196
 
152
197
  test("reconcile manifest recovers raw identity beneath a configured citation", async () => {
@@ -169,7 +214,91 @@ test("reconcile manifest recovers raw identity beneath a configured citation", a
169
214
  citationTemplate,
170
215
  });
171
216
 
172
- assert.equal(manifest.files[0]?.memory?.contentHash, ContentHashIndex.computeHash(content));
217
+ assert.equal(manifest.files[0]?.memory?.contentHash, computeLegacyContentHash(content));
218
+ assert.deepEqual(manifest.files[0]?.memory?.contentHashAliases, [
219
+ ContentHashIndex.computeHash(content),
220
+ ]);
221
+ });
222
+
223
+ test("reconcile manifest prefers a persisted explicit hash over a colliding legacy body hash (issue #2367)", async () => {
224
+ // Source `caf` with body `café`: hash("caf") numerically equals the legacy
225
+ // hash of the stored body, but it is the fact's explicit contentHashSource
226
+ // identity written by the current normalizer. The legacy candidate match
227
+ // must not replace it.
228
+ const source = "caf";
229
+ const body = "café";
230
+ const persistedHash = ContentHashIndex.computeHash(source);
231
+ assert.equal(persistedHash, computeLegacyContentHash(body));
232
+ const serialized = memoryFile({ id: "explicit-source", content: body, contentHash: persistedHash });
233
+ const manifest = await buildReconcileManifest({
234
+ files: [{ path: "facts/explicit-source.md", sha256: fileHash(serialized) }],
235
+ parseMemory: parseFrontmatter,
236
+ readFile: async () => serialized,
237
+ });
238
+
239
+ assert.equal(manifest.files[0]?.memory?.contentHash, persistedHash);
240
+ assert.notEqual(manifest.files[0]?.memory?.contentHash, ContentHashIndex.computeHash(body));
241
+ assert.deepEqual(manifest.files[0]?.memory?.contentHashAliases, [
242
+ ContentHashIndex.computeHash(body),
243
+ ]);
244
+ });
245
+
246
+ test("reconcile collapse matches an explicit-source replica through the persisted hash (issue #2367)", async () => {
247
+ const source = "caf";
248
+ const persistedHash = ContentHashIndex.computeHash(source);
249
+ const localSerialized = memoryFile({ id: "explicit-local", content: "café", contentHash: persistedHash });
250
+ const peerSerialized = memoryFile({ id: "explicit-peer", content: source, contentHash: persistedHash });
251
+ const localFile = { path: "facts/explicit-local.md", sha256: fileHash(localSerialized) };
252
+ const peerFile = { path: "facts/explicit-peer.md", sha256: fileHash(peerSerialized) };
253
+ const build = async (file: typeof localFile, raw: string) =>
254
+ await buildReconcileManifest({
255
+ files: [file],
256
+ parseMemory: parseFrontmatter,
257
+ readFile: async () => raw,
258
+ });
259
+ const local = await build(localFile, localSerialized);
260
+ const peer = await build(peerFile, peerSerialized);
261
+ const plan = planReconciliation([{ namespace: "default", local: [localFile], peer: [peerFile] }]);
262
+
263
+ const collapsed = collapseActiveFactDuplicates(
264
+ plan,
265
+ new Map([["default", local]]),
266
+ new Map([["default", peer]]),
267
+ );
268
+
269
+ assert.equal(collapsed.converged, true);
270
+ assert.equal(collapsed.entries.length, 1);
271
+ assert.equal(collapsed.entries[0]?.reason, "semantic_duplicate");
272
+ });
273
+
274
+ test("reconcile manifest does not collapse distinct pure-CJK legacy facts through the empty skeleton (issue #2367)", async () => {
275
+ const first = "利用者は紅茶を好む。";
276
+ const second = "利用者は珈琲を好む。";
277
+ assert.equal(computeLegacyContentHash(first), computeLegacyContentHash(second));
278
+ const build = async (id: string, content: string) => {
279
+ const serialized = memoryFile({ id, content, contentHash: computeLegacyContentHash(content) });
280
+ const file = { path: `facts/${id}.md`, sha256: fileHash(serialized) };
281
+ const manifest = await buildReconcileManifest({
282
+ files: [file],
283
+ parseMemory: parseFrontmatter,
284
+ readFile: async () => serialized,
285
+ });
286
+ return { file, manifest };
287
+ };
288
+ const a = await build("legacy-cjk-first", first);
289
+ const b = await build("legacy-cjk-second", second);
290
+ const plan = planReconciliation([
291
+ { namespace: "default", local: [a.file], peer: [b.file] },
292
+ ]);
293
+
294
+ const collapsed = collapseActiveFactDuplicates(
295
+ plan,
296
+ new Map([["default", a.manifest]]),
297
+ new Map([["default", b.manifest]]),
298
+ );
299
+
300
+ assert.equal(collapsed.converged, false);
301
+ assert.equal(collapsed.entries.length, 2);
173
302
  });
174
303
 
175
304
  test("reconcile manifest does not add a legacy alias to a current Unicode identity", async () => {