@remnic/core 9.3.741 → 9.3.743

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 (286) hide show
  1. package/dist/access-boundary.d.ts +5 -5
  2. package/dist/access-boundary.js +10 -10
  3. package/dist/access-cli.js +32 -32
  4. package/dist/access-http.d.ts +5 -5
  5. package/dist/access-http.js +15 -15
  6. package/dist/access-mcp.d.ts +5 -5
  7. package/dist/access-mcp.js +14 -14
  8. package/dist/access-operations-batch.js +12 -12
  9. package/dist/access-operations.d.ts +5 -5
  10. package/dist/access-operations.js +13 -13
  11. package/dist/{access-service-Cbk-Kv_A.d.ts → access-service-BeW5GOg1.d.ts} +3 -3
  12. package/dist/access-service.d.ts +5 -5
  13. package/dist/access-service.js +9 -9
  14. package/dist/access-surface-catalog.d.ts +5 -5
  15. package/dist/action-confidence.d.ts +1 -1
  16. package/dist/active-memory-bridge.d.ts +1 -1
  17. package/dist/active-memory-bridge.js +3 -3
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/{auto-sync-G3V5AN4C.js → auto-sync-XHSKKQAH.js} +2 -2
  20. package/dist/behavior-learner.d.ts +1 -1
  21. package/dist/behavior-signals.d.ts +1 -1
  22. package/dist/bootstrap.d.ts +4 -4
  23. package/dist/briefing.d.ts +1 -1
  24. package/dist/buffer-surprise-report.d.ts +1 -1
  25. package/dist/buffer.d.ts +1 -1
  26. package/dist/buffer.js +2 -2
  27. package/dist/calibration.d.ts +1 -1
  28. package/dist/capabilities.d.ts +10 -5
  29. package/dist/capabilities.js +1 -1
  30. package/dist/{catalog-_Bap6vfD.d.ts → catalog-CX0CjOaf.d.ts} +1 -1
  31. package/dist/causal-behavior.d.ts +1 -1
  32. package/dist/causal-consolidation.d.ts +1 -1
  33. package/dist/causal-consolidation.js +2 -2
  34. package/dist/causal-trajectory-graph.d.ts +1 -1
  35. package/dist/{chunk-X5PMDVY4.js → chunk-3EA5LIFJ.js} +4 -4
  36. package/dist/{chunk-YNHRWFAP.js → chunk-4DLFJJOQ.js} +2 -2
  37. package/dist/{chunk-WIMKOTNY.js → chunk-5QANTTY2.js} +2 -2
  38. package/dist/{chunk-QCO2QFLZ.js → chunk-5UNSGRCR.js} +7 -6
  39. package/dist/{chunk-QCO2QFLZ.js.map → chunk-5UNSGRCR.js.map} +1 -1
  40. package/dist/{chunk-Y6PNYJVO.js → chunk-A2KKLCOS.js} +2 -2
  41. package/dist/{chunk-O4IWVWSW.js → chunk-AVBT5WEW.js} +3 -3
  42. package/dist/{chunk-M5KLYHHI.js → chunk-BYLC4DKI.js} +2 -2
  43. package/dist/{chunk-OZECYVGI.js → chunk-C7LDPZJJ.js} +6 -4
  44. package/dist/{chunk-OZECYVGI.js.map → chunk-C7LDPZJJ.js.map} +1 -1
  45. package/dist/{chunk-UOVDO6TC.js → chunk-CHELXDTO.js} +3 -3
  46. package/dist/{chunk-TQQN64J2.js → chunk-DBSMLRTO.js} +2 -2
  47. package/dist/{chunk-4J53ZVPQ.js → chunk-DYK27X7V.js} +3 -3
  48. package/dist/{chunk-K2N6WIZM.js → chunk-E7RGJQWP.js} +2 -2
  49. package/dist/{chunk-M4WI23X3.js → chunk-EEKDRAWX.js} +2 -2
  50. package/dist/{chunk-H3WSZWHK.js → chunk-G5FP7VSQ.js} +13 -12
  51. package/dist/chunk-G5FP7VSQ.js.map +1 -0
  52. package/dist/{chunk-BE6NEQLF.js → chunk-HAZVVOYT.js} +3 -3
  53. package/dist/{chunk-OT5K26NG.js → chunk-HM6UJPPO.js} +2 -2
  54. package/dist/{chunk-PI4JHLDD.js → chunk-IP5SANO2.js} +2 -2
  55. package/dist/{chunk-WHEF76BQ.js → chunk-JRZV3767.js} +2 -2
  56. package/dist/{chunk-OS5RKJOH.js → chunk-JZ7P26GF.js} +2 -2
  57. package/dist/{chunk-Y62QPRKV.js → chunk-K5LLP4CY.js} +2 -2
  58. package/dist/{chunk-C3Z5YJSM.js → chunk-LOPZ2DWR.js} +2 -2
  59. package/dist/{chunk-BJPL5WAL.js → chunk-MXDG6SRH.js} +3 -3
  60. package/dist/{chunk-UYYSOMS2.js → chunk-NBP3YHHS.js} +4 -4
  61. package/dist/{chunk-USHVHI6J.js → chunk-NNL4LJAD.js} +3 -3
  62. package/dist/{chunk-GPX5E36D.js → chunk-OSMBC3JU.js} +2 -2
  63. package/dist/{chunk-OUSOMUFV.js → chunk-PE6XR4GG.js} +2 -2
  64. package/dist/{chunk-DGVM5SFL.js → chunk-PHRLJFWZ.js} +3 -2
  65. package/dist/{chunk-DGVM5SFL.js.map → chunk-PHRLJFWZ.js.map} +1 -1
  66. package/dist/{chunk-CMPXLMC3.js → chunk-PI23H7FV.js} +3 -3
  67. package/dist/{chunk-WGDE2TJP.js → chunk-QOGXUNWL.js} +4 -4
  68. package/dist/{chunk-ELL5VYXC.js → chunk-RNWWAS5V.js} +3 -3
  69. package/dist/{chunk-LD6A7XG5.js → chunk-TQPSOTC7.js} +7 -7
  70. package/dist/{chunk-AX4TRSRE.js → chunk-U5WVRMCA.js} +2 -2
  71. package/dist/{chunk-773DPI6T.js → chunk-V5RVMULT.js} +11 -8
  72. package/dist/chunk-V5RVMULT.js.map +1 -0
  73. package/dist/{chunk-DBVBV2RF.js → chunk-VE54E6RP.js} +4 -4
  74. package/dist/{chunk-VC7QELR6.js → chunk-VO4VARZL.js} +1054 -869
  75. package/dist/chunk-VO4VARZL.js.map +1 -0
  76. package/dist/{chunk-G7Q4D2G3.js → chunk-VSF7AAGE.js} +1 -3
  77. package/dist/chunk-VSF7AAGE.js.map +1 -0
  78. package/dist/{chunk-OVYBENIJ.js → chunk-W3M34XT4.js} +3 -3
  79. package/dist/{chunk-XPOOY35N.js → chunk-W4H5A3TJ.js} +3 -2
  80. package/dist/chunk-W4H5A3TJ.js.map +1 -0
  81. package/dist/{chunk-7Y5KKMIP.js → chunk-WPLRJ4XM.js} +9 -8
  82. package/dist/{chunk-7Y5KKMIP.js.map → chunk-WPLRJ4XM.js.map} +1 -1
  83. package/dist/{chunk-3TUDKDTQ.js → chunk-XEADGIAA.js} +6 -6
  84. package/dist/{cli-BQW2xKdb.d.ts → cli-BYad9YYY.d.ts} +3 -3
  85. package/dist/cli.d.ts +6 -6
  86. package/dist/cli.js +21 -21
  87. package/dist/compounding/engine.d.ts +1 -1
  88. package/dist/compounding/engine.js +3 -3
  89. package/dist/compounding/preference-consolidator.d.ts +1 -1
  90. package/dist/compression-optimizer.d.ts +1 -1
  91. package/dist/config.d.ts +1 -1
  92. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  93. package/dist/connectors/codex-materialize.d.ts +1 -1
  94. package/dist/connectors/index.d.ts +1 -1
  95. package/dist/connectors/index.js +2 -2
  96. package/dist/consolidation-provenance-check.d.ts +1 -1
  97. package/dist/consolidation-undo.d.ts +1 -1
  98. package/dist/contradiction/index.d.ts +1 -1
  99. package/dist/contradiction/index.js +2 -2
  100. package/dist/{contradiction-scan-UERKJESC.js → contradiction-scan-3FJYWS3G.js} +3 -3
  101. package/dist/conversation-index/backend.d.ts +1 -1
  102. package/dist/conversation-index/chunker.d.ts +1 -1
  103. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  104. package/dist/conversation-index/indexer.d.ts +1 -1
  105. package/dist/conversation-index/search.d.ts +1 -1
  106. package/dist/day-summary.d.ts +1 -1
  107. package/dist/day-summary.js +2 -2
  108. package/dist/delinearize.d.ts +1 -1
  109. package/dist/direct-answer-wiring.d.ts +1 -1
  110. package/dist/direct-answer.d.ts +1 -1
  111. package/dist/embedding-fallback.d.ts +1 -1
  112. package/dist/embedding-fallback.js +2 -2
  113. package/dist/enrichment/index.d.ts +1 -1
  114. package/dist/entity-retrieval.d.ts +1 -1
  115. package/dist/entity-retrieval.js +2 -2
  116. package/dist/entity-schema.d.ts +1 -1
  117. package/dist/explicit-capture.d.ts +4 -4
  118. package/dist/explicit-capture.js +2 -2
  119. package/dist/extraction-faithfulness.d.ts +1 -1
  120. package/dist/extraction-judge-telemetry.d.ts +1 -1
  121. package/dist/extraction-judge-training.d.ts +1 -1
  122. package/dist/extraction-judge.d.ts +1 -1
  123. package/dist/extraction.d.ts +1 -1
  124. package/dist/extraction.js +4 -4
  125. package/dist/fallback-llm.d.ts +1 -1
  126. package/dist/{first-start-migration-GQ3UQNIL.js → first-start-migration-4I3VDSYS.js} +2 -2
  127. package/dist/graph-dashboard-diff.d.ts +1 -1
  128. package/dist/graph-dashboard-key.d.ts +1 -1
  129. package/dist/graph-dashboard-parser.d.ts +1 -1
  130. package/dist/graph-edge-reinforcement.d.ts +1 -1
  131. package/dist/graph-recall.js +1 -1
  132. package/dist/graph-snapshot.d.ts +1 -1
  133. package/dist/graph.d.ts +1 -1
  134. package/dist/identity-continuity.d.ts +1 -1
  135. package/dist/importance.d.ts +1 -1
  136. package/dist/index.d.ts +9 -9
  137. package/dist/index.js +40 -40
  138. package/dist/intent.d.ts +1 -1
  139. package/dist/lcm/engine.d.ts +1 -1
  140. package/dist/lcm/engine.js +2 -2
  141. package/dist/lcm/index.d.ts +1 -1
  142. package/dist/lcm/index.js +2 -2
  143. package/dist/lcm/summarizer.js +1 -1
  144. package/dist/lcm/tools.d.ts +1 -1
  145. package/dist/lifecycle.d.ts +1 -1
  146. package/dist/live-connectors-runner.d.ts +1 -1
  147. package/dist/local-llm.d.ts +1 -1
  148. package/dist/local-llm.js +2 -2
  149. package/dist/local-model-endpoint.d.ts +1 -1
  150. package/dist/maintenance/memory-governance.d.ts +1 -1
  151. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  152. package/dist/memory-action-policy.d.ts +1 -1
  153. package/dist/memory-cache.d.ts +1 -1
  154. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  155. package/dist/memory-projection-store.d.ts +1 -1
  156. package/dist/memory-provenance.d.ts +1 -1
  157. package/dist/memory-worth-outcomes.d.ts +1 -1
  158. package/dist/models-json.d.ts +1 -1
  159. package/dist/namespaces/migrate.d.ts +2 -2
  160. package/dist/namespaces/migrate.js +6 -6
  161. package/dist/namespaces/principal.d.ts +1 -1
  162. package/dist/namespaces/principal.js +2 -2
  163. package/dist/namespaces/search.d.ts +1 -1
  164. package/dist/namespaces/search.js +4 -4
  165. package/dist/namespaces/storage.d.ts +2 -2
  166. package/dist/namespaces/storage.js +2 -2
  167. package/dist/native-knowledge.d.ts +1 -1
  168. package/dist/operator-toolkit.d.ts +1 -1
  169. package/dist/operator-toolkit.js +11 -11
  170. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  171. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  172. package/dist/orchestration/maintenance.d.ts +2 -2
  173. package/dist/orchestration/maintenance.js +6 -6
  174. package/dist/{orchestrator-BOAFN_Yr.d.ts → orchestrator-CupigmWu.d.ts} +221 -7
  175. package/dist/orchestrator.d.ts +4 -4
  176. package/dist/orchestrator.js +27 -27
  177. package/dist/patterns-cli.d.ts +1 -1
  178. package/dist/policy-runtime.d.ts +1 -1
  179. package/dist/provenance.d.ts +1 -1
  180. package/dist/qmd-recall-cache.d.ts +1 -1
  181. package/dist/qmd.d.ts +1 -1
  182. package/dist/recall-disclosure-escalation.d.ts +1 -1
  183. package/dist/recall-explain-renderer.d.ts +1 -1
  184. package/dist/recall-planner-llm.d.ts +1 -1
  185. package/dist/recall-state.d.ts +1 -1
  186. package/dist/recall-tag-filter.d.ts +1 -1
  187. package/dist/recall-xray-cli.d.ts +1 -1
  188. package/dist/recall-xray-renderer.d.ts +1 -1
  189. package/dist/recall-xray.d.ts +1 -1
  190. package/dist/resolve-auth-token.d.ts +1 -1
  191. package/dist/retrieval-agents.d.ts +1 -1
  192. package/dist/retrieval-tiers.d.ts +1 -1
  193. package/dist/routing/engine.d.ts +1 -1
  194. package/dist/routing/store.d.ts +1 -1
  195. package/dist/search/embed-helper.d.ts +1 -1
  196. package/dist/search/embed-helper.js +2 -2
  197. package/dist/search/factory.d.ts +1 -1
  198. package/dist/search/factory.js +3 -3
  199. package/dist/search/index.d.ts +1 -1
  200. package/dist/search/index.js +3 -3
  201. package/dist/search/lancedb-backend.d.ts +1 -1
  202. package/dist/search/meilisearch-backend.d.ts +1 -1
  203. package/dist/search/noop-backend.d.ts +1 -1
  204. package/dist/search/orama-backend.d.ts +1 -1
  205. package/dist/search/port.d.ts +1 -1
  206. package/dist/search/remote-backend.d.ts +1 -1
  207. package/dist/{semantic-consolidation-DsIEiCka.d.ts → semantic-consolidation-ByzGwC9c.d.ts} +1 -1
  208. package/dist/semantic-consolidation.d.ts +2 -2
  209. package/dist/semantic-consolidation.js +2 -2
  210. package/dist/semantic-rule-verifier.d.ts +1 -1
  211. package/dist/session-observer-bands.d.ts +1 -1
  212. package/dist/session-observer-state.d.ts +1 -1
  213. package/dist/shared-context/manager.d.ts +1 -1
  214. package/dist/shared-context/manager.js +2 -2
  215. package/dist/signal.d.ts +1 -1
  216. package/dist/storage.d.ts +1 -1
  217. package/dist/summarizer.d.ts +1 -1
  218. package/dist/summarizer.js +3 -3
  219. package/dist/summary-snapshot.d.ts +1 -1
  220. package/dist/temporal-supersession.d.ts +1 -1
  221. package/dist/temporal-validity.d.ts +1 -1
  222. package/dist/threading.d.ts +1 -1
  223. package/dist/tier-migration.d.ts +1 -1
  224. package/dist/tier-routing.d.ts +1 -1
  225. package/dist/{tier-stats-CSKL7BDG.js → tier-stats-5XF4UBRQ.js} +2 -2
  226. package/dist/topics.d.ts +1 -1
  227. package/dist/transcript.d.ts +1 -1
  228. package/dist/trust-score-stage.d.ts +1 -1
  229. package/dist/trust-score.d.ts +1 -1
  230. package/dist/{types-CglNn2V-.d.ts → types-5Jik3r4G.d.ts} +1 -1
  231. package/dist/types.d.ts +1 -1
  232. package/dist/utility-runtime.d.ts +1 -1
  233. package/package.json +2 -2
  234. package/src/capabilities.test.ts +0 -2
  235. package/src/capabilities.ts +7 -6
  236. package/src/cli.ts +2 -1
  237. package/src/graph-recall.ts +2 -1
  238. package/src/lcm/engine.ts +9 -6
  239. package/src/lcm/summarizer.ts +2 -1
  240. package/src/operator-toolkit.ts +2 -1
  241. package/src/orchestration/contradiction-linking-coordinator.ts +336 -0
  242. package/src/orchestration/qmd-result-resolver.ts +377 -0
  243. package/src/orchestration/recall-section-coordinator.ts +349 -0
  244. package/src/orchestrator.ts +81 -679
  245. package/src/procedural/procedure-stats.ts +2 -1
  246. package/src/wearables/pipeline.ts +5 -3
  247. package/dist/chunk-773DPI6T.js.map +0 -1
  248. package/dist/chunk-G7Q4D2G3.js.map +0 -1
  249. package/dist/chunk-H3WSZWHK.js.map +0 -1
  250. package/dist/chunk-VC7QELR6.js.map +0 -1
  251. package/dist/chunk-XPOOY35N.js.map +0 -1
  252. /package/dist/{auto-sync-G3V5AN4C.js.map → auto-sync-XHSKKQAH.js.map} +0 -0
  253. /package/dist/{chunk-X5PMDVY4.js.map → chunk-3EA5LIFJ.js.map} +0 -0
  254. /package/dist/{chunk-YNHRWFAP.js.map → chunk-4DLFJJOQ.js.map} +0 -0
  255. /package/dist/{chunk-WIMKOTNY.js.map → chunk-5QANTTY2.js.map} +0 -0
  256. /package/dist/{chunk-Y6PNYJVO.js.map → chunk-A2KKLCOS.js.map} +0 -0
  257. /package/dist/{chunk-O4IWVWSW.js.map → chunk-AVBT5WEW.js.map} +0 -0
  258. /package/dist/{chunk-M5KLYHHI.js.map → chunk-BYLC4DKI.js.map} +0 -0
  259. /package/dist/{chunk-UOVDO6TC.js.map → chunk-CHELXDTO.js.map} +0 -0
  260. /package/dist/{chunk-TQQN64J2.js.map → chunk-DBSMLRTO.js.map} +0 -0
  261. /package/dist/{chunk-4J53ZVPQ.js.map → chunk-DYK27X7V.js.map} +0 -0
  262. /package/dist/{chunk-K2N6WIZM.js.map → chunk-E7RGJQWP.js.map} +0 -0
  263. /package/dist/{chunk-M4WI23X3.js.map → chunk-EEKDRAWX.js.map} +0 -0
  264. /package/dist/{chunk-BE6NEQLF.js.map → chunk-HAZVVOYT.js.map} +0 -0
  265. /package/dist/{chunk-OT5K26NG.js.map → chunk-HM6UJPPO.js.map} +0 -0
  266. /package/dist/{chunk-PI4JHLDD.js.map → chunk-IP5SANO2.js.map} +0 -0
  267. /package/dist/{chunk-WHEF76BQ.js.map → chunk-JRZV3767.js.map} +0 -0
  268. /package/dist/{chunk-OS5RKJOH.js.map → chunk-JZ7P26GF.js.map} +0 -0
  269. /package/dist/{chunk-Y62QPRKV.js.map → chunk-K5LLP4CY.js.map} +0 -0
  270. /package/dist/{chunk-C3Z5YJSM.js.map → chunk-LOPZ2DWR.js.map} +0 -0
  271. /package/dist/{chunk-BJPL5WAL.js.map → chunk-MXDG6SRH.js.map} +0 -0
  272. /package/dist/{chunk-UYYSOMS2.js.map → chunk-NBP3YHHS.js.map} +0 -0
  273. /package/dist/{chunk-USHVHI6J.js.map → chunk-NNL4LJAD.js.map} +0 -0
  274. /package/dist/{chunk-GPX5E36D.js.map → chunk-OSMBC3JU.js.map} +0 -0
  275. /package/dist/{chunk-OUSOMUFV.js.map → chunk-PE6XR4GG.js.map} +0 -0
  276. /package/dist/{chunk-CMPXLMC3.js.map → chunk-PI23H7FV.js.map} +0 -0
  277. /package/dist/{chunk-WGDE2TJP.js.map → chunk-QOGXUNWL.js.map} +0 -0
  278. /package/dist/{chunk-ELL5VYXC.js.map → chunk-RNWWAS5V.js.map} +0 -0
  279. /package/dist/{chunk-LD6A7XG5.js.map → chunk-TQPSOTC7.js.map} +0 -0
  280. /package/dist/{chunk-AX4TRSRE.js.map → chunk-U5WVRMCA.js.map} +0 -0
  281. /package/dist/{chunk-DBVBV2RF.js.map → chunk-VE54E6RP.js.map} +0 -0
  282. /package/dist/{chunk-OVYBENIJ.js.map → chunk-W3M34XT4.js.map} +0 -0
  283. /package/dist/{chunk-3TUDKDTQ.js.map → chunk-XEADGIAA.js.map} +0 -0
  284. /package/dist/{contradiction-scan-UERKJESC.js.map → contradiction-scan-3FJYWS3G.js.map} +0 -0
  285. /package/dist/{first-start-migration-GQ3UQNIL.js.map → first-start-migration-4I3VDSYS.js.map} +0 -0
  286. /package/dist/{tier-stats-CSKL7BDG.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
@@ -4,13 +4,13 @@ import {
4
4
  loadSyncState,
5
5
  syncWearableSource,
6
6
  wearableSourceLabel
7
- } from "./chunk-OZECYVGI.js";
7
+ } from "./chunk-C7LDPZJJ.js";
8
8
  import {
9
9
  CompressionGuidelineCoordinator
10
- } from "./chunk-WIMKOTNY.js";
10
+ } from "./chunk-5QANTTY2.js";
11
11
  import {
12
12
  MaintenanceScheduler
13
- } from "./chunk-BJPL5WAL.js";
13
+ } from "./chunk-MXDG6SRH.js";
14
14
  import {
15
15
  runPeerProfileReasoner
16
16
  } from "./chunk-I74SUMNI.js";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-7HYPN2GC.js";
20
20
  import {
21
21
  LcmEngine
22
- } from "./chunk-773DPI6T.js";
22
+ } from "./chunk-V5RVMULT.js";
23
23
  import {
24
24
  chunkTranscriptEntries
25
25
  } from "./chunk-TECVW3JP.js";
@@ -29,10 +29,10 @@ import {
29
29
  import {
30
30
  CompoundingEngine,
31
31
  defaultTierMigrationCycleBudget
32
- } from "./chunk-UOVDO6TC.js";
32
+ } from "./chunk-CHELXDTO.js";
33
33
  import {
34
34
  SharedContextManager
35
- } from "./chunk-WHEF76BQ.js";
35
+ } from "./chunk-JRZV3767.js";
36
36
  import {
37
37
  applyTrustScoreStage,
38
38
  buildTrustSignalsForRerank,
@@ -63,7 +63,7 @@ import {
63
63
  } from "./chunk-UHGBNIOS.js";
64
64
  import {
65
65
  HourlySummarizer
66
- } from "./chunk-USHVHI6J.js";
66
+ } from "./chunk-NNL4LJAD.js";
67
67
  import {
68
68
  buildTargetedFactRecallSection,
69
69
  shouldRecallTargetedFactEvidence
@@ -160,7 +160,7 @@ import {
160
160
  } from "./chunk-LTHVM4XN.js";
161
161
  import {
162
162
  ExtractionEngine
163
- } from "./chunk-WGDE2TJP.js";
163
+ } from "./chunk-QOGXUNWL.js";
164
164
  import {
165
165
  parseMemoryActionEligibilityContext
166
166
  } from "./chunk-5GSUBCZM.js";
@@ -169,7 +169,7 @@ import {
169
169
  } from "./chunk-PWFWCGOO.js";
170
170
  import {
171
171
  LocalLlmClient
172
- } from "./chunk-TQQN64J2.js";
172
+ } from "./chunk-DBSMLRTO.js";
173
173
  import {
174
174
  buildFocusedListRecallSection,
175
175
  shouldRecallFocusedListEvidence
@@ -187,18 +187,18 @@ import {
187
187
  } from "./chunk-4463LUIE.js";
188
188
  import {
189
189
  formatDaySummaryMemories
190
- } from "./chunk-C3Z5YJSM.js";
190
+ } from "./chunk-LOPZ2DWR.js";
191
191
  import {
192
192
  tryDirectAnswer
193
193
  } from "./chunk-Q6IP2ARR.js";
194
194
  import {
195
195
  EmbeddingFallback
196
- } from "./chunk-GPX5E36D.js";
196
+ } from "./chunk-OSMBC3JU.js";
197
197
  import {
198
198
  buildEntityRecallSection,
199
199
  entityRecentTranscriptLookbackHours,
200
200
  readRecentEntityTranscriptEntries
201
- } from "./chunk-K2N6WIZM.js";
201
+ } from "./chunk-E7RGJQWP.js";
202
202
  import {
203
203
  RoutingRulesStore
204
204
  } from "./chunk-WIWPSQYU.js";
@@ -228,14 +228,14 @@ import {
228
228
  import {
229
229
  runNamespaceMaintenanceFanout,
230
230
  summarizeNamespaceMaintenanceHealth
231
- } from "./chunk-O4IWVWSW.js";
231
+ } from "./chunk-AVBT5WEW.js";
232
232
  import {
233
233
  NamespaceCatalog,
234
234
  planNamespaceMaintenance
235
- } from "./chunk-X5PMDVY4.js";
235
+ } from "./chunk-3EA5LIFJ.js";
236
236
  import {
237
237
  NamespaceStorageRouter
238
- } from "./chunk-AX4TRSRE.js";
238
+ } from "./chunk-U5WVRMCA.js";
239
239
  import {
240
240
  searchHarmonicRetrieval
241
241
  } from "./chunk-AV5ZEH4M.js";
@@ -270,7 +270,7 @@ import {
270
270
  materializeAfterSemanticConsolidation,
271
271
  parseConsolidationResponse,
272
272
  parseOperatorAwareConsolidationResponse
273
- } from "./chunk-PI4JHLDD.js";
273
+ } from "./chunk-IP5SANO2.js";
274
274
  import {
275
275
  buildRecallQueryPolicy
276
276
  } from "./chunk-LBJBNWS2.js";
@@ -292,7 +292,7 @@ import {
292
292
  } from "./chunk-UQ7RN5HK.js";
293
293
  import {
294
294
  SmartBuffer
295
- } from "./chunk-OS5RKJOH.js";
295
+ } from "./chunk-JZ7P26GF.js";
296
296
  import {
297
297
  isDisagreementPrompt
298
298
  } from "./chunk-H3FZVNRN.js";
@@ -311,7 +311,7 @@ import {
311
311
  clusterByKey,
312
312
  createCorrectionService,
313
313
  detectPassiveCorrections
314
- } from "./chunk-Y6PNYJVO.js";
314
+ } from "./chunk-A2KKLCOS.js";
315
315
  import {
316
316
  listTrustZoneRecords,
317
317
  searchTrustZoneRecords
@@ -333,14 +333,14 @@ import {
333
333
  resolveNamespaceFromStorageDir,
334
334
  resolveScopePlan,
335
335
  resolveScopeProfilePlan
336
- } from "./chunk-OVYBENIJ.js";
336
+ } from "./chunk-W3M34XT4.js";
337
337
  import {
338
338
  NamespaceSearchRouter
339
- } from "./chunk-BE6NEQLF.js";
339
+ } from "./chunk-HAZVVOYT.js";
340
340
  import {
341
341
  createConversationIndexRuntime,
342
342
  createSearchBackend
343
- } from "./chunk-ELL5VYXC.js";
343
+ } from "./chunk-RNWWAS5V.js";
344
344
  import {
345
345
  NoopSearchBackend
346
346
  } from "./chunk-CYEPCZN5.js";
@@ -363,7 +363,7 @@ import {
363
363
  } from "./chunk-QDW3E4RD.js";
364
364
  import {
365
365
  shouldSkipImplicitExtraction
366
- } from "./chunk-Y62QPRKV.js";
366
+ } from "./chunk-K5LLP4CY.js";
367
367
  import {
368
368
  searchCausalTrajectories
369
369
  } from "./chunk-SQNED75R.js";
@@ -465,7 +465,7 @@ import {
465
465
  defaultNamespaceForPrincipal,
466
466
  recallNamespacesForPrincipal,
467
467
  resolvePrincipal
468
- } from "./chunk-OUSOMUFV.js";
468
+ } from "./chunk-PE6XR4GG.js";
469
469
  import {
470
470
  isSafeRouteNamespace,
471
471
  selectRouteRule
@@ -491,7 +491,7 @@ import {
491
491
  resolveRecallEnhancementCapabilities,
492
492
  resolveSecurityCapabilities,
493
493
  resolveUtilityLearningCapabilities
494
- } from "./chunk-G7Q4D2G3.js";
494
+ } from "./chunk-VSF7AAGE.js";
495
495
  import {
496
496
  sanitizeMemoryContent
497
497
  } from "./chunk-5GKPFL3S.js";
@@ -512,7 +512,7 @@ import {
512
512
  } from "./chunk-PVGDJXVK.js";
513
513
 
514
514
  // src/orchestrator.ts
515
- import path5 from "path";
515
+ import path6 from "path";
516
516
  import os2 from "os";
517
517
  import { createHash as createHash2, randomBytes } from "crypto";
518
518
  import { existsSync, readFileSync } from "fs";
@@ -2196,7 +2196,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2196
2196
  nsMap = buildMemoryWorthCounterMap(memories);
2197
2197
  this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
2198
2198
  }
2199
- for (const [path6, c] of nsMap) counters.set(path6, c);
2199
+ for (const [path7, c] of nsMap) counters.set(path7, c);
2200
2200
  } catch (err) {
2201
2201
  log.debug("memory-worth: failed to read namespace, skipping", {
2202
2202
  namespace: ns,
@@ -2281,7 +2281,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2281
2281
  namespaces,
2282
2282
  {
2283
2283
  readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
2284
- readMemoryFrontmatter: async (path6) => {
2284
+ readMemoryFrontmatter: async (path7) => {
2285
2285
  if (!fallbackReader) {
2286
2286
  for (const ns of namespaces) {
2287
2287
  try {
@@ -2292,7 +2292,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2292
2292
  }
2293
2293
  }
2294
2294
  if (!fallbackReader) return null;
2295
- const memory = await this.readQmdResultMemory(path6, fallbackReader, namespaces);
2295
+ const memory = await this.readQmdResultMemory(path7, fallbackReader, namespaces);
2296
2296
  return memory ? memory.frontmatter : null;
2297
2297
  }
2298
2298
  },
@@ -2391,214 +2391,839 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2391
2391
  }
2392
2392
  };
2393
2393
 
2394
- // src/maintenance/pattern-reinforcement.ts
2395
- function patternReinforcementKey(content) {
2396
- return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
2397
- }
2398
- function patternReinforcementClusterKey(category, content) {
2399
- return `${category}::${patternReinforcementKey(content)}`;
2400
- }
2401
- function pickCanonical(memories) {
2402
- let best = memories[0];
2403
- let bestInstant = memoryInstant(best);
2404
- let bestStamp = memoryStamp(best);
2405
- for (let i = 1; i < memories.length; i += 1) {
2406
- const candidate = memories[i];
2407
- const instant = memoryInstant(candidate);
2408
- const stamp = memoryStamp(candidate);
2409
- let cmp;
2410
- if (instant !== null && bestInstant !== null) {
2411
- cmp = instant - bestInstant;
2412
- } else {
2413
- cmp = stamp.localeCompare(bestStamp);
2414
- }
2415
- if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
2416
- best = candidate;
2417
- bestInstant = instant;
2418
- bestStamp = stamp;
2419
- }
2420
- }
2421
- return best;
2422
- }
2423
- function memoryStamp(memory) {
2424
- return memory.frontmatter.updated || memory.frontmatter.created || "";
2425
- }
2426
- function memoryInstant(memory) {
2427
- const stamp = memoryStamp(memory);
2428
- if (stamp.length === 0) return null;
2429
- const parsed = Date.parse(stamp);
2430
- return Number.isFinite(parsed) ? parsed : null;
2431
- }
2432
- var ACTIVE_STATUS = "active";
2433
- async function runPatternReinforcement(storage, options) {
2434
- const minCount = Math.max(2, Math.floor(options.minCount));
2435
- const targetCategories = new Set(options.categories);
2436
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
2437
- const nowIso = now().toISOString();
2438
- if (targetCategories.size === 0) {
2439
- return emptyResult();
2440
- }
2441
- const memories = await storage.readAllMemories();
2442
- const eligible = memories.filter((m) => {
2443
- if (!targetCategories.has(m.frontmatter.category)) return false;
2444
- const status = m.frontmatter.status ?? ACTIVE_STATUS;
2445
- return status === ACTIVE_STATUS || status === "superseded";
2446
- });
2447
- if (eligible.length === 0) return emptyResult();
2448
- const clusters = clusterByKey(
2449
- eligible,
2450
- (m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
2451
- );
2452
- const result = {
2453
- clustersFound: 0,
2454
- canonicalsUpdated: 0,
2455
- duplicatesSuperseded: 0,
2456
- clusters: []
2457
- };
2458
- for (const cluster of clusters.values()) {
2459
- if (cluster.length < minCount) continue;
2460
- const activeMembers = cluster.filter((m) => {
2461
- const status = m.frontmatter.status ?? ACTIVE_STATUS;
2462
- return status === ACTIVE_STATUS;
2463
- });
2464
- if (activeMembers.length === 0) continue;
2465
- result.clustersFound += 1;
2466
- const canonical = pickCanonical(activeMembers);
2467
- const activeDuplicates = activeMembers.filter((m) => m !== canonical);
2468
- const sourceIds = [...cluster].map((m) => m.frontmatter.id).filter((id) => typeof id === "string" && id.length > 0).sort();
2469
- const previousCount = canonical.frontmatter.reinforcement_count ?? 0;
2470
- const newCount = sourceIds.length;
2471
- const reinforcementBumped = newCount > previousCount;
2472
- const previousDerivedFrom = Array.isArray(canonical.frontmatter.derived_from) ? [...canonical.frontmatter.derived_from].sort() : [];
2473
- const sortedSourceIds = [...sourceIds].sort();
2474
- const membershipChanged = previousDerivedFrom.length !== sortedSourceIds.length || previousDerivedFrom.some((id, i) => id !== sortedSourceIds[i]);
2475
- const previousVia = canonical.frontmatter.derived_via;
2476
- const viaChanged = previousVia !== "pattern-reinforcement";
2477
- const canonicalNeedsRefresh = reinforcementBumped || membershipChanged || viaChanged;
2478
- if (canonicalNeedsRefresh) {
2479
- const patch = {
2480
- derived_from: sourceIds,
2481
- derived_via: "pattern-reinforcement",
2482
- updated: nowIso
2483
- };
2484
- if (reinforcementBumped) {
2485
- patch.reinforcement_count = newCount;
2486
- patch.last_reinforced_at = nowIso;
2487
- } else {
2488
- patch.reinforcement_count = canonical.frontmatter.reinforcement_count ?? newCount;
2489
- patch.last_reinforced_at = canonical.frontmatter.last_reinforced_at ?? nowIso;
2490
- }
2491
- await storage.writeMemoryFrontmatter(canonical, patch);
2492
- result.canonicalsUpdated += 1;
2493
- }
2494
- const supersededIds = [];
2495
- for (const dup of activeDuplicates) {
2496
- const patch = {
2497
- status: "superseded",
2498
- supersededBy: canonical.frontmatter.id,
2499
- supersededAt: nowIso,
2500
- updated: nowIso
2501
- };
2502
- await storage.writeMemoryFrontmatter(dup, patch);
2503
- supersededIds.push(dup.frontmatter.id);
2504
- result.duplicatesSuperseded += 1;
2505
- if (storage.appendTombstone) {
2506
- for (const input of buildRetiredFactTombstoneInputs(
2507
- {
2508
- id: dup.frontmatter.id,
2509
- content: dup.content,
2510
- contentHash: dup.frontmatter.contentHash,
2511
- entityRef: dup.frontmatter.entityRef,
2512
- structuredAttributes: dup.frontmatter.structuredAttributes
2513
- },
2514
- { reason: "supersession", createdBy: "supersession", createdAt: nowIso, supersessionKeysForFact }
2515
- )) {
2516
- try {
2517
- await storage.appendTombstone(input);
2518
- } catch {
2519
- }
2520
- }
2521
- }
2522
- }
2523
- result.clusters.push({
2524
- canonicalId: canonical.frontmatter.id,
2525
- count: newCount,
2526
- sourceIds,
2527
- supersededIds,
2528
- reinforcementBumped
2529
- });
2530
- }
2531
- return result;
2532
- }
2533
- function emptyResult() {
2534
- return {
2535
- clustersFound: 0,
2536
- canonicalsUpdated: 0,
2537
- duplicatesSuperseded: 0,
2538
- clusters: []
2539
- };
2540
- }
2541
-
2542
- // src/dedup/semantic.ts
2543
- var DEFAULT_SEMANTIC_THRESHOLD = 0.92;
2544
- var DEFAULT_SEMANTIC_CANDIDATES = 5;
2545
- function normalizeSemanticThreshold(value) {
2546
- return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : DEFAULT_SEMANTIC_THRESHOLD;
2547
- }
2548
- function normalizeSemanticCandidates(value) {
2549
- if (!Number.isFinite(value) || value < 0) {
2550
- return DEFAULT_SEMANTIC_CANDIDATES;
2394
+ // src/orchestration/recall-section-coordinator.ts
2395
+ var RecallSectionCoordinator = class {
2396
+ getConfig;
2397
+ resolveSectionEnabled;
2398
+ constructor(options) {
2399
+ this.getConfig = options.getConfig;
2400
+ this.resolveSectionEnabled = options.resolveSectionEnabled ?? ((id, def) => this.isRecallSectionEnabled(id, def));
2551
2401
  }
2552
- const normalized = Math.floor(value);
2553
- return value > 0 && normalized === 0 ? 1 : normalized;
2554
- }
2555
- async function decideSemanticDedup(content, lookup, options) {
2556
- if (!options.enabled) {
2557
- return { action: "keep", reason: "disabled" };
2402
+ getRecallSectionEntry(sectionId) {
2403
+ const pipeline = Array.isArray(this.getConfig().recallPipeline) ? this.getConfig().recallPipeline : [];
2404
+ return pipeline.find((entry) => entry.id === sectionId);
2558
2405
  }
2559
- const threshold = normalizeSemanticThreshold(options.threshold);
2560
- const candidates = normalizeSemanticCandidates(options.candidates);
2561
- if (candidates === 0) {
2562
- return { action: "keep", reason: "disabled" };
2406
+ isRecallSectionEnabled(sectionId, defaultEnabled = true) {
2407
+ const entry = this.getRecallSectionEntry(sectionId);
2408
+ if (!entry) return defaultEnabled;
2409
+ return entry.enabled !== false;
2563
2410
  }
2564
- const trimmed = typeof content === "string" ? content.trim() : "";
2565
- if (!trimmed) {
2566
- return { action: "keep", reason: "no_near_duplicate" };
2411
+ isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
2412
+ const entry = this.getRecallSectionEntry(sectionId);
2413
+ if (!entry) return topLevelEnabled;
2414
+ return entry.enabled === true || topLevelEnabled && entry.enabled !== false;
2567
2415
  }
2568
- let hits = [];
2569
- try {
2570
- hits = await lookup(trimmed, candidates);
2571
- } catch {
2572
- return { action: "keep", reason: "backend_unavailable" };
2416
+ getRecallSectionMaxChars(sectionId) {
2417
+ const entry = this.getRecallSectionEntry(sectionId);
2418
+ if (!entry) return void 0;
2419
+ if (entry.maxChars === null) return null;
2420
+ if (typeof entry.maxChars !== "number") return void 0;
2421
+ return Math.max(0, Math.floor(entry.maxChars));
2573
2422
  }
2574
- if (!Array.isArray(hits) || hits.length === 0) {
2575
- return { action: "keep", reason: "no_candidates" };
2423
+ getRecallSectionNumber(sectionId, key) {
2424
+ const entry = this.getRecallSectionEntry(sectionId);
2425
+ if (!entry) return void 0;
2426
+ const value = entry[key];
2427
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
2428
+ return Math.max(0, Math.floor(value));
2576
2429
  }
2577
- let top;
2578
- for (const hit of hits) {
2579
- if (!hit || typeof hit.id !== "string" || hit.id.trim().length === 0 || typeof hit.score !== "number" || !Number.isFinite(hit.score)) {
2580
- continue;
2430
+ appendRecallSection(sectionBuckets, sectionId, content) {
2431
+ if (!this.resolveSectionEnabled(sectionId, true)) return false;
2432
+ const trimmed = content.trim();
2433
+ if (trimmed.length === 0) return false;
2434
+ const maxChars = this.getRecallSectionMaxChars(sectionId);
2435
+ let finalContent = trimmed;
2436
+ if (maxChars === 0) return false;
2437
+ if (typeof maxChars === "number" && finalContent.length > maxChars) {
2438
+ finalContent = `${finalContent.slice(0, maxChars)}
2439
+
2440
+ ...(trimmed)
2441
+ `;
2581
2442
  }
2582
- if (!top || hit.score > top.score) {
2583
- top = hit;
2443
+ const existing = sectionBuckets.get(sectionId) ?? [];
2444
+ existing.push(finalContent);
2445
+ sectionBuckets.set(sectionId, existing);
2446
+ return true;
2447
+ }
2448
+ truncateRecallSectionToBudget(content, maxChars) {
2449
+ if (maxChars <= 0) return "";
2450
+ if (content.length <= maxChars) return content;
2451
+ const suffix = "\n\n...(memory context trimmed)";
2452
+ if (maxChars <= suffix.length) {
2453
+ return content.slice(0, maxChars);
2584
2454
  }
2455
+ return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
2585
2456
  }
2586
- if (!top) {
2587
- return { action: "keep", reason: "no_near_duplicate" };
2457
+ protectedRecallSectionIds(sectionBuckets) {
2458
+ const protectedIds = /* @__PURE__ */ new Set();
2459
+ if ((sectionBuckets.get("memories")?.length ?? 0) > 0) {
2460
+ protectedIds.add("memories");
2461
+ }
2462
+ return protectedIds;
2588
2463
  }
2589
- if (top.score >= threshold) {
2590
- return {
2591
- action: "skip",
2592
- reason: "near_duplicate",
2593
- topScore: top.score,
2594
- topId: top.id,
2595
- topPath: top.path
2596
- };
2464
+ protectedRecallReservationChars(content) {
2465
+ const headingBoundary = content.indexOf("\n\n");
2466
+ const headingChars = headingBoundary >= 0 ? headingBoundary + 2 : Math.min(content.length, 24);
2467
+ return Math.min(content.length, Math.max(headingChars, 24));
2597
2468
  }
2598
- return {
2599
- action: "keep",
2600
- reason: "no_near_duplicate",
2601
- topScore: top.score,
2469
+ estimateReservedRecallBudget(entries, startIndex, protectedIds, alreadyIncludedCount) {
2470
+ const separatorLength = "\n\n---\n\n".length;
2471
+ let reserved = 0;
2472
+ let simulatedIncluded = alreadyIncludedCount;
2473
+ for (let i = startIndex; i < entries.length; i += 1) {
2474
+ const entry = entries[i];
2475
+ if (!entry || !protectedIds.has(entry.id)) continue;
2476
+ if (simulatedIncluded > 0) {
2477
+ reserved += separatorLength;
2478
+ }
2479
+ reserved += this.protectedRecallReservationChars(entry.content);
2480
+ simulatedIncluded += 1;
2481
+ }
2482
+ return reserved;
2483
+ }
2484
+ getRecallBudgetChars(override) {
2485
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
2486
+ return Math.floor(override);
2487
+ }
2488
+ const configuredBudget = this.getConfig().recallBudgetChars;
2489
+ if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
2490
+ return Math.floor(configuredBudget);
2491
+ }
2492
+ const tokenBudget = this.getConfig().maxMemoryTokens;
2493
+ if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget >= 0) {
2494
+ return Math.floor(tokenBudget * 4);
2495
+ }
2496
+ return 0;
2497
+ }
2498
+ assembleRecallSections(sectionBuckets, budgetOverride) {
2499
+ const orderedEntries = [];
2500
+ const pipeline = Array.isArray(this.getConfig().recallPipeline) ? this.getConfig().recallPipeline : [];
2501
+ const orderedIds = pipeline.filter((entry) => entry.enabled !== false).map((entry) => entry.id);
2502
+ const seen = /* @__PURE__ */ new Set();
2503
+ for (const id of orderedIds) {
2504
+ const chunks = sectionBuckets.get(id);
2505
+ if (!chunks || chunks.length === 0) continue;
2506
+ orderedEntries.push({ id, content: chunks.join("\n\n") });
2507
+ seen.add(id);
2508
+ }
2509
+ for (const [id, chunks] of sectionBuckets.entries()) {
2510
+ if (seen.has(id)) continue;
2511
+ if (chunks.length === 0) continue;
2512
+ orderedEntries.push({ id, content: chunks.join("\n\n") });
2513
+ }
2514
+ const budget = this.getRecallBudgetChars(budgetOverride);
2515
+ if (budget === 0) {
2516
+ return {
2517
+ sections: [],
2518
+ includedIds: [],
2519
+ omittedIds: orderedEntries.map((entry) => entry.id),
2520
+ truncated: orderedEntries.length > 0,
2521
+ finalChars: 0
2522
+ };
2523
+ }
2524
+ const separator = "\n\n---\n\n";
2525
+ const protectedIds = this.protectedRecallSectionIds(sectionBuckets);
2526
+ const sections = [];
2527
+ const includedIds = [];
2528
+ const omittedIds = [];
2529
+ let usedChars = 0;
2530
+ let truncated = false;
2531
+ for (let index = 0; index < orderedEntries.length; index += 1) {
2532
+ const entry = orderedEntries[index];
2533
+ const separatorChars = sections.length > 0 ? separator.length : 0;
2534
+ const reserve = protectedIds.has(entry.id) ? 0 : this.estimateReservedRecallBudget(
2535
+ orderedEntries,
2536
+ index + 1,
2537
+ protectedIds,
2538
+ sections.length + 1
2539
+ );
2540
+ const availableForEntry = budget - usedChars - separatorChars - reserve;
2541
+ if (availableForEntry <= 0) {
2542
+ omittedIds.push(entry.id);
2543
+ truncated = true;
2544
+ continue;
2545
+ }
2546
+ const finalContent = this.truncateRecallSectionToBudget(
2547
+ entry.content,
2548
+ availableForEntry
2549
+ );
2550
+ if (!finalContent) {
2551
+ omittedIds.push(entry.id);
2552
+ truncated = true;
2553
+ continue;
2554
+ }
2555
+ if (finalContent.length < entry.content.length) {
2556
+ truncated = true;
2557
+ }
2558
+ sections.push(finalContent);
2559
+ includedIds.push(entry.id);
2560
+ usedChars += separatorChars + finalContent.length;
2561
+ }
2562
+ return {
2563
+ sections,
2564
+ includedIds,
2565
+ omittedIds,
2566
+ truncated,
2567
+ finalChars: usedChars
2568
+ };
2569
+ }
2570
+ buildLastRecallBudgetSummary(options) {
2571
+ return {
2572
+ requestedTopK: options.requestedTopK,
2573
+ appliedTopK: options.recallResultLimit,
2574
+ recallBudgetChars: this.getRecallBudgetChars(),
2575
+ maxMemoryTokens: this.getConfig().maxMemoryTokens,
2576
+ qmdFetchLimit: options.qmdFetchLimit,
2577
+ qmdHybridFetchLimit: options.qmdHybridFetchLimit,
2578
+ finalContextChars: options.finalContextChars,
2579
+ truncated: options.truncated,
2580
+ includedSections: [...options.includedSections ?? []],
2581
+ omittedSections: [...options.omittedSections ?? []]
2582
+ };
2583
+ }
2584
+ collectLastRecallSources(sectionBuckets, recallSource) {
2585
+ const used = /* @__PURE__ */ new Set();
2586
+ if (recallSource !== "none") {
2587
+ used.add(recallSource);
2588
+ }
2589
+ for (const [sectionId, chunks] of sectionBuckets.entries()) {
2590
+ if (chunks.length > 0) {
2591
+ used.add(sectionId);
2592
+ }
2593
+ }
2594
+ return [...used];
2595
+ }
2596
+ };
2597
+
2598
+ // src/orchestration/qmd-result-resolver.ts
2599
+ import path4 from "path";
2600
+ function qmdCollectionPathParts(resultPath) {
2601
+ if (!resultPath || path4.isAbsolute(resultPath)) return null;
2602
+ const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
2603
+ const slashIndex = normalized.indexOf("/");
2604
+ if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
2605
+ const collection = normalized.slice(0, slashIndex);
2606
+ if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
2607
+ return {
2608
+ collection,
2609
+ relativePath: normalized.slice(slashIndex + 1)
2610
+ };
2611
+ }
2612
+ function qmdResultPathCandidates(storageDir, resultPath) {
2613
+ const candidates = /* @__PURE__ */ new Set();
2614
+ const storageRoot = path4.resolve(storageDir);
2615
+ const addCandidate = (candidate) => {
2616
+ const resolved = path4.resolve(candidate);
2617
+ if (isPathInsideStorageRoot(storageRoot, resolved)) {
2618
+ candidates.add(resolved);
2619
+ }
2620
+ };
2621
+ const addRelativeCandidates = (relativePath) => {
2622
+ const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
2623
+ if (!normalized) return;
2624
+ addCandidate(path4.join(storageRoot, normalized));
2625
+ if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
2626
+ addCandidate(path4.join(storageRoot, "facts", normalized));
2627
+ }
2628
+ };
2629
+ if (path4.isAbsolute(resultPath)) {
2630
+ addCandidate(resultPath);
2631
+ } else {
2632
+ addRelativeCandidates(resultPath);
2633
+ }
2634
+ return [...candidates];
2635
+ }
2636
+ function storageDirOrNull(storage) {
2637
+ const dir = storage.dir;
2638
+ return typeof dir === "string" && dir.length > 0 ? dir : null;
2639
+ }
2640
+ var QmdResultResolver = class {
2641
+ getConfig;
2642
+ storageFor;
2643
+ storageDirNamespace;
2644
+ qmdCollectionNamespaceFromPrefix;
2645
+ namespaceFromPath;
2646
+ constructor(options) {
2647
+ this.getConfig = options.getConfig;
2648
+ this.storageFor = options.storageFor;
2649
+ this.storageDirNamespace = options.storageDirNamespace;
2650
+ this.qmdCollectionNamespaceFromPrefix = options.qmdCollectionNamespaceFromPrefix;
2651
+ this.namespaceFromPath = options.namespaceFromPath;
2652
+ }
2653
+ async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
2654
+ const parts = qmdCollectionPathParts(resultPath);
2655
+ const fallbackStorageDir = storageDirOrNull(fallbackStorage);
2656
+ const config = this.getConfig();
2657
+ const coldCollection = config.qmdColdCollection ?? "openclaw-engram-cold";
2658
+ if (parts && parts.collection === coldCollection) {
2659
+ const storages = [];
2660
+ const seenStorageDirs = /* @__PURE__ */ new Set();
2661
+ const addStorage = (storage) => {
2662
+ const storageDir = storageDirOrNull(storage);
2663
+ const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
2664
+ if (seenStorageDirs.has(storageKey)) return;
2665
+ seenStorageDirs.add(storageKey);
2666
+ storages.push(storage);
2667
+ };
2668
+ const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : config.defaultNamespace;
2669
+ if (recallNamespaces.length === 0 || !resolveNamespaceCapabilities(config).namespaces || recallNamespaces.includes(fallbackNamespace)) {
2670
+ addStorage(fallbackStorage);
2671
+ }
2672
+ if (recallNamespaces.length > 0) {
2673
+ for (const namespace of recallNamespaces) {
2674
+ try {
2675
+ addStorage(await this.storageFor(namespace));
2676
+ } catch (err) {
2677
+ log.debug("qmd cold result namespace storage lookup skipped", {
2678
+ path: resultPath,
2679
+ namespace,
2680
+ error: err.message
2681
+ });
2682
+ }
2683
+ }
2684
+ }
2685
+ for (const storage of storages) {
2686
+ const storageDir = storageDirOrNull(storage);
2687
+ if (!storageDir) {
2688
+ const memory = await storage.readMemoryByPath(resultPath);
2689
+ if (memory) return memory;
2690
+ continue;
2691
+ }
2692
+ try {
2693
+ const coldRoot = path4.join(storageDir, "cold");
2694
+ for (const candidate of qmdResultPathCandidates(
2695
+ coldRoot,
2696
+ parts.relativePath
2697
+ )) {
2698
+ const memory = await storage.readMemoryByPath(candidate);
2699
+ if (memory) return memory;
2700
+ }
2701
+ } catch (err) {
2702
+ if (err instanceof SecureStoreLockedError) throw err;
2703
+ log.debug("qmd cold result path lookup failed open", {
2704
+ path: resultPath,
2705
+ collection: coldCollection,
2706
+ error: err.message
2707
+ });
2708
+ }
2709
+ }
2710
+ return null;
2711
+ }
2712
+ const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
2713
+ if (parts && collectionNamespace) {
2714
+ try {
2715
+ const collectionStorage = await this.storageFor(collectionNamespace);
2716
+ for (const candidate of qmdResultPathCandidates(
2717
+ collectionStorage.dir,
2718
+ parts.relativePath
2719
+ )) {
2720
+ const memory = await collectionStorage.readMemoryByPath(candidate);
2721
+ if (memory) return memory;
2722
+ }
2723
+ return null;
2724
+ } catch (err) {
2725
+ if (err instanceof SecureStoreLockedError) throw err;
2726
+ log.debug("qmd result namespace path lookup failed open", {
2727
+ path: resultPath,
2728
+ namespace: collectionNamespace,
2729
+ error: err.message
2730
+ });
2731
+ return null;
2732
+ }
2733
+ }
2734
+ if (path4.isAbsolute(resultPath)) {
2735
+ if (!fallbackStorageDir) {
2736
+ return await fallbackStorage.readMemoryByPath(resultPath);
2737
+ }
2738
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
2739
+ resultPath,
2740
+ fallbackStorage,
2741
+ recallNamespaces
2742
+ );
2743
+ if (!ownerStorage) return null;
2744
+ for (const candidate of qmdResultPathCandidates(
2745
+ ownerStorage.dir,
2746
+ resultPath
2747
+ )) {
2748
+ const memory = await ownerStorage.storage.readMemoryByPath(candidate);
2749
+ if (memory) return memory;
2750
+ }
2751
+ return null;
2752
+ }
2753
+ if (!fallbackStorageDir) {
2754
+ return await fallbackStorage.readMemoryByPath(resultPath);
2755
+ }
2756
+ for (const candidate of qmdResultPathCandidates(
2757
+ fallbackStorageDir,
2758
+ resultPath
2759
+ )) {
2760
+ const memory = await fallbackStorage.readMemoryByPath(candidate);
2761
+ if (memory) return memory;
2762
+ }
2763
+ return null;
2764
+ }
2765
+ async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
2766
+ const memory = await this.readQmdResultMemory(
2767
+ result.path,
2768
+ fallbackStorage,
2769
+ recallNamespaces
2770
+ );
2771
+ if (!memory) return null;
2772
+ let ownerNamespace = null;
2773
+ if (path4.isAbsolute(memory.path)) {
2774
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
2775
+ memory.path,
2776
+ fallbackStorage,
2777
+ recallNamespaces
2778
+ );
2779
+ ownerNamespace = ownerStorage?.namespace ?? null;
2780
+ if (!ownerNamespace && resolveNamespaceCapabilities(this.getConfig()).namespaces) return null;
2781
+ }
2782
+ ownerNamespace ??= this.namespaceFromPath(memory.path);
2783
+ if (recallNamespaces.length > 0 && !recallNamespaces.includes(ownerNamespace)) {
2784
+ return null;
2785
+ }
2786
+ return {
2787
+ namespace: ownerNamespace,
2788
+ result: {
2789
+ ...result,
2790
+ docid: result.docid || memory.frontmatter.id,
2791
+ path: memory.path,
2792
+ snippet: result.snippet || memory.content.slice(0, 400)
2793
+ }
2794
+ };
2795
+ }
2796
+ async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
2797
+ const resolvedPath = path4.resolve(resultPath);
2798
+ const config = this.getConfig();
2799
+ const memoryRoot = path4.resolve(config.memoryDir);
2800
+ const namespacesRoot = path4.join(memoryRoot, "namespaces");
2801
+ const fallbackStorageDir = storageDirOrNull(fallbackStorage);
2802
+ const matches = [];
2803
+ const seenDirs = /* @__PURE__ */ new Set();
2804
+ const maybeAddStorage = (storage, namespace) => {
2805
+ const storageDir = storageDirOrNull(storage);
2806
+ if (!storageDir) return;
2807
+ const candidateRoot = path4.resolve(storageDir);
2808
+ if (seenDirs.has(candidateRoot)) return;
2809
+ if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
2810
+ if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
2811
+ return;
2812
+ }
2813
+ seenDirs.add(candidateRoot);
2814
+ matches.push({ storage, dir: candidateRoot, namespace });
2815
+ };
2816
+ const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : config.defaultNamespace;
2817
+ maybeAddStorage(fallbackStorage, fallbackNamespace);
2818
+ const candidateNamespaces = /* @__PURE__ */ new Set();
2819
+ candidateNamespaces.add(config.defaultNamespace);
2820
+ candidateNamespaces.add(config.sharedNamespace);
2821
+ for (const ns of recallNamespaces) {
2822
+ candidateNamespaces.add(ns);
2823
+ }
2824
+ if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
2825
+ const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
2826
+ const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
2827
+ if (namespaceSegment) {
2828
+ candidateNamespaces.add(
2829
+ namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment
2830
+ );
2831
+ }
2832
+ }
2833
+ for (const policy of config.namespacePolicies ?? []) {
2834
+ candidateNamespaces.add(policy.name);
2835
+ }
2836
+ for (const ns of candidateNamespaces) {
2837
+ if (!ns) continue;
2838
+ try {
2839
+ maybeAddStorage(await this.storageFor(ns), ns);
2840
+ } catch {
2841
+ continue;
2842
+ }
2843
+ }
2844
+ matches.sort((a, b) => b.dir.length - a.dir.length);
2845
+ return matches[0] ?? null;
2846
+ }
2847
+ };
2848
+
2849
+ // src/orchestration/contradiction-linking-coordinator.ts
2850
+ var ContradictionLinkingCoordinator = class {
2851
+ getConfig;
2852
+ isSearchAvailable;
2853
+ searchAcrossNamespaces;
2854
+ extractMemoryIdsFromResults;
2855
+ namespaceFromPath;
2856
+ storageForNamespace;
2857
+ getExtraction;
2858
+ constructor(options) {
2859
+ this.getConfig = options.getConfig;
2860
+ this.isSearchAvailable = options.isSearchAvailable;
2861
+ this.searchAcrossNamespaces = options.searchAcrossNamespaces;
2862
+ this.extractMemoryIdsFromResults = options.extractMemoryIdsFromResults;
2863
+ this.namespaceFromPath = options.namespaceFromPath;
2864
+ this.storageForNamespace = options.storageForNamespace;
2865
+ this.getExtraction = options.getExtraction;
2866
+ }
2867
+ /**
2868
+ * Check if a new memory contradicts an existing one.
2869
+ * Uses QMD to find similar memories, then LLM to verify contradiction.
2870
+ */
2871
+ async checkForContradiction(content, category, namespaceScope) {
2872
+ if (!this.isSearchAvailable()) return null;
2873
+ const config = this.getConfig();
2874
+ const results = await this.searchAcrossNamespaces({
2875
+ query: content,
2876
+ namespaces: [namespaceScope],
2877
+ maxResults: 5,
2878
+ mode: "search"
2879
+ });
2880
+ for (const result of results) {
2881
+ if (result.score < config.contradictionSimilarityThreshold) {
2882
+ continue;
2883
+ }
2884
+ const memoryId = this.extractMemoryIdsFromResults([result])[0];
2885
+ if (!memoryId) continue;
2886
+ const resultNamespace = this.namespaceFromPath(result.path);
2887
+ if (resultNamespace !== namespaceScope) continue;
2888
+ const resultStorage = await this.storageForNamespace(resultNamespace);
2889
+ const existingMemory = await resultStorage.getMemoryById(memoryId);
2890
+ if (!existingMemory) continue;
2891
+ if (existingMemory.frontmatter.status === "superseded" || existingMemory.frontmatter.status === "forgotten") {
2892
+ continue;
2893
+ }
2894
+ const extraction = this.getExtraction();
2895
+ const verification = await extraction.verifyContradiction(
2896
+ { content, category },
2897
+ {
2898
+ id: existingMemory.frontmatter.id,
2899
+ content: existingMemory.content,
2900
+ category: existingMemory.frontmatter.category,
2901
+ created: existingMemory.frontmatter.created
2902
+ }
2903
+ );
2904
+ if (!verification) continue;
2905
+ if (verification.isContradiction && verification.confidence >= config.contradictionMinConfidence) {
2906
+ if (verification.whichIsNewer === "first") {
2907
+ log.info(
2908
+ `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory \u2014 existing is newer, incoming fact is stale`
2909
+ );
2910
+ continue;
2911
+ }
2912
+ log.info(
2913
+ `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`
2914
+ );
2915
+ return {
2916
+ supersededId: existingMemory.frontmatter.id,
2917
+ confidence: verification.confidence,
2918
+ reason: verification.reasoning,
2919
+ supersededPath: existingMemory.path,
2920
+ supersededCreated: existingMemory.frontmatter.created,
2921
+ supersededTags: existingMemory.frontmatter.tags ?? []
2922
+ };
2923
+ }
2924
+ }
2925
+ return null;
2926
+ }
2927
+ /**
2928
+ * #1645: Complete the deferred contradiction auto-resolve after writeMemory
2929
+ * returns and the new write's tombstone status is known. Retires the old
2930
+ * memory + deindexes it ONLY when the new write is genuinely active (not
2931
+ * tombstone-blocked / pending_review). A blocked write must not retire the
2932
+ * only active copy — deferring here closes the "contradictionAutoResolve
2933
+ * supersedes before tombstone status is known" defect class.
2934
+ */
2935
+ async applyDeferredContradictionResolve(contradiction, storage, newMemoryId, postWriteGuard) {
2936
+ const config = this.getConfig();
2937
+ if (postWriteGuard && contradiction && config.contradictionAutoResolve) {
2938
+ try {
2939
+ const blockedRow = await storage.getMemoryById(newMemoryId);
2940
+ if (blockedRow?.frontmatter?.supersedes) {
2941
+ await storage.writeMemoryFrontmatter(blockedRow, { supersedes: void 0 });
2942
+ }
2943
+ } catch (err) {
2944
+ log.warn(
2945
+ `contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`
2946
+ );
2947
+ }
2948
+ }
2949
+ if (!contradiction || !config.contradictionAutoResolve || postWriteGuard) {
2950
+ return;
2951
+ }
2952
+ try {
2953
+ await storage.supersedeMemory(
2954
+ contradiction.supersededId,
2955
+ newMemoryId,
2956
+ contradiction.reason
2957
+ );
2958
+ if (resolveIndexingCapabilities(config).queryAwareIndexing && contradiction.supersededPath) {
2959
+ deindexMemory(
2960
+ config.memoryDir,
2961
+ contradiction.supersededPath,
2962
+ contradiction.supersededCreated,
2963
+ contradiction.supersededTags
2964
+ );
2965
+ }
2966
+ } catch (err) {
2967
+ log.warn(
2968
+ `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
2969
+ );
2970
+ }
2971
+ }
2972
+ // ---------------------------------------------------------------------------
2973
+ // Memory Linking (Phase 3A)
2974
+ // ---------------------------------------------------------------------------
2975
+ /**
2976
+ * Suggest links for a new memory based on similar existing memories.
2977
+ */
2978
+ async suggestLinksForMemory(content, category, namespaceScope) {
2979
+ if (!this.isSearchAvailable()) return [];
2980
+ const results = await this.searchAcrossNamespaces({
2981
+ query: content,
2982
+ namespaces: [namespaceScope],
2983
+ maxResults: 5,
2984
+ mode: "search"
2985
+ });
2986
+ if (results.length === 0) return [];
2987
+ const candidates = [];
2988
+ for (const result of results) {
2989
+ const memoryId = this.extractMemoryIdsFromResults([result])[0];
2990
+ if (!memoryId) continue;
2991
+ const resultNamespace = this.namespaceFromPath(result.path);
2992
+ if (resultNamespace !== namespaceScope) continue;
2993
+ const resultStorage = await this.storageForNamespace(resultNamespace);
2994
+ const memory = await resultStorage.getMemoryById(memoryId);
2995
+ if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
2996
+ candidates.push({
2997
+ id: memory.frontmatter.id,
2998
+ content: memory.content,
2999
+ category: memory.frontmatter.category
3000
+ });
3001
+ }
3002
+ }
3003
+ if (candidates.length === 0) return [];
3004
+ const extraction = this.getExtraction();
3005
+ const suggestions = await extraction.suggestLinks(
3006
+ { content, category },
3007
+ candidates
3008
+ );
3009
+ if (!suggestions || suggestions.links.length === 0) return [];
3010
+ return suggestions.links.map((link) => ({
3011
+ targetId: link.targetId,
3012
+ linkType: link.linkType,
3013
+ strength: link.strength,
3014
+ reason: link.reason || void 0
3015
+ }));
3016
+ }
3017
+ };
3018
+
3019
+ // src/maintenance/pattern-reinforcement.ts
3020
+ function patternReinforcementKey(content) {
3021
+ return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
3022
+ }
3023
+ function patternReinforcementClusterKey(category, content) {
3024
+ return `${category}::${patternReinforcementKey(content)}`;
3025
+ }
3026
+ function pickCanonical(memories) {
3027
+ let best = memories[0];
3028
+ let bestInstant = memoryInstant(best);
3029
+ let bestStamp = memoryStamp(best);
3030
+ for (let i = 1; i < memories.length; i += 1) {
3031
+ const candidate = memories[i];
3032
+ const instant = memoryInstant(candidate);
3033
+ const stamp = memoryStamp(candidate);
3034
+ let cmp;
3035
+ if (instant !== null && bestInstant !== null) {
3036
+ cmp = instant - bestInstant;
3037
+ } else {
3038
+ cmp = stamp.localeCompare(bestStamp);
3039
+ }
3040
+ if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
3041
+ best = candidate;
3042
+ bestInstant = instant;
3043
+ bestStamp = stamp;
3044
+ }
3045
+ }
3046
+ return best;
3047
+ }
3048
+ function memoryStamp(memory) {
3049
+ return memory.frontmatter.updated || memory.frontmatter.created || "";
3050
+ }
3051
+ function memoryInstant(memory) {
3052
+ const stamp = memoryStamp(memory);
3053
+ if (stamp.length === 0) return null;
3054
+ const parsed = Date.parse(stamp);
3055
+ return Number.isFinite(parsed) ? parsed : null;
3056
+ }
3057
+ var ACTIVE_STATUS = "active";
3058
+ async function runPatternReinforcement(storage, options) {
3059
+ const minCount = Math.max(2, Math.floor(options.minCount));
3060
+ const targetCategories = new Set(options.categories);
3061
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
3062
+ const nowIso = now().toISOString();
3063
+ if (targetCategories.size === 0) {
3064
+ return emptyResult();
3065
+ }
3066
+ const memories = await storage.readAllMemories();
3067
+ const eligible = memories.filter((m) => {
3068
+ if (!targetCategories.has(m.frontmatter.category)) return false;
3069
+ const status = m.frontmatter.status ?? ACTIVE_STATUS;
3070
+ return status === ACTIVE_STATUS || status === "superseded";
3071
+ });
3072
+ if (eligible.length === 0) return emptyResult();
3073
+ const clusters = clusterByKey(
3074
+ eligible,
3075
+ (m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
3076
+ );
3077
+ const result = {
3078
+ clustersFound: 0,
3079
+ canonicalsUpdated: 0,
3080
+ duplicatesSuperseded: 0,
3081
+ clusters: []
3082
+ };
3083
+ for (const cluster of clusters.values()) {
3084
+ if (cluster.length < minCount) continue;
3085
+ const activeMembers = cluster.filter((m) => {
3086
+ const status = m.frontmatter.status ?? ACTIVE_STATUS;
3087
+ return status === ACTIVE_STATUS;
3088
+ });
3089
+ if (activeMembers.length === 0) continue;
3090
+ result.clustersFound += 1;
3091
+ const canonical = pickCanonical(activeMembers);
3092
+ const activeDuplicates = activeMembers.filter((m) => m !== canonical);
3093
+ const sourceIds = [...cluster].map((m) => m.frontmatter.id).filter((id) => typeof id === "string" && id.length > 0).sort();
3094
+ const previousCount = canonical.frontmatter.reinforcement_count ?? 0;
3095
+ const newCount = sourceIds.length;
3096
+ const reinforcementBumped = newCount > previousCount;
3097
+ const previousDerivedFrom = Array.isArray(canonical.frontmatter.derived_from) ? [...canonical.frontmatter.derived_from].sort() : [];
3098
+ const sortedSourceIds = [...sourceIds].sort();
3099
+ const membershipChanged = previousDerivedFrom.length !== sortedSourceIds.length || previousDerivedFrom.some((id, i) => id !== sortedSourceIds[i]);
3100
+ const previousVia = canonical.frontmatter.derived_via;
3101
+ const viaChanged = previousVia !== "pattern-reinforcement";
3102
+ const canonicalNeedsRefresh = reinforcementBumped || membershipChanged || viaChanged;
3103
+ if (canonicalNeedsRefresh) {
3104
+ const patch = {
3105
+ derived_from: sourceIds,
3106
+ derived_via: "pattern-reinforcement",
3107
+ updated: nowIso
3108
+ };
3109
+ if (reinforcementBumped) {
3110
+ patch.reinforcement_count = newCount;
3111
+ patch.last_reinforced_at = nowIso;
3112
+ } else {
3113
+ patch.reinforcement_count = canonical.frontmatter.reinforcement_count ?? newCount;
3114
+ patch.last_reinforced_at = canonical.frontmatter.last_reinforced_at ?? nowIso;
3115
+ }
3116
+ await storage.writeMemoryFrontmatter(canonical, patch);
3117
+ result.canonicalsUpdated += 1;
3118
+ }
3119
+ const supersededIds = [];
3120
+ for (const dup of activeDuplicates) {
3121
+ const patch = {
3122
+ status: "superseded",
3123
+ supersededBy: canonical.frontmatter.id,
3124
+ supersededAt: nowIso,
3125
+ updated: nowIso
3126
+ };
3127
+ await storage.writeMemoryFrontmatter(dup, patch);
3128
+ supersededIds.push(dup.frontmatter.id);
3129
+ result.duplicatesSuperseded += 1;
3130
+ if (storage.appendTombstone) {
3131
+ for (const input of buildRetiredFactTombstoneInputs(
3132
+ {
3133
+ id: dup.frontmatter.id,
3134
+ content: dup.content,
3135
+ contentHash: dup.frontmatter.contentHash,
3136
+ entityRef: dup.frontmatter.entityRef,
3137
+ structuredAttributes: dup.frontmatter.structuredAttributes
3138
+ },
3139
+ { reason: "supersession", createdBy: "supersession", createdAt: nowIso, supersessionKeysForFact }
3140
+ )) {
3141
+ try {
3142
+ await storage.appendTombstone(input);
3143
+ } catch {
3144
+ }
3145
+ }
3146
+ }
3147
+ }
3148
+ result.clusters.push({
3149
+ canonicalId: canonical.frontmatter.id,
3150
+ count: newCount,
3151
+ sourceIds,
3152
+ supersededIds,
3153
+ reinforcementBumped
3154
+ });
3155
+ }
3156
+ return result;
3157
+ }
3158
+ function emptyResult() {
3159
+ return {
3160
+ clustersFound: 0,
3161
+ canonicalsUpdated: 0,
3162
+ duplicatesSuperseded: 0,
3163
+ clusters: []
3164
+ };
3165
+ }
3166
+
3167
+ // src/dedup/semantic.ts
3168
+ var DEFAULT_SEMANTIC_THRESHOLD = 0.92;
3169
+ var DEFAULT_SEMANTIC_CANDIDATES = 5;
3170
+ function normalizeSemanticThreshold(value) {
3171
+ return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : DEFAULT_SEMANTIC_THRESHOLD;
3172
+ }
3173
+ function normalizeSemanticCandidates(value) {
3174
+ if (!Number.isFinite(value) || value < 0) {
3175
+ return DEFAULT_SEMANTIC_CANDIDATES;
3176
+ }
3177
+ const normalized = Math.floor(value);
3178
+ return value > 0 && normalized === 0 ? 1 : normalized;
3179
+ }
3180
+ async function decideSemanticDedup(content, lookup, options) {
3181
+ if (!options.enabled) {
3182
+ return { action: "keep", reason: "disabled" };
3183
+ }
3184
+ const threshold = normalizeSemanticThreshold(options.threshold);
3185
+ const candidates = normalizeSemanticCandidates(options.candidates);
3186
+ if (candidates === 0) {
3187
+ return { action: "keep", reason: "disabled" };
3188
+ }
3189
+ const trimmed = typeof content === "string" ? content.trim() : "";
3190
+ if (!trimmed) {
3191
+ return { action: "keep", reason: "no_near_duplicate" };
3192
+ }
3193
+ let hits = [];
3194
+ try {
3195
+ hits = await lookup(trimmed, candidates);
3196
+ } catch {
3197
+ return { action: "keep", reason: "backend_unavailable" };
3198
+ }
3199
+ if (!Array.isArray(hits) || hits.length === 0) {
3200
+ return { action: "keep", reason: "no_candidates" };
3201
+ }
3202
+ let top;
3203
+ for (const hit of hits) {
3204
+ if (!hit || typeof hit.id !== "string" || hit.id.trim().length === 0 || typeof hit.score !== "number" || !Number.isFinite(hit.score)) {
3205
+ continue;
3206
+ }
3207
+ if (!top || hit.score > top.score) {
3208
+ top = hit;
3209
+ }
3210
+ }
3211
+ if (!top) {
3212
+ return { action: "keep", reason: "no_near_duplicate" };
3213
+ }
3214
+ if (top.score >= threshold) {
3215
+ return {
3216
+ action: "skip",
3217
+ reason: "near_duplicate",
3218
+ topScore: top.score,
3219
+ topId: top.id,
3220
+ topPath: top.path
3221
+ };
3222
+ }
3223
+ return {
3224
+ action: "keep",
3225
+ reason: "no_near_duplicate",
3226
+ topScore: top.score,
2602
3227
  topId: top.id
2603
3228
  };
2604
3229
  }
@@ -2724,7 +3349,7 @@ function generateResolverDocument(taxonomy) {
2724
3349
 
2725
3350
  // src/taxonomy/taxonomy-loader.ts
2726
3351
  import { readFile, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
2727
- import path4 from "path";
3352
+ import path5 from "path";
2728
3353
  var TAXONOMY_DIR = ".taxonomy";
2729
3354
  var TAXONOMY_FILE = "taxonomy.json";
2730
3355
  var MAX_SLUG_LENGTH = 32;
@@ -2822,7 +3447,7 @@ function validateTaxonomy(taxonomy) {
2822
3447
  }
2823
3448
  }
2824
3449
  async function loadTaxonomy(memoryDir) {
2825
- const taxonomyPath = path4.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3450
+ const taxonomyPath = path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2826
3451
  let raw;
2827
3452
  try {
2828
3453
  raw = await readFile(taxonomyPath, "utf-8");
@@ -2872,16 +3497,16 @@ async function loadTaxonomy(memoryDir) {
2872
3497
  }
2873
3498
  async function saveTaxonomy(memoryDir, taxonomy) {
2874
3499
  validateTaxonomy(taxonomy);
2875
- const dir = path4.join(memoryDir, TAXONOMY_DIR);
3500
+ const dir = path5.join(memoryDir, TAXONOMY_DIR);
2876
3501
  await mkdir2(dir, { recursive: true });
2877
- const filePath = path4.join(dir, TAXONOMY_FILE);
3502
+ const filePath = path5.join(dir, TAXONOMY_FILE);
2878
3503
  await writeFile2(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
2879
3504
  }
2880
3505
  function getTaxonomyDir(memoryDir) {
2881
- return path4.join(memoryDir, TAXONOMY_DIR);
3506
+ return path5.join(memoryDir, TAXONOMY_DIR);
2882
3507
  }
2883
3508
  function getTaxonomyFilePath(memoryDir) {
2884
- return path4.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3509
+ return path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2885
3510
  }
2886
3511
 
2887
3512
  // src/wearables/registry.ts
@@ -3781,42 +4406,6 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
3781
4406
  }
3782
4407
  }
3783
4408
  }
3784
- function qmdCollectionPathParts(resultPath) {
3785
- if (!resultPath || path5.isAbsolute(resultPath)) return null;
3786
- const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
3787
- const slashIndex = normalized.indexOf("/");
3788
- if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
3789
- const collection = normalized.slice(0, slashIndex);
3790
- if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
3791
- return {
3792
- collection,
3793
- relativePath: normalized.slice(slashIndex + 1)
3794
- };
3795
- }
3796
- function qmdResultPathCandidates(storageDir, resultPath) {
3797
- const candidates = /* @__PURE__ */ new Set();
3798
- const storageRoot = path5.resolve(storageDir);
3799
- const addCandidate = (candidate) => {
3800
- const resolved = path5.resolve(candidate);
3801
- if (isPathInsideStorageRoot(storageRoot, resolved)) {
3802
- candidates.add(resolved);
3803
- }
3804
- };
3805
- const addRelativeCandidates = (relativePath) => {
3806
- const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
3807
- if (!normalized) return;
3808
- addCandidate(path5.join(storageRoot, normalized));
3809
- if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
3810
- addCandidate(path5.join(storageRoot, "facts", normalized));
3811
- }
3812
- };
3813
- if (path5.isAbsolute(resultPath)) {
3814
- addCandidate(resultPath);
3815
- } else {
3816
- addRelativeCandidates(resultPath);
3817
- }
3818
- return [...candidates];
3819
- }
3820
4409
  var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
3821
4410
  var DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS = 1e4;
3822
4411
  function normalizeIanaTimeZone(value) {
@@ -3927,7 +4516,7 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
3927
4516
  return await Promise.race([checkedPromise, timeoutPromise]);
3928
4517
  }
3929
4518
  function defaultWorkspaceDir() {
3930
- return path5.join(os2.homedir(), ".openclaw", "workspace");
4519
+ return path6.join(os2.homedir(), ".openclaw", "workspace");
3931
4520
  }
3932
4521
  function sanitizeSessionKeyForFilename(sessionKey) {
3933
4522
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -4204,11 +4793,11 @@ function mergeGraphExpandedResults(primary, expanded) {
4204
4793
  return Array.from(mergedByPath.values());
4205
4794
  }
4206
4795
  function graphPathRelativeToStorage(storageDir, candidatePath) {
4207
- const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
4208
- const rel = path5.relative(storageDir, absolutePath);
4796
+ const absolutePath = path6.isAbsolute(candidatePath) ? candidatePath : path6.resolve(storageDir, candidatePath);
4797
+ const rel = path6.relative(storageDir, absolutePath);
4209
4798
  if (!rel || rel === ".") return null;
4210
4799
  if (rel.startsWith("..")) return null;
4211
- return rel.split(path5.sep).join("/");
4800
+ return rel.split(path6.sep).join("/");
4212
4801
  }
4213
4802
  function normalizeGraphActivationScore(score) {
4214
4803
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -4353,7 +4942,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
4353
4942
  for (const mem of allMemsForGraph ?? []) {
4354
4943
  const id = mem.frontmatter.id;
4355
4944
  if (!id) continue;
4356
- pathById.set(id, path5.relative(storageDir, mem.path));
4945
+ pathById.set(id, path6.relative(storageDir, mem.path));
4357
4946
  }
4358
4947
  return pathById;
4359
4948
  }
@@ -4361,7 +4950,7 @@ function appendMemoryToGraphContext(options) {
4361
4950
  if (!Array.isArray(options.allMemsForGraph)) return;
4362
4951
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4363
4952
  options.allMemsForGraph.push({
4364
- path: path5.join(options.storageDir, options.memoryRelPath),
4953
+ path: path6.join(options.storageDir, options.memoryRelPath),
4365
4954
  content: options.content,
4366
4955
  frontmatter: {
4367
4956
  id: options.memoryId,
@@ -4381,16 +4970,16 @@ function resolvePersistedMemoryRelativePath(options) {
4381
4970
  const persisted = options.pathById.get(options.memoryId);
4382
4971
  if (persisted) return persisted;
4383
4972
  if (options.category === "correction") {
4384
- return path5.join("corrections", `${options.memoryId}.md`);
4973
+ return path6.join("corrections", `${options.memoryId}.md`);
4385
4974
  }
4386
4975
  const subtree = categoryDirName(options.category);
4387
4976
  const idParts = options.memoryId.split("-");
4388
4977
  const maybeTimestamp = Number(idParts[1]);
4389
4978
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
4390
4979
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
4391
- return path5.join(subtree, day, `${options.memoryId}.md`);
4980
+ return path6.join(subtree, day, `${options.memoryId}.md`);
4392
4981
  }
4393
- return path5.join(subtree, `${options.memoryId}.md`);
4982
+ return path6.join(subtree, `${options.memoryId}.md`);
4394
4983
  }
4395
4984
  var Orchestrator = class _Orchestrator {
4396
4985
  storage;
@@ -4552,6 +5141,9 @@ var Orchestrator = class _Orchestrator {
4552
5141
  */
4553
5142
  conversationIndexCoordinator;
4554
5143
  recallRerankCoordinator;
5144
+ recallSectionCoordinator;
5145
+ qmdResultResolver;
5146
+ contradictionLinkingCoordinator;
4555
5147
  heartbeatObserverChains = /* @__PURE__ */ new Map();
4556
5148
  recentExtractionFingerprints = /* @__PURE__ */ new Map();
4557
5149
  consolidationObservers = /* @__PURE__ */ new Set();
@@ -4844,7 +5436,7 @@ var Orchestrator = class _Orchestrator {
4844
5436
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4845
5437
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
4846
5438
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
4847
- const resolvedStorageDir = path5.resolve(storageDir);
5439
+ const resolvedStorageDir = path6.resolve(storageDir);
4848
5440
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
4849
5441
  if (!hints) {
4850
5442
  hints = /* @__PURE__ */ new Set();
@@ -4855,21 +5447,21 @@ var Orchestrator = class _Orchestrator {
4855
5447
  storageDirMatchesNamespaceHint(namespace, storageDir) {
4856
5448
  const ns = normalizeNamespaceIdentity(namespace);
4857
5449
  if (!ns) return false;
4858
- const resolvedStorageDir = path5.resolve(storageDir);
4859
- const resolvedMemoryDir = path5.resolve(this.config.memoryDir);
5450
+ const resolvedStorageDir = path6.resolve(storageDir);
5451
+ const resolvedMemoryDir = path6.resolve(this.config.memoryDir);
4860
5452
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4861
5453
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
4862
- const resolvedNamespacesDir = path5.join(resolvedMemoryDir, "namespaces");
5454
+ const resolvedNamespacesDir = path6.join(resolvedMemoryDir, "namespaces");
4863
5455
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
4864
- const rawRoot = path5.resolve(resolvedNamespacesDir, ns);
4865
- const tokenRoot = path5.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
5456
+ const rawRoot = path6.resolve(resolvedNamespacesDir, ns);
5457
+ const tokenRoot = path6.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4866
5458
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
4867
5459
  }
4868
5460
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
4869
- if (resolvedStorageDir === path5.resolve(this.config.memoryDir)) {
5461
+ if (resolvedStorageDir === path6.resolve(this.config.memoryDir)) {
4870
5462
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
4871
5463
  }
4872
- const leaf = path5.basename(resolvedStorageDir);
5464
+ const leaf = path6.basename(resolvedStorageDir);
4873
5465
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
4874
5466
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
4875
5467
  if (record.namespace === leaf) return 1;
@@ -4897,7 +5489,7 @@ var Orchestrator = class _Orchestrator {
4897
5489
  loadNamespaceStorageDirHintsFromCatalog() {
4898
5490
  if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
4899
5491
  this.namespaceStorageDirHintsLoaded = true;
4900
- const catalogPath = path5.join(this.config.memoryDir, "state", "namespaces.jsonl");
5492
+ const catalogPath = path6.join(this.config.memoryDir, "state", "namespaces.jsonl");
4901
5493
  if (!existsSync(catalogPath)) return;
4902
5494
  let body;
4903
5495
  try {
@@ -4934,7 +5526,7 @@ var Orchestrator = class _Orchestrator {
4934
5526
  if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
4935
5527
  continue;
4936
5528
  }
4937
- const resolvedStorageDir = path5.resolve(record.storageDir);
5529
+ const resolvedStorageDir = path6.resolve(record.storageDir);
4938
5530
  const current = preferredByStorageDir.get(resolvedStorageDir);
4939
5531
  preferredByStorageDir.set(
4940
5532
  resolvedStorageDir,
@@ -5198,7 +5790,7 @@ var Orchestrator = class _Orchestrator {
5198
5790
  this.config = config;
5199
5791
  this.profiler = new ProfilingCollector({
5200
5792
  enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
5201
- storageDir: config.profilingStorageDir || path5.join(config.memoryDir, "profiling"),
5793
+ storageDir: config.profilingStorageDir || path6.join(config.memoryDir, "profiling"),
5202
5794
  maxTraces: config.profilingMaxTraces
5203
5795
  });
5204
5796
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -5268,7 +5860,7 @@ var Orchestrator = class _Orchestrator {
5268
5860
  this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
5269
5861
  this.buffer = new SmartBuffer(config, this.storage);
5270
5862
  this.transcript = new TranscriptManager(config);
5271
- this.conversationIndexDir = path5.join(
5863
+ this.conversationIndexDir = path6.join(
5272
5864
  config.memoryDir,
5273
5865
  "conversation-index",
5274
5866
  "chunks"
@@ -5284,6 +5876,19 @@ var Orchestrator = class _Orchestrator {
5284
5876
  getStorage: (namespace) => this.getStorage(namespace),
5285
5877
  readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
5286
5878
  });
5879
+ this.recallSectionCoordinator = new RecallSectionCoordinator({
5880
+ getConfig: () => this.config,
5881
+ resolveSectionEnabled: (id, def) => this.isRecallSectionEnabled(id, def)
5882
+ });
5883
+ this.contradictionLinkingCoordinator = new ContradictionLinkingCoordinator({
5884
+ getConfig: () => this.config,
5885
+ isSearchAvailable: () => this.isSearchAvailableForNamespaceRouting(),
5886
+ searchAcrossNamespaces: (options) => this.searchAcrossNamespaces(options),
5887
+ extractMemoryIdsFromResults: (results) => this.extractMemoryIdsFromResults(results),
5888
+ namespaceFromPath: (p) => this.namespaceFromPath(p),
5889
+ storageForNamespace: (namespace) => this.storageRouter.storageFor(namespace),
5890
+ getExtraction: () => this.extraction
5891
+ });
5287
5892
  this.modelRegistry = new ModelRegistry(config.memoryDir);
5288
5893
  this.relevance = new RelevanceStore(config.memoryDir);
5289
5894
  this.negatives = new NegativeExampleStore(config.memoryDir);
@@ -5310,6 +5915,13 @@ var Orchestrator = class _Orchestrator {
5310
5915
  getStorage: (namespace) => this.getStorage(namespace),
5311
5916
  fastChatCompletion: (messages, options) => this.fastChatCompletion(messages, options)
5312
5917
  });
5918
+ this.qmdResultResolver = new QmdResultResolver({
5919
+ getConfig: () => this.config,
5920
+ storageFor: (namespace) => this.storageRouter.storageFor(namespace),
5921
+ storageDirNamespace: (storageDir) => this.storageDirNamespace(storageDir),
5922
+ qmdCollectionNamespaceFromPrefix: (prefix) => this.qmdCollectionNamespaceFromPrefix(prefix),
5923
+ namespaceFromPath: (p) => this.namespaceFromPath(p)
5924
+ });
5313
5925
  this.sessionObserver = new SessionObserverState({
5314
5926
  memoryDir: config.memoryDir,
5315
5927
  debounceMs: config.sessionObserverDebounceMs ?? 12e4,
@@ -5374,7 +5986,7 @@ var Orchestrator = class _Orchestrator {
5374
5986
  saveContentHashIndexes: () => this.saveContentHashIndexes()
5375
5987
  });
5376
5988
  this.threading = new ThreadingManager(
5377
- path5.join(config.memoryDir, "threads"),
5989
+ path6.join(config.memoryDir, "threads"),
5378
5990
  config.threadingGapMinutes
5379
5991
  );
5380
5992
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
@@ -5697,7 +6309,7 @@ var Orchestrator = class _Orchestrator {
5697
6309
  const files = await readdir2(wsDir).catch(() => []);
5698
6310
  for (const f of files) {
5699
6311
  if (!f.startsWith(".compaction-reset-signal-")) continue;
5700
- const fp = path5.join(wsDir, f);
6312
+ const fp = path6.join(wsDir, f);
5701
6313
  const s = await stat(fp).catch(() => null);
5702
6314
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
5703
6315
  await unlink(fp).catch(() => {
@@ -5892,7 +6504,7 @@ var Orchestrator = class _Orchestrator {
5892
6504
  if (signal.aborted) return;
5893
6505
  if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.config).qmdTierMigration) {
5894
6506
  try {
5895
- const { runFirstStartMigration } = await import("./first-start-migration-GQ3UQNIL.js");
6507
+ const { runFirstStartMigration } = await import("./first-start-migration-4I3VDSYS.js");
5896
6508
  const result = await runFirstStartMigration({
5897
6509
  storage: this.storage,
5898
6510
  config: this.config,
@@ -5915,7 +6527,7 @@ var Orchestrator = class _Orchestrator {
5915
6527
  if (signal.aborted) return;
5916
6528
  if (!this.wearablesAutoSyncHandle && this.config.wearables.enabled && this.config.wearables.autoSyncEnabled && Object.values(this.config.wearables.sources).some((source) => source.enabled)) {
5917
6529
  try {
5918
- const { startWearablesAutoSync } = await import("./auto-sync-G3V5AN4C.js");
6530
+ const { startWearablesAutoSync } = await import("./auto-sync-XHSKKQAH.js");
5919
6531
  if (signal.aborted) return;
5920
6532
  this.wearablesAutoSyncHandle = startWearablesAutoSync(
5921
6533
  {
@@ -6206,15 +6818,15 @@ ${doc.content}` : doc.content,
6206
6818
  this.lastFileHygieneRunAtMs = now;
6207
6819
  if (hygiene.rotateEnabled) {
6208
6820
  for (const rel of hygiene.rotatePaths) {
6209
- const abs = path5.isAbsolute(rel) ? rel : path5.join(this.config.workspaceDir, rel);
6821
+ const abs = path6.isAbsolute(rel) ? rel : path6.join(this.config.workspaceDir, rel);
6210
6822
  try {
6211
6823
  const raw = await readFile2(abs, "utf-8");
6212
6824
  if (raw.length > hygiene.rotateMaxBytes) {
6213
- const archiveDir = path5.join(
6825
+ const archiveDir = path6.join(
6214
6826
  this.config.workspaceDir,
6215
6827
  hygiene.archiveDir
6216
6828
  );
6217
- const base = path5.basename(abs);
6829
+ const base = path6.basename(abs);
6218
6830
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
6219
6831
  const { newContent } = await rotateMarkdownFileToArchive({
6220
6832
  filePath: abs,
@@ -6239,8 +6851,8 @@ ${doc.content}` : doc.content,
6239
6851
  log.warn(w.message);
6240
6852
  }
6241
6853
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
6242
- const fp = path5.join(this.config.memoryDir, hygiene.warningsLogPath);
6243
- await mkdir3(path5.dirname(fp), { recursive: true });
6854
+ const fp = path6.join(this.config.memoryDir, hygiene.warningsLogPath);
6855
+ await mkdir3(path6.dirname(fp), { recursive: true });
6244
6856
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
6245
6857
  const block = `
6246
6858
 
@@ -6379,7 +6991,7 @@ ${doc.content}` : doc.content,
6379
6991
  for (const categoryDir of RECALL_FALLBACK_DIRS) {
6380
6992
  if (memoryRootReal === null) break;
6381
6993
  for (const date of datesToScan) {
6382
- const dateDir = path5.join(storage.dir, categoryDir, date);
6994
+ const dateDir = path6.join(storage.dir, categoryDir, date);
6383
6995
  try {
6384
6996
  const dirStat = await lstat(dateDir);
6385
6997
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
@@ -6388,7 +7000,7 @@ ${doc.content}` : doc.content,
6388
7000
  for (const entry of entries) {
6389
7001
  if (entry.isSymbolicLink()) continue;
6390
7002
  if (!entry.name.endsWith(".md")) continue;
6391
- const fullPath = path5.join(dateDir, entry.name);
7003
+ const fullPath = path6.join(dateDir, entry.name);
6392
7004
  try {
6393
7005
  assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
6394
7006
  const raw = await readFile2(fullPath, "utf-8");
@@ -6410,7 +7022,7 @@ ${doc.content}` : doc.content,
6410
7022
  facts.push({
6411
7023
  path: fullPath,
6412
7024
  frontmatter: {
6413
- id: fm.id || path5.basename(entry.name, ".md"),
7025
+ id: fm.id || path6.basename(entry.name, ".md"),
6414
7026
  category: fm.category || "fact",
6415
7027
  created,
6416
7028
  updated: fm.updated || created,
@@ -6433,13 +7045,13 @@ ${doc.content}` : doc.content,
6433
7045
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
6434
7046
  });
6435
7047
  const hourlySummaries = [];
6436
- const hourlyBaseDir = path5.join(storage.dir, "summaries", "hourly");
7048
+ const hourlyBaseDir = path6.join(storage.dir, "summaries", "hourly");
6437
7049
  try {
6438
7050
  const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
6439
7051
  for (const sk of sessionKeys) {
6440
7052
  if (!sk.isDirectory()) continue;
6441
7053
  for (const date of datesToScan) {
6442
- const summaryFile = path5.join(hourlyBaseDir, sk.name, `${date}.md`);
7054
+ const summaryFile = path6.join(hourlyBaseDir, sk.name, `${date}.md`);
6443
7055
  try {
6444
7056
  const raw = await readFile2(summaryFile, "utf-8");
6445
7057
  const filtered = filterHourlySummaryMarkdownForLocalDay(
@@ -6543,7 +7155,7 @@ ${doc.content}` : doc.content,
6543
7155
  }
6544
7156
  async getLastGraphRecallSnapshot(namespace) {
6545
7157
  const storage = await this.getStorage(namespace);
6546
- const snapshotPath = path5.join(
7158
+ const snapshotPath = path6.join(
6547
7159
  storage.dir,
6548
7160
  "state",
6549
7161
  "last_graph_recall.json"
@@ -6582,7 +7194,7 @@ ${doc.content}` : doc.content,
6582
7194
  }
6583
7195
  async getLastIntentSnapshot(namespace) {
6584
7196
  const storage = await this.getStorage(namespace);
6585
- const snapshotPath = path5.join(storage.dir, "state", "last_intent.json");
7197
+ const snapshotPath = path6.join(storage.dir, "state", "last_intent.json");
6586
7198
  try {
6587
7199
  const raw = await readFile2(snapshotPath, "utf-8");
6588
7200
  const parsed = JSON.parse(raw);
@@ -6615,7 +7227,7 @@ ${doc.content}` : doc.content,
6615
7227
  }
6616
7228
  async getLastQmdRecallSnapshot(namespace) {
6617
7229
  const storage = await this.getStorage(namespace);
6618
- const snapshotPath = path5.join(
7230
+ const snapshotPath = path6.join(
6619
7231
  storage.dir,
6620
7232
  "state",
6621
7233
  "last_qmd_recall.json"
@@ -7499,7 +8111,7 @@ ${doc.content}` : doc.content,
7499
8111
  resolvedPath = resolvedCold.result.path;
7500
8112
  resolvedResult = resolvedCold.result;
7501
8113
  }
7502
- if (!path5.isAbsolute(resolvedPath)) {
8114
+ if (!path6.isAbsolute(resolvedPath)) {
7503
8115
  resolvedAmbiguousSeeds.set(result.path, null);
7504
8116
  return null;
7505
8117
  }
@@ -7524,7 +8136,7 @@ ${doc.content}` : doc.content,
7524
8136
  }
7525
8137
  continue;
7526
8138
  }
7527
- if (path5.isAbsolute(result.path)) {
8139
+ if (path6.isAbsolute(result.path)) {
7528
8140
  const resolved = await resolveAmbiguousSeedOwner(result, null);
7529
8141
  if (resolved) {
7530
8142
  addResultForNamespace(resolved.namespace, resolved.result);
@@ -7567,7 +8179,7 @@ ${doc.content}` : doc.content,
7567
8179
  0
7568
8180
  );
7569
8181
  seedPaths.push(
7570
- ...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
8182
+ ...seedRelativePaths.map((rel) => path6.join(storage.dir, rel))
7571
8183
  );
7572
8184
  const seedSet = new Set(seedRelativePaths);
7573
8185
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -7583,7 +8195,7 @@ ${doc.content}` : doc.content,
7583
8195
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
7584
8196
  if (deadlineExpired()) break;
7585
8197
  if (seedSet.has(candidate.path)) continue;
7586
- const memoryPath = path5.resolve(storage.dir, candidate.path);
8198
+ const memoryPath = path6.resolve(storage.dir, candidate.path);
7587
8199
  const memory = await storage.readMemoryByPath(memoryPath);
7588
8200
  if (deadlineExpired()) break;
7589
8201
  if (!memory) continue;
@@ -7608,7 +8220,7 @@ ${doc.content}` : doc.content,
7608
8220
  path: memory.path,
7609
8221
  score,
7610
8222
  namespace,
7611
- seed: path5.resolve(storage.dir, candidate.seed),
8223
+ seed: path6.resolve(storage.dir, candidate.seed),
7612
8224
  hopDepth: candidate.hopDepth,
7613
8225
  decayedWeight: candidate.decayedWeight,
7614
8226
  graphType: candidate.graphType,
@@ -7629,12 +8241,12 @@ ${doc.content}` : doc.content,
7629
8241
  }
7630
8242
  async recordLastGraphRecallSnapshot(options) {
7631
8243
  try {
7632
- const snapshotPath = path5.join(
8244
+ const snapshotPath = path6.join(
7633
8245
  options.storage.dir,
7634
8246
  "state",
7635
8247
  "last_graph_recall.json"
7636
8248
  );
7637
- await mkdir3(path5.dirname(snapshotPath), { recursive: true });
8249
+ await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7638
8250
  const now = (/* @__PURE__ */ new Date()).toISOString();
7639
8251
  const totalSeedCount = options.seedPaths.length;
7640
8252
  const totalExpandedCount = options.expandedPaths.length;
@@ -7668,12 +8280,12 @@ ${doc.content}` : doc.content,
7668
8280
  }
7669
8281
  async recordLastIntentSnapshot(options) {
7670
8282
  try {
7671
- const snapshotPath = path5.join(
8283
+ const snapshotPath = path6.join(
7672
8284
  options.storage.dir,
7673
8285
  "state",
7674
8286
  "last_intent.json"
7675
8287
  );
7676
- await mkdir3(path5.dirname(snapshotPath), { recursive: true });
8288
+ await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7677
8289
  await writeFile3(
7678
8290
  snapshotPath,
7679
8291
  JSON.stringify(options.snapshot, null, 2),
@@ -7685,12 +8297,12 @@ ${doc.content}` : doc.content,
7685
8297
  }
7686
8298
  async recordLastQmdRecallSnapshot(options) {
7687
8299
  try {
7688
- const snapshotPath = path5.join(
8300
+ const snapshotPath = path6.join(
7689
8301
  options.storage.dir,
7690
8302
  "state",
7691
8303
  "last_qmd_recall.json"
7692
8304
  );
7693
- await mkdir3(path5.dirname(snapshotPath), { recursive: true });
8305
+ await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7694
8306
  await writeFile3(
7695
8307
  snapshotPath,
7696
8308
  JSON.stringify(options.snapshot, null, 2),
@@ -7705,8 +8317,8 @@ ${doc.content}` : doc.content,
7705
8317
  const stateDir = await this.resolveStateDirForNamespace(
7706
8318
  options.namespace
7707
8319
  );
7708
- const snapshotPath = path5.join(stateDir, "last_intent.json");
7709
- await mkdir3(path5.dirname(snapshotPath), { recursive: true });
8320
+ const snapshotPath = path6.join(stateDir, "last_intent.json");
8321
+ await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7710
8322
  await writeFile3(
7711
8323
  snapshotPath,
7712
8324
  JSON.stringify(options.snapshot, null, 2),
@@ -7718,12 +8330,12 @@ ${doc.content}` : doc.content,
7718
8330
  }
7719
8331
  async resolveStateDirForNamespace(namespace) {
7720
8332
  if (!resolveNamespaceCapabilities(this.config).namespaces) {
7721
- return path5.join(this.config.memoryDir, "state");
8333
+ return path6.join(this.config.memoryDir, "state");
7722
8334
  }
7723
8335
  if (namespace !== this.config.defaultNamespace) {
7724
- return path5.join(this.config.memoryDir, "namespaces", namespace, "state");
8336
+ return path6.join(this.config.memoryDir, "namespaces", namespace, "state");
7725
8337
  }
7726
- const candidate = path5.join(
8338
+ const candidate = path6.join(
7727
8339
  this.config.memoryDir,
7728
8340
  "namespaces",
7729
8341
  this.config.defaultNamespace
@@ -7731,11 +8343,11 @@ ${doc.content}` : doc.content,
7731
8343
  try {
7732
8344
  const candidateStat = await stat(candidate);
7733
8345
  if (candidateStat.isDirectory()) {
7734
- return path5.join(candidate, "state");
8346
+ return path6.join(candidate, "state");
7735
8347
  }
7736
8348
  } catch {
7737
8349
  }
7738
- return path5.join(this.config.memoryDir, "state");
8350
+ return path6.join(this.config.memoryDir, "state");
7739
8351
  }
7740
8352
  buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
7741
8353
  return results.slice(0, limit).map((result) => ({
@@ -7745,173 +8357,51 @@ ${doc.content}` : doc.content,
7745
8357
  sourceLabels: sourceLabelResolver(result.path)
7746
8358
  }));
7747
8359
  }
8360
+ // Issue #1526 (seam 13): recall section budgeting/assembly moved to
8361
+ // RecallSectionCoordinator. Thin delegation keeps the orchestrator's
8362
+ // recallInternal call sites stable.
7748
8363
  getRecallSectionEntry(sectionId) {
7749
- const pipeline = Array.isArray(this.config.recallPipeline) ? this.config.recallPipeline : [];
7750
- return pipeline.find((entry) => entry.id === sectionId);
8364
+ return this.recallSectionCoordinator.getRecallSectionEntry(sectionId);
7751
8365
  }
7752
8366
  isRecallSectionEnabled(sectionId, defaultEnabled = true) {
7753
- const entry = this.getRecallSectionEntry(sectionId);
7754
- if (!entry) return defaultEnabled;
7755
- return entry.enabled !== false;
8367
+ return this.recallSectionCoordinator.isRecallSectionEnabled(
8368
+ sectionId,
8369
+ defaultEnabled
8370
+ );
7756
8371
  }
7757
8372
  isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
7758
- const entry = this.getRecallSectionEntry(sectionId);
7759
- if (!entry) return topLevelEnabled;
7760
- return entry.enabled === true || topLevelEnabled && entry.enabled !== false;
7761
- }
7762
- getRecallSectionMaxChars(sectionId) {
7763
- const entry = this.getRecallSectionEntry(sectionId);
7764
- if (!entry) return void 0;
7765
- if (entry.maxChars === null) return null;
7766
- if (typeof entry.maxChars !== "number") return void 0;
7767
- return Math.max(0, Math.floor(entry.maxChars));
7768
- }
7769
- getRecallSectionNumber(sectionId, key) {
7770
- const entry = this.getRecallSectionEntry(sectionId);
7771
- if (!entry) return void 0;
7772
- const value = entry[key];
7773
- if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
7774
- return Math.max(0, Math.floor(value));
7775
- }
7776
- appendRecallSection(sectionBuckets, sectionId, content) {
7777
- if (!this.isRecallSectionEnabled(sectionId)) return false;
7778
- const trimmed = content.trim();
7779
- if (trimmed.length === 0) return false;
7780
- const maxChars = this.getRecallSectionMaxChars(sectionId);
7781
- let finalContent = trimmed;
7782
- if (maxChars === 0) return false;
7783
- if (typeof maxChars === "number" && finalContent.length > maxChars) {
7784
- finalContent = `${finalContent.slice(0, maxChars)}
7785
-
7786
- ...(trimmed)
7787
- `;
7788
- }
7789
- const existing = sectionBuckets.get(sectionId) ?? [];
7790
- existing.push(finalContent);
7791
- sectionBuckets.set(sectionId, existing);
7792
- return true;
8373
+ return this.recallSectionCoordinator.isSpecializedRecallSectionEnabled(
8374
+ sectionId,
8375
+ topLevelEnabled
8376
+ );
7793
8377
  }
7794
- truncateRecallSectionToBudget(content, maxChars) {
7795
- if (maxChars <= 0) return "";
7796
- if (content.length <= maxChars) return content;
7797
- const suffix = "\n\n...(memory context trimmed)";
7798
- if (maxChars <= suffix.length) {
7799
- return content.slice(0, maxChars);
7800
- }
7801
- return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
8378
+ getRecallSectionMaxChars(sectionId) {
8379
+ return this.recallSectionCoordinator.getRecallSectionMaxChars(sectionId);
7802
8380
  }
7803
- protectedRecallSectionIds(sectionBuckets) {
7804
- const protectedIds = /* @__PURE__ */ new Set();
7805
- if ((sectionBuckets.get("memories")?.length ?? 0) > 0) {
7806
- protectedIds.add("memories");
7807
- }
7808
- return protectedIds;
8381
+ getRecallSectionNumber(sectionId, key) {
8382
+ return this.recallSectionCoordinator.getRecallSectionNumber(sectionId, key);
7809
8383
  }
7810
- protectedRecallReservationChars(content) {
7811
- const headingBoundary = content.indexOf("\n\n");
7812
- const headingChars = headingBoundary >= 0 ? headingBoundary + 2 : Math.min(content.length, 24);
7813
- return Math.min(content.length, Math.max(headingChars, 24));
8384
+ appendRecallSection(sectionBuckets, sectionId, content) {
8385
+ return this.recallSectionCoordinator.appendRecallSection(
8386
+ sectionBuckets,
8387
+ sectionId,
8388
+ content
8389
+ );
7814
8390
  }
7815
- estimateReservedRecallBudget(entries, startIndex, protectedIds, alreadyIncludedCount) {
7816
- const separatorLength = "\n\n---\n\n".length;
7817
- let reserved = 0;
7818
- let simulatedIncluded = alreadyIncludedCount;
7819
- for (let i = startIndex; i < entries.length; i += 1) {
7820
- const entry = entries[i];
7821
- if (!entry || !protectedIds.has(entry.id)) continue;
7822
- if (simulatedIncluded > 0) {
7823
- reserved += separatorLength;
7824
- }
7825
- reserved += this.protectedRecallReservationChars(entry.content);
7826
- simulatedIncluded += 1;
7827
- }
7828
- return reserved;
8391
+ truncateRecallSectionToBudget(content, maxChars) {
8392
+ return this.recallSectionCoordinator.truncateRecallSectionToBudget(
8393
+ content,
8394
+ maxChars
8395
+ );
7829
8396
  }
7830
8397
  getRecallBudgetChars(override) {
7831
- if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
7832
- return Math.floor(override);
7833
- }
7834
- const configuredBudget = this.config.recallBudgetChars;
7835
- if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
7836
- return Math.floor(configuredBudget);
7837
- }
7838
- const tokenBudget = this.config.maxMemoryTokens;
7839
- if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget >= 0) {
7840
- return Math.floor(tokenBudget * 4);
7841
- }
7842
- return 0;
8398
+ return this.recallSectionCoordinator.getRecallBudgetChars(override);
7843
8399
  }
7844
8400
  assembleRecallSections(sectionBuckets, budgetOverride) {
7845
- const orderedEntries = [];
7846
- const pipeline = Array.isArray(this.config.recallPipeline) ? this.config.recallPipeline : [];
7847
- const orderedIds = pipeline.filter((entry) => entry.enabled !== false).map((entry) => entry.id);
7848
- const seen = /* @__PURE__ */ new Set();
7849
- for (const id of orderedIds) {
7850
- const chunks = sectionBuckets.get(id);
7851
- if (!chunks || chunks.length === 0) continue;
7852
- orderedEntries.push({ id, content: chunks.join("\n\n") });
7853
- seen.add(id);
7854
- }
7855
- for (const [id, chunks] of sectionBuckets.entries()) {
7856
- if (seen.has(id)) continue;
7857
- if (chunks.length === 0) continue;
7858
- orderedEntries.push({ id, content: chunks.join("\n\n") });
7859
- }
7860
- const budget = this.getRecallBudgetChars(budgetOverride);
7861
- if (budget === 0) {
7862
- return {
7863
- sections: [],
7864
- includedIds: [],
7865
- omittedIds: orderedEntries.map((entry) => entry.id),
7866
- truncated: orderedEntries.length > 0,
7867
- finalChars: 0
7868
- };
7869
- }
7870
- const separator = "\n\n---\n\n";
7871
- const protectedIds = this.protectedRecallSectionIds(sectionBuckets);
7872
- const sections = [];
7873
- const includedIds = [];
7874
- const omittedIds = [];
7875
- let usedChars = 0;
7876
- let truncated = false;
7877
- for (let index = 0; index < orderedEntries.length; index += 1) {
7878
- const entry = orderedEntries[index];
7879
- const separatorChars = sections.length > 0 ? separator.length : 0;
7880
- const reserve = protectedIds.has(entry.id) ? 0 : this.estimateReservedRecallBudget(
7881
- orderedEntries,
7882
- index + 1,
7883
- protectedIds,
7884
- sections.length + 1
7885
- );
7886
- const availableForEntry = budget - usedChars - separatorChars - reserve;
7887
- if (availableForEntry <= 0) {
7888
- omittedIds.push(entry.id);
7889
- truncated = true;
7890
- continue;
7891
- }
7892
- const finalContent = this.truncateRecallSectionToBudget(
7893
- entry.content,
7894
- availableForEntry
7895
- );
7896
- if (!finalContent) {
7897
- omittedIds.push(entry.id);
7898
- truncated = true;
7899
- continue;
7900
- }
7901
- if (finalContent.length < entry.content.length) {
7902
- truncated = true;
7903
- }
7904
- sections.push(finalContent);
7905
- includedIds.push(entry.id);
7906
- usedChars += separatorChars + finalContent.length;
7907
- }
7908
- return {
7909
- sections,
7910
- includedIds,
7911
- omittedIds,
7912
- truncated,
7913
- finalChars: usedChars
7914
- };
8401
+ return this.recallSectionCoordinator.assembleRecallSections(
8402
+ sectionBuckets,
8403
+ budgetOverride
8404
+ );
7915
8405
  }
7916
8406
  /**
7917
8407
  * Clock source for the shared post-retrieval assembly/enrichment budget. The
@@ -8137,7 +8627,7 @@ ${doc.content}` : doc.content,
8137
8627
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
8138
8628
  const graphSourceLabelsForPath = (resultPath) => {
8139
8629
  const labels = [];
8140
- const normalizedPath = resultPath.split(path5.sep).join("/");
8630
+ const normalizedPath = resultPath.split(path6.sep).join("/");
8141
8631
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
8142
8632
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
8143
8633
  if (graphExpandedResultPaths.has(resultPath))
@@ -8287,7 +8777,7 @@ ${doc.content}` : doc.content,
8287
8777
  profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
8288
8778
  );
8289
8779
  const emptyProfileStorage = new Proxy(
8290
- { dir: path5.join(this.config.memoryDir, ".empty-scope-profile") },
8780
+ { dir: path6.join(this.config.memoryDir, ".empty-scope-profile") },
8291
8781
  {
8292
8782
  get(target, prop) {
8293
8783
  if (prop in target) return target[prop];
@@ -9763,11 +10253,11 @@ ${formatted}`;
9763
10253
  if (!resolveRecallAuxiliaryCapabilities(this.config).compactionReset) return null;
9764
10254
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
9765
10255
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
9766
- const signalPath = path5.join(
10256
+ const signalPath = path6.join(
9767
10257
  workspaceDir,
9768
10258
  `.compaction-reset-signal-${safeSessionKey}`
9769
10259
  );
9770
- const bootPath = path5.join(workspaceDir, "BOOT.md");
10260
+ const bootPath = path6.join(workspaceDir, "BOOT.md");
9771
10261
  try {
9772
10262
  const signalStat = await stat(signalPath).catch(() => null);
9773
10263
  if (!signalStat) return null;
@@ -14369,7 +14859,7 @@ ${normalized}`).digest("hex");
14369
14859
  const allMems = allMemsForGraph ?? [];
14370
14860
  for (const m of allMems) {
14371
14861
  if (m.frontmatter.entityRef === entityRef) {
14372
- const rel = path5.relative(storage.dir, m.path);
14862
+ const rel = path6.relative(storage.dir, m.path);
14373
14863
  if (rel !== memoryRelPath) entitySiblings.push(rel);
14374
14864
  }
14375
14865
  }
@@ -14693,7 +15183,7 @@ ${normalized}`).digest("hex");
14693
15183
  }
14694
15184
  if (resolveConsolidationCapabilities(this.config).semanticConsolidation) {
14695
15185
  try {
14696
- const stateFilePath = path5.join(
15186
+ const stateFilePath = path6.join(
14697
15187
  this.config.memoryDir,
14698
15188
  "state",
14699
15189
  "semantic-consolidation-last-run.json"
@@ -14741,7 +15231,7 @@ ${normalized}`).digest("hex");
14741
15231
  );
14742
15232
  }
14743
15233
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
14744
- const stateDir = path5.join(this.config.memoryDir, "state");
15234
+ const stateDir = path6.join(this.config.memoryDir, "state");
14745
15235
  await mkdir3(stateDir, { recursive: true });
14746
15236
  await writeFile3(
14747
15237
  stateFilePath,
@@ -15003,247 +15493,65 @@ ${reflectionsContent.trim()}
15003
15493
  if (!resolveEvalCapabilities(this.config).evalHarness || !resolveEvalCapabilities(this.config).evalShadowMode)
15004
15494
  return;
15005
15495
  this.evalShadowWriteChain = this.evalShadowWriteChain.catch(() => void 0).then(async () => {
15006
- try {
15007
- await recordEvalShadowRecall({
15008
- memoryDir: this.config.memoryDir,
15009
- evalStoreDir: this.config.evalStoreDir,
15010
- record: {
15011
- schemaVersion: 1,
15012
- ...record
15013
- }
15014
- });
15015
- } catch (err) {
15016
- log.debug(`eval shadow recall write failed: ${err}`);
15017
- }
15018
- });
15019
- }
15020
- publishRecallResults(options) {
15021
- const sectionId = "memories";
15022
- const trustByPath = options.trustByPath ?? null;
15023
- const injectable = trustByPath ? options.results.filter((r) => !trustByPath.get(r.path)?.quarantined) : options.results;
15024
- const memoryIds = this.extractMemoryIdsFromResults(injectable);
15025
- this.trackMemoryAccess(memoryIds);
15026
- this.appendRecallSection(
15027
- options.sectionBuckets,
15028
- sectionId,
15029
- this.formatQmdResults(options.title, injectable, options.sessionKey, trustByPath)
15030
- );
15031
- }
15032
- /**
15033
- * Apply MMR over the pre-truncation recall candidate pool and then slice
15034
- * the result to `limit`. This is the single place in the pipeline where
15035
- * MMR runs, and it must be called *before* callers throw away candidates
15036
- * that would otherwise sit below the final cutoff. Running MMR post-slice
15037
- * is a no-op in the cases we care about — diverse candidates just below
15038
- * the cutoff are already gone and can never be promoted.
15039
- *
15040
- * Callers must pass the full candidate pool (post-rerank, pre-slice).
15041
- */
15042
- qmdCollectionNamespaceFromPrefix(collectionPrefix) {
15043
- const baseCollection = this.config.qmdCollection;
15044
- if (collectionPrefix === baseCollection) return this.config.defaultNamespace;
15045
- const namespaceSuffix = collectionPrefix.startsWith(`${baseCollection}--`) ? collectionPrefix.slice(baseCollection.length + 2) : "";
15046
- if (!namespaceSuffix) return null;
15047
- const decoded = namespaceIdentityFromToken(namespaceSuffix);
15048
- if (decoded !== null) return decoded || this.config.defaultNamespace;
15049
- if (namespaceSuffix.startsWith("ns--")) {
15050
- const legacyNamespace = namespaceSuffix.slice("ns--".length).trim();
15051
- return legacyNamespace || null;
15052
- }
15053
- return null;
15054
- }
15055
- async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
15056
- const parts = qmdCollectionPathParts(resultPath);
15057
- const storageDirFor = (storage) => typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15058
- const fallbackStorageDir = storageDirFor(fallbackStorage);
15059
- const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
15060
- if (parts && parts.collection === coldCollection) {
15061
- const storages = [];
15062
- const seenStorageDirs = /* @__PURE__ */ new Set();
15063
- const addStorage = (storage) => {
15064
- const storageDir = storageDirFor(storage);
15065
- const storageKey = storageDir ? path5.resolve(storageDir) : `storage-without-dir-${storages.length}`;
15066
- if (seenStorageDirs.has(storageKey)) return;
15067
- seenStorageDirs.add(storageKey);
15068
- storages.push(storage);
15069
- };
15070
- const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : this.config.defaultNamespace;
15071
- if (recallNamespaces.length === 0 || !resolveNamespaceCapabilities(this.config).namespaces || recallNamespaces.includes(fallbackNamespace)) {
15072
- addStorage(fallbackStorage);
15073
- }
15074
- if (recallNamespaces.length > 0) {
15075
- for (const namespace of recallNamespaces) {
15076
- try {
15077
- addStorage(await this.storageRouter.storageFor(namespace));
15078
- } catch (err) {
15079
- log.debug("qmd cold result namespace storage lookup skipped", {
15080
- path: resultPath,
15081
- namespace,
15082
- error: err.message
15083
- });
15084
- }
15085
- }
15086
- }
15087
- for (const storage of storages) {
15088
- const storageDir = storageDirFor(storage);
15089
- if (!storageDir) {
15090
- const memory = await storage.readMemoryByPath(resultPath);
15091
- if (memory) return memory;
15092
- continue;
15093
- }
15094
- try {
15095
- const coldRoot = path5.join(storageDir, "cold");
15096
- for (const candidate of qmdResultPathCandidates(
15097
- coldRoot,
15098
- parts.relativePath
15099
- )) {
15100
- const memory = await storage.readMemoryByPath(candidate);
15101
- if (memory) return memory;
15102
- }
15103
- } catch (err) {
15104
- if (err instanceof SecureStoreLockedError) throw err;
15105
- log.debug("qmd cold result path lookup failed open", {
15106
- path: resultPath,
15107
- collection: coldCollection,
15108
- error: err.message
15109
- });
15110
- }
15111
- }
15112
- return null;
15113
- }
15114
- const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
15115
- if (parts && collectionNamespace) {
15116
- try {
15117
- const collectionStorage = await this.storageRouter.storageFor(collectionNamespace);
15118
- for (const candidate of qmdResultPathCandidates(
15119
- collectionStorage.dir,
15120
- parts.relativePath
15121
- )) {
15122
- const memory = await collectionStorage.readMemoryByPath(candidate);
15123
- if (memory) return memory;
15124
- }
15125
- return null;
15126
- } catch (err) {
15127
- if (err instanceof SecureStoreLockedError) throw err;
15128
- log.debug("qmd result namespace path lookup failed open", {
15129
- path: resultPath,
15130
- namespace: collectionNamespace,
15131
- error: err.message
15132
- });
15133
- return null;
15134
- }
15135
- }
15136
- if (path5.isAbsolute(resultPath)) {
15137
- if (!fallbackStorageDir) {
15138
- return await fallbackStorage.readMemoryByPath(resultPath);
15139
- }
15140
- const ownerStorage = await this.storageForAbsoluteQmdResultPath(
15141
- resultPath,
15142
- fallbackStorage,
15143
- recallNamespaces
15144
- );
15145
- if (!ownerStorage) return null;
15146
- for (const candidate of qmdResultPathCandidates(
15147
- ownerStorage.dir,
15148
- resultPath
15149
- )) {
15150
- const memory = await ownerStorage.storage.readMemoryByPath(candidate);
15151
- if (memory) return memory;
15496
+ try {
15497
+ await recordEvalShadowRecall({
15498
+ memoryDir: this.config.memoryDir,
15499
+ evalStoreDir: this.config.evalStoreDir,
15500
+ record: {
15501
+ schemaVersion: 1,
15502
+ ...record
15503
+ }
15504
+ });
15505
+ } catch (err) {
15506
+ log.debug(`eval shadow recall write failed: ${err}`);
15152
15507
  }
15153
- return null;
15154
- }
15155
- if (!fallbackStorageDir) {
15156
- return await fallbackStorage.readMemoryByPath(resultPath);
15157
- }
15158
- for (const candidate of qmdResultPathCandidates(
15159
- fallbackStorageDir,
15160
- resultPath
15161
- )) {
15162
- const memory = await fallbackStorage.readMemoryByPath(candidate);
15163
- if (memory) return memory;
15508
+ });
15509
+ }
15510
+ publishRecallResults(options) {
15511
+ const sectionId = "memories";
15512
+ const trustByPath = options.trustByPath ?? null;
15513
+ const injectable = trustByPath ? options.results.filter((r) => !trustByPath.get(r.path)?.quarantined) : options.results;
15514
+ const memoryIds = this.extractMemoryIdsFromResults(injectable);
15515
+ this.trackMemoryAccess(memoryIds);
15516
+ this.appendRecallSection(
15517
+ options.sectionBuckets,
15518
+ sectionId,
15519
+ this.formatQmdResults(options.title, injectable, options.sessionKey, trustByPath)
15520
+ );
15521
+ }
15522
+ /**
15523
+ * Apply MMR over the pre-truncation recall candidate pool and then slice
15524
+ * the result to `limit`. This is the single place in the pipeline where
15525
+ * MMR runs, and it must be called *before* callers throw away candidates
15526
+ * that would otherwise sit below the final cutoff. Running MMR post-slice
15527
+ * is a no-op in the cases we care about — diverse candidates just below
15528
+ * the cutoff are already gone and can never be promoted.
15529
+ *
15530
+ * Callers must pass the full candidate pool (post-rerank, pre-slice).
15531
+ */
15532
+ qmdCollectionNamespaceFromPrefix(collectionPrefix) {
15533
+ const baseCollection = this.config.qmdCollection;
15534
+ if (collectionPrefix === baseCollection) return this.config.defaultNamespace;
15535
+ const namespaceSuffix = collectionPrefix.startsWith(`${baseCollection}--`) ? collectionPrefix.slice(baseCollection.length + 2) : "";
15536
+ if (!namespaceSuffix) return null;
15537
+ const decoded = namespaceIdentityFromToken(namespaceSuffix);
15538
+ if (decoded !== null) return decoded || this.config.defaultNamespace;
15539
+ if (namespaceSuffix.startsWith("ns--")) {
15540
+ const legacyNamespace = namespaceSuffix.slice("ns--".length).trim();
15541
+ return legacyNamespace || null;
15164
15542
  }
15165
15543
  return null;
15166
15544
  }
15545
+ // Issue #1526 seam 11: QMD result-resolution methods moved to QmdResultResolver.
15546
+ // Thin delegation keeps the private API stable for callers + tests.
15547
+ async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
15548
+ return this.qmdResultResolver.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces);
15549
+ }
15167
15550
  async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
15168
- const memory = await this.readQmdResultMemory(
15169
- result.path,
15170
- fallbackStorage,
15171
- recallNamespaces
15172
- );
15173
- if (!memory) return null;
15174
- let ownerNamespace = null;
15175
- if (path5.isAbsolute(memory.path)) {
15176
- const ownerStorage = await this.storageForAbsoluteQmdResultPath(
15177
- memory.path,
15178
- fallbackStorage,
15179
- recallNamespaces
15180
- );
15181
- ownerNamespace = ownerStorage?.namespace ?? null;
15182
- if (!ownerNamespace && resolveNamespaceCapabilities(this.config).namespaces) return null;
15183
- }
15184
- ownerNamespace ??= this.namespaceFromPath(memory.path);
15185
- if (recallNamespaces.length > 0 && !recallNamespaces.includes(ownerNamespace)) {
15186
- return null;
15187
- }
15188
- return {
15189
- namespace: ownerNamespace,
15190
- result: {
15191
- ...result,
15192
- docid: result.docid || memory.frontmatter.id,
15193
- path: memory.path,
15194
- snippet: result.snippet || memory.content.slice(0, 400)
15195
- }
15196
- };
15551
+ return this.qmdResultResolver.resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces);
15197
15552
  }
15198
15553
  async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
15199
- const resolvedPath = path5.resolve(resultPath);
15200
- const memoryRoot = path5.resolve(this.config.memoryDir);
15201
- const namespacesRoot = path5.join(memoryRoot, "namespaces");
15202
- const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
15203
- const matches = [];
15204
- const seenDirs = /* @__PURE__ */ new Set();
15205
- const maybeAddStorage = (storage, namespace) => {
15206
- const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15207
- if (!storageDir) return;
15208
- const candidateRoot = path5.resolve(storageDir);
15209
- if (seenDirs.has(candidateRoot)) return;
15210
- if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
15211
- if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
15212
- return;
15213
- }
15214
- seenDirs.add(candidateRoot);
15215
- matches.push({ storage, dir: candidateRoot, namespace });
15216
- };
15217
- const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : this.config.defaultNamespace;
15218
- maybeAddStorage(fallbackStorage, fallbackNamespace);
15219
- const candidateNamespaces = /* @__PURE__ */ new Set();
15220
- candidateNamespaces.add(this.config.defaultNamespace);
15221
- candidateNamespaces.add(this.config.sharedNamespace);
15222
- for (const ns of recallNamespaces) {
15223
- candidateNamespaces.add(ns);
15224
- }
15225
- if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
15226
- const relativeToNamespaces = path5.relative(namespacesRoot, resolvedPath);
15227
- const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
15228
- if (namespaceSegment) {
15229
- candidateNamespaces.add(
15230
- namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment
15231
- );
15232
- }
15233
- }
15234
- for (const policy of this.config.namespacePolicies ?? []) {
15235
- candidateNamespaces.add(policy.name);
15236
- }
15237
- for (const ns of candidateNamespaces) {
15238
- if (!ns) continue;
15239
- try {
15240
- maybeAddStorage(await this.storageRouter.storageFor(ns), ns);
15241
- } catch {
15242
- continue;
15243
- }
15244
- }
15245
- matches.sort((a, b) => b.dir.length - a.dir.length);
15246
- return matches[0] ?? null;
15554
+ return this.qmdResultResolver.storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces);
15247
15555
  }
15248
15556
  // Issue #1526: recall-rerank methods moved to RecallRerankCoordinator.
15249
15557
  // Thin delegation keeps the private API stable for callers + tests.
@@ -15263,30 +15571,13 @@ ${reflectionsContent.trim()}
15263
15571
  return this.recallRerankCoordinator.applyMmrToQmdResults(sectionId, results, caps);
15264
15572
  }
15265
15573
  buildLastRecallBudgetSummary(options) {
15266
- return {
15267
- requestedTopK: options.requestedTopK,
15268
- appliedTopK: options.recallResultLimit,
15269
- recallBudgetChars: this.getRecallBudgetChars(),
15270
- maxMemoryTokens: this.config.maxMemoryTokens,
15271
- qmdFetchLimit: options.qmdFetchLimit,
15272
- qmdHybridFetchLimit: options.qmdHybridFetchLimit,
15273
- finalContextChars: options.finalContextChars,
15274
- truncated: options.truncated,
15275
- includedSections: [...options.includedSections ?? []],
15276
- omittedSections: [...options.omittedSections ?? []]
15277
- };
15574
+ return this.recallSectionCoordinator.buildLastRecallBudgetSummary(options);
15278
15575
  }
15279
15576
  collectLastRecallSources(sectionBuckets, recallSource) {
15280
- const used = /* @__PURE__ */ new Set();
15281
- if (recallSource !== "none") {
15282
- used.add(recallSource);
15283
- }
15284
- for (const [sectionId, chunks] of sectionBuckets.entries()) {
15285
- if (chunks.length > 0) {
15286
- used.add(sectionId);
15287
- }
15288
- }
15289
- return [...used];
15577
+ return this.recallSectionCoordinator.collectLastRecallSources(
15578
+ sectionBuckets,
15579
+ recallSource
15580
+ );
15290
15581
  }
15291
15582
  /**
15292
15583
  * Issue #373 — nearest-neighbor lookup for the write-time semantic dedup
@@ -15336,12 +15627,12 @@ ${reflectionsContent.trim()}
15336
15627
  */
15337
15628
  semanticDedupScopeFor(targetStorage) {
15338
15629
  if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
15339
- const memoryDir = path5.resolve(this.config.memoryDir);
15340
- const storageDir = path5.resolve(targetStorage.dir);
15630
+ const memoryDir = path6.resolve(this.config.memoryDir);
15631
+ const storageDir = path6.resolve(targetStorage.dir);
15341
15632
  if (storageDir === memoryDir) {
15342
15633
  return { pathExcludePrefixes: ["namespaces/"] };
15343
15634
  }
15344
- let rel = path5.relative(memoryDir, storageDir);
15635
+ let rel = path6.relative(memoryDir, storageDir);
15345
15636
  if (!rel || rel.startsWith("..")) {
15346
15637
  log.debug(
15347
15638
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -15360,7 +15651,7 @@ ${reflectionsContent.trim()}
15360
15651
  if (hits.length === 0) return [];
15361
15652
  const results = [];
15362
15653
  for (const hit of hits) {
15363
- const fullPath = path5.isAbsolute(hit.path) ? hit.path : path5.join(this.config.memoryDir, hit.path);
15654
+ const fullPath = path6.isAbsolute(hit.path) ? hit.path : path6.join(this.config.memoryDir, hit.path);
15364
15655
  const memory = await this.storage.readMemoryByPath(fullPath);
15365
15656
  if (!memory) continue;
15366
15657
  results.push({
@@ -15557,7 +15848,7 @@ ${reflectionsContent.trim()}
15557
15848
  const storage = await this.storageRouter.storageFor(namespace);
15558
15849
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15559
15850
  if (!storageDir) continue;
15560
- const recallRoot = path5.resolve(storageDir);
15851
+ const recallRoot = path6.resolve(storageDir);
15561
15852
  if (seenRecallRoots.has(recallRoot)) continue;
15562
15853
  seenRecallRoots.add(recallRoot);
15563
15854
  recallRoots.push(recallRoot);
@@ -15581,8 +15872,8 @@ ${reflectionsContent.trim()}
15581
15872
  if (resolvedCold) scopedResults.push(resolvedCold.result);
15582
15873
  continue;
15583
15874
  }
15584
- if (path5.isAbsolute(result.path)) {
15585
- const resolvedPath = path5.resolve(result.path);
15875
+ if (path6.isAbsolute(result.path)) {
15876
+ const resolvedPath = path6.resolve(result.path);
15586
15877
  if (recallRoots.some(
15587
15878
  (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
15588
15879
  )) {
@@ -16248,58 +16539,11 @@ ${reflectionsContent.trim()}
16248
16539
  * Uses QMD to find similar memories, then LLM to verify contradiction.
16249
16540
  */
16250
16541
  async checkForContradiction(content, category, namespaceScope) {
16251
- if (!this.isSearchAvailableForNamespaceRouting()) return null;
16252
- const results = await this.searchAcrossNamespaces({
16253
- query: content,
16254
- namespaces: [namespaceScope],
16255
- maxResults: 5,
16256
- mode: "search"
16257
- });
16258
- for (const result of results) {
16259
- if (result.score < this.config.contradictionSimilarityThreshold) {
16260
- continue;
16261
- }
16262
- const memoryId = this.extractMemoryIdsFromResults([result])[0];
16263
- if (!memoryId) continue;
16264
- const resultNamespace = this.namespaceFromPath(result.path);
16265
- if (resultNamespace !== namespaceScope) continue;
16266
- const resultStorage = await this.storageRouter.storageFor(resultNamespace);
16267
- const existingMemory = await resultStorage.getMemoryById(memoryId);
16268
- if (!existingMemory) continue;
16269
- if (existingMemory.frontmatter.status === "superseded" || existingMemory.frontmatter.status === "forgotten") {
16270
- continue;
16271
- }
16272
- const verification = await this.extraction.verifyContradiction(
16273
- { content, category },
16274
- {
16275
- id: existingMemory.frontmatter.id,
16276
- content: existingMemory.content,
16277
- category: existingMemory.frontmatter.category,
16278
- created: existingMemory.frontmatter.created
16279
- }
16280
- );
16281
- if (!verification) continue;
16282
- if (verification.isContradiction && verification.confidence >= this.config.contradictionMinConfidence) {
16283
- if (verification.whichIsNewer === "first") {
16284
- log.info(
16285
- `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory \u2014 existing is newer, incoming fact is stale`
16286
- );
16287
- continue;
16288
- }
16289
- log.info(
16290
- `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${this.config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`
16291
- );
16292
- return {
16293
- supersededId: existingMemory.frontmatter.id,
16294
- confidence: verification.confidence,
16295
- reason: verification.reasoning,
16296
- supersededPath: existingMemory.path,
16297
- supersededCreated: existingMemory.frontmatter.created,
16298
- supersededTags: existingMemory.frontmatter.tags ?? []
16299
- };
16300
- }
16301
- }
16302
- return null;
16542
+ return this.contradictionLinkingCoordinator.checkForContradiction(
16543
+ content,
16544
+ category,
16545
+ namespaceScope
16546
+ );
16303
16547
  }
16304
16548
  /**
16305
16549
  * #1645: Complete the deferred contradiction auto-resolve after writeMemory
@@ -16310,40 +16554,12 @@ ${reflectionsContent.trim()}
16310
16554
  * supersedes before tombstone status is known" defect class.
16311
16555
  */
16312
16556
  async applyDeferredContradictionResolve(contradiction, storage, newMemoryId, postWriteGuard) {
16313
- if (postWriteGuard && contradiction && this.config.contradictionAutoResolve) {
16314
- try {
16315
- const blockedRow = await storage.getMemoryById(newMemoryId);
16316
- if (blockedRow?.frontmatter?.supersedes) {
16317
- await storage.writeMemoryFrontmatter(blockedRow, { supersedes: void 0 });
16318
- }
16319
- } catch (err) {
16320
- log.warn(
16321
- `contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`
16322
- );
16323
- }
16324
- }
16325
- if (!contradiction || !this.config.contradictionAutoResolve || postWriteGuard) {
16326
- return;
16327
- }
16328
- try {
16329
- await storage.supersedeMemory(
16330
- contradiction.supersededId,
16331
- newMemoryId,
16332
- contradiction.reason
16333
- );
16334
- if (resolveIndexingCapabilities(this.config).queryAwareIndexing && contradiction.supersededPath) {
16335
- deindexMemory(
16336
- this.config.memoryDir,
16337
- contradiction.supersededPath,
16338
- contradiction.supersededCreated,
16339
- contradiction.supersededTags
16340
- );
16341
- }
16342
- } catch (err) {
16343
- log.warn(
16344
- `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
16345
- );
16346
- }
16557
+ return this.contradictionLinkingCoordinator.applyDeferredContradictionResolve(
16558
+ contradiction,
16559
+ storage,
16560
+ newMemoryId,
16561
+ postWriteGuard
16562
+ );
16347
16563
  }
16348
16564
  // ---------------------------------------------------------------------------
16349
16565
  // Memory Linking (Phase 3A)
@@ -16352,42 +16568,11 @@ ${reflectionsContent.trim()}
16352
16568
  * Suggest links for a new memory based on similar existing memories.
16353
16569
  */
16354
16570
  async suggestLinksForMemory(content, category, namespaceScope) {
16355
- if (!this.isSearchAvailableForNamespaceRouting()) return [];
16356
- const results = await this.searchAcrossNamespaces({
16357
- query: content,
16358
- namespaces: [namespaceScope],
16359
- maxResults: 5,
16360
- mode: "search"
16361
- });
16362
- if (results.length === 0) return [];
16363
- const candidates = [];
16364
- for (const result of results) {
16365
- const memoryId = this.extractMemoryIdsFromResults([result])[0];
16366
- if (!memoryId) continue;
16367
- const resultNamespace = this.namespaceFromPath(result.path);
16368
- if (resultNamespace !== namespaceScope) continue;
16369
- const resultStorage = await this.storageRouter.storageFor(resultNamespace);
16370
- const memory = await resultStorage.getMemoryById(memoryId);
16371
- if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
16372
- candidates.push({
16373
- id: memory.frontmatter.id,
16374
- content: memory.content,
16375
- category: memory.frontmatter.category
16376
- });
16377
- }
16378
- }
16379
- if (candidates.length === 0) return [];
16380
- const suggestions = await this.extraction.suggestLinks(
16381
- { content, category },
16382
- candidates
16571
+ return this.contradictionLinkingCoordinator.suggestLinksForMemory(
16572
+ content,
16573
+ category,
16574
+ namespaceScope
16383
16575
  );
16384
- if (!suggestions || suggestions.links.length === 0) return [];
16385
- return suggestions.links.map((link) => ({
16386
- targetId: link.targetId,
16387
- linkType: link.linkType,
16388
- strength: link.strength,
16389
- reason: link.reason || void 0
16390
- }));
16391
16576
  }
16392
16577
  async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
16393
16578
  const parts = qmdCollectionPathParts(result.path);
@@ -16516,4 +16701,4 @@ export {
16516
16701
  resolvePersistedMemoryRelativePath,
16517
16702
  Orchestrator
16518
16703
  };
16519
- //# sourceMappingURL=chunk-VC7QELR6.js.map
16704
+ //# sourceMappingURL=chunk-VO4VARZL.js.map