@remnic/core 9.28.0 → 9.29.1

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 (426) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -10
  2. package/dist/access-admin-ops-surface.js +32 -32
  3. package/dist/access-authorization-probe.d.ts +10 -10
  4. package/dist/access-authorization-probe.js +33 -33
  5. package/dist/access-boundary.d.ts +10 -10
  6. package/dist/access-boundary.js +32 -32
  7. package/dist/access-cli.js +101 -98
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-health-types.d.ts +1 -1
  10. package/dist/access-http-lcm-compaction.d.ts +10 -10
  11. package/dist/access-http.d.ts +10 -10
  12. package/dist/access-http.js +43 -43
  13. package/dist/access-identity-continuity-surface.d.ts +8 -8
  14. package/dist/access-identity-continuity-surface.js +32 -32
  15. package/dist/access-lcm-surface.d.ts +10 -10
  16. package/dist/access-lcm-surface.js +32 -32
  17. package/dist/access-mcp.d.ts +10 -10
  18. package/dist/access-mcp.js +38 -38
  19. package/dist/access-memory-search-fanout.d.ts +2 -2
  20. package/dist/access-memory-search-fanout.js +3 -3
  21. package/dist/{access-namespace-preflight-BiQ_-iUJ.d.ts → access-namespace-preflight-DCXBkDp0.d.ts} +1 -1
  22. package/dist/access-namespace-preflight.d.ts +3 -3
  23. package/dist/access-namespace-preflight.js +32 -32
  24. package/dist/access-observe-write-surface.d.ts +10 -10
  25. package/dist/access-observe-write-surface.js +32 -32
  26. package/dist/access-operations-batch.js +35 -35
  27. package/dist/access-operations.d.ts +10 -10
  28. package/dist/access-operations.js +37 -37
  29. package/dist/access-recall-concurrency.d.ts +10 -10
  30. package/dist/access-recall-concurrency.js +32 -32
  31. package/dist/access-recall-response.d.ts +10 -10
  32. package/dist/access-recall-response.js +32 -32
  33. package/dist/access-recall-surface.d.ts +10 -10
  34. package/dist/access-recall-surface.js +32 -32
  35. package/dist/access-schema.d.ts +7 -7
  36. package/dist/access-schema.js +4 -4
  37. package/dist/{access-service-CXkIgcGh.d.ts → access-service-DvPW_M5j.d.ts} +7 -7
  38. package/dist/access-service.d.ts +10 -10
  39. package/dist/access-service.js +32 -32
  40. package/dist/access-surface-catalog.d.ts +10 -10
  41. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  42. package/dist/action-confidence.d.ts +1 -1
  43. package/dist/active-memory-bridge.d.ts +1 -1
  44. package/dist/active-memory-bridge.js +3 -3
  45. package/dist/active-recall.d.ts +1 -1
  46. package/dist/active-recall.js +1 -1
  47. package/dist/adapters/index.js +4 -4
  48. package/dist/adapters/registry.js +2 -2
  49. package/dist/behavior-learner.d.ts +1 -1
  50. package/dist/behavior-signals.d.ts +1 -1
  51. package/dist/bootstrap.d.ts +8 -8
  52. package/dist/briefing.d.ts +2 -2
  53. package/dist/briefing.js +8 -8
  54. package/dist/buffer-surprise-report.d.ts +1 -1
  55. package/dist/buffer.d.ts +2 -2
  56. package/dist/buffer.js +2 -2
  57. package/dist/bulk-import/index.d.ts +3 -3
  58. package/dist/calibration.d.ts +1 -1
  59. package/dist/capabilities.d.ts +3 -2
  60. package/dist/capabilities.js +1 -1
  61. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
  62. package/dist/{catalog-Bouj8Gfg.d.ts → catalog-BIVgftWu.d.ts} +1 -1
  63. package/dist/causal-behavior.d.ts +1 -1
  64. package/dist/causal-consolidation.d.ts +1 -1
  65. package/dist/causal-consolidation.js +9 -9
  66. package/dist/causal-trajectory-graph.d.ts +1 -1
  67. package/dist/{chunk-GQSMYXKL.js → chunk-2AXMQWCN.js} +2 -2
  68. package/dist/{chunk-VYYNBJXH.js → chunk-2D7FEUCK.js} +6 -6
  69. package/dist/{chunk-PXQM2HOG.js → chunk-2GXM5N5A.js} +2 -2
  70. package/dist/{chunk-RDQGLJRR.js → chunk-2XRE6FLM.js} +2 -1
  71. package/dist/{chunk-RDQGLJRR.js.map → chunk-2XRE6FLM.js.map} +1 -1
  72. package/dist/{chunk-JIF3VRKQ.js → chunk-35DL7IOI.js} +10 -10
  73. package/dist/{chunk-2H7OEVPO.js → chunk-3GD2HFR6.js} +2 -2
  74. package/dist/{chunk-KKBTBUVT.js → chunk-3JNDOAQ2.js} +5 -5
  75. package/dist/{chunk-4TFIRMTE.js → chunk-4A6YGWQN.js} +2 -2
  76. package/dist/{chunk-IKMAO55B.js → chunk-55MDBZLC.js} +2 -2
  77. package/dist/{chunk-RKXZ7P4V.js → chunk-5QDRGWT2.js} +3 -3
  78. package/dist/{chunk-IPLYGWQF.js → chunk-5W7CTZ2E.js} +6 -6
  79. package/dist/{chunk-ALTP3MFS.js → chunk-5ZCUDWD4.js} +2 -2
  80. package/dist/{chunk-B7GROTXD.js → chunk-6LKEUCEM.js} +2 -2
  81. package/dist/{chunk-2AJ72VVS.js → chunk-7BZOBA5J.js} +3 -3
  82. package/dist/{chunk-44DUJETW.js → chunk-7HXCF4RE.js} +2 -2
  83. package/dist/{chunk-WVVK2RFM.js → chunk-7L45JFPW.js} +14 -14
  84. package/dist/{chunk-R372P2EH.js → chunk-ACXPX4AG.js} +2 -2
  85. package/dist/{chunk-7CPOZH6Y.js → chunk-ALSGMEJR.js} +5 -5
  86. package/dist/{chunk-JGUXPJUQ.js → chunk-AS7YMSL6.js} +2 -2
  87. package/dist/{chunk-DKQM5Q6Q.js → chunk-CW4AGY3G.js} +4 -4
  88. package/dist/{chunk-ZN4UZWMT.js → chunk-D2ANTDGO.js} +3 -3
  89. package/dist/{chunk-3UOSVTFR.js → chunk-D3LMYTBV.js} +9 -9
  90. package/dist/{chunk-FOCEI3TN.js → chunk-DRBXHRXE.js} +2 -1
  91. package/dist/chunk-DRBXHRXE.js.map +1 -0
  92. package/dist/{chunk-LIHC3T43.js → chunk-E5OBR6CJ.js} +4 -4
  93. package/dist/{chunk-XY7QPJDA.js → chunk-E6EE5B67.js} +2 -2
  94. package/dist/{chunk-TBMRQZDY.js → chunk-EP5BVCRI.js} +2 -2
  95. package/dist/{chunk-MJPV4LBH.js → chunk-FUYEVEX7.js} +83 -83
  96. package/dist/{chunk-2BEJ4XCF.js → chunk-FZRQZW4H.js} +2 -2
  97. package/dist/{chunk-X6ROIHFE.js → chunk-G5R3D5UP.js} +2 -2
  98. package/dist/{chunk-2FYNLDKJ.js → chunk-GAWOEQEQ.js} +2 -2
  99. package/dist/{chunk-TKBDJTXG.js → chunk-GBJ4RDFR.js} +94 -20
  100. package/dist/chunk-GBJ4RDFR.js.map +1 -0
  101. package/dist/{chunk-QH6CS6XJ.js → chunk-H24WNPA2.js} +2 -2
  102. package/dist/{chunk-VFNI3RPT.js → chunk-HKJCMOT6.js} +2 -2
  103. package/dist/{chunk-JQ7T5VDC.js → chunk-HUHX2OCX.js} +1 -1
  104. package/dist/chunk-HUHX2OCX.js.map +1 -0
  105. package/dist/{chunk-EZWWCN7I.js → chunk-IAEAFLF2.js} +2 -2
  106. package/dist/{chunk-NBNDVNJ2.js → chunk-IGPEJVBY.js} +3 -3
  107. package/dist/{chunk-MQVINOJQ.js → chunk-IYZ5K7MU.js} +3 -3
  108. package/dist/{chunk-Q5VJUNXA.js → chunk-JMQUBRV6.js} +105 -42
  109. package/dist/chunk-JMQUBRV6.js.map +1 -0
  110. package/dist/{chunk-2TQ2UFKH.js → chunk-JP3YPDAW.js} +57 -57
  111. package/dist/{chunk-P2CLYN6H.js → chunk-K5GB36ME.js} +2 -2
  112. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  113. package/dist/{chunk-FBZTWUK5.js → chunk-OFHFH655.js} +8 -8
  114. package/dist/{chunk-GJPCP5CA.js → chunk-OP6F6L3S.js} +2 -2
  115. package/dist/{chunk-FGBJBYWP.js → chunk-OVRQLAYR.js} +3 -3
  116. package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
  117. package/dist/{chunk-3BSJBIZ3.js → chunk-OYJKSZIQ.js} +2 -2
  118. package/dist/chunk-P2BM76KT.js +528 -0
  119. package/dist/chunk-P2BM76KT.js.map +1 -0
  120. package/dist/{chunk-UR5SIN7H.js → chunk-PBUZNGMX.js} +30 -30
  121. package/dist/{chunk-P2OZKKYP.js → chunk-PHWUFPCO.js} +2 -2
  122. package/dist/{chunk-Q6YJW6KE.js → chunk-PKRIQL3V.js} +2 -2
  123. package/dist/{chunk-BR4UFMLO.js → chunk-PTSNLEXK.js} +3 -3
  124. package/dist/{chunk-AHFZXUZM.js → chunk-QDKK63Y7.js} +3 -3
  125. package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
  126. package/dist/{chunk-FCCMFVS6.js → chunk-RPSYDM6C.js} +2 -2
  127. package/dist/chunk-RPW2NOU6.js +33 -0
  128. package/dist/chunk-RPW2NOU6.js.map +1 -0
  129. package/dist/{chunk-MWTMTW2T.js → chunk-SH6YO3LT.js} +3 -3
  130. package/dist/{chunk-IYT632D5.js → chunk-UBKEQOTD.js} +3 -3
  131. package/dist/{chunk-BJJAX3IZ.js → chunk-UTRO5UJU.js} +2 -2
  132. package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
  133. package/dist/{chunk-S24E4MBQ.js → chunk-VSURVXKY.js} +9 -9
  134. package/dist/chunk-WOCNN776.js +742 -0
  135. package/dist/chunk-WOCNN776.js.map +1 -0
  136. package/dist/{chunk-YOBNCD3Z.js → chunk-WRFBW2TT.js} +10 -10
  137. package/dist/{chunk-MXJ3VP6S.js → chunk-WU7TTVOD.js} +7 -7
  138. package/dist/{chunk-EG64LXKL.js → chunk-XOZ4ALGB.js} +3 -3
  139. package/dist/{chunk-2PHX3I5C.js → chunk-Z54EM5YZ.js} +10 -10
  140. package/dist/{cli-DJbkaZBU.d.ts → cli-CxoSOiG0.d.ts} +5 -5
  141. package/dist/cli.d.ts +12 -12
  142. package/dist/cli.js +65 -65
  143. package/dist/compounding/engine.d.ts +2 -2
  144. package/dist/compounding/engine.js +9 -9
  145. package/dist/compounding/preference-consolidator.d.ts +1 -1
  146. package/dist/compression-optimizer.d.ts +1 -1
  147. package/dist/config.d.ts +1 -1
  148. package/dist/config.js +1 -1
  149. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  150. package/dist/connectors/codex-materialize-runner.js +8 -8
  151. package/dist/connectors/codex-materialize.d.ts +1 -1
  152. package/dist/connectors/index.d.ts +1 -1
  153. package/dist/connectors/index.js +9 -9
  154. package/dist/consolidation-provenance-check.d.ts +2 -2
  155. package/dist/consolidation-undo.d.ts +2 -2
  156. package/dist/contradiction/index.d.ts +2 -2
  157. package/dist/contradiction/index.js +6 -6
  158. package/dist/{contradiction-scan-HMF7CNKD.js → contradiction-scan-HYLIRMJ2.js} +3 -3
  159. package/dist/conversation-index/backend.d.ts +1 -1
  160. package/dist/conversation-index/backend.js +2 -2
  161. package/dist/conversation-index/chunker.d.ts +1 -1
  162. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  163. package/dist/conversation-index/indexer.d.ts +1 -1
  164. package/dist/conversation-index/search.d.ts +1 -1
  165. package/dist/corpus-watermark.d.ts +1 -1
  166. package/dist/corpus-watermark.js +16 -16
  167. package/dist/day-summary.d.ts +1 -1
  168. package/dist/day-summary.js +2 -2
  169. package/dist/delinearize.d.ts +1 -1
  170. package/dist/direct-answer-wiring.d.ts +1 -1
  171. package/dist/direct-answer.d.ts +1 -1
  172. package/dist/embedding-fallback.d.ts +1 -1
  173. package/dist/embedding-fallback.js +2 -2
  174. package/dist/enrichment/index.d.ts +1 -1
  175. package/dist/entity-retrieval.d.ts +2 -2
  176. package/dist/entity-retrieval.js +8 -8
  177. package/dist/entity-schema.d.ts +1 -1
  178. package/dist/explicit-capture.d.ts +8 -8
  179. package/dist/explicit-capture.js +2 -2
  180. package/dist/extraction-error-classification.d.ts +1 -1
  181. package/dist/extraction-faithfulness.d.ts +1 -1
  182. package/dist/extraction-judge-telemetry.d.ts +1 -1
  183. package/dist/extraction-judge-training.d.ts +1 -1
  184. package/dist/extraction-judge.d.ts +1 -1
  185. package/dist/extraction-liveness.d.ts +1 -1
  186. package/dist/extraction-source-grounding-helpers.d.ts +34 -0
  187. package/dist/extraction-source-grounding-helpers.js +62 -0
  188. package/dist/extraction-source-grounding-helpers.js.map +1 -0
  189. package/dist/extraction-source-grounding-rules.d.ts +18 -0
  190. package/dist/extraction-source-grounding-rules.js +12 -0
  191. package/dist/extraction-source-grounding-rules.js.map +1 -0
  192. package/dist/extraction-source-grounding.d.ts +11 -0
  193. package/dist/extraction-source-grounding.js +13 -0
  194. package/dist/extraction-source-grounding.js.map +1 -0
  195. package/dist/extraction.d.ts +3 -1
  196. package/dist/extraction.js +7 -4
  197. package/dist/fallback-llm.d.ts +1 -1
  198. package/dist/{first-start-migration-BKNGOFED.js → first-start-migration-F2QJD66E.js} +5 -5
  199. package/dist/graph-dashboard-diff.d.ts +1 -1
  200. package/dist/graph-dashboard-key.d.ts +1 -1
  201. package/dist/graph-dashboard-parser.d.ts +1 -1
  202. package/dist/graph-edge-reinforcement.d.ts +1 -1
  203. package/dist/graph-snapshot.d.ts +1 -1
  204. package/dist/graph.d.ts +1 -1
  205. package/dist/importance.d.ts +1 -1
  206. package/dist/importers/index.d.ts +1 -1
  207. package/dist/in-flight-reads.d.ts +1 -1
  208. package/dist/index.d.ts +19 -19
  209. package/dist/index.js +156 -153
  210. package/dist/intent.d.ts +1 -1
  211. package/dist/lcm/engine.d.ts +1 -1
  212. package/dist/lcm/engine.js +4 -4
  213. package/dist/lcm/index.d.ts +1 -1
  214. package/dist/lcm/index.js +10 -10
  215. package/dist/lcm/tools.d.ts +1 -1
  216. package/dist/lifecycle.d.ts +1 -1
  217. package/dist/live-connectors-runner.d.ts +1 -1
  218. package/dist/local-llm.d.ts +1 -1
  219. package/dist/local-llm.js +2 -2
  220. package/dist/local-model-endpoint.d.ts +1 -1
  221. package/dist/maintenance/memory-governance.d.ts +1 -1
  222. package/dist/maintenance/memory-governance.js +8 -8
  223. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  224. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
  225. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  226. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  227. package/dist/{maintenance-DveW6azo.d.ts → maintenance-Cb-PjxQd.d.ts} +3 -3
  228. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  229. package/dist/memory-action-policy.d.ts +1 -1
  230. package/dist/memory-cache.d.ts +1 -1
  231. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  232. package/dist/memory-projection-store.d.ts +1 -1
  233. package/dist/memory-provenance.d.ts +1 -1
  234. package/dist/memory-worth-outcomes.d.ts +2 -2
  235. package/dist/models-json.d.ts +1 -1
  236. package/dist/namespaces/migrate.d.ts +3 -3
  237. package/dist/namespaces/migrate.js +15 -15
  238. package/dist/namespaces/principal.d.ts +1 -1
  239. package/dist/namespaces/principal.js +2 -2
  240. package/dist/namespaces/search.d.ts +1 -1
  241. package/dist/namespaces/search.js +7 -7
  242. package/dist/namespaces/storage.d.ts +3 -3
  243. package/dist/namespaces/storage.js +8 -8
  244. package/dist/native-knowledge.d.ts +1 -1
  245. package/dist/offline-sync-impression-drain.d.ts +1 -1
  246. package/dist/offline-sync-impression-drain.js +6 -6
  247. package/dist/operator-doctor-corpus.d.ts +1 -1
  248. package/dist/operator-doctor-corpus.js +17 -17
  249. package/dist/operator-doctor-replica.d.ts +1 -1
  250. package/dist/operator-toolkit.d.ts +3 -3
  251. package/dist/operator-toolkit.js +23 -23
  252. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  253. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  254. package/dist/orchestration/maintenance.d.ts +4 -4
  255. package/dist/orchestration/maintenance.js +15 -15
  256. package/dist/{orchestrator-Cvlgpe6I.d.ts → orchestrator-5GKqb_HL.d.ts} +7 -7
  257. package/dist/orchestrator.d.ts +8 -8
  258. package/dist/orchestrator.js +103 -100
  259. package/dist/patterns-cli.d.ts +1 -1
  260. package/dist/{pipeline-BveYVaz7.d.ts → pipeline-3Qi1TpRo.d.ts} +1 -1
  261. package/dist/policy-runtime.d.ts +1 -1
  262. package/dist/proactive-contention.d.ts +1 -1
  263. package/dist/provenance.d.ts +1 -1
  264. package/dist/{qmd-CLWDsbYR.d.ts → qmd-D9JqzzRX.d.ts} +1 -1
  265. package/dist/qmd-preflight.d.ts +2 -2
  266. package/dist/qmd-recall-cache.d.ts +1 -1
  267. package/dist/qmd.d.ts +2 -2
  268. package/dist/recall-concurrency-config.d.ts +1 -1
  269. package/dist/recall-disclosure-escalation.d.ts +1 -1
  270. package/dist/recall-explain-renderer.d.ts +1 -1
  271. package/dist/recall-explain-renderer.js +3 -3
  272. package/dist/recall-memory-map.d.ts +1 -1
  273. package/dist/recall-planner-llm.d.ts +1 -1
  274. package/dist/recall-state.d.ts +1 -1
  275. package/dist/recall-tag-filter.d.ts +1 -1
  276. package/dist/recall-timings.d.ts +1 -1
  277. package/dist/recall-xray-cli.d.ts +1 -1
  278. package/dist/recall-xray-cli.js +4 -4
  279. package/dist/recall-xray-renderer.d.ts +1 -1
  280. package/dist/recall-xray-renderer.js +3 -3
  281. package/dist/recall-xray.d.ts +1 -1
  282. package/dist/recall-xray.js +2 -2
  283. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  284. package/dist/replay/normalizers/claude.d.ts +1 -1
  285. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  286. package/dist/replay/normalizers/shared.d.ts +1 -1
  287. package/dist/replay/runner.d.ts +1 -1
  288. package/dist/replay/types.d.ts +1 -1
  289. package/dist/replica-divergence.d.ts +1 -1
  290. package/dist/replica-peers-config.d.ts +1 -1
  291. package/dist/resolve-auth-token.d.ts +1 -1
  292. package/dist/resume-bundles.js +2 -2
  293. package/dist/retrieval-agents.d.ts +2 -2
  294. package/dist/retrieval-tiers.d.ts +1 -1
  295. package/dist/routing/engine.d.ts +1 -1
  296. package/dist/routing/store.d.ts +1 -1
  297. package/dist/salvage-envelope.d.ts +1 -1
  298. package/dist/{scope-profiles-BVf3DZ7z.d.ts → scope-profiles-C4g6_UdP.d.ts} +1 -1
  299. package/dist/search/embed-helper.d.ts +1 -1
  300. package/dist/search/embed-helper.js +2 -2
  301. package/dist/search/factory.d.ts +1 -1
  302. package/dist/search/factory.js +6 -6
  303. package/dist/search/index.d.ts +1 -1
  304. package/dist/search/index.js +10 -10
  305. package/dist/search/lancedb-backend.d.ts +1 -1
  306. package/dist/search/meilisearch-backend.d.ts +1 -1
  307. package/dist/search/noop-backend.d.ts +1 -1
  308. package/dist/search/orama-backend.d.ts +1 -1
  309. package/dist/search/port.d.ts +1 -1
  310. package/dist/search/remote-backend.d.ts +1 -1
  311. package/dist/{semantic-consolidation-DXLV47y2.d.ts → semantic-consolidation-BrxqnzTW.d.ts} +1 -1
  312. package/dist/semantic-consolidation.d.ts +2 -2
  313. package/dist/semantic-consolidation.js +9 -9
  314. package/dist/semantic-rule-promotion.js +8 -8
  315. package/dist/semantic-rule-verifier.d.ts +1 -1
  316. package/dist/semantic-rule-verifier.js +8 -8
  317. package/dist/{service-DbgPTeMJ.d.ts → service-Bi1JgxdP.d.ts} +2 -2
  318. package/dist/session-observer-bands.d.ts +1 -1
  319. package/dist/session-observer-state.d.ts +1 -1
  320. package/dist/shared-context/manager.d.ts +1 -1
  321. package/dist/shared-context/manager.js +2 -2
  322. package/dist/signal.d.ts +1 -1
  323. package/dist/{storage-DOzTm8wG.d.ts → storage-CcH6yPk2.d.ts} +1 -1
  324. package/dist/storage.d.ts +2 -2
  325. package/dist/storage.js +7 -7
  326. package/dist/summarizer.d.ts +1 -1
  327. package/dist/summarizer.js +3 -3
  328. package/dist/summary-snapshot.d.ts +1 -1
  329. package/dist/temporal-supersession.d.ts +2 -2
  330. package/dist/temporal-timeline-recall.d.ts +1 -1
  331. package/dist/temporal-validity.d.ts +1 -1
  332. package/dist/threading.d.ts +1 -1
  333. package/dist/tier-migration.d.ts +2 -2
  334. package/dist/tier-routing.d.ts +1 -1
  335. package/dist/{tier-stats-XKD7SXYY.js → tier-stats-OPTSBNRH.js} +2 -2
  336. package/dist/topics.d.ts +1 -1
  337. package/dist/transcript.d.ts +1 -1
  338. package/dist/transfer/autodetect.js +1 -1
  339. package/dist/transfer/backup.js +2 -2
  340. package/dist/transfer/capsule-export.js +3 -3
  341. package/dist/transfer/capsule-import.js +2 -2
  342. package/dist/trust-score-stage.d.ts +1 -1
  343. package/dist/trust-score.d.ts +1 -1
  344. package/dist/{types-BA7W-_xy.d.ts → types-Dg0w9ADr.d.ts} +1 -0
  345. package/dist/types.d.ts +1 -1
  346. package/dist/types.js +1 -1
  347. package/dist/utility-runtime.d.ts +1 -1
  348. package/dist/verified-recall.js +8 -8
  349. package/dist/write-envelope.d.ts +1 -1
  350. package/package.json +2 -2
  351. package/src/capabilities.test.ts +1 -0
  352. package/src/capabilities.ts +7 -7
  353. package/src/config.test.ts +5 -0
  354. package/src/config.ts +1 -1
  355. package/src/extraction-source-grounding-helpers.ts +603 -0
  356. package/src/extraction-source-grounding-rules.ts +1031 -0
  357. package/src/extraction-source-grounding.test.ts +2337 -0
  358. package/src/extraction-source-grounding.ts +50 -0
  359. package/src/extraction.ts +120 -15
  360. package/src/storage/entity-canonical-id-migration.ts +151 -23
  361. package/src/types.ts +2 -2
  362. package/dist/chunk-FOCEI3TN.js.map +0 -1
  363. package/dist/chunk-JQ7T5VDC.js.map +0 -1
  364. package/dist/chunk-Q5VJUNXA.js.map +0 -1
  365. package/dist/chunk-TKBDJTXG.js.map +0 -1
  366. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  367. /package/dist/{chunk-GQSMYXKL.js.map → chunk-2AXMQWCN.js.map} +0 -0
  368. /package/dist/{chunk-VYYNBJXH.js.map → chunk-2D7FEUCK.js.map} +0 -0
  369. /package/dist/{chunk-PXQM2HOG.js.map → chunk-2GXM5N5A.js.map} +0 -0
  370. /package/dist/{chunk-JIF3VRKQ.js.map → chunk-35DL7IOI.js.map} +0 -0
  371. /package/dist/{chunk-2H7OEVPO.js.map → chunk-3GD2HFR6.js.map} +0 -0
  372. /package/dist/{chunk-KKBTBUVT.js.map → chunk-3JNDOAQ2.js.map} +0 -0
  373. /package/dist/{chunk-4TFIRMTE.js.map → chunk-4A6YGWQN.js.map} +0 -0
  374. /package/dist/{chunk-IKMAO55B.js.map → chunk-55MDBZLC.js.map} +0 -0
  375. /package/dist/{chunk-RKXZ7P4V.js.map → chunk-5QDRGWT2.js.map} +0 -0
  376. /package/dist/{chunk-IPLYGWQF.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  377. /package/dist/{chunk-ALTP3MFS.js.map → chunk-5ZCUDWD4.js.map} +0 -0
  378. /package/dist/{chunk-B7GROTXD.js.map → chunk-6LKEUCEM.js.map} +0 -0
  379. /package/dist/{chunk-2AJ72VVS.js.map → chunk-7BZOBA5J.js.map} +0 -0
  380. /package/dist/{chunk-44DUJETW.js.map → chunk-7HXCF4RE.js.map} +0 -0
  381. /package/dist/{chunk-WVVK2RFM.js.map → chunk-7L45JFPW.js.map} +0 -0
  382. /package/dist/{chunk-R372P2EH.js.map → chunk-ACXPX4AG.js.map} +0 -0
  383. /package/dist/{chunk-7CPOZH6Y.js.map → chunk-ALSGMEJR.js.map} +0 -0
  384. /package/dist/{chunk-JGUXPJUQ.js.map → chunk-AS7YMSL6.js.map} +0 -0
  385. /package/dist/{chunk-DKQM5Q6Q.js.map → chunk-CW4AGY3G.js.map} +0 -0
  386. /package/dist/{chunk-ZN4UZWMT.js.map → chunk-D2ANTDGO.js.map} +0 -0
  387. /package/dist/{chunk-3UOSVTFR.js.map → chunk-D3LMYTBV.js.map} +0 -0
  388. /package/dist/{chunk-LIHC3T43.js.map → chunk-E5OBR6CJ.js.map} +0 -0
  389. /package/dist/{chunk-XY7QPJDA.js.map → chunk-E6EE5B67.js.map} +0 -0
  390. /package/dist/{chunk-TBMRQZDY.js.map → chunk-EP5BVCRI.js.map} +0 -0
  391. /package/dist/{chunk-MJPV4LBH.js.map → chunk-FUYEVEX7.js.map} +0 -0
  392. /package/dist/{chunk-2BEJ4XCF.js.map → chunk-FZRQZW4H.js.map} +0 -0
  393. /package/dist/{chunk-X6ROIHFE.js.map → chunk-G5R3D5UP.js.map} +0 -0
  394. /package/dist/{chunk-2FYNLDKJ.js.map → chunk-GAWOEQEQ.js.map} +0 -0
  395. /package/dist/{chunk-QH6CS6XJ.js.map → chunk-H24WNPA2.js.map} +0 -0
  396. /package/dist/{chunk-VFNI3RPT.js.map → chunk-HKJCMOT6.js.map} +0 -0
  397. /package/dist/{chunk-EZWWCN7I.js.map → chunk-IAEAFLF2.js.map} +0 -0
  398. /package/dist/{chunk-NBNDVNJ2.js.map → chunk-IGPEJVBY.js.map} +0 -0
  399. /package/dist/{chunk-MQVINOJQ.js.map → chunk-IYZ5K7MU.js.map} +0 -0
  400. /package/dist/{chunk-2TQ2UFKH.js.map → chunk-JP3YPDAW.js.map} +0 -0
  401. /package/dist/{chunk-P2CLYN6H.js.map → chunk-K5GB36ME.js.map} +0 -0
  402. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  403. /package/dist/{chunk-FBZTWUK5.js.map → chunk-OFHFH655.js.map} +0 -0
  404. /package/dist/{chunk-GJPCP5CA.js.map → chunk-OP6F6L3S.js.map} +0 -0
  405. /package/dist/{chunk-FGBJBYWP.js.map → chunk-OVRQLAYR.js.map} +0 -0
  406. /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
  407. /package/dist/{chunk-3BSJBIZ3.js.map → chunk-OYJKSZIQ.js.map} +0 -0
  408. /package/dist/{chunk-UR5SIN7H.js.map → chunk-PBUZNGMX.js.map} +0 -0
  409. /package/dist/{chunk-P2OZKKYP.js.map → chunk-PHWUFPCO.js.map} +0 -0
  410. /package/dist/{chunk-Q6YJW6KE.js.map → chunk-PKRIQL3V.js.map} +0 -0
  411. /package/dist/{chunk-BR4UFMLO.js.map → chunk-PTSNLEXK.js.map} +0 -0
  412. /package/dist/{chunk-AHFZXUZM.js.map → chunk-QDKK63Y7.js.map} +0 -0
  413. /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
  414. /package/dist/{chunk-FCCMFVS6.js.map → chunk-RPSYDM6C.js.map} +0 -0
  415. /package/dist/{chunk-MWTMTW2T.js.map → chunk-SH6YO3LT.js.map} +0 -0
  416. /package/dist/{chunk-IYT632D5.js.map → chunk-UBKEQOTD.js.map} +0 -0
  417. /package/dist/{chunk-BJJAX3IZ.js.map → chunk-UTRO5UJU.js.map} +0 -0
  418. /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
  419. /package/dist/{chunk-S24E4MBQ.js.map → chunk-VSURVXKY.js.map} +0 -0
  420. /package/dist/{chunk-YOBNCD3Z.js.map → chunk-WRFBW2TT.js.map} +0 -0
  421. /package/dist/{chunk-MXJ3VP6S.js.map → chunk-WU7TTVOD.js.map} +0 -0
  422. /package/dist/{chunk-EG64LXKL.js.map → chunk-XOZ4ALGB.js.map} +0 -0
  423. /package/dist/{chunk-2PHX3I5C.js.map → chunk-Z54EM5YZ.js.map} +0 -0
  424. /package/dist/{contradiction-scan-HMF7CNKD.js.map → contradiction-scan-HYLIRMJ2.js.map} +0 -0
  425. /package/dist/{first-start-migration-BKNGOFED.js.map → first-start-migration-F2QJD66E.js.map} +0 -0
  426. /package/dist/{tier-stats-XKD7SXYY.js.map → tier-stats-OPTSBNRH.js.map} +0 -0
@@ -0,0 +1,50 @@
1
+ import type { ExtractionResult } from "./types.js";
2
+ import { delinearize } from "./delinearize.js";
3
+ import {
4
+ applyExtractionSourceGrounding as applyGroundingRules,
5
+ filterExtractionResultBySource as filterGroundingRules,
6
+ } from "./extraction-source-grounding-rules.js";
7
+ import type {
8
+ ExtractionGroundingRoleSources,
9
+ ExtractionSourceGroundingOptions,
10
+ } from "./extraction-source-grounding-rules.js";
11
+
12
+ export type { ExtractionGroundingRoleSources, ExtractionSourceGroundingOptions } from "./extraction-source-grounding-rules.js";
13
+
14
+ export function applyExtractionSourceGrounding(
15
+ result: ExtractionResult,
16
+ sourceText: string,
17
+ assertionSourceText: string = sourceText,
18
+ roleAssertionSources: ExtractionGroundingRoleSources | undefined,
19
+ messageTimestamp: Date | undefined,
20
+ options: ExtractionSourceGroundingOptions,
21
+ ): ExtractionResult {
22
+ const sourceForGrounding = (source: string | undefined): string | undefined =>
23
+ source === undefined || !options.anchorTemporalExpressions
24
+ ? source
25
+ : delinearize(source, result.entities, messageTimestamp ?? new Date());
26
+ const groundedRoleSources = roleAssertionSources === undefined
27
+ ? undefined
28
+ : {
29
+ profile: sourceForGrounding(roleAssertionSources.profile),
30
+ identity: sourceForGrounding(roleAssertionSources.identity),
31
+ };
32
+ return applyGroundingRules(
33
+ result,
34
+ sourceForGrounding(sourceText) ?? sourceText,
35
+ sourceForGrounding(assertionSourceText) ?? assertionSourceText,
36
+ groundedRoleSources,
37
+ messageTimestamp,
38
+ options,
39
+ );
40
+ }
41
+
42
+ export function filterExtractionResultBySource(
43
+ result: ExtractionResult,
44
+ source: string,
45
+ assertionSource?: string,
46
+ roleAssertionSources?: ExtractionGroundingRoleSources,
47
+ eventTimeNormalizer?: (eventTime: string) => string,
48
+ ): ExtractionResult {
49
+ return filterGroundingRules(result, source, assertionSource, roleAssertionSources, eventTimeNormalizer);
50
+ }
package/src/extraction.ts CHANGED
@@ -40,6 +40,7 @@ import { normalizeProcedureSteps } from "./procedural/procedure-types.js";
40
40
  import { normalizeReasoningTrace } from "./reasoning-trace-types.js";
41
41
  import { looksLikeMechanicalTelemetryTranscript } from "./telemetry-transcript.js";
42
42
  import { buildFactProvenance, type ProvenanceTurnInput } from "./provenance.js";
43
+ import { applyExtractionSourceGrounding, type ExtractionGroundingRoleSources } from "./extraction-source-grounding.js";
43
44
  import { isMemoryCategory } from "./write-envelope.js";
44
45
  import { classifyExtractionThrownError, classifyFallbackParseFailure } from "./extraction-error-classification.js";
45
46
  export { classifyExtractionThrownError, classifyFallbackParseFailure } from "./extraction-error-classification.js";
@@ -656,6 +657,10 @@ export class ExtractionEngine {
656
657
  private async applyProactiveQuestionPass(
657
658
  conversation: string,
658
659
  base: ExtractionResult,
660
+ groundingSource: string,
661
+ assertionSource: string,
662
+ messageTimestamp?: Date,
663
+ roleAssertionSources?: ExtractionGroundingRoleSources,
659
664
  ): Promise<ExtractionResult> {
660
665
  if (!resolvePipelineProcessingCapabilities(this.config).proactiveExtraction) return base;
661
666
  const maxAdditional = Math.max(0, Math.floor(this.config.maxProactiveQuestionsPerExtraction));
@@ -670,8 +675,16 @@ export class ExtractionEngine {
670
675
  proactive,
671
676
  maxAdditional,
672
677
  );
673
- if (!this.hasExtractionOutputs(proactiveAdditions)) return base;
674
- return this.mergeProactiveExtractionPass(base, proactiveAdditions, maxAdditional);
678
+ const sanitizedAdditions = this.sanitizeExtractionResult(proactiveAdditions, messageTimestamp);
679
+ const groundedAdditions = this.applySourceGrounding(
680
+ sanitizedAdditions,
681
+ groundingSource,
682
+ assertionSource,
683
+ roleAssertionSources,
684
+ messageTimestamp,
685
+ );
686
+ if (!this.hasExtractionOutputs(groundedAdditions)) return base;
687
+ return this.mergeProactiveExtractionPass(base, groundedAdditions, maxAdditional);
675
688
  } catch (err) {
676
689
  log.debug(`proactive extraction question pass failed (ignored): ${err}`);
677
690
  return base;
@@ -875,7 +888,7 @@ export class ExtractionEngine {
875
888
  if (localResponse?.content) {
876
889
  const parsed = this.parseProactiveExtractionResultFromText(localResponse.content.trim());
877
890
  if (parsed) {
878
- return this.sanitizeExtractionResult(parsed);
891
+ return parsed;
879
892
  }
880
893
  }
881
894
  if (!this.config.localLlmFallback) {
@@ -906,12 +919,10 @@ export class ExtractionEngine {
906
919
  if (!fallbackResult) {
907
920
  return { facts: [], profileUpdates: [], entities: [], questions: [] };
908
921
  }
909
- return this.sanitizeExtractionResult(
910
- this.normalizeExtractionResultPayload({
911
- ...fallbackResult,
912
- questions: [],
913
- }),
914
- );
922
+ return this.normalizeExtractionResultPayload({
923
+ ...fallbackResult,
924
+ questions: [],
925
+ });
915
926
  }
916
927
 
917
928
  private mergeProactiveExtractionPass(
@@ -1133,6 +1144,40 @@ export class ExtractionEngine {
1133
1144
  return { ...result, facts };
1134
1145
  }
1135
1146
 
1147
+ private applySourceGrounding(
1148
+ result: ExtractionResult,
1149
+ sourceText: string,
1150
+ assertionSourceText: string = sourceText,
1151
+ roleAssertionSources?: ExtractionGroundingRoleSources,
1152
+ messageTimestamp?: Date,
1153
+ ): ExtractionResult {
1154
+ const capabilities = resolvePipelineProcessingCapabilities(this.config);
1155
+ return applyExtractionSourceGrounding(
1156
+ result,
1157
+ sourceText,
1158
+ assertionSourceText,
1159
+ roleAssertionSources,
1160
+ messageTimestamp,
1161
+ {
1162
+ sourceGrounding: capabilities.sourceGrounding,
1163
+ anchorTemporalExpressions: capabilities.delinearize,
1164
+ },
1165
+ );
1166
+ }
1167
+
1168
+ private finalizeExtractionResult(
1169
+ result: ExtractionResult,
1170
+ turns: ReadonlyArray<{
1171
+ content: string;
1172
+ sessionKey?: string;
1173
+ logicalSessionKey?: string;
1174
+ timestamp: string;
1175
+ turnFingerprint?: string;
1176
+ }>,
1177
+ ): ExtractionResult {
1178
+ return this.attachProvenanceToResult(result, turns);
1179
+ }
1180
+
1136
1181
  async extract(turns: BufferTurn[], existingEntities?: string[]): Promise<ExtractionResult> {
1137
1182
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
1138
1183
 
@@ -1158,6 +1203,24 @@ export class ExtractionEngine {
1158
1203
  return `[${roleLabel}] ${t.content}`;
1159
1204
  })
1160
1205
  .join("\n\n");
1206
+
1207
+ const groundingSource = boundedTurns
1208
+ .map((turn) => turn.content)
1209
+ .join("\n\n");
1210
+ const assertionSource = boundedTurns
1211
+ .filter((turn) => turn.extractionContextOnly !== true)
1212
+ .map((turn) => turn.content)
1213
+ .join("\n\n");
1214
+ const roleAssertionSources: ExtractionGroundingRoleSources = {
1215
+ profile: boundedTurns
1216
+ .filter((turn) => turn.role === "user" && turn.extractionContextOnly !== true)
1217
+ .map((turn) => turn.content)
1218
+ .join("\n\n"),
1219
+ identity: boundedTurns
1220
+ .filter((turn) => turn.role === "assistant" && turn.extractionContextOnly !== true)
1221
+ .map((turn) => turn.content)
1222
+ .join("\n\n"),
1223
+ };
1161
1224
  if (conversation.trim().length === 0) {
1162
1225
  log.debug("extraction skipped — conversation only contained non-memory work-layer context");
1163
1226
  return { facts: [], profileUpdates: [], entities: [], questions: [] };
@@ -1213,8 +1276,22 @@ export class ExtractionEngine {
1213
1276
  this.emit({ kind: "llm_end", traceId, model: this.config.localLlmModel, operation: "extraction", durationMs });
1214
1277
  log.debug(`extraction: used local LLM — ${localResult.facts.length} facts, ${localResult.entities.length} entities`);
1215
1278
  const sanitized = this.sanitizeExtractionResult(localResult, messageTimestamp);
1216
- const finalResult = await this.applyProactiveQuestionPass(conversation, sanitized);
1217
- return this.attachProvenanceToResult(finalResult, boundedTurns);
1279
+ const grounded = this.applySourceGrounding(
1280
+ sanitized,
1281
+ groundingSource,
1282
+ assertionSource,
1283
+ roleAssertionSources,
1284
+ messageTimestamp,
1285
+ );
1286
+ const finalResult = await this.applyProactiveQuestionPass(
1287
+ conversation,
1288
+ grounded,
1289
+ groundingSource,
1290
+ assertionSource,
1291
+ messageTimestamp,
1292
+ roleAssertionSources,
1293
+ );
1294
+ return this.finalizeExtractionResult(finalResult, boundedTurns);
1218
1295
  }
1219
1296
  // Local failed, fall back if allowed
1220
1297
  if (!this.config.localLlmFallback) {
@@ -1260,8 +1337,22 @@ export class ExtractionEngine {
1260
1337
  this.emit({ kind: "llm_end", traceId, model: this.config.model, operation: "extraction", durationMs });
1261
1338
  log.debug(`extraction: used direct client (${this.config.model}) — ${directResult.facts.length} facts, ${directResult.entities.length} entities`);
1262
1339
  const sanitized = this.sanitizeExtractionResult(directResult, messageTimestamp);
1263
- const finalResult = await this.applyProactiveQuestionPass(conversation, sanitized);
1264
- return this.attachProvenanceToResult(finalResult, boundedTurns);
1340
+ const grounded = this.applySourceGrounding(
1341
+ sanitized,
1342
+ groundingSource,
1343
+ assertionSource,
1344
+ roleAssertionSources,
1345
+ messageTimestamp,
1346
+ );
1347
+ const finalResult = await this.applyProactiveQuestionPass(
1348
+ conversation,
1349
+ grounded,
1350
+ groundingSource,
1351
+ assertionSource,
1352
+ messageTimestamp,
1353
+ roleAssertionSources,
1354
+ );
1355
+ return this.finalizeExtractionResult(finalResult, boundedTurns);
1265
1356
  }
1266
1357
  // Emit error event so Opik sees the direct client failure before fallback.
1267
1358
  // Wrapped in try/catch so a subscriber error doesn't break the fallback path.
@@ -1345,8 +1436,22 @@ export class ExtractionEngine {
1345
1436
  );
1346
1437
  const normalized = this.normalizeExtractionResultPayload(result);
1347
1438
  const sanitized = this.sanitizeExtractionResult(normalized, messageTimestamp);
1348
- const finalResult = await this.applyProactiveQuestionPass(conversation, sanitized);
1349
- return this.attachProvenanceToResult(finalResult, boundedTurns);
1439
+ const grounded = this.applySourceGrounding(
1440
+ sanitized,
1441
+ groundingSource,
1442
+ assertionSource,
1443
+ roleAssertionSources,
1444
+ messageTimestamp,
1445
+ );
1446
+ const finalResult = await this.applyProactiveQuestionPass(
1447
+ conversation,
1448
+ grounded,
1449
+ groundingSource,
1450
+ assertionSource,
1451
+ messageTimestamp,
1452
+ roleAssertionSources,
1453
+ );
1454
+ return this.finalizeExtractionResult(finalResult, boundedTurns);
1350
1455
  }
1351
1456
 
1352
1457
  this.emit({
@@ -15,6 +15,7 @@ import { readFileSync } from "node:fs";
15
15
  import { z } from "zod";
16
16
  import { computeSupersessionKey, normalizeSupersessionKey } from "../temporal-supersession.js";
17
17
  import type { EntityFile, MemoryFile } from "../types.js";
18
+ import { log } from "../logger.js";
18
19
  import { isErrnoCode } from "../utils/errno.js";
19
20
  import { withHeldFileLock } from "../utils/serialize-mutations.js";
20
21
  import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
@@ -69,6 +70,14 @@ const EntityCanonicalIdMigrationStateSchema = z.object({
69
70
  version: z.literal(ENTITY_CANONICAL_ID_MIGRATION_VERSION),
70
71
  complete: z.boolean(),
71
72
  mappings: z.record(z.string().min(1)),
73
+ /**
74
+ * Pairs the migration refused to resolve, PARKED rather than dropped.
75
+ * Deleting the record would strand the collision: once an operator removes
76
+ * the legacy file, no later scan can rediscover the mapping, so references
77
+ * still naming the legacy id would never be rewritten. Optional so a journal
78
+ * written by an older build still parses.
79
+ */
80
+ blocked: z.record(z.string().min(1)).optional(),
72
81
  });
73
82
 
74
83
  type EntityCanonicalIdMigrationState = z.infer<typeof EntityCanonicalIdMigrationStateSchema>;
@@ -348,12 +357,28 @@ async function readSafeEntityEntries(entitiesDir: string): Promise<string[]> {
348
357
  return entries;
349
358
  }
350
359
 
360
+ /**
361
+ * Legacy ids the migration cannot resolve on its own, mapped to the canonical
362
+ * id they collide with. Two entity files describing one entity is an ORDINARY
363
+ * operator state, and picking a winner would silently drop whichever side lost.
364
+ * So the pair is skipped and reported: reads of the legacy id keep working
365
+ * exactly as they did before the migration ran.
366
+ */
367
+ export type BlockedEntityPairs = Map<string, string>;
368
+
351
369
  async function discoverMappings(
352
370
  deps: EntityCanonicalIdMigrationDependencies,
353
371
  knownMappings: Readonly<Record<string, string>> = {},
372
+ blocked: BlockedEntityPairs = new Map(),
354
373
  ): Promise<Record<string, string>> {
355
374
  const mappings: Record<string, string> = {};
356
- const canonicalOwners = new Map<string, string>();
375
+ const canonicalOwners = new Map<string, string[]>();
376
+ // Blocks describe THIS scan of the directory, so they are rebuilt per pass.
377
+ // Accumulating them across a run would let a collision another writer has
378
+ // since resolved keep pruning its now-valid mapping: the entity file gets
379
+ // renamed while the pruned mapping skips the reference rewrite, stranding
380
+ // memories on a filename that no longer exists.
381
+ blocked.clear();
357
382
  const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
358
383
  for (const entry of entityEntries) {
359
384
  if (!entry.endsWith(".md")) continue;
@@ -386,18 +411,23 @@ async function discoverMappings(
386
411
  if (canonicalExists) {
387
412
  const canonicalContent = await deps.readStorageSecureFile(canonicalPath);
388
413
  if (entityContent !== canonicalContent) {
389
- throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
414
+ blocked.set(legacyId, canonicalId);
415
+ continue;
390
416
  }
391
417
  }
392
- const previousOwner = canonicalOwners.get(canonicalId);
393
- if (previousOwner !== undefined && previousOwner !== legacyId) {
394
- throw new Error(
395
- `Cannot migrate legacy entity ids ${previousOwner} and ${legacyId}: both normalize to ${canonicalId}.`,
396
- );
397
- }
398
- canonicalOwners.set(canonicalId, legacyId);
418
+ canonicalOwners.set(canonicalId, [...(canonicalOwners.get(canonicalId) ?? []), legacyId]);
399
419
  mappings[legacyId] = canonicalId;
400
420
  }
421
+ // A canonical id claimed by more than one legacy file has no non-arbitrary
422
+ // winner, and readdir order is not stable (§6) - so the "winner" would differ
423
+ // between hosts reading identical data. Block every claimant instead.
424
+ for (const [canonicalId, claimants] of canonicalOwners) {
425
+ if (claimants.length < 2) continue;
426
+ for (const legacyId of claimants) {
427
+ blocked.set(legacyId, canonicalId);
428
+ delete mappings[legacyId];
429
+ }
430
+ }
401
431
  return mappings;
402
432
  }
403
433
 
@@ -645,7 +675,19 @@ function mergeDiscoveredMappings(
645
675
  for (const [legacyId, canonicalId] of Object.entries(discovered)) {
646
676
  const previousMapping = merged[legacyId];
647
677
  if (previousMapping !== undefined && previousMapping !== canonicalId) {
648
- throw new Error(`Legacy entity id ${legacyId} changed canonical target during migration.`);
678
+ // A -> B collapses to A -> C once B -> C exists, so a rescan that still
679
+ // reads A -> B off disk is reporting the same chain, not a new target.
680
+ // Only a target the chain cannot reach is a real conflict.
681
+ let hop: string | undefined = canonicalId;
682
+ const seen = new Set<string>();
683
+ while (hop !== undefined && hop !== previousMapping && !seen.has(hop)) {
684
+ seen.add(hop);
685
+ hop = merged[hop];
686
+ }
687
+ if (hop !== previousMapping) {
688
+ throw new Error(`Legacy entity id ${legacyId} changed canonical target during migration.`);
689
+ }
690
+ continue;
649
691
  }
650
692
  if (previousMapping === undefined && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
651
693
  const previousOwner = canonicalOwners.get(canonicalId);
@@ -681,6 +723,8 @@ function collapseMappings(mappings: Readonly<Record<string, string>>): Record<st
681
723
  type EntityFileMigrationResult = {
682
724
  deferred: boolean;
683
725
  progressed: boolean;
726
+ /** The pair collided on content; skipped and reported, never migrated. */
727
+ blocked?: boolean;
684
728
  };
685
729
 
686
730
  async function migrateEntityFilePair(
@@ -711,7 +755,9 @@ async function migrateEntityFilePair(
711
755
  deps.isEncryptedStorageFile(canonicalPath),
712
756
  ]);
713
757
  if (legacyContent !== canonicalContent) {
714
- throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
758
+ // A mapping persisted by an older build, or a file changed since
759
+ // discovery. Same verdict as discovery: skip the pair, keep both files.
760
+ return { deferred: false, progressed: false, blocked: true };
715
761
  }
716
762
  if (legacyEncrypted && !canonicalEncrypted) {
717
763
  if (!(await refreshMigrationLock()) || !(await refreshEntityLock())) {
@@ -792,6 +838,77 @@ export async function migrateLegacyEntityCanonicalIds(
792
838
  mappings: {},
793
839
  };
794
840
  }
841
+ const blocked: BlockedEntityPairs = new Map();
842
+ // ONE aggregated line per run, not one per pair per restart: this used to
843
+ // abort the daemon, so the operator needs the whole list and the remedy.
844
+ const finish = (): Promise<string | undefined> | string | undefined => {
845
+ if (blocked.size > 0) {
846
+ const pairs = [...blocked].map(([legacyId, canonicalId]) => `${legacyId} -> ${canonicalId}`).join(", ");
847
+ log.warn(
848
+ `entity canonical-id migration skipped ${blocked.size} unresolvable pair(s): ${pairs}. `
849
+ + "Both files were kept and the legacy id still resolves; merge or delete one side to migrate it.",
850
+ );
851
+ }
852
+ return deps.readMigrationFingerprint?.();
853
+ };
854
+ /**
855
+ * Drop blocked pairs from the working set. Discovery only refuses to
856
+ * ADD them; a mapping persisted by an earlier run would otherwise still
857
+ * be applied - migrating one claimant and rewriting every reference onto
858
+ * the canonical file, i.e. picking the winner this fix exists to avoid,
859
+ * off stale state rather than what is on disk.
860
+ */
861
+ /** @returns true when a park was promoted back into the mapping set. */
862
+ const pruneBlocked = async (): Promise<boolean> => {
863
+ const current = state;
864
+ if (!current) return false;
865
+ // THIS scan's verdict wins over the journal: normalization can change
866
+ // between runs, so a stale parked target would otherwise be promoted
867
+ // later and rewrite references onto an id that does not exist.
868
+ let revived = false;
869
+ const parked: Record<string, string> = { ...(current.blocked ?? {}) };
870
+ const active: Record<string, string> = {};
871
+ for (const [legacyId, canonicalId] of Object.entries(current.mappings)) {
872
+ if (!blocked.has(legacyId)) active[legacyId] = canonicalId;
873
+ }
874
+ for (const [legacyId, canonicalId] of blocked) parked[legacyId] = canonicalId;
875
+ // A parked pair whose legacy file is gone was resolved by keeping the
876
+ // canonical side. The rename is moot; the reference rewrite is not, and
877
+ // this record is the only thing that can still perform it.
878
+ // A park survives ONLY while this scan re-establishes the collision.
879
+ // Anything else - the scan found a real migration, or found the source
880
+ // needs none (already canonical under a newer normalization) - makes
881
+ // the record obsolete, and keeping it lets a later deletion promote a
882
+ // target the entity never occupied.
883
+ for (const [legacyId, canonicalId] of Object.entries(parked)) {
884
+ if (blocked.has(legacyId)) continue;
885
+ delete parked[legacyId];
886
+ if (active[legacyId] !== undefined) continue;
887
+ const legacyPath = deps.resolveEntityFilePath(legacyId);
888
+ if (legacyPath !== null && (await fileExists(legacyPath))) continue;
889
+ // Source gone: the rename is moot, but references still name it and
890
+ // this record is the only thing that can still rewrite them.
891
+ active[legacyId] = canonicalId;
892
+ revived = true;
893
+ }
894
+ // Reviving a whole chain at once yields A -> B -> C, and each rewrite
895
+ // surface makes a different number of passes over it - so collapse
896
+ // transitively before anything consumes the set.
897
+ const collapsed = collapseMappings(active);
898
+ // Parked targets follow ACTIVE moves only: hopping over a still-blocked
899
+ // link would jump to an id the migration has not been allowed to reach.
900
+ for (const [legacyId, canonicalId] of Object.entries(parked)) {
901
+ const moved = collapsed[canonicalId];
902
+ if (moved !== undefined && moved !== legacyId) parked[legacyId] = moved;
903
+ }
904
+ const same = (a: Record<string, string>, b: Record<string, string>): boolean =>
905
+ Object.keys(a).length === Object.keys(b).length
906
+ && Object.entries(a).every(([key, value]) => b[key] === value);
907
+ if (same(collapsed, current.mappings) && same(parked, current.blocked ?? {})) return revived;
908
+ state = { ...current, mappings: collapsed, blocked: parked };
909
+ await writeState(deps, state);
910
+ return revived;
911
+ };
795
912
  const previousMappings = state.mappings;
796
913
  const collapsedMappings = collapseMappings(previousMappings);
797
914
  const mappingsChanged =
@@ -804,11 +921,12 @@ export async function migrateLegacyEntityCanonicalIds(
804
921
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
805
922
  const discoveredBefore = rejectMappingCycles(
806
923
  state.mappings,
807
- await discoverMappings(deps, state.mappings),
924
+ await discoverMappings(deps, state.mappings, blocked),
808
925
  );
926
+ await pruneBlocked();
809
927
  const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
810
928
  if (state.complete && Object.keys(discoveredBefore).length === 0 && !mappingsChanged) {
811
- if (Object.keys(state.mappings).length === 0) return deps.readMigrationFingerprint?.();
929
+ if (Object.keys(state.mappings).length === 0) return finish();
812
930
  const rewroteColdMemory = await rewriteKnownReferences(
813
931
  deps,
814
932
  state.mappings,
@@ -818,7 +936,7 @@ export async function migrateLegacyEntityCanonicalIds(
818
936
  deps.invalidateAllMemoriesCache();
819
937
  if (rewroteColdMemory) deps.invalidateColdMemoriesCache();
820
938
  deps.bumpMemoryStatusVersion();
821
- return deps.readMigrationFingerprint?.();
939
+ return finish();
822
940
  }
823
941
  if (
824
942
  state.complete
@@ -832,11 +950,16 @@ export async function migrateLegacyEntityCanonicalIds(
832
950
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
833
951
  const discoveredAfter = rejectMappingCycles(
834
952
  state.mappings,
835
- await discoverMappings(deps, state.mappings),
953
+ await discoverMappings(deps, state.mappings, blocked),
836
954
  );
837
- if (Object.keys(discoveredAfter).length === 0) {
955
+ // Reconcile before declaring completion: this rescan can resolve a
956
+ // park (another writer removed the legacy file), and completing
957
+ // without promoting it strands its references behind a fingerprint
958
+ // that already reflects the deletion - so no later run revisits it.
959
+ const revivedInRescan = await pruneBlocked();
960
+ if (Object.keys(discoveredAfter).length === 0 && !revivedInRescan) {
838
961
  await writeState(deps, { ...state, complete: true });
839
- return deps.readMigrationFingerprint?.();
962
+ return finish();
840
963
  }
841
964
  state = {
842
965
  ...state,
@@ -857,9 +980,8 @@ export async function migrateLegacyEntityCanonicalIds(
857
980
  canonicalId,
858
981
  () => lock.refresh(),
859
982
  );
860
- if (result.deferred) {
861
- deferredMappings.push([legacyId, canonicalId]);
862
- }
983
+ if (result.blocked) blocked.set(legacyId, canonicalId);
984
+ else if (result.deferred) deferredMappings.push([legacyId, canonicalId]);
863
985
  progressed ||= result.progressed;
864
986
  }
865
987
  if (deferredMappings.length === 0) break;
@@ -871,6 +993,7 @@ export async function migrateLegacyEntityCanonicalIds(
871
993
  }
872
994
  pendingMappings = deferredMappings;
873
995
  }
996
+ await pruneBlocked();
874
997
 
875
998
  const rewroteColdMemory = await rewriteKnownReferences(
876
999
  deps,
@@ -885,11 +1008,16 @@ export async function migrateLegacyEntityCanonicalIds(
885
1008
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
886
1009
  const discoveredAfter = rejectMappingCycles(
887
1010
  state.mappings,
888
- await discoverMappings(deps, state.mappings),
1011
+ await discoverMappings(deps, state.mappings, blocked),
889
1012
  );
890
- if (Object.keys(discoveredAfter).length === 0) {
1013
+ // A park resolved after the rewrite pass is promoted here, and a
1014
+ // promotion still has to be APPLIED. Completing on `discoveredAfter`
1015
+ // alone fingerprints the post-deletion corpus, so the runner never
1016
+ // retries and those references stay stranded.
1017
+ const revivedAfterRewrite = await pruneBlocked();
1018
+ if (Object.keys(discoveredAfter).length === 0 && !revivedAfterRewrite) {
891
1019
  await writeState(deps, { ...state, complete: true });
892
- return deps.readMigrationFingerprint?.();
1020
+ return finish();
893
1021
  }
894
1022
  state = {
895
1023
  ...state,
package/src/types.ts CHANGED
@@ -1556,8 +1556,8 @@ export interface PluginConfig extends BoundedJsonlStateConfig {
1556
1556
  profilingStorageDir: string;
1557
1557
  /** Maximum number of trace files to keep (rolling window). */
1558
1558
  profilingMaxTraces: number;
1559
- // Extraction stability guards (P0/P1)
1560
- extractionDedupeEnabled: boolean;
1559
+ // Extraction stability guards (P0/P1).
1560
+ extractionDedupeEnabled: boolean; extractionSourceGroundingEnabled: boolean;
1561
1561
  extractionDedupeWindowMs: number;
1562
1562
  extractionMinChars: number;
1563
1563
  extractionMinUserTurns: number;