@remnic/core 9.3.742 → 9.3.744

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 (262) hide show
  1. package/dist/access-boundary.d.ts +6 -6
  2. package/dist/access-boundary.js +10 -10
  3. package/dist/access-cli.js +29 -29
  4. package/dist/access-http.d.ts +6 -6
  5. package/dist/access-http.js +15 -15
  6. package/dist/access-mcp.d.ts +6 -6
  7. package/dist/access-mcp.js +14 -14
  8. package/dist/access-operations-batch.js +12 -12
  9. package/dist/access-operations.d.ts +6 -6
  10. package/dist/access-operations.js +13 -13
  11. package/dist/{access-service-K8n12dXu.d.ts → access-service-OT3Gk79W.d.ts} +3 -3
  12. package/dist/access-service.d.ts +6 -6
  13. package/dist/access-service.js +9 -9
  14. package/dist/access-surface-catalog.d.ts +6 -6
  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/behavior-learner.d.ts +1 -1
  20. package/dist/behavior-signals.d.ts +1 -1
  21. package/dist/bootstrap.d.ts +5 -4
  22. package/dist/briefing.d.ts +1 -1
  23. package/dist/buffer-surprise-report.d.ts +1 -1
  24. package/dist/buffer.d.ts +1 -1
  25. package/dist/buffer.js +2 -2
  26. package/dist/calibration.d.ts +1 -1
  27. package/dist/capabilities.d.ts +10 -5
  28. package/dist/capabilities.js +1 -1
  29. package/dist/{catalog-_Bap6vfD.d.ts → catalog-CX0CjOaf.d.ts} +1 -1
  30. package/dist/causal-behavior.d.ts +1 -1
  31. package/dist/causal-consolidation.d.ts +1 -1
  32. package/dist/causal-consolidation.js +2 -2
  33. package/dist/causal-trajectory-graph.d.ts +1 -1
  34. package/dist/{chunk-X5PMDVY4.js → chunk-3EA5LIFJ.js} +4 -4
  35. package/dist/{chunk-YNHRWFAP.js → chunk-4DLFJJOQ.js} +2 -2
  36. package/dist/{chunk-WIMKOTNY.js → chunk-5QANTTY2.js} +2 -2
  37. package/dist/{chunk-AM7YKD7V.js → chunk-5UNSGRCR.js} +5 -5
  38. package/dist/{chunk-Y6PNYJVO.js → chunk-A2KKLCOS.js} +2 -2
  39. package/dist/{chunk-O4IWVWSW.js → chunk-AVBT5WEW.js} +3 -3
  40. package/dist/{chunk-QUNH5UZH.js → chunk-BYLC4DKI.js} +2 -2
  41. package/dist/{chunk-UOVDO6TC.js → chunk-CHELXDTO.js} +3 -3
  42. package/dist/{chunk-TQQN64J2.js → chunk-DBSMLRTO.js} +2 -2
  43. package/dist/{chunk-EZZUNKMJ.js → chunk-DYK27X7V.js} +3 -3
  44. package/dist/{chunk-K2N6WIZM.js → chunk-E7RGJQWP.js} +2 -2
  45. package/dist/{chunk-M4WI23X3.js → chunk-EEKDRAWX.js} +2 -2
  46. package/dist/{chunk-GFJ5ABKS.js → chunk-G5FP7VSQ.js} +11 -11
  47. package/dist/{chunk-BE6NEQLF.js → chunk-HAZVVOYT.js} +3 -3
  48. package/dist/{chunk-OT5K26NG.js → chunk-HM6UJPPO.js} +2 -2
  49. package/dist/{chunk-PI4JHLDD.js → chunk-IP5SANO2.js} +2 -2
  50. package/dist/{chunk-WHEF76BQ.js → chunk-JRZV3767.js} +2 -2
  51. package/dist/{chunk-OS5RKJOH.js → chunk-JZ7P26GF.js} +2 -2
  52. package/dist/{chunk-Y62QPRKV.js → chunk-K5LLP4CY.js} +2 -2
  53. package/dist/{chunk-C3Z5YJSM.js → chunk-LOPZ2DWR.js} +2 -2
  54. package/dist/{chunk-BJPL5WAL.js → chunk-MXDG6SRH.js} +3 -3
  55. package/dist/{chunk-UYYSOMS2.js → chunk-NBP3YHHS.js} +4 -4
  56. package/dist/{chunk-USHVHI6J.js → chunk-NNL4LJAD.js} +3 -3
  57. package/dist/{chunk-GPX5E36D.js → chunk-OSMBC3JU.js} +2 -2
  58. package/dist/{chunk-OUSOMUFV.js → chunk-PE6XR4GG.js} +2 -2
  59. package/dist/{chunk-CMPXLMC3.js → chunk-PI23H7FV.js} +3 -3
  60. package/dist/{chunk-WGDE2TJP.js → chunk-QOGXUNWL.js} +4 -4
  61. package/dist/{chunk-ELL5VYXC.js → chunk-RNWWAS5V.js} +3 -3
  62. package/dist/{chunk-7HUGLMSW.js → chunk-SODQQCAZ.js} +1013 -821
  63. package/dist/chunk-SODQQCAZ.js.map +1 -0
  64. package/dist/{chunk-JMMSVRF4.js → chunk-TQPSOTC7.js} +7 -7
  65. package/dist/{chunk-AX4TRSRE.js → chunk-U5WVRMCA.js} +2 -2
  66. package/dist/{chunk-7ADHJ6SU.js → chunk-VE54E6RP.js} +4 -4
  67. package/dist/{chunk-G7Q4D2G3.js → chunk-VSF7AAGE.js} +1 -3
  68. package/dist/chunk-VSF7AAGE.js.map +1 -0
  69. package/dist/{chunk-OVYBENIJ.js → chunk-W3M34XT4.js} +3 -3
  70. package/dist/{chunk-NHJYUIII.js → chunk-WPLRJ4XM.js} +7 -7
  71. package/dist/{chunk-UEIF7RWQ.js → chunk-XEADGIAA.js} +6 -6
  72. package/dist/{cli-BEOLy1xo.d.ts → cli-BQiTZ7Zs.d.ts} +3 -3
  73. package/dist/cli.d.ts +6 -6
  74. package/dist/cli.js +21 -21
  75. package/dist/compounding/engine.d.ts +1 -1
  76. package/dist/compounding/engine.js +3 -3
  77. package/dist/compounding/preference-consolidator.d.ts +1 -1
  78. package/dist/compression-optimizer.d.ts +1 -1
  79. package/dist/config.d.ts +1 -1
  80. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  81. package/dist/connectors/codex-materialize.d.ts +1 -1
  82. package/dist/connectors/index.d.ts +1 -1
  83. package/dist/connectors/index.js +2 -2
  84. package/dist/consolidation-provenance-check.d.ts +1 -1
  85. package/dist/consolidation-undo.d.ts +1 -1
  86. package/dist/contradiction/index.d.ts +1 -1
  87. package/dist/contradiction/index.js +2 -2
  88. package/dist/{contradiction-scan-UERKJESC.js → contradiction-scan-3FJYWS3G.js} +3 -3
  89. package/dist/conversation-index/backend.d.ts +1 -1
  90. package/dist/conversation-index/chunker.d.ts +1 -1
  91. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  92. package/dist/conversation-index/indexer.d.ts +1 -1
  93. package/dist/conversation-index/search.d.ts +1 -1
  94. package/dist/day-summary.d.ts +1 -1
  95. package/dist/day-summary.js +2 -2
  96. package/dist/delinearize.d.ts +1 -1
  97. package/dist/direct-answer-wiring.d.ts +1 -1
  98. package/dist/direct-answer.d.ts +1 -1
  99. package/dist/embedding-fallback.d.ts +1 -1
  100. package/dist/embedding-fallback.js +2 -2
  101. package/dist/enrichment/index.d.ts +1 -1
  102. package/dist/entity-retrieval.d.ts +1 -1
  103. package/dist/entity-retrieval.js +2 -2
  104. package/dist/entity-schema.d.ts +1 -1
  105. package/dist/explicit-capture.d.ts +5 -4
  106. package/dist/explicit-capture.js +2 -2
  107. package/dist/extraction-faithfulness.d.ts +1 -1
  108. package/dist/extraction-judge-telemetry.d.ts +1 -1
  109. package/dist/extraction-judge-training.d.ts +1 -1
  110. package/dist/extraction-judge.d.ts +1 -1
  111. package/dist/extraction.d.ts +1 -1
  112. package/dist/extraction.js +4 -4
  113. package/dist/fallback-llm.d.ts +1 -1
  114. package/dist/{first-start-migration-GQ3UQNIL.js → first-start-migration-4I3VDSYS.js} +2 -2
  115. package/dist/graph-dashboard-diff.d.ts +1 -1
  116. package/dist/graph-dashboard-key.d.ts +1 -1
  117. package/dist/graph-dashboard-parser.d.ts +1 -1
  118. package/dist/graph-edge-reinforcement.d.ts +1 -1
  119. package/dist/graph-snapshot.d.ts +1 -1
  120. package/dist/graph.d.ts +1 -1
  121. package/dist/identity-continuity.d.ts +1 -1
  122. package/dist/importance.d.ts +1 -1
  123. package/dist/index.d.ts +10 -10
  124. package/dist/index.js +36 -36
  125. package/dist/intent.d.ts +1 -1
  126. package/dist/lcm/engine.d.ts +1 -1
  127. package/dist/lcm/index.d.ts +1 -1
  128. package/dist/lcm/tools.d.ts +1 -1
  129. package/dist/lifecycle.d.ts +1 -1
  130. package/dist/live-connectors-runner.d.ts +1 -1
  131. package/dist/local-llm.d.ts +1 -1
  132. package/dist/local-llm.js +2 -2
  133. package/dist/local-model-endpoint.d.ts +1 -1
  134. package/dist/maintenance/memory-governance.d.ts +1 -1
  135. package/dist/mcp-memory-inspector-app.d.ts +6 -6
  136. package/dist/memory-action-policy.d.ts +1 -1
  137. package/dist/memory-cache.d.ts +1 -1
  138. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  139. package/dist/memory-projection-store.d.ts +1 -1
  140. package/dist/memory-provenance.d.ts +1 -1
  141. package/dist/memory-worth-outcomes.d.ts +1 -1
  142. package/dist/models-json.d.ts +1 -1
  143. package/dist/namespaces/migrate.d.ts +2 -2
  144. package/dist/namespaces/migrate.js +6 -6
  145. package/dist/namespaces/principal.d.ts +1 -1
  146. package/dist/namespaces/principal.js +2 -2
  147. package/dist/namespaces/search.d.ts +1 -1
  148. package/dist/namespaces/search.js +4 -4
  149. package/dist/namespaces/storage.d.ts +2 -2
  150. package/dist/namespaces/storage.js +2 -2
  151. package/dist/native-knowledge.d.ts +1 -1
  152. package/dist/operator-toolkit.d.ts +1 -1
  153. package/dist/operator-toolkit.js +11 -11
  154. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  155. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  156. package/dist/orchestration/maintenance.d.ts +2 -2
  157. package/dist/orchestration/maintenance.js +6 -6
  158. package/dist/{orchestrator-Dr-1v5EL.d.ts → orchestrator-BPQGHpJz.d.ts} +263 -31
  159. package/dist/orchestrator.d.ts +5 -4
  160. package/dist/orchestrator.js +24 -24
  161. package/dist/patterns-cli.d.ts +1 -1
  162. package/dist/policy-runtime.d.ts +1 -1
  163. package/dist/provenance.d.ts +1 -1
  164. package/dist/qmd-recall-cache.d.ts +1 -1
  165. package/dist/qmd.d.ts +1 -1
  166. package/dist/recall-disclosure-escalation.d.ts +1 -1
  167. package/dist/recall-explain-renderer.d.ts +1 -1
  168. package/dist/recall-planner-llm.d.ts +1 -1
  169. package/dist/recall-state.d.ts +1 -1
  170. package/dist/recall-tag-filter.d.ts +1 -1
  171. package/dist/recall-xray-cli.d.ts +1 -1
  172. package/dist/recall-xray-renderer.d.ts +1 -1
  173. package/dist/recall-xray.d.ts +1 -1
  174. package/dist/resolve-auth-token.d.ts +1 -1
  175. package/dist/retrieval-agents.d.ts +1 -1
  176. package/dist/retrieval-tiers.d.ts +1 -1
  177. package/dist/routing/engine.d.ts +1 -1
  178. package/dist/routing/store.d.ts +1 -1
  179. package/dist/search/embed-helper.d.ts +1 -1
  180. package/dist/search/embed-helper.js +2 -2
  181. package/dist/search/factory.d.ts +1 -1
  182. package/dist/search/factory.js +3 -3
  183. package/dist/search/index.d.ts +1 -1
  184. package/dist/search/index.js +3 -3
  185. package/dist/search/lancedb-backend.d.ts +1 -1
  186. package/dist/search/meilisearch-backend.d.ts +1 -1
  187. package/dist/search/noop-backend.d.ts +1 -1
  188. package/dist/search/orama-backend.d.ts +1 -1
  189. package/dist/search/port.d.ts +1 -1
  190. package/dist/search/remote-backend.d.ts +1 -1
  191. package/dist/{semantic-consolidation-DsIEiCka.d.ts → semantic-consolidation-ByzGwC9c.d.ts} +1 -1
  192. package/dist/semantic-consolidation.d.ts +2 -2
  193. package/dist/semantic-consolidation.js +2 -2
  194. package/dist/semantic-rule-verifier.d.ts +1 -1
  195. package/dist/session-observer-bands.d.ts +1 -1
  196. package/dist/session-observer-state.d.ts +1 -1
  197. package/dist/shared-context/manager.d.ts +1 -1
  198. package/dist/shared-context/manager.js +2 -2
  199. package/dist/signal.d.ts +1 -1
  200. package/dist/storage.d.ts +1 -1
  201. package/dist/summarizer.d.ts +1 -1
  202. package/dist/summarizer.js +3 -3
  203. package/dist/summary-snapshot.d.ts +1 -1
  204. package/dist/temporal-supersession.d.ts +1 -1
  205. package/dist/temporal-validity.d.ts +1 -1
  206. package/dist/threading.d.ts +1 -1
  207. package/dist/tier-migration.d.ts +1 -1
  208. package/dist/tier-routing.d.ts +1 -1
  209. package/dist/{tier-stats-CSKL7BDG.js → tier-stats-5XF4UBRQ.js} +2 -2
  210. package/dist/topics.d.ts +1 -1
  211. package/dist/transcript.d.ts +1 -1
  212. package/dist/trust-score-stage.d.ts +1 -1
  213. package/dist/trust-score.d.ts +1 -1
  214. package/dist/{types-CglNn2V-.d.ts → types-5Jik3r4G.d.ts} +1 -1
  215. package/dist/types.d.ts +1 -1
  216. package/dist/utility-runtime.d.ts +1 -1
  217. package/package.json +2 -2
  218. package/src/capabilities.test.ts +0 -2
  219. package/src/capabilities.ts +7 -6
  220. package/src/orchestration/contradiction-linking-coordinator.ts +336 -0
  221. package/src/orchestration/graph-recall-coordinator.ts +471 -0
  222. package/src/orchestration/recall-section-coordinator.ts +349 -0
  223. package/src/orchestrator.ts +97 -741
  224. package/dist/chunk-7HUGLMSW.js.map +0 -1
  225. package/dist/chunk-G7Q4D2G3.js.map +0 -1
  226. /package/dist/{chunk-X5PMDVY4.js.map → chunk-3EA5LIFJ.js.map} +0 -0
  227. /package/dist/{chunk-YNHRWFAP.js.map → chunk-4DLFJJOQ.js.map} +0 -0
  228. /package/dist/{chunk-WIMKOTNY.js.map → chunk-5QANTTY2.js.map} +0 -0
  229. /package/dist/{chunk-AM7YKD7V.js.map → chunk-5UNSGRCR.js.map} +0 -0
  230. /package/dist/{chunk-Y6PNYJVO.js.map → chunk-A2KKLCOS.js.map} +0 -0
  231. /package/dist/{chunk-O4IWVWSW.js.map → chunk-AVBT5WEW.js.map} +0 -0
  232. /package/dist/{chunk-QUNH5UZH.js.map → chunk-BYLC4DKI.js.map} +0 -0
  233. /package/dist/{chunk-UOVDO6TC.js.map → chunk-CHELXDTO.js.map} +0 -0
  234. /package/dist/{chunk-TQQN64J2.js.map → chunk-DBSMLRTO.js.map} +0 -0
  235. /package/dist/{chunk-EZZUNKMJ.js.map → chunk-DYK27X7V.js.map} +0 -0
  236. /package/dist/{chunk-K2N6WIZM.js.map → chunk-E7RGJQWP.js.map} +0 -0
  237. /package/dist/{chunk-M4WI23X3.js.map → chunk-EEKDRAWX.js.map} +0 -0
  238. /package/dist/{chunk-GFJ5ABKS.js.map → chunk-G5FP7VSQ.js.map} +0 -0
  239. /package/dist/{chunk-BE6NEQLF.js.map → chunk-HAZVVOYT.js.map} +0 -0
  240. /package/dist/{chunk-OT5K26NG.js.map → chunk-HM6UJPPO.js.map} +0 -0
  241. /package/dist/{chunk-PI4JHLDD.js.map → chunk-IP5SANO2.js.map} +0 -0
  242. /package/dist/{chunk-WHEF76BQ.js.map → chunk-JRZV3767.js.map} +0 -0
  243. /package/dist/{chunk-OS5RKJOH.js.map → chunk-JZ7P26GF.js.map} +0 -0
  244. /package/dist/{chunk-Y62QPRKV.js.map → chunk-K5LLP4CY.js.map} +0 -0
  245. /package/dist/{chunk-C3Z5YJSM.js.map → chunk-LOPZ2DWR.js.map} +0 -0
  246. /package/dist/{chunk-BJPL5WAL.js.map → chunk-MXDG6SRH.js.map} +0 -0
  247. /package/dist/{chunk-UYYSOMS2.js.map → chunk-NBP3YHHS.js.map} +0 -0
  248. /package/dist/{chunk-USHVHI6J.js.map → chunk-NNL4LJAD.js.map} +0 -0
  249. /package/dist/{chunk-GPX5E36D.js.map → chunk-OSMBC3JU.js.map} +0 -0
  250. /package/dist/{chunk-OUSOMUFV.js.map → chunk-PE6XR4GG.js.map} +0 -0
  251. /package/dist/{chunk-CMPXLMC3.js.map → chunk-PI23H7FV.js.map} +0 -0
  252. /package/dist/{chunk-WGDE2TJP.js.map → chunk-QOGXUNWL.js.map} +0 -0
  253. /package/dist/{chunk-ELL5VYXC.js.map → chunk-RNWWAS5V.js.map} +0 -0
  254. /package/dist/{chunk-JMMSVRF4.js.map → chunk-TQPSOTC7.js.map} +0 -0
  255. /package/dist/{chunk-AX4TRSRE.js.map → chunk-U5WVRMCA.js.map} +0 -0
  256. /package/dist/{chunk-7ADHJ6SU.js.map → chunk-VE54E6RP.js.map} +0 -0
  257. /package/dist/{chunk-OVYBENIJ.js.map → chunk-W3M34XT4.js.map} +0 -0
  258. /package/dist/{chunk-NHJYUIII.js.map → chunk-WPLRJ4XM.js.map} +0 -0
  259. /package/dist/{chunk-UEIF7RWQ.js.map → chunk-XEADGIAA.js.map} +0 -0
  260. /package/dist/{contradiction-scan-UERKJESC.js.map → contradiction-scan-3FJYWS3G.js.map} +0 -0
  261. /package/dist/{first-start-migration-GQ3UQNIL.js.map → first-start-migration-4I3VDSYS.js.map} +0 -0
  262. /package/dist/{tier-stats-CSKL7BDG.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
@@ -7,10 +7,10 @@ import {
7
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";
@@ -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,19 +512,19 @@ import {
512
512
  } from "./chunk-PVGDJXVK.js";
513
513
 
514
514
  // src/orchestrator.ts
515
- import path6 from "path";
515
+ import path7 from "path";
516
516
  import os2 from "os";
517
- import { createHash as createHash2, randomBytes } from "crypto";
517
+ import { createHash as createHash3, randomBytes } from "crypto";
518
518
  import { existsSync, readFileSync } from "fs";
519
519
  import {
520
520
  lstat,
521
- mkdir as mkdir3,
521
+ mkdir as mkdir4,
522
522
  readdir as readdir2,
523
523
  readFile as readFile2,
524
524
  realpath,
525
525
  stat,
526
526
  unlink,
527
- writeFile as writeFile3
527
+ writeFile as writeFile4
528
528
  } from "fs/promises";
529
529
 
530
530
  // src/procedural/procedure-recall.ts
@@ -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 [path7, c] of nsMap) counters.set(path7, c);
2199
+ for (const [path8, c] of nsMap) counters.set(path8, 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 (path7) => {
2284
+ readMemoryFrontmatter: async (path8) => {
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(path7, fallbackReader, namespaces);
2295
+ const memory = await this.readQmdResultMemory(path8, fallbackReader, namespaces);
2296
2296
  return memory ? memory.frontmatter : null;
2297
2297
  }
2298
2298
  },
@@ -2391,6 +2391,210 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2391
2391
  }
2392
2392
  };
2393
2393
 
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));
2401
+ }
2402
+ getRecallSectionEntry(sectionId) {
2403
+ const pipeline = Array.isArray(this.getConfig().recallPipeline) ? this.getConfig().recallPipeline : [];
2404
+ return pipeline.find((entry) => entry.id === sectionId);
2405
+ }
2406
+ isRecallSectionEnabled(sectionId, defaultEnabled = true) {
2407
+ const entry = this.getRecallSectionEntry(sectionId);
2408
+ if (!entry) return defaultEnabled;
2409
+ return entry.enabled !== false;
2410
+ }
2411
+ isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
2412
+ const entry = this.getRecallSectionEntry(sectionId);
2413
+ if (!entry) return topLevelEnabled;
2414
+ return entry.enabled === true || topLevelEnabled && entry.enabled !== false;
2415
+ }
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));
2422
+ }
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));
2429
+ }
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
+ `;
2442
+ }
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);
2454
+ }
2455
+ return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
2456
+ }
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;
2463
+ }
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));
2468
+ }
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
+
2394
2598
  // src/orchestration/qmd-result-resolver.ts
2395
2599
  import path4 from "path";
2396
2600
  function qmdCollectionPathParts(resultPath) {
@@ -2642,63 +2846,522 @@ var QmdResultResolver = class {
2642
2846
  }
2643
2847
  };
2644
2848
 
2645
- // src/maintenance/pattern-reinforcement.ts
2646
- function patternReinforcementKey(content) {
2647
- return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
2648
- }
2649
- function patternReinforcementClusterKey(category, content) {
2650
- return `${category}::${patternReinforcementKey(content)}`;
2651
- }
2652
- function pickCanonical(memories) {
2653
- let best = memories[0];
2654
- let bestInstant = memoryInstant(best);
2655
- let bestStamp = memoryStamp(best);
2656
- for (let i = 1; i < memories.length; i += 1) {
2657
- const candidate = memories[i];
2658
- const instant = memoryInstant(candidate);
2659
- const stamp = memoryStamp(candidate);
2660
- let cmp;
2661
- if (instant !== null && bestInstant !== null) {
2662
- cmp = instant - bestInstant;
2663
- } else {
2664
- cmp = stamp.localeCompare(bestStamp);
2665
- }
2666
- if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
2667
- best = candidate;
2668
- bestInstant = instant;
2669
- bestStamp = stamp;
2670
- }
2671
- }
2672
- return best;
2673
- }
2674
- function memoryStamp(memory) {
2675
- return memory.frontmatter.updated || memory.frontmatter.created || "";
2676
- }
2677
- function memoryInstant(memory) {
2678
- const stamp = memoryStamp(memory);
2679
- if (stamp.length === 0) return null;
2680
- const parsed = Date.parse(stamp);
2681
- return Number.isFinite(parsed) ? parsed : null;
2682
- }
2683
- var ACTIVE_STATUS = "active";
2684
- async function runPatternReinforcement(storage, options) {
2685
- const minCount = Math.max(2, Math.floor(options.minCount));
2686
- const targetCategories = new Set(options.categories);
2687
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
2688
- const nowIso = now().toISOString();
2689
- if (targetCategories.size === 0) {
2690
- return emptyResult();
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;
2691
2866
  }
2692
- const memories = await storage.readAllMemories();
2693
- const eligible = memories.filter((m) => {
2694
- if (!targetCategories.has(m.frontmatter.category)) return false;
2695
- const status = m.frontmatter.status ?? ACTIVE_STATUS;
2696
- return status === ACTIVE_STATUS || status === "superseded";
2697
- });
2698
- if (eligible.length === 0) return emptyResult();
2699
- const clusters = clusterByKey(
2700
- eligible,
2701
- (m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
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/orchestration/graph-recall-coordinator.ts
3020
+ import { createHash as createHash2 } from "crypto";
3021
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
3022
+ import path5 from "path";
3023
+ function mergeGraphExpandedResults(primary, expanded) {
3024
+ const mergedByPath = /* @__PURE__ */ new Map();
3025
+ for (const item of [...primary, ...expanded]) {
3026
+ const prev = mergedByPath.get(item.path);
3027
+ if (!prev) {
3028
+ mergedByPath.set(item.path, item);
3029
+ continue;
3030
+ }
3031
+ const better = item.score > prev.score ? item : prev;
3032
+ const snippet = prev.snippet || item.snippet;
3033
+ mergedByPath.set(item.path, { ...better, snippet });
3034
+ }
3035
+ return Array.from(mergedByPath.values());
3036
+ }
3037
+ function graphPathRelativeToStorage(storageDir, candidatePath) {
3038
+ const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
3039
+ const rel = path5.relative(storageDir, absolutePath);
3040
+ if (!rel || rel === ".") return null;
3041
+ if (rel.startsWith("..")) return null;
3042
+ return rel.split(path5.sep).join("/");
3043
+ }
3044
+ function normalizeGraphActivationScore(score) {
3045
+ const bounded = Number.isFinite(score) && score > 0 ? score : 0;
3046
+ return bounded / (1 + bounded);
3047
+ }
3048
+ function blendGraphExpandedRecallScore(options) {
3049
+ const graphNorm = normalizeGraphActivationScore(options.graphActivationScore);
3050
+ const seedScore = Number.isFinite(options.seedRecallScore) ? Math.min(1, Math.max(0, options.seedRecallScore)) : 0;
3051
+ const weight = Math.min(1, Math.max(0, options.activationWeight));
3052
+ const rawMin = Math.min(1, Math.max(0, options.blendMin));
3053
+ const rawMax = Math.min(1, Math.max(0, options.blendMax));
3054
+ const minBound = Math.min(rawMin, rawMax);
3055
+ const maxBound = Math.max(rawMin, rawMax);
3056
+ const blended = graphNorm * weight + seedScore * (1 - weight);
3057
+ return Math.max(minBound, Math.min(maxBound, blended));
3058
+ }
3059
+ var GraphRecallCoordinator = class {
3060
+ getConfig;
3061
+ getStorage;
3062
+ storageFor;
3063
+ graphIndexFor;
3064
+ namespaceFromPath;
3065
+ resolveColdQmdResultForRecall;
3066
+ storageForAbsoluteQmdResultPath;
3067
+ readQmdResultMemory;
3068
+ constructor(options) {
3069
+ this.getConfig = options.getConfig;
3070
+ this.getStorage = options.getStorage;
3071
+ this.storageFor = options.storageFor;
3072
+ this.graphIndexFor = options.graphIndexFor;
3073
+ this.namespaceFromPath = options.namespaceFromPath;
3074
+ this.resolveColdQmdResultForRecall = options.resolveColdQmdResultForRecall;
3075
+ this.storageForAbsoluteQmdResultPath = options.storageForAbsoluteQmdResultPath;
3076
+ this.readQmdResultMemory = options.readQmdResultMemory;
3077
+ }
3078
+ async expandResultsViaGraph(options) {
3079
+ const config = this.getConfig();
3080
+ const deadlineExpired = () => typeof options.deadlineAtMs === "number" && Date.now() >= options.deadlineAtMs;
3081
+ const byNamespace = /* @__PURE__ */ new Map();
3082
+ const addResultForNamespace = (namespace, result) => {
3083
+ const existing = byNamespace.get(namespace);
3084
+ if (existing) {
3085
+ existing.push(result);
3086
+ } else {
3087
+ byNamespace.set(namespace, [result]);
3088
+ }
3089
+ };
3090
+ const resolvedAmbiguousSeeds = /* @__PURE__ */ new Map();
3091
+ const resolveAmbiguousSeedOwner = async (result, parts) => {
3092
+ const cached = resolvedAmbiguousSeeds.get(result.path);
3093
+ if (cached !== void 0) return cached;
3094
+ if (deadlineExpired()) {
3095
+ resolvedAmbiguousSeeds.set(result.path, null);
3096
+ return null;
3097
+ }
3098
+ let resolvedPath = result.path;
3099
+ let resolvedResult = result;
3100
+ if (parts) {
3101
+ const resolvedCold = await this.resolveColdQmdResultForRecall(
3102
+ result,
3103
+ this.getStorage(),
3104
+ options.recallNamespaces
3105
+ );
3106
+ if (!resolvedCold || deadlineExpired()) {
3107
+ resolvedAmbiguousSeeds.set(result.path, null);
3108
+ return null;
3109
+ }
3110
+ resolvedPath = resolvedCold.result.path;
3111
+ resolvedResult = resolvedCold.result;
3112
+ }
3113
+ if (!path5.isAbsolute(resolvedPath)) {
3114
+ resolvedAmbiguousSeeds.set(result.path, null);
3115
+ return null;
3116
+ }
3117
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
3118
+ resolvedPath,
3119
+ this.getStorage(),
3120
+ options.recallNamespaces
3121
+ );
3122
+ const ownerNamespace = ownerStorage?.namespace ?? null;
3123
+ const resolved = ownerNamespace && options.recallNamespaces.includes(ownerNamespace) ? { namespace: ownerNamespace, result: resolvedResult } : null;
3124
+ resolvedAmbiguousSeeds.set(result.path, resolved);
3125
+ return resolved;
3126
+ };
3127
+ const coldCollection = config.qmdColdCollection ?? "openclaw-engram-cold";
3128
+ for (const result of options.memoryResults) {
3129
+ if (deadlineExpired()) break;
3130
+ const parts = qmdCollectionPathParts(result.path);
3131
+ if (parts?.collection === coldCollection) {
3132
+ const resolved = await resolveAmbiguousSeedOwner(result, parts);
3133
+ if (resolved) {
3134
+ addResultForNamespace(resolved.namespace, resolved.result);
3135
+ }
3136
+ continue;
3137
+ }
3138
+ if (path5.isAbsolute(result.path)) {
3139
+ const resolved = await resolveAmbiguousSeedOwner(result, null);
3140
+ if (resolved) {
3141
+ addResultForNamespace(resolved.namespace, resolved.result);
3142
+ }
3143
+ continue;
3144
+ }
3145
+ const ns = this.namespaceFromPath(result.path);
3146
+ if (!options.recallNamespaces.includes(ns)) continue;
3147
+ addResultForNamespace(ns, result);
3148
+ }
3149
+ const perNamespaceSeedCap = Math.max(3, options.recallResultLimit);
3150
+ const perNamespaceExpandedCap = Math.max(8, options.recallResultLimit * 2);
3151
+ const seedPaths = [];
3152
+ const seedResults = [];
3153
+ const expandedPaths = [];
3154
+ const expandedResults = [];
3155
+ for (const [namespace, nsResults] of byNamespace.entries()) {
3156
+ if (deadlineExpired()) break;
3157
+ const storage = await this.storageFor(namespace);
3158
+ const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
3159
+ seedResults.push(...seedCandidates);
3160
+ const seedRelativePaths = typeof options.deadlineAtMs === "number" ? await this.graphSeedPathsWithinDeadline(
3161
+ storage,
3162
+ seedCandidates,
3163
+ options.deadlineAtMs,
3164
+ [namespace]
3165
+ ) : (await Promise.all(
3166
+ seedCandidates.map(
3167
+ (result) => this.graphSeedPathRelativeToStorage(storage, result, [
3168
+ namespace
3169
+ ])
3170
+ )
3171
+ )).filter(
3172
+ (value) => typeof value === "string" && value.length > 0
3173
+ );
3174
+ if (deadlineExpired()) break;
3175
+ if (seedRelativePaths.length === 0) continue;
3176
+ const seedRecallScore = seedCandidates.reduce(
3177
+ (max, item) => Math.max(max, item.score),
3178
+ 0
3179
+ );
3180
+ seedPaths.push(
3181
+ ...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
3182
+ );
3183
+ const seedSet = new Set(seedRelativePaths);
3184
+ const expanded = await this.graphIndexFor(storage).spreadingActivation(
3185
+ seedRelativePaths,
3186
+ config.maxGraphTraversalSteps,
3187
+ {
3188
+ ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {},
3189
+ ...typeof options.deadlineAtMs === "number" ? { deadlineAtMs: options.deadlineAtMs } : {}
3190
+ }
3191
+ );
3192
+ if (expanded.length === 0) continue;
3193
+ if (deadlineExpired()) break;
3194
+ for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
3195
+ if (deadlineExpired()) break;
3196
+ if (seedSet.has(candidate.path)) continue;
3197
+ const memoryPath = path5.resolve(storage.dir, candidate.path);
3198
+ const memory = await storage.readMemoryByPath(memoryPath);
3199
+ if (deadlineExpired()) break;
3200
+ if (!memory) continue;
3201
+ if (/(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(memory.path)) continue;
3202
+ if (memory.frontmatter.status && memory.frontmatter.status !== "active")
3203
+ continue;
3204
+ const snippet = memory.content.slice(0, 400);
3205
+ const score = blendGraphExpandedRecallScore({
3206
+ graphActivationScore: candidate.score,
3207
+ seedRecallScore,
3208
+ activationWeight: config.graphExpansionActivationWeight,
3209
+ blendMin: config.graphExpansionBlendMin,
3210
+ blendMax: config.graphExpansionBlendMax
3211
+ });
3212
+ expandedResults.push({
3213
+ docid: memory.frontmatter.id,
3214
+ path: memory.path,
3215
+ snippet,
3216
+ score
3217
+ });
3218
+ expandedPaths.push({
3219
+ path: memory.path,
3220
+ score,
3221
+ namespace,
3222
+ seed: path5.resolve(storage.dir, candidate.seed),
3223
+ hopDepth: candidate.hopDepth,
3224
+ decayedWeight: candidate.decayedWeight,
3225
+ graphType: candidate.graphType,
3226
+ // Issue #681 PR 3/3 — surface the per-edge confidence used for
3227
+ // PageRank weighting / floor pruning so downstream observability
3228
+ // (recall_xray, memory_graph_explain) can attribute ranking and
3229
+ // pruning decisions to specific edges.
3230
+ edgeConfidence: candidate.edgeConfidence
3231
+ });
3232
+ }
3233
+ }
3234
+ return {
3235
+ merged: mergeGraphExpandedResults(options.memoryResults, expandedResults),
3236
+ seedPaths,
3237
+ expandedPaths,
3238
+ seedResults
3239
+ };
3240
+ }
3241
+ async recordLastGraphRecallSnapshot(options) {
3242
+ try {
3243
+ const snapshotPath = path5.join(
3244
+ options.storage.dir,
3245
+ "state",
3246
+ "last_graph_recall.json"
3247
+ );
3248
+ await mkdir2(path5.dirname(snapshotPath), { recursive: true });
3249
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3250
+ const totalSeedCount = options.seedPaths.length;
3251
+ const totalExpandedCount = options.expandedPaths.length;
3252
+ const seeds = options.seedPaths.slice(0, 64);
3253
+ const expanded = clampGraphRecallExpandedEntries(
3254
+ options.expandedPaths,
3255
+ 64
3256
+ );
3257
+ const payload = {
3258
+ recordedAt: now,
3259
+ mode: options.recallMode,
3260
+ queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
3261
+ queryLength: options.prompt.length,
3262
+ namespaces: options.recallNamespaces,
3263
+ seedCount: totalSeedCount,
3264
+ expandedCount: totalExpandedCount,
3265
+ seeds,
3266
+ expanded,
3267
+ status: options.status,
3268
+ reason: options.reason,
3269
+ shadowMode: options.shadowMode === true,
3270
+ queryIntent: options.queryIntent,
3271
+ seedResults: (options.seedResults ?? []).slice(0, 64),
3272
+ finalResults: (options.finalResults ?? []).slice(0, 64),
3273
+ shadowComparison: options.shadowComparison
3274
+ };
3275
+ await writeFile2(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
3276
+ } catch (err) {
3277
+ log.debug(`last graph recall write failed: ${err}`);
3278
+ }
3279
+ }
3280
+ async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
3281
+ const parts = qmdCollectionPathParts(result.path);
3282
+ if (parts) {
3283
+ const memory = await this.readQmdResultMemory(
3284
+ result.path,
3285
+ storage,
3286
+ recallNamespaces
3287
+ );
3288
+ return memory ? graphPathRelativeToStorage(storage.dir, memory.path) : null;
3289
+ }
3290
+ return graphPathRelativeToStorage(storage.dir, result.path);
3291
+ }
3292
+ async graphSeedPathsWithinDeadline(storage, results, deadlineAtMs, recallNamespaces = []) {
3293
+ const resolved = [];
3294
+ for (const result of results) {
3295
+ if (Date.now() >= deadlineAtMs) break;
3296
+ const seedPath = await this.graphSeedPathRelativeToStorage(
3297
+ storage,
3298
+ result,
3299
+ recallNamespaces
3300
+ );
3301
+ if (Date.now() >= deadlineAtMs) break;
3302
+ if (seedPath) resolved.push(seedPath);
3303
+ }
3304
+ return resolved;
3305
+ }
3306
+ };
3307
+
3308
+ // src/maintenance/pattern-reinforcement.ts
3309
+ function patternReinforcementKey(content) {
3310
+ return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
3311
+ }
3312
+ function patternReinforcementClusterKey(category, content) {
3313
+ return `${category}::${patternReinforcementKey(content)}`;
3314
+ }
3315
+ function pickCanonical(memories) {
3316
+ let best = memories[0];
3317
+ let bestInstant = memoryInstant(best);
3318
+ let bestStamp = memoryStamp(best);
3319
+ for (let i = 1; i < memories.length; i += 1) {
3320
+ const candidate = memories[i];
3321
+ const instant = memoryInstant(candidate);
3322
+ const stamp = memoryStamp(candidate);
3323
+ let cmp;
3324
+ if (instant !== null && bestInstant !== null) {
3325
+ cmp = instant - bestInstant;
3326
+ } else {
3327
+ cmp = stamp.localeCompare(bestStamp);
3328
+ }
3329
+ if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
3330
+ best = candidate;
3331
+ bestInstant = instant;
3332
+ bestStamp = stamp;
3333
+ }
3334
+ }
3335
+ return best;
3336
+ }
3337
+ function memoryStamp(memory) {
3338
+ return memory.frontmatter.updated || memory.frontmatter.created || "";
3339
+ }
3340
+ function memoryInstant(memory) {
3341
+ const stamp = memoryStamp(memory);
3342
+ if (stamp.length === 0) return null;
3343
+ const parsed = Date.parse(stamp);
3344
+ return Number.isFinite(parsed) ? parsed : null;
3345
+ }
3346
+ var ACTIVE_STATUS = "active";
3347
+ async function runPatternReinforcement(storage, options) {
3348
+ const minCount = Math.max(2, Math.floor(options.minCount));
3349
+ const targetCategories = new Set(options.categories);
3350
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
3351
+ const nowIso = now().toISOString();
3352
+ if (targetCategories.size === 0) {
3353
+ return emptyResult();
3354
+ }
3355
+ const memories = await storage.readAllMemories();
3356
+ const eligible = memories.filter((m) => {
3357
+ if (!targetCategories.has(m.frontmatter.category)) return false;
3358
+ const status = m.frontmatter.status ?? ACTIVE_STATUS;
3359
+ return status === ACTIVE_STATUS || status === "superseded";
3360
+ });
3361
+ if (eligible.length === 0) return emptyResult();
3362
+ const clusters = clusterByKey(
3363
+ eligible,
3364
+ (m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
2702
3365
  );
2703
3366
  const result = {
2704
3367
  clustersFound: 0,
@@ -2974,8 +3637,8 @@ function generateResolverDocument(taxonomy) {
2974
3637
  }
2975
3638
 
2976
3639
  // src/taxonomy/taxonomy-loader.ts
2977
- import { readFile, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
2978
- import path5 from "path";
3640
+ import { readFile, mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
3641
+ import path6 from "path";
2979
3642
  var TAXONOMY_DIR = ".taxonomy";
2980
3643
  var TAXONOMY_FILE = "taxonomy.json";
2981
3644
  var MAX_SLUG_LENGTH = 32;
@@ -3073,7 +3736,7 @@ function validateTaxonomy(taxonomy) {
3073
3736
  }
3074
3737
  }
3075
3738
  async function loadTaxonomy(memoryDir) {
3076
- const taxonomyPath = path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3739
+ const taxonomyPath = path6.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3077
3740
  let raw;
3078
3741
  try {
3079
3742
  raw = await readFile(taxonomyPath, "utf-8");
@@ -3123,16 +3786,16 @@ async function loadTaxonomy(memoryDir) {
3123
3786
  }
3124
3787
  async function saveTaxonomy(memoryDir, taxonomy) {
3125
3788
  validateTaxonomy(taxonomy);
3126
- const dir = path5.join(memoryDir, TAXONOMY_DIR);
3127
- await mkdir2(dir, { recursive: true });
3128
- const filePath = path5.join(dir, TAXONOMY_FILE);
3129
- await writeFile2(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
3789
+ const dir = path6.join(memoryDir, TAXONOMY_DIR);
3790
+ await mkdir3(dir, { recursive: true });
3791
+ const filePath = path6.join(dir, TAXONOMY_FILE);
3792
+ await writeFile3(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
3130
3793
  }
3131
3794
  function getTaxonomyDir(memoryDir) {
3132
- return path5.join(memoryDir, TAXONOMY_DIR);
3795
+ return path6.join(memoryDir, TAXONOMY_DIR);
3133
3796
  }
3134
3797
  function getTaxonomyFilePath(memoryDir) {
3135
- return path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3798
+ return path6.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
3136
3799
  }
3137
3800
 
3138
3801
  // src/wearables/registry.ts
@@ -4142,11 +4805,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
4142
4805
  return await Promise.race([checkedPromise, timeoutPromise]);
4143
4806
  }
4144
4807
  function defaultWorkspaceDir() {
4145
- return path6.join(os2.homedir(), ".openclaw", "workspace");
4808
+ return path7.join(os2.homedir(), ".openclaw", "workspace");
4146
4809
  }
4147
4810
  function sanitizeSessionKeyForFilename(sessionKey) {
4148
4811
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
4149
- const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
4812
+ const hash = createHash3("sha256").update(sessionKey).digest("hex").slice(0, 12);
4150
4813
  return `${readable}-${hash}`;
4151
4814
  }
4152
4815
  function latestSourceValidAtFromTurns(turns) {
@@ -4404,42 +5067,6 @@ function computeQmdHybridFetchLimit(recallFetchLimit, artifactsEnabled, maxArtif
4404
5067
  const artifactHeadroom = Math.max(20, Math.max(0, maxArtifactRecall) * 8);
4405
5068
  return Math.min(400, cappedRecallLimit + artifactHeadroom);
4406
5069
  }
4407
- function mergeGraphExpandedResults(primary, expanded) {
4408
- const mergedByPath = /* @__PURE__ */ new Map();
4409
- for (const item of [...primary, ...expanded]) {
4410
- const prev = mergedByPath.get(item.path);
4411
- if (!prev) {
4412
- mergedByPath.set(item.path, item);
4413
- continue;
4414
- }
4415
- const better = item.score > prev.score ? item : prev;
4416
- const snippet = prev.snippet || item.snippet;
4417
- mergedByPath.set(item.path, { ...better, snippet });
4418
- }
4419
- return Array.from(mergedByPath.values());
4420
- }
4421
- function graphPathRelativeToStorage(storageDir, candidatePath) {
4422
- const absolutePath = path6.isAbsolute(candidatePath) ? candidatePath : path6.resolve(storageDir, candidatePath);
4423
- const rel = path6.relative(storageDir, absolutePath);
4424
- if (!rel || rel === ".") return null;
4425
- if (rel.startsWith("..")) return null;
4426
- return rel.split(path6.sep).join("/");
4427
- }
4428
- function normalizeGraphActivationScore(score) {
4429
- const bounded = Number.isFinite(score) && score > 0 ? score : 0;
4430
- return bounded / (1 + bounded);
4431
- }
4432
- function blendGraphExpandedRecallScore(options) {
4433
- const graphNorm = normalizeGraphActivationScore(options.graphActivationScore);
4434
- const seedScore = Number.isFinite(options.seedRecallScore) ? Math.min(1, Math.max(0, options.seedRecallScore)) : 0;
4435
- const weight = Math.min(1, Math.max(0, options.activationWeight));
4436
- const rawMin = Math.min(1, Math.max(0, options.blendMin));
4437
- const rawMax = Math.min(1, Math.max(0, options.blendMax));
4438
- const minBound = Math.min(rawMin, rawMax);
4439
- const maxBound = Math.max(rawMin, rawMax);
4440
- const blended = graphNorm * weight + seedScore * (1 - weight);
4441
- return Math.max(minBound, Math.min(maxBound, blended));
4442
- }
4443
5070
  function summarizeGraphShadowComparison(baseline, merged, topN) {
4444
5071
  const limit = Math.max(0, Math.floor(topN));
4445
5072
  const baselineTop = limit > 0 ? baseline.slice(0, limit) : [];
@@ -4568,7 +5195,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
4568
5195
  for (const mem of allMemsForGraph ?? []) {
4569
5196
  const id = mem.frontmatter.id;
4570
5197
  if (!id) continue;
4571
- pathById.set(id, path6.relative(storageDir, mem.path));
5198
+ pathById.set(id, path7.relative(storageDir, mem.path));
4572
5199
  }
4573
5200
  return pathById;
4574
5201
  }
@@ -4576,7 +5203,7 @@ function appendMemoryToGraphContext(options) {
4576
5203
  if (!Array.isArray(options.allMemsForGraph)) return;
4577
5204
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4578
5205
  options.allMemsForGraph.push({
4579
- path: path6.join(options.storageDir, options.memoryRelPath),
5206
+ path: path7.join(options.storageDir, options.memoryRelPath),
4580
5207
  content: options.content,
4581
5208
  frontmatter: {
4582
5209
  id: options.memoryId,
@@ -4596,16 +5223,16 @@ function resolvePersistedMemoryRelativePath(options) {
4596
5223
  const persisted = options.pathById.get(options.memoryId);
4597
5224
  if (persisted) return persisted;
4598
5225
  if (options.category === "correction") {
4599
- return path6.join("corrections", `${options.memoryId}.md`);
5226
+ return path7.join("corrections", `${options.memoryId}.md`);
4600
5227
  }
4601
5228
  const subtree = categoryDirName(options.category);
4602
5229
  const idParts = options.memoryId.split("-");
4603
5230
  const maybeTimestamp = Number(idParts[1]);
4604
5231
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
4605
5232
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
4606
- return path6.join(subtree, day, `${options.memoryId}.md`);
5233
+ return path7.join(subtree, day, `${options.memoryId}.md`);
4607
5234
  }
4608
- return path6.join(subtree, `${options.memoryId}.md`);
5235
+ return path7.join(subtree, `${options.memoryId}.md`);
4609
5236
  }
4610
5237
  var Orchestrator = class _Orchestrator {
4611
5238
  storage;
@@ -4767,7 +5394,10 @@ var Orchestrator = class _Orchestrator {
4767
5394
  */
4768
5395
  conversationIndexCoordinator;
4769
5396
  recallRerankCoordinator;
5397
+ recallSectionCoordinator;
4770
5398
  qmdResultResolver;
5399
+ contradictionLinkingCoordinator;
5400
+ graphRecallCoordinator;
4771
5401
  heartbeatObserverChains = /* @__PURE__ */ new Map();
4772
5402
  recentExtractionFingerprints = /* @__PURE__ */ new Map();
4773
5403
  consolidationObservers = /* @__PURE__ */ new Set();
@@ -5060,7 +5690,7 @@ var Orchestrator = class _Orchestrator {
5060
5690
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
5061
5691
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
5062
5692
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
5063
- const resolvedStorageDir = path6.resolve(storageDir);
5693
+ const resolvedStorageDir = path7.resolve(storageDir);
5064
5694
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
5065
5695
  if (!hints) {
5066
5696
  hints = /* @__PURE__ */ new Set();
@@ -5071,21 +5701,21 @@ var Orchestrator = class _Orchestrator {
5071
5701
  storageDirMatchesNamespaceHint(namespace, storageDir) {
5072
5702
  const ns = normalizeNamespaceIdentity(namespace);
5073
5703
  if (!ns) return false;
5074
- const resolvedStorageDir = path6.resolve(storageDir);
5075
- const resolvedMemoryDir = path6.resolve(this.config.memoryDir);
5704
+ const resolvedStorageDir = path7.resolve(storageDir);
5705
+ const resolvedMemoryDir = path7.resolve(this.config.memoryDir);
5076
5706
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
5077
5707
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
5078
- const resolvedNamespacesDir = path6.join(resolvedMemoryDir, "namespaces");
5708
+ const resolvedNamespacesDir = path7.join(resolvedMemoryDir, "namespaces");
5079
5709
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
5080
- const rawRoot = path6.resolve(resolvedNamespacesDir, ns);
5081
- const tokenRoot = path6.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
5710
+ const rawRoot = path7.resolve(resolvedNamespacesDir, ns);
5711
+ const tokenRoot = path7.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
5082
5712
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
5083
5713
  }
5084
5714
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
5085
- if (resolvedStorageDir === path6.resolve(this.config.memoryDir)) {
5715
+ if (resolvedStorageDir === path7.resolve(this.config.memoryDir)) {
5086
5716
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
5087
5717
  }
5088
- const leaf = path6.basename(resolvedStorageDir);
5718
+ const leaf = path7.basename(resolvedStorageDir);
5089
5719
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
5090
5720
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
5091
5721
  if (record.namespace === leaf) return 1;
@@ -5113,7 +5743,7 @@ var Orchestrator = class _Orchestrator {
5113
5743
  loadNamespaceStorageDirHintsFromCatalog() {
5114
5744
  if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
5115
5745
  this.namespaceStorageDirHintsLoaded = true;
5116
- const catalogPath = path6.join(this.config.memoryDir, "state", "namespaces.jsonl");
5746
+ const catalogPath = path7.join(this.config.memoryDir, "state", "namespaces.jsonl");
5117
5747
  if (!existsSync(catalogPath)) return;
5118
5748
  let body;
5119
5749
  try {
@@ -5150,7 +5780,7 @@ var Orchestrator = class _Orchestrator {
5150
5780
  if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
5151
5781
  continue;
5152
5782
  }
5153
- const resolvedStorageDir = path6.resolve(record.storageDir);
5783
+ const resolvedStorageDir = path7.resolve(record.storageDir);
5154
5784
  const current = preferredByStorageDir.get(resolvedStorageDir);
5155
5785
  preferredByStorageDir.set(
5156
5786
  resolvedStorageDir,
@@ -5414,7 +6044,7 @@ var Orchestrator = class _Orchestrator {
5414
6044
  this.config = config;
5415
6045
  this.profiler = new ProfilingCollector({
5416
6046
  enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
5417
- storageDir: config.profilingStorageDir || path6.join(config.memoryDir, "profiling"),
6047
+ storageDir: config.profilingStorageDir || path7.join(config.memoryDir, "profiling"),
5418
6048
  maxTraces: config.profilingMaxTraces
5419
6049
  });
5420
6050
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -5484,7 +6114,7 @@ var Orchestrator = class _Orchestrator {
5484
6114
  this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
5485
6115
  this.buffer = new SmartBuffer(config, this.storage);
5486
6116
  this.transcript = new TranscriptManager(config);
5487
- this.conversationIndexDir = path6.join(
6117
+ this.conversationIndexDir = path7.join(
5488
6118
  config.memoryDir,
5489
6119
  "conversation-index",
5490
6120
  "chunks"
@@ -5500,7 +6130,30 @@ var Orchestrator = class _Orchestrator {
5500
6130
  getStorage: (namespace) => this.getStorage(namespace),
5501
6131
  readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
5502
6132
  });
6133
+ this.recallSectionCoordinator = new RecallSectionCoordinator({
6134
+ getConfig: () => this.config,
6135
+ resolveSectionEnabled: (id, def) => this.isRecallSectionEnabled(id, def)
6136
+ });
6137
+ this.contradictionLinkingCoordinator = new ContradictionLinkingCoordinator({
6138
+ getConfig: () => this.config,
6139
+ isSearchAvailable: () => this.isSearchAvailableForNamespaceRouting(),
6140
+ searchAcrossNamespaces: (options) => this.searchAcrossNamespaces(options),
6141
+ extractMemoryIdsFromResults: (results) => this.extractMemoryIdsFromResults(results),
6142
+ namespaceFromPath: (p) => this.namespaceFromPath(p),
6143
+ storageForNamespace: (namespace) => this.storageRouter.storageFor(namespace),
6144
+ getExtraction: () => this.extraction
6145
+ });
5503
6146
  this.modelRegistry = new ModelRegistry(config.memoryDir);
6147
+ this.graphRecallCoordinator = new GraphRecallCoordinator({
6148
+ getConfig: () => this.config,
6149
+ getStorage: () => this.storage,
6150
+ storageFor: (namespace) => this.storageRouter.storageFor(namespace),
6151
+ graphIndexFor: (storage) => this.graphIndexFor(storage),
6152
+ namespaceFromPath: (p) => this.namespaceFromPath(p),
6153
+ resolveColdQmdResultForRecall: (result, fallbackStorage, recallNamespaces) => this.resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces),
6154
+ storageForAbsoluteQmdResultPath: (resultPath, fallbackStorage, recallNamespaces) => this.storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces),
6155
+ readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
6156
+ });
5504
6157
  this.relevance = new RelevanceStore(config.memoryDir);
5505
6158
  this.negatives = new NegativeExampleStore(config.memoryDir);
5506
6159
  this.lastRecall = new LastRecallStore(config.memoryDir);
@@ -5597,7 +6250,7 @@ var Orchestrator = class _Orchestrator {
5597
6250
  saveContentHashIndexes: () => this.saveContentHashIndexes()
5598
6251
  });
5599
6252
  this.threading = new ThreadingManager(
5600
- path6.join(config.memoryDir, "threads"),
6253
+ path7.join(config.memoryDir, "threads"),
5601
6254
  config.threadingGapMinutes
5602
6255
  );
5603
6256
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
@@ -5677,7 +6330,7 @@ var Orchestrator = class _Orchestrator {
5677
6330
  utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
5678
6331
  utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
5679
6332
  };
5680
- return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
6333
+ return createHash3("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
5681
6334
  }
5682
6335
  effectiveLifecycleThresholds() {
5683
6336
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
@@ -5920,7 +6573,7 @@ var Orchestrator = class _Orchestrator {
5920
6573
  const files = await readdir2(wsDir).catch(() => []);
5921
6574
  for (const f of files) {
5922
6575
  if (!f.startsWith(".compaction-reset-signal-")) continue;
5923
- const fp = path6.join(wsDir, f);
6576
+ const fp = path7.join(wsDir, f);
5924
6577
  const s = await stat(fp).catch(() => null);
5925
6578
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
5926
6579
  await unlink(fp).catch(() => {
@@ -6115,7 +6768,7 @@ var Orchestrator = class _Orchestrator {
6115
6768
  if (signal.aborted) return;
6116
6769
  if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.config).qmdTierMigration) {
6117
6770
  try {
6118
- const { runFirstStartMigration } = await import("./first-start-migration-GQ3UQNIL.js");
6771
+ const { runFirstStartMigration } = await import("./first-start-migration-4I3VDSYS.js");
6119
6772
  const result = await runFirstStartMigration({
6120
6773
  storage: this.storage,
6121
6774
  config: this.config,
@@ -6429,15 +7082,15 @@ ${doc.content}` : doc.content,
6429
7082
  this.lastFileHygieneRunAtMs = now;
6430
7083
  if (hygiene.rotateEnabled) {
6431
7084
  for (const rel of hygiene.rotatePaths) {
6432
- const abs = path6.isAbsolute(rel) ? rel : path6.join(this.config.workspaceDir, rel);
7085
+ const abs = path7.isAbsolute(rel) ? rel : path7.join(this.config.workspaceDir, rel);
6433
7086
  try {
6434
7087
  const raw = await readFile2(abs, "utf-8");
6435
7088
  if (raw.length > hygiene.rotateMaxBytes) {
6436
- const archiveDir = path6.join(
7089
+ const archiveDir = path7.join(
6437
7090
  this.config.workspaceDir,
6438
7091
  hygiene.archiveDir
6439
7092
  );
6440
- const base = path6.basename(abs);
7093
+ const base = path7.basename(abs);
6441
7094
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
6442
7095
  const { newContent } = await rotateMarkdownFileToArchive({
6443
7096
  filePath: abs,
@@ -6445,7 +7098,7 @@ ${doc.content}` : doc.content,
6445
7098
  archivePrefix: prefix,
6446
7099
  keepTailChars: hygiene.rotateKeepTailChars
6447
7100
  });
6448
- await writeFile3(abs, newContent, "utf-8");
7101
+ await writeFile4(abs, newContent, "utf-8");
6449
7102
  }
6450
7103
  } catch {
6451
7104
  }
@@ -6462,8 +7115,8 @@ ${doc.content}` : doc.content,
6462
7115
  log.warn(w.message);
6463
7116
  }
6464
7117
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
6465
- const fp = path6.join(this.config.memoryDir, hygiene.warningsLogPath);
6466
- await mkdir3(path6.dirname(fp), { recursive: true });
7118
+ const fp = path7.join(this.config.memoryDir, hygiene.warningsLogPath);
7119
+ await mkdir4(path7.dirname(fp), { recursive: true });
6467
7120
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
6468
7121
  const block = `
6469
7122
 
@@ -6476,7 +7129,7 @@ ${doc.content}` : doc.content,
6476
7129
  } catch {
6477
7130
  existing = "# Engram File Hygiene Warnings\n";
6478
7131
  }
6479
- await writeFile3(fp, existing + block, "utf-8");
7132
+ await writeFile4(fp, existing + block, "utf-8");
6480
7133
  }
6481
7134
  }
6482
7135
  }
@@ -6602,7 +7255,7 @@ ${doc.content}` : doc.content,
6602
7255
  for (const categoryDir of RECALL_FALLBACK_DIRS) {
6603
7256
  if (memoryRootReal === null) break;
6604
7257
  for (const date of datesToScan) {
6605
- const dateDir = path6.join(storage.dir, categoryDir, date);
7258
+ const dateDir = path7.join(storage.dir, categoryDir, date);
6606
7259
  try {
6607
7260
  const dirStat = await lstat(dateDir);
6608
7261
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
@@ -6611,7 +7264,7 @@ ${doc.content}` : doc.content,
6611
7264
  for (const entry of entries) {
6612
7265
  if (entry.isSymbolicLink()) continue;
6613
7266
  if (!entry.name.endsWith(".md")) continue;
6614
- const fullPath = path6.join(dateDir, entry.name);
7267
+ const fullPath = path7.join(dateDir, entry.name);
6615
7268
  try {
6616
7269
  assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
6617
7270
  const raw = await readFile2(fullPath, "utf-8");
@@ -6633,7 +7286,7 @@ ${doc.content}` : doc.content,
6633
7286
  facts.push({
6634
7287
  path: fullPath,
6635
7288
  frontmatter: {
6636
- id: fm.id || path6.basename(entry.name, ".md"),
7289
+ id: fm.id || path7.basename(entry.name, ".md"),
6637
7290
  category: fm.category || "fact",
6638
7291
  created,
6639
7292
  updated: fm.updated || created,
@@ -6656,13 +7309,13 @@ ${doc.content}` : doc.content,
6656
7309
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
6657
7310
  });
6658
7311
  const hourlySummaries = [];
6659
- const hourlyBaseDir = path6.join(storage.dir, "summaries", "hourly");
7312
+ const hourlyBaseDir = path7.join(storage.dir, "summaries", "hourly");
6660
7313
  try {
6661
7314
  const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
6662
7315
  for (const sk of sessionKeys) {
6663
7316
  if (!sk.isDirectory()) continue;
6664
7317
  for (const date of datesToScan) {
6665
- const summaryFile = path6.join(hourlyBaseDir, sk.name, `${date}.md`);
7318
+ const summaryFile = path7.join(hourlyBaseDir, sk.name, `${date}.md`);
6666
7319
  try {
6667
7320
  const raw = await readFile2(summaryFile, "utf-8");
6668
7321
  const filtered = filterHourlySummaryMarkdownForLocalDay(
@@ -6766,7 +7419,7 @@ ${doc.content}` : doc.content,
6766
7419
  }
6767
7420
  async getLastGraphRecallSnapshot(namespace) {
6768
7421
  const storage = await this.getStorage(namespace);
6769
- const snapshotPath = path6.join(
7422
+ const snapshotPath = path7.join(
6770
7423
  storage.dir,
6771
7424
  "state",
6772
7425
  "last_graph_recall.json"
@@ -6805,7 +7458,7 @@ ${doc.content}` : doc.content,
6805
7458
  }
6806
7459
  async getLastIntentSnapshot(namespace) {
6807
7460
  const storage = await this.getStorage(namespace);
6808
- const snapshotPath = path6.join(storage.dir, "state", "last_intent.json");
7461
+ const snapshotPath = path7.join(storage.dir, "state", "last_intent.json");
6809
7462
  try {
6810
7463
  const raw = await readFile2(snapshotPath, "utf-8");
6811
7464
  const parsed = JSON.parse(raw);
@@ -6838,7 +7491,7 @@ ${doc.content}` : doc.content,
6838
7491
  }
6839
7492
  async getLastQmdRecallSnapshot(namespace) {
6840
7493
  const storage = await this.getStorage(namespace);
6841
- const snapshotPath = path6.join(
7494
+ const snapshotPath = path7.join(
6842
7495
  storage.dir,
6843
7496
  "state",
6844
7497
  "last_qmd_recall.json"
@@ -7540,7 +8193,7 @@ ${doc.content}` : doc.content,
7540
8193
  if (!options.onDebugSnapshot) return;
7541
8194
  await options.onDebugSnapshot({
7542
8195
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
7543
- queryHash: createHash2("sha256").update(prompt).digest("hex"),
8196
+ queryHash: createHash3("sha256").update(prompt).digest("hex"),
7544
8197
  queryLength: prompt.length,
7545
8198
  collection: options.collection,
7546
8199
  namespaces: options.recallNamespaces,
@@ -7645,259 +8298,69 @@ ${doc.content}` : doc.content,
7645
8298
  if (scopedSeedResults.length > 0) {
7646
8299
  const mergedByPath = /* @__PURE__ */ new Map();
7647
8300
  for (const result of [...scopedSeedResults, ...mergedResults]) {
7648
- const key = result.path || result.docid;
7649
- const existing = mergedByPath.get(key);
7650
- if (!existing || result.score > existing.score) {
7651
- mergedByPath.set(key, {
7652
- ...result,
7653
- snippet: result.snippet || existing?.snippet || ""
7654
- });
7655
- }
7656
- }
7657
- mergedResults = [...mergedByPath.values()].sort((a, b) => b.score - a.score).slice(0, fetchLimit);
7658
- }
7659
- const filteredResults = filterRecallCandidates(mergedResults, {
7660
- namespacesEnabled: options.namespacesEnabled,
7661
- recallNamespaces: options.recallNamespaces,
7662
- resolveNamespace: options.resolveNamespace,
7663
- limit: fetchLimit
7664
- });
7665
- if (filteredResults.length >= qmdFetchLimit) {
7666
- const capped2 = filteredResults.slice(0, qmdFetchLimit);
7667
- await emitDebugSnapshot(capped2, fetchLimit);
7668
- return capped2;
7669
- }
7670
- if (filteredResults.length > bestFiltered.length) {
7671
- bestFiltered = filteredResults;
7672
- }
7673
- if (mergedResults.length === 0) {
7674
- await emitDebugSnapshot(filteredResults, fetchLimit);
7675
- return filteredResults;
7676
- }
7677
- if (mergedResults.length < fetchLimit && filteredResults.length > 0) {
7678
- await emitDebugSnapshot(filteredResults, fetchLimit);
7679
- return filteredResults;
7680
- }
7681
- if (fetchLimit >= maxFetchLimit) {
7682
- break;
7683
- }
7684
- const growth = Math.max(20, Math.floor(fetchLimit / 2));
7685
- fetchLimit = Math.min(maxFetchLimit, fetchLimit + growth);
7686
- }
7687
- const capped = bestFiltered.slice(0, qmdFetchLimit);
7688
- await emitDebugSnapshot(capped, fetchLimit);
7689
- return capped;
7690
- }
7691
- async expandResultsViaGraph(options) {
7692
- const deadlineExpired = () => typeof options.deadlineAtMs === "number" && Date.now() >= options.deadlineAtMs;
7693
- const byNamespace = /* @__PURE__ */ new Map();
7694
- const addResultForNamespace = (namespace, result) => {
7695
- const existing = byNamespace.get(namespace);
7696
- if (existing) {
7697
- existing.push(result);
7698
- } else {
7699
- byNamespace.set(namespace, [result]);
7700
- }
7701
- };
7702
- const resolvedAmbiguousSeeds = /* @__PURE__ */ new Map();
7703
- const resolveAmbiguousSeedOwner = async (result, parts) => {
7704
- const cached = resolvedAmbiguousSeeds.get(result.path);
7705
- if (cached !== void 0) return cached;
7706
- if (deadlineExpired()) {
7707
- resolvedAmbiguousSeeds.set(result.path, null);
7708
- return null;
7709
- }
7710
- let resolvedPath = result.path;
7711
- let resolvedResult = result;
7712
- if (parts) {
7713
- const resolvedCold = await this.resolveColdQmdResultForRecall(
7714
- result,
7715
- this.storage,
7716
- options.recallNamespaces
7717
- );
7718
- if (!resolvedCold || deadlineExpired()) {
7719
- resolvedAmbiguousSeeds.set(result.path, null);
7720
- return null;
7721
- }
7722
- resolvedPath = resolvedCold.result.path;
7723
- resolvedResult = resolvedCold.result;
7724
- }
7725
- if (!path6.isAbsolute(resolvedPath)) {
7726
- resolvedAmbiguousSeeds.set(result.path, null);
7727
- return null;
7728
- }
7729
- const ownerStorage = await this.storageForAbsoluteQmdResultPath(
7730
- resolvedPath,
7731
- this.storage,
7732
- options.recallNamespaces
7733
- );
7734
- const ownerNamespace = ownerStorage?.namespace ?? null;
7735
- const resolved = ownerNamespace && options.recallNamespaces.includes(ownerNamespace) ? { namespace: ownerNamespace, result: resolvedResult } : null;
7736
- resolvedAmbiguousSeeds.set(result.path, resolved);
7737
- return resolved;
7738
- };
7739
- const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
7740
- for (const result of options.memoryResults) {
7741
- if (deadlineExpired()) break;
7742
- const parts = qmdCollectionPathParts(result.path);
7743
- if (parts?.collection === coldCollection) {
7744
- const resolved = await resolveAmbiguousSeedOwner(result, parts);
7745
- if (resolved) {
7746
- addResultForNamespace(resolved.namespace, resolved.result);
7747
- }
7748
- continue;
7749
- }
7750
- if (path6.isAbsolute(result.path)) {
7751
- const resolved = await resolveAmbiguousSeedOwner(result, null);
7752
- if (resolved) {
7753
- addResultForNamespace(resolved.namespace, resolved.result);
7754
- }
7755
- continue;
7756
- }
7757
- const ns = this.namespaceFromPath(result.path);
7758
- if (!options.recallNamespaces.includes(ns)) continue;
7759
- addResultForNamespace(ns, result);
7760
- }
7761
- const perNamespaceSeedCap = Math.max(3, options.recallResultLimit);
7762
- const perNamespaceExpandedCap = Math.max(8, options.recallResultLimit * 2);
7763
- const seedPaths = [];
7764
- const seedResults = [];
7765
- const expandedPaths = [];
7766
- const expandedResults = [];
7767
- for (const [namespace, nsResults] of byNamespace.entries()) {
7768
- if (deadlineExpired()) break;
7769
- const storage = await this.storageRouter.storageFor(namespace);
7770
- const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
7771
- seedResults.push(...seedCandidates);
7772
- const seedRelativePaths = typeof options.deadlineAtMs === "number" ? await this.graphSeedPathsWithinDeadline(
7773
- storage,
7774
- seedCandidates,
7775
- options.deadlineAtMs,
7776
- [namespace]
7777
- ) : (await Promise.all(
7778
- seedCandidates.map(
7779
- (result) => this.graphSeedPathRelativeToStorage(storage, result, [
7780
- namespace
7781
- ])
7782
- )
7783
- )).filter(
7784
- (value) => typeof value === "string" && value.length > 0
7785
- );
7786
- if (deadlineExpired()) break;
7787
- if (seedRelativePaths.length === 0) continue;
7788
- const seedRecallScore = seedCandidates.reduce(
7789
- (max, item) => Math.max(max, item.score),
7790
- 0
7791
- );
7792
- seedPaths.push(
7793
- ...seedRelativePaths.map((rel) => path6.join(storage.dir, rel))
7794
- );
7795
- const seedSet = new Set(seedRelativePaths);
7796
- const expanded = await this.graphIndexFor(storage).spreadingActivation(
7797
- seedRelativePaths,
7798
- this.config.maxGraphTraversalSteps,
7799
- {
7800
- ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {},
7801
- ...typeof options.deadlineAtMs === "number" ? { deadlineAtMs: options.deadlineAtMs } : {}
7802
- }
7803
- );
7804
- if (expanded.length === 0) continue;
7805
- if (deadlineExpired()) break;
7806
- for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
7807
- if (deadlineExpired()) break;
7808
- if (seedSet.has(candidate.path)) continue;
7809
- const memoryPath = path6.resolve(storage.dir, candidate.path);
7810
- const memory = await storage.readMemoryByPath(memoryPath);
7811
- if (deadlineExpired()) break;
7812
- if (!memory) continue;
7813
- if (isArtifactMemoryPath(memory.path)) continue;
7814
- if (memory.frontmatter.status && memory.frontmatter.status !== "active")
7815
- continue;
7816
- const snippet = memory.content.slice(0, 400);
7817
- const score = blendGraphExpandedRecallScore({
7818
- graphActivationScore: candidate.score,
7819
- seedRecallScore,
7820
- activationWeight: this.config.graphExpansionActivationWeight,
7821
- blendMin: this.config.graphExpansionBlendMin,
7822
- blendMax: this.config.graphExpansionBlendMax
7823
- });
7824
- expandedResults.push({
7825
- docid: memory.frontmatter.id,
7826
- path: memory.path,
7827
- snippet,
7828
- score
7829
- });
7830
- expandedPaths.push({
7831
- path: memory.path,
7832
- score,
7833
- namespace,
7834
- seed: path6.resolve(storage.dir, candidate.seed),
7835
- hopDepth: candidate.hopDepth,
7836
- decayedWeight: candidate.decayedWeight,
7837
- graphType: candidate.graphType,
7838
- // Issue #681 PR 3/3 — surface the per-edge confidence used for
7839
- // PageRank weighting / floor pruning so downstream observability
7840
- // (recall_xray, memory_graph_explain) can attribute ranking and
7841
- // pruning decisions to specific edges.
7842
- edgeConfidence: candidate.edgeConfidence
7843
- });
8301
+ const key = result.path || result.docid;
8302
+ const existing = mergedByPath.get(key);
8303
+ if (!existing || result.score > existing.score) {
8304
+ mergedByPath.set(key, {
8305
+ ...result,
8306
+ snippet: result.snippet || existing?.snippet || ""
8307
+ });
8308
+ }
8309
+ }
8310
+ mergedResults = [...mergedByPath.values()].sort((a, b) => b.score - a.score).slice(0, fetchLimit);
8311
+ }
8312
+ const filteredResults = filterRecallCandidates(mergedResults, {
8313
+ namespacesEnabled: options.namespacesEnabled,
8314
+ recallNamespaces: options.recallNamespaces,
8315
+ resolveNamespace: options.resolveNamespace,
8316
+ limit: fetchLimit
8317
+ });
8318
+ if (filteredResults.length >= qmdFetchLimit) {
8319
+ const capped2 = filteredResults.slice(0, qmdFetchLimit);
8320
+ await emitDebugSnapshot(capped2, fetchLimit);
8321
+ return capped2;
8322
+ }
8323
+ if (filteredResults.length > bestFiltered.length) {
8324
+ bestFiltered = filteredResults;
8325
+ }
8326
+ if (mergedResults.length === 0) {
8327
+ await emitDebugSnapshot(filteredResults, fetchLimit);
8328
+ return filteredResults;
8329
+ }
8330
+ if (mergedResults.length < fetchLimit && filteredResults.length > 0) {
8331
+ await emitDebugSnapshot(filteredResults, fetchLimit);
8332
+ return filteredResults;
7844
8333
  }
8334
+ if (fetchLimit >= maxFetchLimit) {
8335
+ break;
8336
+ }
8337
+ const growth = Math.max(20, Math.floor(fetchLimit / 2));
8338
+ fetchLimit = Math.min(maxFetchLimit, fetchLimit + growth);
7845
8339
  }
7846
- return {
7847
- merged: mergeGraphExpandedResults(options.memoryResults, expandedResults),
7848
- seedPaths,
7849
- expandedPaths,
7850
- seedResults
7851
- };
8340
+ const capped = bestFiltered.slice(0, qmdFetchLimit);
8341
+ await emitDebugSnapshot(capped, fetchLimit);
8342
+ return capped;
8343
+ }
8344
+ // Issue #1526 (seam 14): graph-recall expansion moved to
8345
+ // GraphRecallCoordinator. Thin delegation keeps the private API stable
8346
+ // for callers (recallInternal, cold-fallback pipeline) + tests.
8347
+ async expandResultsViaGraph(options) {
8348
+ return this.graphRecallCoordinator.expandResultsViaGraph(options);
7852
8349
  }
8350
+ // Issue #1526 (seam 14): graph-recall snapshot moved to
8351
+ // GraphRecallCoordinator. Thin delegation keeps the private API stable.
7853
8352
  async recordLastGraphRecallSnapshot(options) {
7854
- try {
7855
- const snapshotPath = path6.join(
7856
- options.storage.dir,
7857
- "state",
7858
- "last_graph_recall.json"
7859
- );
7860
- await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7861
- const now = (/* @__PURE__ */ new Date()).toISOString();
7862
- const totalSeedCount = options.seedPaths.length;
7863
- const totalExpandedCount = options.expandedPaths.length;
7864
- const seeds = options.seedPaths.slice(0, 64);
7865
- const expanded = clampGraphRecallExpandedEntries(
7866
- options.expandedPaths,
7867
- 64
7868
- );
7869
- const payload = {
7870
- recordedAt: now,
7871
- mode: options.recallMode,
7872
- queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
7873
- queryLength: options.prompt.length,
7874
- namespaces: options.recallNamespaces,
7875
- seedCount: totalSeedCount,
7876
- expandedCount: totalExpandedCount,
7877
- seeds,
7878
- expanded,
7879
- status: options.status,
7880
- reason: options.reason,
7881
- shadowMode: options.shadowMode === true,
7882
- queryIntent: options.queryIntent,
7883
- seedResults: (options.seedResults ?? []).slice(0, 64),
7884
- finalResults: (options.finalResults ?? []).slice(0, 64),
7885
- shadowComparison: options.shadowComparison
7886
- };
7887
- await writeFile3(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
7888
- } catch (err) {
7889
- log.debug(`last graph recall write failed: ${err}`);
7890
- }
8353
+ return this.graphRecallCoordinator.recordLastGraphRecallSnapshot(options);
7891
8354
  }
7892
8355
  async recordLastIntentSnapshot(options) {
7893
8356
  try {
7894
- const snapshotPath = path6.join(
8357
+ const snapshotPath = path7.join(
7895
8358
  options.storage.dir,
7896
8359
  "state",
7897
8360
  "last_intent.json"
7898
8361
  );
7899
- await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7900
- await writeFile3(
8362
+ await mkdir4(path7.dirname(snapshotPath), { recursive: true });
8363
+ await writeFile4(
7901
8364
  snapshotPath,
7902
8365
  JSON.stringify(options.snapshot, null, 2),
7903
8366
  "utf-8"
@@ -7908,233 +8371,111 @@ ${doc.content}` : doc.content,
7908
8371
  }
7909
8372
  async recordLastQmdRecallSnapshot(options) {
7910
8373
  try {
7911
- const snapshotPath = path6.join(
8374
+ const snapshotPath = path7.join(
7912
8375
  options.storage.dir,
7913
8376
  "state",
7914
8377
  "last_qmd_recall.json"
7915
8378
  );
7916
- await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7917
- await writeFile3(
7918
- snapshotPath,
7919
- JSON.stringify(options.snapshot, null, 2),
7920
- "utf-8"
7921
- );
7922
- } catch (err) {
7923
- log.debug(`last qmd recall write failed: ${err}`);
7924
- }
7925
- }
7926
- async recordLastIntentSnapshotForNamespace(options) {
7927
- try {
7928
- const stateDir = await this.resolveStateDirForNamespace(
7929
- options.namespace
7930
- );
7931
- const snapshotPath = path6.join(stateDir, "last_intent.json");
7932
- await mkdir3(path6.dirname(snapshotPath), { recursive: true });
7933
- await writeFile3(
8379
+ await mkdir4(path7.dirname(snapshotPath), { recursive: true });
8380
+ await writeFile4(
7934
8381
  snapshotPath,
7935
8382
  JSON.stringify(options.snapshot, null, 2),
7936
8383
  "utf-8"
7937
8384
  );
7938
- } catch (err) {
7939
- log.debug(`last intent write failed: ${err}`);
7940
- }
7941
- }
7942
- async resolveStateDirForNamespace(namespace) {
7943
- if (!resolveNamespaceCapabilities(this.config).namespaces) {
7944
- return path6.join(this.config.memoryDir, "state");
7945
- }
7946
- if (namespace !== this.config.defaultNamespace) {
7947
- return path6.join(this.config.memoryDir, "namespaces", namespace, "state");
7948
- }
7949
- const candidate = path6.join(
7950
- this.config.memoryDir,
7951
- "namespaces",
7952
- this.config.defaultNamespace
7953
- );
7954
- try {
7955
- const candidateStat = await stat(candidate);
7956
- if (candidateStat.isDirectory()) {
7957
- return path6.join(candidate, "state");
7958
- }
7959
- } catch {
7960
- }
7961
- return path6.join(this.config.memoryDir, "state");
7962
- }
7963
- buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
7964
- return results.slice(0, limit).map((result) => ({
7965
- path: result.path,
7966
- score: result.score,
7967
- docid: result.docid,
7968
- sourceLabels: sourceLabelResolver(result.path)
7969
- }));
7970
- }
7971
- getRecallSectionEntry(sectionId) {
7972
- const pipeline = Array.isArray(this.config.recallPipeline) ? this.config.recallPipeline : [];
7973
- return pipeline.find((entry) => entry.id === sectionId);
7974
- }
7975
- isRecallSectionEnabled(sectionId, defaultEnabled = true) {
7976
- const entry = this.getRecallSectionEntry(sectionId);
7977
- if (!entry) return defaultEnabled;
7978
- return entry.enabled !== false;
7979
- }
7980
- isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
7981
- const entry = this.getRecallSectionEntry(sectionId);
7982
- if (!entry) return topLevelEnabled;
7983
- return entry.enabled === true || topLevelEnabled && entry.enabled !== false;
7984
- }
7985
- getRecallSectionMaxChars(sectionId) {
7986
- const entry = this.getRecallSectionEntry(sectionId);
7987
- if (!entry) return void 0;
7988
- if (entry.maxChars === null) return null;
7989
- if (typeof entry.maxChars !== "number") return void 0;
7990
- return Math.max(0, Math.floor(entry.maxChars));
7991
- }
7992
- getRecallSectionNumber(sectionId, key) {
7993
- const entry = this.getRecallSectionEntry(sectionId);
7994
- if (!entry) return void 0;
7995
- const value = entry[key];
7996
- if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
7997
- return Math.max(0, Math.floor(value));
7998
- }
7999
- appendRecallSection(sectionBuckets, sectionId, content) {
8000
- if (!this.isRecallSectionEnabled(sectionId)) return false;
8001
- const trimmed = content.trim();
8002
- if (trimmed.length === 0) return false;
8003
- const maxChars = this.getRecallSectionMaxChars(sectionId);
8004
- let finalContent = trimmed;
8005
- if (maxChars === 0) return false;
8006
- if (typeof maxChars === "number" && finalContent.length > maxChars) {
8007
- finalContent = `${finalContent.slice(0, maxChars)}
8008
-
8009
- ...(trimmed)
8010
- `;
8011
- }
8012
- const existing = sectionBuckets.get(sectionId) ?? [];
8013
- existing.push(finalContent);
8014
- sectionBuckets.set(sectionId, existing);
8015
- return true;
8016
- }
8017
- truncateRecallSectionToBudget(content, maxChars) {
8018
- if (maxChars <= 0) return "";
8019
- if (content.length <= maxChars) return content;
8020
- const suffix = "\n\n...(memory context trimmed)";
8021
- if (maxChars <= suffix.length) {
8022
- return content.slice(0, maxChars);
8023
- }
8024
- return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
8025
- }
8026
- protectedRecallSectionIds(sectionBuckets) {
8027
- const protectedIds = /* @__PURE__ */ new Set();
8028
- if ((sectionBuckets.get("memories")?.length ?? 0) > 0) {
8029
- protectedIds.add("memories");
8030
- }
8031
- return protectedIds;
8032
- }
8033
- protectedRecallReservationChars(content) {
8034
- const headingBoundary = content.indexOf("\n\n");
8035
- const headingChars = headingBoundary >= 0 ? headingBoundary + 2 : Math.min(content.length, 24);
8036
- return Math.min(content.length, Math.max(headingChars, 24));
8037
- }
8038
- estimateReservedRecallBudget(entries, startIndex, protectedIds, alreadyIncludedCount) {
8039
- const separatorLength = "\n\n---\n\n".length;
8040
- let reserved = 0;
8041
- let simulatedIncluded = alreadyIncludedCount;
8042
- for (let i = startIndex; i < entries.length; i += 1) {
8043
- const entry = entries[i];
8044
- if (!entry || !protectedIds.has(entry.id)) continue;
8045
- if (simulatedIncluded > 0) {
8046
- reserved += separatorLength;
8047
- }
8048
- reserved += this.protectedRecallReservationChars(entry.content);
8049
- simulatedIncluded += 1;
8050
- }
8051
- return reserved;
8052
- }
8053
- getRecallBudgetChars(override) {
8054
- if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
8055
- return Math.floor(override);
8056
- }
8057
- const configuredBudget = this.config.recallBudgetChars;
8058
- if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
8059
- return Math.floor(configuredBudget);
8060
- }
8061
- const tokenBudget = this.config.maxMemoryTokens;
8062
- if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget >= 0) {
8063
- return Math.floor(tokenBudget * 4);
8064
- }
8065
- return 0;
8066
- }
8067
- assembleRecallSections(sectionBuckets, budgetOverride) {
8068
- const orderedEntries = [];
8069
- const pipeline = Array.isArray(this.config.recallPipeline) ? this.config.recallPipeline : [];
8070
- const orderedIds = pipeline.filter((entry) => entry.enabled !== false).map((entry) => entry.id);
8071
- const seen = /* @__PURE__ */ new Set();
8072
- for (const id of orderedIds) {
8073
- const chunks = sectionBuckets.get(id);
8074
- if (!chunks || chunks.length === 0) continue;
8075
- orderedEntries.push({ id, content: chunks.join("\n\n") });
8076
- seen.add(id);
8077
- }
8078
- for (const [id, chunks] of sectionBuckets.entries()) {
8079
- if (seen.has(id)) continue;
8080
- if (chunks.length === 0) continue;
8081
- orderedEntries.push({ id, content: chunks.join("\n\n") });
8082
- }
8083
- const budget = this.getRecallBudgetChars(budgetOverride);
8084
- if (budget === 0) {
8085
- return {
8086
- sections: [],
8087
- includedIds: [],
8088
- omittedIds: orderedEntries.map((entry) => entry.id),
8089
- truncated: orderedEntries.length > 0,
8090
- finalChars: 0
8091
- };
8092
- }
8093
- const separator = "\n\n---\n\n";
8094
- const protectedIds = this.protectedRecallSectionIds(sectionBuckets);
8095
- const sections = [];
8096
- const includedIds = [];
8097
- const omittedIds = [];
8098
- let usedChars = 0;
8099
- let truncated = false;
8100
- for (let index = 0; index < orderedEntries.length; index += 1) {
8101
- const entry = orderedEntries[index];
8102
- const separatorChars = sections.length > 0 ? separator.length : 0;
8103
- const reserve = protectedIds.has(entry.id) ? 0 : this.estimateReservedRecallBudget(
8104
- orderedEntries,
8105
- index + 1,
8106
- protectedIds,
8107
- sections.length + 1
8108
- );
8109
- const availableForEntry = budget - usedChars - separatorChars - reserve;
8110
- if (availableForEntry <= 0) {
8111
- omittedIds.push(entry.id);
8112
- truncated = true;
8113
- continue;
8114
- }
8115
- const finalContent = this.truncateRecallSectionToBudget(
8116
- entry.content,
8117
- availableForEntry
8385
+ } catch (err) {
8386
+ log.debug(`last qmd recall write failed: ${err}`);
8387
+ }
8388
+ }
8389
+ async recordLastIntentSnapshotForNamespace(options) {
8390
+ try {
8391
+ const stateDir = await this.resolveStateDirForNamespace(
8392
+ options.namespace
8118
8393
  );
8119
- if (!finalContent) {
8120
- omittedIds.push(entry.id);
8121
- truncated = true;
8122
- continue;
8123
- }
8124
- if (finalContent.length < entry.content.length) {
8125
- truncated = true;
8394
+ const snapshotPath = path7.join(stateDir, "last_intent.json");
8395
+ await mkdir4(path7.dirname(snapshotPath), { recursive: true });
8396
+ await writeFile4(
8397
+ snapshotPath,
8398
+ JSON.stringify(options.snapshot, null, 2),
8399
+ "utf-8"
8400
+ );
8401
+ } catch (err) {
8402
+ log.debug(`last intent write failed: ${err}`);
8403
+ }
8404
+ }
8405
+ async resolveStateDirForNamespace(namespace) {
8406
+ if (!resolveNamespaceCapabilities(this.config).namespaces) {
8407
+ return path7.join(this.config.memoryDir, "state");
8408
+ }
8409
+ if (namespace !== this.config.defaultNamespace) {
8410
+ return path7.join(this.config.memoryDir, "namespaces", namespace, "state");
8411
+ }
8412
+ const candidate = path7.join(
8413
+ this.config.memoryDir,
8414
+ "namespaces",
8415
+ this.config.defaultNamespace
8416
+ );
8417
+ try {
8418
+ const candidateStat = await stat(candidate);
8419
+ if (candidateStat.isDirectory()) {
8420
+ return path7.join(candidate, "state");
8126
8421
  }
8127
- sections.push(finalContent);
8128
- includedIds.push(entry.id);
8129
- usedChars += separatorChars + finalContent.length;
8422
+ } catch {
8130
8423
  }
8131
- return {
8132
- sections,
8133
- includedIds,
8134
- omittedIds,
8135
- truncated,
8136
- finalChars: usedChars
8137
- };
8424
+ return path7.join(this.config.memoryDir, "state");
8425
+ }
8426
+ buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
8427
+ return results.slice(0, limit).map((result) => ({
8428
+ path: result.path,
8429
+ score: result.score,
8430
+ docid: result.docid,
8431
+ sourceLabels: sourceLabelResolver(result.path)
8432
+ }));
8433
+ }
8434
+ // Issue #1526 (seam 13): recall section budgeting/assembly moved to
8435
+ // RecallSectionCoordinator. Thin delegation keeps the orchestrator's
8436
+ // recallInternal call sites stable.
8437
+ getRecallSectionEntry(sectionId) {
8438
+ return this.recallSectionCoordinator.getRecallSectionEntry(sectionId);
8439
+ }
8440
+ isRecallSectionEnabled(sectionId, defaultEnabled = true) {
8441
+ return this.recallSectionCoordinator.isRecallSectionEnabled(
8442
+ sectionId,
8443
+ defaultEnabled
8444
+ );
8445
+ }
8446
+ isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
8447
+ return this.recallSectionCoordinator.isSpecializedRecallSectionEnabled(
8448
+ sectionId,
8449
+ topLevelEnabled
8450
+ );
8451
+ }
8452
+ getRecallSectionMaxChars(sectionId) {
8453
+ return this.recallSectionCoordinator.getRecallSectionMaxChars(sectionId);
8454
+ }
8455
+ getRecallSectionNumber(sectionId, key) {
8456
+ return this.recallSectionCoordinator.getRecallSectionNumber(sectionId, key);
8457
+ }
8458
+ appendRecallSection(sectionBuckets, sectionId, content) {
8459
+ return this.recallSectionCoordinator.appendRecallSection(
8460
+ sectionBuckets,
8461
+ sectionId,
8462
+ content
8463
+ );
8464
+ }
8465
+ truncateRecallSectionToBudget(content, maxChars) {
8466
+ return this.recallSectionCoordinator.truncateRecallSectionToBudget(
8467
+ content,
8468
+ maxChars
8469
+ );
8470
+ }
8471
+ getRecallBudgetChars(override) {
8472
+ return this.recallSectionCoordinator.getRecallBudgetChars(override);
8473
+ }
8474
+ assembleRecallSections(sectionBuckets, budgetOverride) {
8475
+ return this.recallSectionCoordinator.assembleRecallSections(
8476
+ sectionBuckets,
8477
+ budgetOverride
8478
+ );
8138
8479
  }
8139
8480
  /**
8140
8481
  * Clock source for the shared post-retrieval assembly/enrichment budget. The
@@ -8211,8 +8552,8 @@ ${doc.content}` : doc.content,
8211
8552
  timings,
8212
8553
  logger: log
8213
8554
  });
8214
- const promptHash = createHash2("sha256").update(prompt).digest("hex");
8215
- const traceId = createHash2("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
8555
+ const promptHash = createHash3("sha256").update(prompt).digest("hex");
8556
+ const traceId = createHash3("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
8216
8557
  const sectionBuckets = /* @__PURE__ */ new Map();
8217
8558
  const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
8218
8559
  cronRecallPolicyEnabled: resolveRecallAuxiliaryCapabilities(this.config).cronRecallPolicy,
@@ -8221,7 +8562,7 @@ ${doc.content}` : doc.content,
8221
8562
  cronConversationRecallMode: this.config.cronConversationRecallMode
8222
8563
  });
8223
8564
  const retrievalQuery = queryPolicy.retrievalQuery || prompt;
8224
- const retrievalQueryHash = createHash2("sha256").update(retrievalQuery).digest("hex");
8565
+ const retrievalQueryHash = createHash3("sha256").update(retrievalQuery).digest("hex");
8225
8566
  const policyVersion = this.currentPolicyVersion();
8226
8567
  let impressionRecorded = false;
8227
8568
  let recallSource = "none";
@@ -8360,7 +8701,7 @@ ${doc.content}` : doc.content,
8360
8701
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
8361
8702
  const graphSourceLabelsForPath = (resultPath) => {
8362
8703
  const labels = [];
8363
- const normalizedPath = resultPath.split(path6.sep).join("/");
8704
+ const normalizedPath = resultPath.split(path7.sep).join("/");
8364
8705
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
8365
8706
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
8366
8707
  if (graphExpandedResultPaths.has(resultPath))
@@ -8510,7 +8851,7 @@ ${doc.content}` : doc.content,
8510
8851
  profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
8511
8852
  );
8512
8853
  const emptyProfileStorage = new Proxy(
8513
- { dir: path6.join(this.config.memoryDir, ".empty-scope-profile") },
8854
+ { dir: path7.join(this.config.memoryDir, ".empty-scope-profile") },
8514
8855
  {
8515
8856
  get(target, prop) {
8516
8857
  if (prop in target) return target[prop];
@@ -9986,11 +10327,11 @@ ${formatted}`;
9986
10327
  if (!resolveRecallAuxiliaryCapabilities(this.config).compactionReset) return null;
9987
10328
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
9988
10329
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
9989
- const signalPath = path6.join(
10330
+ const signalPath = path7.join(
9990
10331
  workspaceDir,
9991
10332
  `.compaction-reset-signal-${safeSessionKey}`
9992
10333
  );
9993
- const bootPath = path6.join(workspaceDir, "BOOT.md");
10334
+ const bootPath = path7.join(workspaceDir, "BOOT.md");
9994
10335
  try {
9995
10336
  const signalStat = await stat(signalPath).catch(() => null);
9996
10337
  if (!signalStat) return null;
@@ -12261,7 +12602,7 @@ _Context: ${topQuestion.context}_`
12261
12602
  const shouldUseStableBatchKey = turns.some(
12262
12603
  (turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
12263
12604
  );
12264
- const stableBatchFingerprint = shouldUseStableBatchKey ? createHash2("sha256").update(
12605
+ const stableBatchFingerprint = shouldUseStableBatchKey ? createHash3("sha256").update(
12265
12606
  turns.map(
12266
12607
  (turn) => [
12267
12608
  turn.role,
@@ -12511,7 +12852,7 @@ _Context: ${topQuestion.context}_`
12511
12852
  buildExtractionFingerprint(turns, bufferKey) {
12512
12853
  const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
12513
12854
  if (!normalized) return null;
12514
- return createHash2("sha256").update(`${bufferKey}
12855
+ return createHash3("sha256").update(`${bufferKey}
12515
12856
  ${normalized}`).digest("hex");
12516
12857
  }
12517
12858
  shouldQueueExtraction(turns, options = {}) {
@@ -14592,7 +14933,7 @@ ${normalized}`).digest("hex");
14592
14933
  const allMems = allMemsForGraph ?? [];
14593
14934
  for (const m of allMems) {
14594
14935
  if (m.frontmatter.entityRef === entityRef) {
14595
- const rel = path6.relative(storage.dir, m.path);
14936
+ const rel = path7.relative(storage.dir, m.path);
14596
14937
  if (rel !== memoryRelPath) entitySiblings.push(rel);
14597
14938
  }
14598
14939
  }
@@ -14916,7 +15257,7 @@ ${normalized}`).digest("hex");
14916
15257
  }
14917
15258
  if (resolveConsolidationCapabilities(this.config).semanticConsolidation) {
14918
15259
  try {
14919
- const stateFilePath = path6.join(
15260
+ const stateFilePath = path7.join(
14920
15261
  this.config.memoryDir,
14921
15262
  "state",
14922
15263
  "semantic-consolidation-last-run.json"
@@ -14964,9 +15305,9 @@ ${normalized}`).digest("hex");
14964
15305
  );
14965
15306
  }
14966
15307
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
14967
- const stateDir = path6.join(this.config.memoryDir, "state");
14968
- await mkdir3(stateDir, { recursive: true });
14969
- await writeFile3(
15308
+ const stateDir = path7.join(this.config.memoryDir, "state");
15309
+ await mkdir4(stateDir, { recursive: true });
15310
+ await writeFile4(
14970
15311
  stateFilePath,
14971
15312
  JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
14972
15313
  "utf-8"
@@ -15304,30 +15645,13 @@ ${reflectionsContent.trim()}
15304
15645
  return this.recallRerankCoordinator.applyMmrToQmdResults(sectionId, results, caps);
15305
15646
  }
15306
15647
  buildLastRecallBudgetSummary(options) {
15307
- return {
15308
- requestedTopK: options.requestedTopK,
15309
- appliedTopK: options.recallResultLimit,
15310
- recallBudgetChars: this.getRecallBudgetChars(),
15311
- maxMemoryTokens: this.config.maxMemoryTokens,
15312
- qmdFetchLimit: options.qmdFetchLimit,
15313
- qmdHybridFetchLimit: options.qmdHybridFetchLimit,
15314
- finalContextChars: options.finalContextChars,
15315
- truncated: options.truncated,
15316
- includedSections: [...options.includedSections ?? []],
15317
- omittedSections: [...options.omittedSections ?? []]
15318
- };
15648
+ return this.recallSectionCoordinator.buildLastRecallBudgetSummary(options);
15319
15649
  }
15320
15650
  collectLastRecallSources(sectionBuckets, recallSource) {
15321
- const used = /* @__PURE__ */ new Set();
15322
- if (recallSource !== "none") {
15323
- used.add(recallSource);
15324
- }
15325
- for (const [sectionId, chunks] of sectionBuckets.entries()) {
15326
- if (chunks.length > 0) {
15327
- used.add(sectionId);
15328
- }
15329
- }
15330
- return [...used];
15651
+ return this.recallSectionCoordinator.collectLastRecallSources(
15652
+ sectionBuckets,
15653
+ recallSource
15654
+ );
15331
15655
  }
15332
15656
  /**
15333
15657
  * Issue #373 — nearest-neighbor lookup for the write-time semantic dedup
@@ -15377,12 +15701,12 @@ ${reflectionsContent.trim()}
15377
15701
  */
15378
15702
  semanticDedupScopeFor(targetStorage) {
15379
15703
  if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
15380
- const memoryDir = path6.resolve(this.config.memoryDir);
15381
- const storageDir = path6.resolve(targetStorage.dir);
15704
+ const memoryDir = path7.resolve(this.config.memoryDir);
15705
+ const storageDir = path7.resolve(targetStorage.dir);
15382
15706
  if (storageDir === memoryDir) {
15383
15707
  return { pathExcludePrefixes: ["namespaces/"] };
15384
15708
  }
15385
- let rel = path6.relative(memoryDir, storageDir);
15709
+ let rel = path7.relative(memoryDir, storageDir);
15386
15710
  if (!rel || rel.startsWith("..")) {
15387
15711
  log.debug(
15388
15712
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -15401,7 +15725,7 @@ ${reflectionsContent.trim()}
15401
15725
  if (hits.length === 0) return [];
15402
15726
  const results = [];
15403
15727
  for (const hit of hits) {
15404
- const fullPath = path6.isAbsolute(hit.path) ? hit.path : path6.join(this.config.memoryDir, hit.path);
15728
+ const fullPath = path7.isAbsolute(hit.path) ? hit.path : path7.join(this.config.memoryDir, hit.path);
15405
15729
  const memory = await this.storage.readMemoryByPath(fullPath);
15406
15730
  if (!memory) continue;
15407
15731
  results.push({
@@ -15598,7 +15922,7 @@ ${reflectionsContent.trim()}
15598
15922
  const storage = await this.storageRouter.storageFor(namespace);
15599
15923
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15600
15924
  if (!storageDir) continue;
15601
- const recallRoot = path6.resolve(storageDir);
15925
+ const recallRoot = path7.resolve(storageDir);
15602
15926
  if (seenRecallRoots.has(recallRoot)) continue;
15603
15927
  seenRecallRoots.add(recallRoot);
15604
15928
  recallRoots.push(recallRoot);
@@ -15622,8 +15946,8 @@ ${reflectionsContent.trim()}
15622
15946
  if (resolvedCold) scopedResults.push(resolvedCold.result);
15623
15947
  continue;
15624
15948
  }
15625
- if (path6.isAbsolute(result.path)) {
15626
- const resolvedPath = path6.resolve(result.path);
15949
+ if (path7.isAbsolute(result.path)) {
15950
+ const resolvedPath = path7.resolve(result.path);
15627
15951
  if (recallRoots.some(
15628
15952
  (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
15629
15953
  )) {
@@ -16289,58 +16613,11 @@ ${reflectionsContent.trim()}
16289
16613
  * Uses QMD to find similar memories, then LLM to verify contradiction.
16290
16614
  */
16291
16615
  async checkForContradiction(content, category, namespaceScope) {
16292
- if (!this.isSearchAvailableForNamespaceRouting()) return null;
16293
- const results = await this.searchAcrossNamespaces({
16294
- query: content,
16295
- namespaces: [namespaceScope],
16296
- maxResults: 5,
16297
- mode: "search"
16298
- });
16299
- for (const result of results) {
16300
- if (result.score < this.config.contradictionSimilarityThreshold) {
16301
- continue;
16302
- }
16303
- const memoryId = this.extractMemoryIdsFromResults([result])[0];
16304
- if (!memoryId) continue;
16305
- const resultNamespace = this.namespaceFromPath(result.path);
16306
- if (resultNamespace !== namespaceScope) continue;
16307
- const resultStorage = await this.storageRouter.storageFor(resultNamespace);
16308
- const existingMemory = await resultStorage.getMemoryById(memoryId);
16309
- if (!existingMemory) continue;
16310
- if (existingMemory.frontmatter.status === "superseded" || existingMemory.frontmatter.status === "forgotten") {
16311
- continue;
16312
- }
16313
- const verification = await this.extraction.verifyContradiction(
16314
- { content, category },
16315
- {
16316
- id: existingMemory.frontmatter.id,
16317
- content: existingMemory.content,
16318
- category: existingMemory.frontmatter.category,
16319
- created: existingMemory.frontmatter.created
16320
- }
16321
- );
16322
- if (!verification) continue;
16323
- if (verification.isContradiction && verification.confidence >= this.config.contradictionMinConfidence) {
16324
- if (verification.whichIsNewer === "first") {
16325
- log.info(
16326
- `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory \u2014 existing is newer, incoming fact is stale`
16327
- );
16328
- continue;
16329
- }
16330
- log.info(
16331
- `detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${this.config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`
16332
- );
16333
- return {
16334
- supersededId: existingMemory.frontmatter.id,
16335
- confidence: verification.confidence,
16336
- reason: verification.reasoning,
16337
- supersededPath: existingMemory.path,
16338
- supersededCreated: existingMemory.frontmatter.created,
16339
- supersededTags: existingMemory.frontmatter.tags ?? []
16340
- };
16341
- }
16342
- }
16343
- return null;
16616
+ return this.contradictionLinkingCoordinator.checkForContradiction(
16617
+ content,
16618
+ category,
16619
+ namespaceScope
16620
+ );
16344
16621
  }
16345
16622
  /**
16346
16623
  * #1645: Complete the deferred contradiction auto-resolve after writeMemory
@@ -16351,40 +16628,12 @@ ${reflectionsContent.trim()}
16351
16628
  * supersedes before tombstone status is known" defect class.
16352
16629
  */
16353
16630
  async applyDeferredContradictionResolve(contradiction, storage, newMemoryId, postWriteGuard) {
16354
- if (postWriteGuard && contradiction && this.config.contradictionAutoResolve) {
16355
- try {
16356
- const blockedRow = await storage.getMemoryById(newMemoryId);
16357
- if (blockedRow?.frontmatter?.supersedes) {
16358
- await storage.writeMemoryFrontmatter(blockedRow, { supersedes: void 0 });
16359
- }
16360
- } catch (err) {
16361
- log.warn(
16362
- `contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`
16363
- );
16364
- }
16365
- }
16366
- if (!contradiction || !this.config.contradictionAutoResolve || postWriteGuard) {
16367
- return;
16368
- }
16369
- try {
16370
- await storage.supersedeMemory(
16371
- contradiction.supersededId,
16372
- newMemoryId,
16373
- contradiction.reason
16374
- );
16375
- if (resolveIndexingCapabilities(this.config).queryAwareIndexing && contradiction.supersededPath) {
16376
- deindexMemory(
16377
- this.config.memoryDir,
16378
- contradiction.supersededPath,
16379
- contradiction.supersededCreated,
16380
- contradiction.supersededTags
16381
- );
16382
- }
16383
- } catch (err) {
16384
- log.warn(
16385
- `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
16386
- );
16387
- }
16631
+ return this.contradictionLinkingCoordinator.applyDeferredContradictionResolve(
16632
+ contradiction,
16633
+ storage,
16634
+ newMemoryId,
16635
+ postWriteGuard
16636
+ );
16388
16637
  }
16389
16638
  // ---------------------------------------------------------------------------
16390
16639
  // Memory Linking (Phase 3A)
@@ -16393,68 +16642,11 @@ ${reflectionsContent.trim()}
16393
16642
  * Suggest links for a new memory based on similar existing memories.
16394
16643
  */
16395
16644
  async suggestLinksForMemory(content, category, namespaceScope) {
16396
- if (!this.isSearchAvailableForNamespaceRouting()) return [];
16397
- const results = await this.searchAcrossNamespaces({
16398
- query: content,
16399
- namespaces: [namespaceScope],
16400
- maxResults: 5,
16401
- mode: "search"
16402
- });
16403
- if (results.length === 0) return [];
16404
- const candidates = [];
16405
- for (const result of results) {
16406
- const memoryId = this.extractMemoryIdsFromResults([result])[0];
16407
- if (!memoryId) continue;
16408
- const resultNamespace = this.namespaceFromPath(result.path);
16409
- if (resultNamespace !== namespaceScope) continue;
16410
- const resultStorage = await this.storageRouter.storageFor(resultNamespace);
16411
- const memory = await resultStorage.getMemoryById(memoryId);
16412
- if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
16413
- candidates.push({
16414
- id: memory.frontmatter.id,
16415
- content: memory.content,
16416
- category: memory.frontmatter.category
16417
- });
16418
- }
16419
- }
16420
- if (candidates.length === 0) return [];
16421
- const suggestions = await this.extraction.suggestLinks(
16422
- { content, category },
16423
- candidates
16645
+ return this.contradictionLinkingCoordinator.suggestLinksForMemory(
16646
+ content,
16647
+ category,
16648
+ namespaceScope
16424
16649
  );
16425
- if (!suggestions || suggestions.links.length === 0) return [];
16426
- return suggestions.links.map((link) => ({
16427
- targetId: link.targetId,
16428
- linkType: link.linkType,
16429
- strength: link.strength,
16430
- reason: link.reason || void 0
16431
- }));
16432
- }
16433
- async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
16434
- const parts = qmdCollectionPathParts(result.path);
16435
- if (parts) {
16436
- const memory = await this.readQmdResultMemory(
16437
- result.path,
16438
- storage,
16439
- recallNamespaces
16440
- );
16441
- return memory ? graphPathRelativeToStorage(storage.dir, memory.path) : null;
16442
- }
16443
- return graphPathRelativeToStorage(storage.dir, result.path);
16444
- }
16445
- async graphSeedPathsWithinDeadline(storage, results, deadlineAtMs, recallNamespaces = []) {
16446
- const resolved = [];
16447
- for (const result of results) {
16448
- if (Date.now() >= deadlineAtMs) break;
16449
- const seedPath = await this.graphSeedPathRelativeToStorage(
16450
- storage,
16451
- result,
16452
- recallNamespaces
16453
- );
16454
- if (Date.now() >= deadlineAtMs) break;
16455
- if (seedPath) resolved.push(seedPath);
16456
- }
16457
- return resolved;
16458
16650
  }
16459
16651
  namespaceFromPath(p) {
16460
16652
  if (!resolveNamespaceCapabilities(this.config).namespaces) return this.config.defaultNamespace;
@@ -16515,6 +16707,9 @@ export {
16515
16707
  buildProcedureRecallSection,
16516
16708
  hasIdentityRecoveryIntent,
16517
16709
  resolveEffectiveIdentityInjectionMode,
16710
+ mergeGraphExpandedResults,
16711
+ graphPathRelativeToStorage,
16712
+ blendGraphExpandedRecallScore,
16518
16713
  decideSemanticDedup,
16519
16714
  DEFAULT_TAXONOMY,
16520
16715
  generateResolverDocument,
@@ -16546,9 +16741,6 @@ export {
16546
16741
  resolveRecallModeDecisionAsync,
16547
16742
  computeArtifactCandidateFetchLimit,
16548
16743
  computeQmdHybridFetchLimit,
16549
- mergeGraphExpandedResults,
16550
- graphPathRelativeToStorage,
16551
- blendGraphExpandedRecallScore,
16552
16744
  summarizeGraphShadowComparison,
16553
16745
  mergeArtifactRecallCandidates,
16554
16746
  resolveRecentThreadMemoryPaths,
@@ -16557,4 +16749,4 @@ export {
16557
16749
  resolvePersistedMemoryRelativePath,
16558
16750
  Orchestrator
16559
16751
  };
16560
- //# sourceMappingURL=chunk-7HUGLMSW.js.map
16752
+ //# sourceMappingURL=chunk-SODQQCAZ.js.map