@remnic/core 9.3.637 → 9.3.639

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 (279) hide show
  1. package/dist/access-cli.js +29 -29
  2. package/dist/access-http.d.ts +56 -5
  3. package/dist/access-http.js +15 -13
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +14 -12
  6. package/dist/access-schema.d.ts +3 -0
  7. package/dist/access-schema.js +1 -1
  8. package/dist/{access-service-GVOE5U3C.d.ts → access-service-jyYute38.d.ts} +4 -2
  9. package/dist/access-service.d.ts +4 -4
  10. package/dist/access-service.js +12 -10
  11. package/dist/action-confidence.d.ts +1 -1
  12. package/dist/active-memory-bridge.d.ts +1 -1
  13. package/dist/active-recall.d.ts +1 -1
  14. package/dist/active-recall.js +1 -1
  15. package/dist/{auto-sync-RFADEHIQ.js → auto-sync-54QQHOG5.js} +4 -4
  16. package/dist/behavior-learner.d.ts +1 -1
  17. package/dist/behavior-signals.d.ts +1 -1
  18. package/dist/bootstrap.d.ts +3 -3
  19. package/dist/briefing.d.ts +1 -1
  20. package/dist/briefing.js +3 -3
  21. package/dist/buffer-surprise-report.d.ts +1 -1
  22. package/dist/buffer.d.ts +1 -1
  23. package/dist/calibration.d.ts +1 -1
  24. package/dist/calibration.js +1 -1
  25. package/dist/causal-behavior.d.ts +1 -1
  26. package/dist/causal-behavior.js +2 -2
  27. package/dist/causal-chain.js +2 -2
  28. package/dist/causal-consolidation.d.ts +1 -1
  29. package/dist/causal-consolidation.js +7 -7
  30. package/dist/causal-retrieval.js +2 -2
  31. package/dist/causal-trajectory-graph.js +1 -1
  32. package/dist/causal-trajectory.js +1 -1
  33. package/dist/{chunk-TFICNXXU.js → chunk-2BHNQRE5.js} +1153 -294
  34. package/dist/chunk-2BHNQRE5.js.map +1 -0
  35. package/dist/{chunk-3RDYU3JS.js → chunk-3AZDLWDW.js} +3 -3
  36. package/dist/{chunk-FPNQF475.js → chunk-3F7RMHC4.js} +1 -1
  37. package/dist/chunk-3F7RMHC4.js.map +1 -0
  38. package/dist/{chunk-3EJ5OOZ3.js → chunk-3SF7QNKF.js} +3 -3
  39. package/dist/{chunk-NFNQ7TWF.js → chunk-4VTVCWVB.js} +20 -12
  40. package/dist/chunk-4VTVCWVB.js.map +1 -0
  41. package/dist/{chunk-XM6M6DHG.js → chunk-52XI77OQ.js} +204 -13
  42. package/dist/chunk-52XI77OQ.js.map +1 -0
  43. package/dist/{chunk-6BDVBBBY.js → chunk-666A3MOW.js} +88 -30
  44. package/dist/chunk-666A3MOW.js.map +1 -0
  45. package/dist/{chunk-242XFZ36.js → chunk-7OH7KPF5.js} +2 -2
  46. package/dist/{chunk-HZVIYZYN.js → chunk-7R37SOT4.js} +6 -6
  47. package/dist/{chunk-7A2QKUUA.js → chunk-7XRSLMUD.js} +2 -2
  48. package/dist/{chunk-723OMPUI.js → chunk-A3BS64GV.js} +7 -1
  49. package/dist/chunk-A3BS64GV.js.map +1 -0
  50. package/dist/{chunk-JCLECECB.js → chunk-A3UPMOJZ.js} +2 -2
  51. package/dist/{chunk-YCX45GOQ.js → chunk-AFH2JXSF.js} +2 -2
  52. package/dist/{chunk-BK35NOJL.js → chunk-BB6FNMMB.js} +52 -6
  53. package/dist/chunk-BB6FNMMB.js.map +1 -0
  54. package/dist/{chunk-3XNMN242.js → chunk-BTY5XQG3.js} +7 -7
  55. package/dist/{chunk-QHXW3LZV.js → chunk-C3EJ3UIS.js} +3 -3
  56. package/dist/{chunk-A3HKTPPV.js → chunk-C63WC454.js} +12 -1
  57. package/dist/chunk-C63WC454.js.map +1 -0
  58. package/dist/{chunk-4S3N6HFG.js → chunk-C6XO6ONP.js} +2 -2
  59. package/dist/{chunk-WD2W4234.js → chunk-CDHRUNBX.js} +11 -2
  60. package/dist/chunk-CDHRUNBX.js.map +1 -0
  61. package/dist/{chunk-YQNADJCT.js → chunk-CMZLMIZI.js} +2 -2
  62. package/dist/{chunk-KVDUDYEN.js → chunk-DDRNDPX4.js} +2 -2
  63. package/dist/{chunk-PW6GURU3.js → chunk-EKIQBGAY.js} +2 -2
  64. package/dist/{chunk-QJGTSCJN.js → chunk-FGRV3X3Y.js} +19 -19
  65. package/dist/{chunk-2IT7WFYE.js → chunk-FWIROLS6.js} +2 -1
  66. package/dist/chunk-FWIROLS6.js.map +1 -0
  67. package/dist/{chunk-X7EJF46S.js → chunk-H4RWKZE2.js} +2 -2
  68. package/dist/{chunk-A6D7A2FW.js → chunk-IHG27THY.js} +4 -4
  69. package/dist/{chunk-PUEAEQSN.js → chunk-ISMZIMD3.js} +2 -2
  70. package/dist/{chunk-LEG7XWS2.js → chunk-IXSTQGYV.js} +2 -2
  71. package/dist/{chunk-CMN5AWAZ.js → chunk-J2KFC47S.js} +2 -2
  72. package/dist/{chunk-K47C6M2C.js → chunk-M75TBFKQ.js} +2 -2
  73. package/dist/{chunk-7V2SGZ3H.js → chunk-NE566K4E.js} +2 -2
  74. package/dist/{chunk-YROCXMCK.js → chunk-RJGPH2Q3.js} +2 -2
  75. package/dist/{chunk-UXFOGILU.js → chunk-SBHQBC37.js} +2 -2
  76. package/dist/{chunk-QYGIQ5NM.js → chunk-SHHT4JTC.js} +2 -2
  77. package/dist/{chunk-TQOU3VAT.js → chunk-SSOMTUCA.js} +1 -1
  78. package/dist/{chunk-NRST7W5Q.js → chunk-UI2UP7XX.js} +2 -2
  79. package/dist/{chunk-C4KKM62E.js → chunk-UU5LHD6J.js} +2 -2
  80. package/dist/{chunk-EWC6W6AB.js → chunk-UXA5L2DZ.js} +2 -2
  81. package/dist/{chunk-XL7FK7PJ.js → chunk-Y56J7CXW.js} +33 -16
  82. package/dist/{chunk-XL7FK7PJ.js.map → chunk-Y56J7CXW.js.map} +1 -1
  83. package/dist/{cli-B-fHk59D.d.ts → cli-A4AIhv9e.d.ts} +3 -3
  84. package/dist/cli.d.ts +5 -5
  85. package/dist/cli.js +28 -27
  86. package/dist/compounding/engine.d.ts +1 -1
  87. package/dist/compounding/engine.js +3 -3
  88. package/dist/compounding/preference-consolidator.d.ts +1 -1
  89. package/dist/compression-optimizer.d.ts +1 -1
  90. package/dist/config.d.ts +1 -1
  91. package/dist/config.js +1 -1
  92. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  93. package/dist/connectors/codex-materialize-runner.js +3 -3
  94. package/dist/connectors/codex-materialize.d.ts +1 -1
  95. package/dist/connectors/index.d.ts +1 -1
  96. package/dist/connectors/index.js +3 -3
  97. package/dist/consolidation-provenance-check.d.ts +1 -1
  98. package/dist/consolidation-undo.d.ts +1 -1
  99. package/dist/contradiction/index.d.ts +1 -1
  100. package/dist/conversation-index/backend.d.ts +1 -1
  101. package/dist/conversation-index/chunker.d.ts +1 -1
  102. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  103. package/dist/conversation-index/indexer.d.ts +1 -1
  104. package/dist/conversation-index/search.d.ts +1 -1
  105. package/dist/day-summary.d.ts +1 -1
  106. package/dist/delinearize.d.ts +1 -1
  107. package/dist/direct-answer-wiring.d.ts +1 -1
  108. package/dist/direct-answer.d.ts +1 -1
  109. package/dist/embedding-fallback.d.ts +1 -1
  110. package/dist/enrichment/index.d.ts +1 -1
  111. package/dist/entity-retrieval.d.ts +1 -1
  112. package/dist/entity-retrieval.js +3 -3
  113. package/dist/entity-schema.d.ts +1 -1
  114. package/dist/explicit-capture.d.ts +3 -3
  115. package/dist/extraction-judge-telemetry.d.ts +1 -1
  116. package/dist/extraction-judge-training.d.ts +1 -1
  117. package/dist/extraction-judge.d.ts +1 -1
  118. package/dist/extraction-judge.js +2 -2
  119. package/dist/extraction.d.ts +1 -1
  120. package/dist/extraction.js +2 -2
  121. package/dist/fallback-llm.d.ts +1 -1
  122. package/dist/fallback-llm.js +1 -1
  123. package/dist/{graph-edge-decay-5ZOK7ZNO.js → graph-edge-decay-PUFNHOBS.js} +2 -2
  124. package/dist/graph-snapshot.js +2 -2
  125. package/dist/graph.d.ts +3 -0
  126. package/dist/graph.js +1 -1
  127. package/dist/identity-continuity.d.ts +1 -1
  128. package/dist/importance.d.ts +1 -1
  129. package/dist/index.d.ts +9 -9
  130. package/dist/index.js +40 -40
  131. package/dist/intent.d.ts +1 -1
  132. package/dist/lcm/engine.d.ts +1 -1
  133. package/dist/lcm/index.d.ts +1 -1
  134. package/dist/lcm/tools.d.ts +1 -1
  135. package/dist/lifecycle.d.ts +1 -1
  136. package/dist/live-connectors-runner.d.ts +1 -1
  137. package/dist/local-llm.d.ts +1 -1
  138. package/dist/maintenance/memory-governance-cron.d.ts +8 -0
  139. package/dist/maintenance/memory-governance-cron.js +1 -1
  140. package/dist/maintenance/memory-governance.d.ts +1 -1
  141. package/dist/maintenance/memory-governance.js +3 -3
  142. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  143. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  144. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  145. package/dist/memory-action-policy.d.ts +1 -1
  146. package/dist/memory-cache.d.ts +1 -1
  147. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  148. package/dist/memory-projection-store.d.ts +1 -1
  149. package/dist/memory-provenance.d.ts +1 -1
  150. package/dist/memory-worth-outcomes.d.ts +1 -1
  151. package/dist/models-json.d.ts +1 -1
  152. package/dist/namespaces/migrate.d.ts +1 -1
  153. package/dist/namespaces/migrate.js +4 -4
  154. package/dist/namespaces/principal.d.ts +1 -1
  155. package/dist/namespaces/search.d.ts +1 -1
  156. package/dist/namespaces/storage.d.ts +1 -1
  157. package/dist/namespaces/storage.js +3 -3
  158. package/dist/native-knowledge.d.ts +1 -1
  159. package/dist/operator-toolkit.d.ts +1 -1
  160. package/dist/operator-toolkit.js +8 -8
  161. package/dist/{orchestrator-CoqytbK_.d.ts → orchestrator-BEDTiuEO.d.ts} +20 -5
  162. package/dist/orchestrator.d.ts +3 -3
  163. package/dist/orchestrator.js +24 -24
  164. package/dist/patterns-cli.d.ts +1 -1
  165. package/dist/policy-runtime.d.ts +1 -1
  166. package/dist/qmd-recall-cache.d.ts +1 -1
  167. package/dist/qmd.d.ts +1 -1
  168. package/dist/recall-disclosure-escalation.d.ts +1 -1
  169. package/dist/recall-explain-renderer.d.ts +1 -1
  170. package/dist/recall-explain-renderer.js +3 -3
  171. package/dist/recall-planner-llm.d.ts +1 -1
  172. package/dist/recall-planner-llm.js +1 -1
  173. package/dist/recall-state.d.ts +3 -1
  174. package/dist/recall-state.js +1 -1
  175. package/dist/recall-tag-filter.d.ts +1 -1
  176. package/dist/recall-xray-cli.d.ts +1 -1
  177. package/dist/recall-xray-cli.js +4 -4
  178. package/dist/recall-xray-renderer.d.ts +1 -1
  179. package/dist/recall-xray-renderer.js +3 -3
  180. package/dist/recall-xray.d.ts +1 -1
  181. package/dist/recall-xray.js +2 -2
  182. package/dist/resolve-auth-token.d.ts +1 -1
  183. package/dist/resume-bundles.js +4 -4
  184. package/dist/retrieval-agents.d.ts +1 -1
  185. package/dist/retrieval-tiers.d.ts +1 -1
  186. package/dist/routing/engine.d.ts +1 -1
  187. package/dist/routing/store.d.ts +1 -1
  188. package/dist/search/embed-helper.d.ts +1 -1
  189. package/dist/search/factory.d.ts +1 -1
  190. package/dist/search/index.d.ts +1 -1
  191. package/dist/search/lancedb-backend.d.ts +1 -1
  192. package/dist/search/meilisearch-backend.d.ts +1 -1
  193. package/dist/search/noop-backend.d.ts +1 -1
  194. package/dist/search/orama-backend.d.ts +1 -1
  195. package/dist/search/port.d.ts +1 -1
  196. package/dist/search/remote-backend.d.ts +1 -1
  197. package/dist/{semantic-consolidation-BPs6BURk.d.ts → semantic-consolidation-Byut1ufK.d.ts} +1 -1
  198. package/dist/semantic-consolidation.d.ts +2 -2
  199. package/dist/semantic-consolidation.js +4 -4
  200. package/dist/semantic-rule-promotion.js +3 -3
  201. package/dist/semantic-rule-verifier.d.ts +1 -1
  202. package/dist/semantic-rule-verifier.js +3 -3
  203. package/dist/session-observer-bands.d.ts +1 -1
  204. package/dist/session-observer-state.d.ts +1 -1
  205. package/dist/shared-context/manager.d.ts +1 -1
  206. package/dist/signal.d.ts +1 -1
  207. package/dist/storage.d.ts +1 -1
  208. package/dist/storage.js +2 -2
  209. package/dist/summarizer.d.ts +1 -1
  210. package/dist/summarizer.js +3 -3
  211. package/dist/summary-snapshot.d.ts +1 -1
  212. package/dist/temporal-supersession.d.ts +1 -1
  213. package/dist/temporal-validity.d.ts +1 -1
  214. package/dist/threading.d.ts +1 -1
  215. package/dist/tier-migration.d.ts +1 -1
  216. package/dist/tier-routing.d.ts +1 -1
  217. package/dist/topics.d.ts +1 -1
  218. package/dist/transcript.d.ts +1 -1
  219. package/dist/transcript.js +2 -2
  220. package/dist/{types-CpMPD8xl.d.ts → types-BzA1FKbg.d.ts} +4 -0
  221. package/dist/types.d.ts +1 -1
  222. package/dist/types.js +1 -1
  223. package/dist/utility-runtime.d.ts +1 -1
  224. package/dist/verified-recall.js +3 -3
  225. package/package.json +1 -1
  226. package/src/access-http.test.ts +110 -2
  227. package/src/access-http.ts +117 -1
  228. package/src/access-mcp.ts +15 -6
  229. package/src/access-schema.ts +14 -0
  230. package/src/access-service-namespace.test.ts +740 -0
  231. package/src/access-service.ts +226 -4
  232. package/src/config.ts +14 -0
  233. package/src/fallback-llm.ts +16 -0
  234. package/src/graph.ts +39 -17
  235. package/src/index.ts +9 -1
  236. package/src/maintenance/memory-governance-cron.ts +113 -30
  237. package/src/orchestrator.ts +1456 -336
  238. package/src/recall-state.ts +3 -0
  239. package/src/types.ts +4 -0
  240. package/dist/chunk-2IT7WFYE.js.map +0 -1
  241. package/dist/chunk-6BDVBBBY.js.map +0 -1
  242. package/dist/chunk-723OMPUI.js.map +0 -1
  243. package/dist/chunk-A3HKTPPV.js.map +0 -1
  244. package/dist/chunk-BK35NOJL.js.map +0 -1
  245. package/dist/chunk-FPNQF475.js.map +0 -1
  246. package/dist/chunk-NFNQ7TWF.js.map +0 -1
  247. package/dist/chunk-TFICNXXU.js.map +0 -1
  248. package/dist/chunk-WD2W4234.js.map +0 -1
  249. package/dist/chunk-XM6M6DHG.js.map +0 -1
  250. /package/dist/{auto-sync-RFADEHIQ.js.map → auto-sync-54QQHOG5.js.map} +0 -0
  251. /package/dist/{chunk-3RDYU3JS.js.map → chunk-3AZDLWDW.js.map} +0 -0
  252. /package/dist/{chunk-3EJ5OOZ3.js.map → chunk-3SF7QNKF.js.map} +0 -0
  253. /package/dist/{chunk-242XFZ36.js.map → chunk-7OH7KPF5.js.map} +0 -0
  254. /package/dist/{chunk-HZVIYZYN.js.map → chunk-7R37SOT4.js.map} +0 -0
  255. /package/dist/{chunk-7A2QKUUA.js.map → chunk-7XRSLMUD.js.map} +0 -0
  256. /package/dist/{chunk-JCLECECB.js.map → chunk-A3UPMOJZ.js.map} +0 -0
  257. /package/dist/{chunk-YCX45GOQ.js.map → chunk-AFH2JXSF.js.map} +0 -0
  258. /package/dist/{chunk-3XNMN242.js.map → chunk-BTY5XQG3.js.map} +0 -0
  259. /package/dist/{chunk-QHXW3LZV.js.map → chunk-C3EJ3UIS.js.map} +0 -0
  260. /package/dist/{chunk-4S3N6HFG.js.map → chunk-C6XO6ONP.js.map} +0 -0
  261. /package/dist/{chunk-YQNADJCT.js.map → chunk-CMZLMIZI.js.map} +0 -0
  262. /package/dist/{chunk-KVDUDYEN.js.map → chunk-DDRNDPX4.js.map} +0 -0
  263. /package/dist/{chunk-PW6GURU3.js.map → chunk-EKIQBGAY.js.map} +0 -0
  264. /package/dist/{chunk-QJGTSCJN.js.map → chunk-FGRV3X3Y.js.map} +0 -0
  265. /package/dist/{chunk-X7EJF46S.js.map → chunk-H4RWKZE2.js.map} +0 -0
  266. /package/dist/{chunk-A6D7A2FW.js.map → chunk-IHG27THY.js.map} +0 -0
  267. /package/dist/{chunk-PUEAEQSN.js.map → chunk-ISMZIMD3.js.map} +0 -0
  268. /package/dist/{chunk-LEG7XWS2.js.map → chunk-IXSTQGYV.js.map} +0 -0
  269. /package/dist/{chunk-CMN5AWAZ.js.map → chunk-J2KFC47S.js.map} +0 -0
  270. /package/dist/{chunk-K47C6M2C.js.map → chunk-M75TBFKQ.js.map} +0 -0
  271. /package/dist/{chunk-7V2SGZ3H.js.map → chunk-NE566K4E.js.map} +0 -0
  272. /package/dist/{chunk-YROCXMCK.js.map → chunk-RJGPH2Q3.js.map} +0 -0
  273. /package/dist/{chunk-UXFOGILU.js.map → chunk-SBHQBC37.js.map} +0 -0
  274. /package/dist/{chunk-QYGIQ5NM.js.map → chunk-SHHT4JTC.js.map} +0 -0
  275. /package/dist/{chunk-TQOU3VAT.js.map → chunk-SSOMTUCA.js.map} +0 -0
  276. /package/dist/{chunk-NRST7W5Q.js.map → chunk-UI2UP7XX.js.map} +0 -0
  277. /package/dist/{chunk-C4KKM62E.js.map → chunk-UU5LHD6J.js.map} +0 -0
  278. /package/dist/{chunk-EWC6W6AB.js.map → chunk-UXA5L2DZ.js.map} +0 -0
  279. /package/dist/{graph-edge-decay-5ZOK7ZNO.js.map → graph-edge-decay-PUFNHOBS.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  loadSyncState,
5
5
  syncWearableSource,
6
6
  wearableSourceLabel
7
- } from "./chunk-KVDUDYEN.js";
7
+ } from "./chunk-DDRNDPX4.js";
8
8
  import {
9
9
  migrateFromEngram
10
10
  } from "./chunk-4HFJQCJZ.js";
@@ -16,7 +16,7 @@ import {
16
16
  ensurePatternReinforcementCron,
17
17
  ensureProceduralMiningCron,
18
18
  graphEdgeDecayCadenceToCronExpr
19
- } from "./chunk-6BDVBBBY.js";
19
+ } from "./chunk-666A3MOW.js";
20
20
  import {
21
21
  LcmEngine
22
22
  } from "./chunk-D2B22JDF.js";
@@ -29,7 +29,7 @@ import {
29
29
  import {
30
30
  CompoundingEngine,
31
31
  defaultTierMigrationCycleBudget
32
- } from "./chunk-UXFOGILU.js";
32
+ } from "./chunk-SBHQBC37.js";
33
33
  import {
34
34
  SharedContextManager
35
35
  } from "./chunk-DRD2Q7HQ.js";
@@ -64,7 +64,7 @@ import {
64
64
  } from "./chunk-VOUOLGIP.js";
65
65
  import {
66
66
  HourlySummarizer
67
- } from "./chunk-HZVIYZYN.js";
67
+ } from "./chunk-7R37SOT4.js";
68
68
  import {
69
69
  SessionObserverState
70
70
  } from "./chunk-MHQC2WU2.js";
@@ -113,7 +113,7 @@ import {
113
113
  LastRecallStore,
114
114
  TierMigrationStatusStore,
115
115
  clampGraphRecallExpandedEntries
116
- } from "./chunk-2IT7WFYE.js";
116
+ } from "./chunk-FWIROLS6.js";
117
117
  import {
118
118
  buildQmdRecallCacheKey,
119
119
  getCachedQmdRecall,
@@ -154,10 +154,10 @@ import {
154
154
  getVerdictKind,
155
155
  judgeFactDurability,
156
156
  validateProcedureExtraction
157
- } from "./chunk-K47C6M2C.js";
157
+ } from "./chunk-M75TBFKQ.js";
158
158
  import {
159
159
  ExtractionEngine
160
- } from "./chunk-NRST7W5Q.js";
160
+ } from "./chunk-UI2UP7XX.js";
161
161
  import {
162
162
  parseMemoryActionEligibilityContext
163
163
  } from "./chunk-ROZJACKP.js";
@@ -175,7 +175,7 @@ import {
175
175
  buildEntityRecallSection,
176
176
  entityRecentTranscriptLookbackHours,
177
177
  readRecentEntityTranscriptEntries
178
- } from "./chunk-JCLECECB.js";
178
+ } from "./chunk-A3UPMOJZ.js";
179
179
  import {
180
180
  buildEventOrderRecallSection,
181
181
  shouldRecallEventOrderEvidence
@@ -210,7 +210,7 @@ import {
210
210
  materializeAfterSemanticConsolidation,
211
211
  parseConsolidationResponse,
212
212
  parseOperatorAwareConsolidationResponse
213
- } from "./chunk-X7EJF46S.js";
213
+ } from "./chunk-H4RWKZE2.js";
214
214
  import {
215
215
  normalizeReplaySessionKey
216
216
  } from "./chunk-2PRQG7PV.js";
@@ -219,22 +219,22 @@ import {
219
219
  } from "./chunk-X6IRLNOO.js";
220
220
  import {
221
221
  searchVerifiedEpisodes
222
- } from "./chunk-YROCXMCK.js";
222
+ } from "./chunk-RJGPH2Q3.js";
223
223
  import {
224
224
  ThreadingManager
225
225
  } from "./chunk-W4RVMTHR.js";
226
226
  import {
227
227
  searchVerifiedSemanticRules
228
- } from "./chunk-4S3N6HFG.js";
228
+ } from "./chunk-C6XO6ONP.js";
229
229
  import {
230
230
  searchWorkProductLedgerEntries
231
231
  } from "./chunk-ZRWB5D4H.js";
232
232
  import {
233
233
  TranscriptManager
234
- } from "./chunk-A6D7A2FW.js";
234
+ } from "./chunk-IHG27THY.js";
235
235
  import {
236
236
  NamespaceStorageRouter
237
- } from "./chunk-LEG7XWS2.js";
237
+ } from "./chunk-IXSTQGYV.js";
238
238
  import {
239
239
  PolicyRuntimeManager
240
240
  } from "./chunk-33JBK2XP.js";
@@ -271,8 +271,9 @@ import {
271
271
  } from "./chunk-IBTZEBUD.js";
272
272
  import {
273
273
  FallbackLlmClient,
274
- fallbackLlmRuntimeContextFromConfig
275
- } from "./chunk-723OMPUI.js";
274
+ fallbackLlmRuntimeContextFromConfig,
275
+ gatewayTaskChainOptions
276
+ } from "./chunk-A3BS64GV.js";
276
277
  import {
277
278
  compileCorrectionRule,
278
279
  correctionsFilePath,
@@ -308,9 +309,12 @@ import {
308
309
  listTrustZoneRecords,
309
310
  searchTrustZoneRecords
310
311
  } from "./chunk-JGSKJHF7.js";
312
+ import {
313
+ isPathInsideStorageRoot
314
+ } from "./chunk-FF4KLI5W.js";
311
315
  import {
312
316
  buildXraySnapshot
313
- } from "./chunk-YQNADJCT.js";
317
+ } from "./chunk-CMZLMIZI.js";
314
318
  import {
315
319
  NamespaceSearchRouter
316
320
  } from "./chunk-LASA46TQ.js";
@@ -345,10 +349,10 @@ import {
345
349
  } from "./chunk-H3PHZLMF.js";
346
350
  import {
347
351
  GraphIndex
348
- } from "./chunk-XL7FK7PJ.js";
352
+ } from "./chunk-Y56J7CXW.js";
349
353
  import {
350
354
  buildChainFollowupGenerator
351
- } from "./chunk-CMN5AWAZ.js";
355
+ } from "./chunk-J2KFC47S.js";
352
356
  import {
353
357
  ContentHashIndex,
354
358
  StorageManager,
@@ -358,7 +362,7 @@ import {
358
362
  normalizeEntityName,
359
363
  parseEntityFile,
360
364
  stripAttributesSuffix
361
- } from "./chunk-QYGIQ5NM.js";
365
+ } from "./chunk-SHHT4JTC.js";
362
366
  import {
363
367
  isValidTranscriptDate,
364
368
  loadSpeakerRegistry,
@@ -373,7 +377,7 @@ import {
373
377
  } from "./chunk-J6A3CX5N.js";
374
378
  import {
375
379
  confidenceTier
376
- } from "./chunk-FPNQF475.js";
380
+ } from "./chunk-3F7RMHC4.js";
377
381
  import {
378
382
  inferMemoryStatus,
379
383
  isActiveMemoryStatus
@@ -387,7 +391,7 @@ import {
387
391
  } from "./chunk-FVQJYWH7.js";
388
392
  import {
389
393
  searchCausalTrajectories
390
- } from "./chunk-TQOU3VAT.js";
394
+ } from "./chunk-SSOMTUCA.js";
391
395
  import {
392
396
  canReadNamespace,
393
397
  defaultNamespaceForPrincipal,
@@ -416,6 +420,9 @@ import {
416
420
  keyring_exports,
417
421
  secureStoreDir
418
422
  } from "./chunk-BJMBJZ2Y.js";
423
+ import {
424
+ SecureStoreLockedError
425
+ } from "./chunk-ILXTATKK.js";
419
426
  import {
420
427
  parseFlexibleIsoTimestamp
421
428
  } from "./chunk-P7FMDTKL.js";
@@ -1633,8 +1640,119 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
1633
1640
  }
1634
1641
  }
1635
1642
  }
1643
+ function qmdCollectionPathParts(resultPath) {
1644
+ if (!resultPath || path2.isAbsolute(resultPath)) return null;
1645
+ const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
1646
+ const slashIndex = normalized.indexOf("/");
1647
+ if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
1648
+ const collection = normalized.slice(0, slashIndex);
1649
+ if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
1650
+ return {
1651
+ collection,
1652
+ relativePath: normalized.slice(slashIndex + 1)
1653
+ };
1654
+ }
1655
+ function qmdResultPathCandidates(storageDir, resultPath) {
1656
+ const candidates = /* @__PURE__ */ new Set();
1657
+ const storageRoot = path2.resolve(storageDir);
1658
+ const addCandidate = (candidate) => {
1659
+ const resolved = path2.resolve(candidate);
1660
+ if (isPathInsideStorageRoot(storageRoot, resolved)) {
1661
+ candidates.add(resolved);
1662
+ }
1663
+ };
1664
+ const addRelativeCandidates = (relativePath) => {
1665
+ const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
1666
+ if (!normalized) return;
1667
+ addCandidate(path2.join(storageRoot, normalized));
1668
+ if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
1669
+ addCandidate(path2.join(storageRoot, "facts", normalized));
1670
+ }
1671
+ };
1672
+ if (path2.isAbsolute(resultPath)) {
1673
+ addCandidate(resultPath);
1674
+ } else {
1675
+ addRelativeCandidates(resultPath);
1676
+ }
1677
+ return [...candidates];
1678
+ }
1636
1679
  var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
1637
1680
  var DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS = 1e4;
1681
+ function normalizeIanaTimeZone(value) {
1682
+ if (typeof value !== "string") return void 0;
1683
+ const trimmed = value.trim();
1684
+ if (!trimmed) return void 0;
1685
+ try {
1686
+ Intl.DateTimeFormat(void 0, { timeZone: trimmed });
1687
+ return trimmed;
1688
+ } catch {
1689
+ return void 0;
1690
+ }
1691
+ }
1692
+ function formatDateInTimeZone(date, timeZone) {
1693
+ const parts = new Intl.DateTimeFormat("en-US", {
1694
+ timeZone,
1695
+ year: "numeric",
1696
+ month: "2-digit",
1697
+ day: "2-digit"
1698
+ }).formatToParts(date);
1699
+ const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
1700
+ return `${get("year")}-${get("month")}-${get("day")}`;
1701
+ }
1702
+ function utcDateKey(date) {
1703
+ return date.toISOString().slice(0, 10);
1704
+ }
1705
+ function utcDateKeysAround(date) {
1706
+ const dayMs = 864e5;
1707
+ const keys = [
1708
+ utcDateKey(new Date(date.getTime() - dayMs)),
1709
+ utcDateKey(date),
1710
+ utcDateKey(new Date(date.getTime() + dayMs))
1711
+ ];
1712
+ return keys.filter((value, index, array) => array.indexOf(value) === index);
1713
+ }
1714
+ function utcDateKeysForLocalDay(date, timeZone) {
1715
+ const targetLocalDate = formatDateInTimeZone(date, timeZone);
1716
+ const keys = /* @__PURE__ */ new Set();
1717
+ const hourMs = 36e5;
1718
+ const scanStart = date.getTime() - 48 * hourMs;
1719
+ const scanEnd = date.getTime() + 48 * hourMs;
1720
+ for (let ms = scanStart; ms <= scanEnd; ms += hourMs) {
1721
+ const candidate = new Date(ms);
1722
+ if (formatDateInTimeZone(candidate, timeZone) === targetLocalDate) {
1723
+ keys.add(utcDateKey(candidate));
1724
+ }
1725
+ }
1726
+ return keys.size > 0 ? [...keys].sort() : utcDateKeysAround(date);
1727
+ }
1728
+ function parseFiniteDate(value) {
1729
+ if (typeof value !== "string" || value.trim().length === 0) return null;
1730
+ const parsed = new Date(value);
1731
+ return Number.isFinite(parsed.getTime()) ? parsed : null;
1732
+ }
1733
+ function filterHourlySummaryMarkdownForLocalDay(raw, utcDate, timeZone, targetLocalDate) {
1734
+ const hourHeaderPattern = /^## ([01]\d|2[0-3]):00[ \t]*$/gm;
1735
+ const matches = Array.from(raw.matchAll(hourHeaderPattern));
1736
+ if (matches.length === 0) return null;
1737
+ const firstSectionStart = matches[0]?.index ?? 0;
1738
+ const preamble = raw.slice(0, firstSectionStart).trim();
1739
+ const sections = [];
1740
+ for (let index = 0; index < matches.length; index += 1) {
1741
+ const match = matches[index];
1742
+ const hour = match[1];
1743
+ if (!hour) continue;
1744
+ const sectionTimestamp = parseFiniteDate(`${utcDate}T${hour}:00:00.000Z`);
1745
+ if (!sectionTimestamp || formatDateInTimeZone(sectionTimestamp, timeZone) !== targetLocalDate) {
1746
+ continue;
1747
+ }
1748
+ const sectionStart = match.index ?? 0;
1749
+ const sectionEnd = matches[index + 1]?.index ?? raw.length;
1750
+ const section = raw.slice(sectionStart, sectionEnd).trim();
1751
+ if (section.length > 0) sections.push(section);
1752
+ }
1753
+ if (sections.length === 0) return null;
1754
+ return [preamble, ...sections].filter((section) => section.length > 0).join("\n\n");
1755
+ }
1638
1756
  function qmdStartupCollectionCheckTimeoutMs() {
1639
1757
  const raw = process.env.REMNIC_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS ?? process.env.ENGRAM_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
1640
1758
  if (raw === void 0) return DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
@@ -2714,7 +2832,10 @@ var Orchestrator = class _Orchestrator {
2714
2832
  const result = this.config.modelSource === "gateway" && this._fastGatewayLlm ? await this._fastGatewayLlm.chatCompletion(messages, {
2715
2833
  maxTokens: targetTokens * 2,
2716
2834
  timeoutMs: this.config.localLlmFastTimeoutMs,
2717
- agentId: this.config.fastGatewayAgentId || this.config.gatewayAgentId || void 0
2835
+ // LCM is latency-sensitive. A configured fast persona is the
2836
+ // explicit fast-tier route; otherwise use taskModelChain so LCM
2837
+ // avoids falling to an expensive gateway default. Issue #1473.
2838
+ ...this.config.fastGatewayAgentId ? { agentId: this.config.fastGatewayAgentId } : gatewayTaskChainOptions(this.config)
2718
2839
  }) : await this.localLlm.chatCompletion(messages, {
2719
2840
  maxTokens: targetTokens * 2,
2720
2841
  operation: "lcm-summarize",
@@ -3251,7 +3372,7 @@ var Orchestrator = class _Orchestrator {
3251
3372
  if (signal.aborted) return;
3252
3373
  if (!this.wearablesAutoSyncHandle && this.config.wearables.enabled && this.config.wearables.autoSyncEnabled && Object.values(this.config.wearables.sources).some((source) => source.enabled)) {
3253
3374
  try {
3254
- const { startWearablesAutoSync } = await import("./auto-sync-RFADEHIQ.js");
3375
+ const { startWearablesAutoSync } = await import("./auto-sync-54QQHOG5.js");
3255
3376
  if (signal.aborted) return;
3256
3377
  this.wearablesAutoSyncHandle = startWearablesAutoSync(
3257
3378
  {
@@ -3380,8 +3501,10 @@ var Orchestrator = class _Orchestrator {
3380
3501
  return true;
3381
3502
  }
3382
3503
  /**
3383
- * Auto-register the engram-day-summary cron job in OpenClaw if it doesn't exist.
3504
+ * Auto-register the engram-day-summary cron job in OpenClaw.
3505
+ * Reconciles model and timezone on every startup so config changes propagate.
3384
3506
  * Fire-and-forget — never blocks init or crashes on failure.
3507
+ * Issues #1474, #1475.
3385
3508
  */
3386
3509
  async autoRegisterDaySummaryCron() {
3387
3510
  const home = resolveHomeDir();
@@ -3393,15 +3516,44 @@ var Orchestrator = class _Orchestrator {
3393
3516
  );
3394
3517
  return;
3395
3518
  }
3396
- const created = await ensureDaySummaryCron(jobsPath, {
3397
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
3519
+ const rawSummaryModel = this.config.summaryModel;
3520
+ const taskPrimary = this.config.taskModelChain?.primary;
3521
+ const isGateway = this.config.modelSource === "gateway";
3522
+ const model = isGateway ? rawSummaryModel || taskPrimary || void 0 : void 0;
3523
+ const fallbacks = [];
3524
+ if (model && taskPrimary && model === taskPrimary) {
3525
+ const seen = new Set(model ? [model] : []);
3526
+ const addUnique = (value) => {
3527
+ if (typeof value !== "string") return;
3528
+ const trimmed = value.trim();
3529
+ if (trimmed.length > 0 && !seen.has(trimmed)) {
3530
+ seen.add(trimmed);
3531
+ fallbacks.push(trimmed);
3532
+ }
3533
+ };
3534
+ for (const fb of this.config.taskModelChain?.fallbacks ?? []) addUnique(fb);
3535
+ const gwDefaults = this.config.gatewayConfig?.agents?.defaults?.model;
3536
+ addUnique(gwDefaults?.primary);
3537
+ if (Array.isArray(gwDefaults?.fallbacks)) {
3538
+ for (const fb of gwDefaults.fallbacks) addUnique(fb);
3539
+ }
3540
+ }
3541
+ const timezone = this.config.daySummaryTimezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
3542
+ const result = await ensureDaySummaryCron(jobsPath, {
3543
+ timezone,
3544
+ ...model ? { model } : {},
3545
+ ...fallbacks.length > 0 ? { fallbacks } : {}
3398
3546
  });
3399
- if (created.created) {
3547
+ if (result.created) {
3548
+ log.info(
3549
+ `day-summary cron auto-registered (${result.jobId}, 23:47 ${timezone}${model ? `, model: ${model}` : ""})`
3550
+ );
3551
+ } else if (result.updated) {
3400
3552
  log.info(
3401
- `day-summary cron auto-registered (${created.jobId}, 23:47 ${Intl.DateTimeFormat().resolvedOptions().timeZone})`
3553
+ `day-summary cron reconciled (${result.jobId}, timezone: ${timezone}${model ? `, model: ${model}` : ""})`
3402
3554
  );
3403
3555
  } else {
3404
- log.debug("day-summary cron already exists, skipping auto-register");
3556
+ log.debug("day-summary cron already up to date");
3405
3557
  }
3406
3558
  } catch (err) {
3407
3559
  log.debug(`day-summary cron auto-register error: ${err}`);
@@ -3720,13 +3872,13 @@ ${doc.content}` : doc.content,
3720
3872
  );
3721
3873
  return result;
3722
3874
  }
3723
- const { FallbackLlmClient: FallbackLlmClient2, gatewayTaskChainOptions } = await import("./fallback-llm.js");
3875
+ const { FallbackLlmClient: FallbackLlmClient2, gatewayTaskChainOptions: gatewayTaskChainOptions2 } = await import("./fallback-llm.js");
3724
3876
  const useGateway = this.config.modelSource === "gateway";
3725
3877
  const modelSetting = this.config.semanticConsolidationModel;
3726
3878
  if (modelSetting === "fast" && this.fastLlm && !useGateway) {
3727
3879
  log.info("[semantic-consolidation] using fast local LLM for synthesis");
3728
3880
  }
3729
- const gatewayChainOptions = !useGateway ? {} : modelSetting === "fast" ? this.config.fastGatewayAgentId ? { agentId: this.config.fastGatewayAgentId } : this.config.gatewayAgentId ? { agentId: this.config.gatewayAgentId } : {} : gatewayTaskChainOptions(this.config);
3881
+ const gatewayChainOptions = !useGateway ? {} : modelSetting === "fast" ? this.config.fastGatewayAgentId ? { agentId: this.config.fastGatewayAgentId } : this.config.gatewayAgentId ? { agentId: this.config.gatewayAgentId } : {} : gatewayTaskChainOptions2(this.config);
3730
3882
  const llm = new FallbackLlmClient2(
3731
3883
  this.config.gatewayConfig,
3732
3884
  fallbackLlmRuntimeContextFromConfig(this.config)
@@ -4072,8 +4224,8 @@ ${evidenceText}`
4072
4224
  * Auto-gather today's facts and hourly summaries from storage, then generate a day summary.
4073
4225
  * Returns null if no facts are found for today.
4074
4226
  */
4075
- async generateDaySummaryAuto(namespace) {
4076
- const gathered = await this.gatherTodayFacts(namespace);
4227
+ async generateDaySummaryAuto(namespace, options = {}) {
4228
+ const gathered = await this.gatherTodayFacts(namespace, options);
4077
4229
  if (!gathered || !gathered.trim()) {
4078
4230
  log.warn("generateDaySummaryAuto: no facts found for today, skipping");
4079
4231
  return null;
@@ -4084,15 +4236,14 @@ ${evidenceText}`
4084
4236
  * Read today's facts and hourly summaries from storage, returning them
4085
4237
  * as a formatted string suitable for generateDaySummary().
4086
4238
  */
4087
- async gatherTodayFacts(namespace) {
4239
+ async gatherTodayFacts(namespace, options = {}) {
4088
4240
  const ns = namespace && namespace.length > 0 ? namespace : this.config.defaultNamespace;
4089
4241
  const storage = await this.storageRouter.storageFor(ns);
4090
- const now = /* @__PURE__ */ new Date();
4091
- const utcToday = now.toISOString().slice(0, 10);
4092
- const yesterday = new Date(now.getTime() - 864e5).toISOString().slice(0, 10);
4093
- const datesToScan = [yesterday, utcToday].filter(
4094
- (v, i, a) => a.indexOf(v) === i
4095
- );
4242
+ const configuredTimeZone = normalizeIanaTimeZone(options.timeZone) ?? normalizeIanaTimeZone(this.config.daySummaryTimezone);
4243
+ const timeZone = configuredTimeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
4244
+ const now = options.now instanceof Date && Number.isFinite(options.now.getTime()) ? options.now : /* @__PURE__ */ new Date();
4245
+ const targetLocalDate = formatDateInTimeZone(now, timeZone);
4246
+ const datesToScan = utcDateKeysForLocalDay(now, timeZone);
4096
4247
  const factsBaseDir = path2.join(storage.dir, "facts");
4097
4248
  const MAX_CHARS = 1e5;
4098
4249
  const facts = [];
@@ -4115,13 +4266,18 @@ ${evidenceText}`
4115
4266
  if (colonIdx === -1) continue;
4116
4267
  fm[line.slice(0, colonIdx).trim()] = line.slice(colonIdx + 1).trim();
4117
4268
  }
4269
+ const created = fm.created || "unknown";
4270
+ const createdAt = parseFiniteDate(created);
4271
+ if (createdAt && formatDateInTimeZone(createdAt, timeZone) !== targetLocalDate) {
4272
+ continue;
4273
+ }
4118
4274
  facts.push({
4119
4275
  path: fullPath,
4120
4276
  frontmatter: {
4121
4277
  id: fm.id || path2.basename(entry.name, ".md"),
4122
4278
  category: fm.category || "fact",
4123
- created: fm.created || "unknown",
4124
- updated: fm.updated || fm.created || "unknown",
4279
+ created,
4280
+ updated: fm.updated || created,
4125
4281
  source: fm.source || "unknown",
4126
4282
  confidence: parseFloat(fm.confidence || "0.8"),
4127
4283
  confidenceTier: fm.confidenceTier || "implied",
@@ -4135,9 +4291,10 @@ ${evidenceText}`
4135
4291
  } catch {
4136
4292
  }
4137
4293
  }
4138
- facts.sort(
4139
- (a, b) => a.frontmatter.created < b.frontmatter.created ? -1 : 1
4140
- );
4294
+ facts.sort((a, b) => {
4295
+ if (a.frontmatter.created === b.frontmatter.created) return 0;
4296
+ return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
4297
+ });
4141
4298
  const hourlySummaries = [];
4142
4299
  const hourlyBaseDir = path2.join(storage.dir, "summaries", "hourly");
4143
4300
  try {
@@ -4148,8 +4305,14 @@ ${evidenceText}`
4148
4305
  const summaryFile = path2.join(hourlyBaseDir, sk.name, `${date}.md`);
4149
4306
  try {
4150
4307
  const raw = await readFile2(summaryFile, "utf-8");
4151
- if (raw.trim().length > 0) {
4152
- hourlySummaries.push(raw.trim());
4308
+ const filtered = filterHourlySummaryMarkdownForLocalDay(
4309
+ raw,
4310
+ date,
4311
+ timeZone,
4312
+ targetLocalDate
4313
+ );
4314
+ if (filtered) {
4315
+ hourlySummaries.push(filtered);
4153
4316
  }
4154
4317
  } catch {
4155
4318
  }
@@ -4174,7 +4337,7 @@ ${evidenceText}`
4174
4337
  }
4175
4338
  }
4176
4339
  log.info(
4177
- `gatherTodayFacts: collected ${facts.length} facts, ${hourlySummaries.length} hourly summaries (${formatted.length} chars)`
4340
+ `gatherTodayFacts: collected ${facts.length} facts, ${hourlySummaries.length} hourly summaries for ${targetLocalDate} (${timeZone}, ${formatted.length} chars)`
4178
4341
  );
4179
4342
  return formatted;
4180
4343
  }
@@ -5334,16 +5497,74 @@ ${r.snippet.trim()}
5334
5497
  return capped;
5335
5498
  }
5336
5499
  async expandResultsViaGraph(options) {
5500
+ const deadlineExpired = () => typeof options.deadlineAtMs === "number" && Date.now() >= options.deadlineAtMs;
5337
5501
  const byNamespace = /* @__PURE__ */ new Map();
5338
- for (const result of options.memoryResults) {
5339
- const ns = this.namespaceFromPath(result.path);
5340
- if (!options.recallNamespaces.includes(ns)) continue;
5341
- const existing = byNamespace.get(ns);
5502
+ const addResultForNamespace = (namespace, result) => {
5503
+ const existing = byNamespace.get(namespace);
5342
5504
  if (existing) {
5343
5505
  existing.push(result);
5344
5506
  } else {
5345
- byNamespace.set(ns, [result]);
5507
+ byNamespace.set(namespace, [result]);
5508
+ }
5509
+ };
5510
+ const resolvedAmbiguousSeeds = /* @__PURE__ */ new Map();
5511
+ const resolveAmbiguousSeedOwner = async (result, parts) => {
5512
+ const cached = resolvedAmbiguousSeeds.get(result.path);
5513
+ if (cached !== void 0) return cached;
5514
+ if (deadlineExpired()) {
5515
+ resolvedAmbiguousSeeds.set(result.path, null);
5516
+ return null;
5517
+ }
5518
+ let resolvedPath = result.path;
5519
+ let resolvedResult = result;
5520
+ if (parts) {
5521
+ const resolvedCold = await this.resolveColdQmdResultForRecall(
5522
+ result,
5523
+ this.storage,
5524
+ options.recallNamespaces
5525
+ );
5526
+ if (!resolvedCold || deadlineExpired()) {
5527
+ resolvedAmbiguousSeeds.set(result.path, null);
5528
+ return null;
5529
+ }
5530
+ resolvedPath = resolvedCold.result.path;
5531
+ resolvedResult = resolvedCold.result;
5532
+ }
5533
+ if (!path2.isAbsolute(resolvedPath)) {
5534
+ resolvedAmbiguousSeeds.set(result.path, null);
5535
+ return null;
5536
+ }
5537
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
5538
+ resolvedPath,
5539
+ this.storage,
5540
+ options.recallNamespaces
5541
+ );
5542
+ const ownerNamespace = ownerStorage?.namespace ?? null;
5543
+ const resolved = ownerNamespace && options.recallNamespaces.includes(ownerNamespace) ? { namespace: ownerNamespace, result: resolvedResult } : null;
5544
+ resolvedAmbiguousSeeds.set(result.path, resolved);
5545
+ return resolved;
5546
+ };
5547
+ const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
5548
+ for (const result of options.memoryResults) {
5549
+ if (deadlineExpired()) break;
5550
+ const parts = qmdCollectionPathParts(result.path);
5551
+ if (parts?.collection === coldCollection) {
5552
+ const resolved = await resolveAmbiguousSeedOwner(result, parts);
5553
+ if (resolved) {
5554
+ addResultForNamespace(resolved.namespace, resolved.result);
5555
+ }
5556
+ continue;
5557
+ }
5558
+ if (path2.isAbsolute(result.path)) {
5559
+ const resolved = await resolveAmbiguousSeedOwner(result, null);
5560
+ if (resolved) {
5561
+ addResultForNamespace(resolved.namespace, resolved.result);
5562
+ }
5563
+ continue;
5346
5564
  }
5565
+ const ns = this.namespaceFromPath(result.path);
5566
+ if (!options.recallNamespaces.includes(ns)) continue;
5567
+ addResultForNamespace(ns, result);
5347
5568
  }
5348
5569
  const perNamespaceSeedCap = Math.max(3, options.recallResultLimit);
5349
5570
  const perNamespaceExpandedCap = Math.max(8, options.recallResultLimit * 2);
@@ -5352,12 +5573,25 @@ ${r.snippet.trim()}
5352
5573
  const expandedPaths = [];
5353
5574
  const expandedResults = [];
5354
5575
  for (const [namespace, nsResults] of byNamespace.entries()) {
5576
+ if (deadlineExpired()) break;
5355
5577
  const storage = await this.storageRouter.storageFor(namespace);
5356
5578
  const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
5357
5579
  seedResults.push(...seedCandidates);
5358
- const seedRelativePaths = seedCandidates.map((result) => graphPathRelativeToStorage(storage.dir, result.path)).filter(
5580
+ const seedRelativePaths = typeof options.deadlineAtMs === "number" ? await this.graphSeedPathsWithinDeadline(
5581
+ storage,
5582
+ seedCandidates,
5583
+ options.deadlineAtMs,
5584
+ [namespace]
5585
+ ) : (await Promise.all(
5586
+ seedCandidates.map(
5587
+ (result) => this.graphSeedPathRelativeToStorage(storage, result, [
5588
+ namespace
5589
+ ])
5590
+ )
5591
+ )).filter(
5359
5592
  (value) => typeof value === "string" && value.length > 0
5360
5593
  );
5594
+ if (deadlineExpired()) break;
5361
5595
  if (seedRelativePaths.length === 0) continue;
5362
5596
  const seedRecallScore = seedCandidates.reduce(
5363
5597
  (max, item) => Math.max(max, item.score),
@@ -5370,13 +5604,19 @@ ${r.snippet.trim()}
5370
5604
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
5371
5605
  seedRelativePaths,
5372
5606
  this.config.maxGraphTraversalSteps,
5373
- options.includeLowConfidence === true ? { includeLowConfidence: true } : void 0
5607
+ {
5608
+ ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {},
5609
+ ...typeof options.deadlineAtMs === "number" ? { deadlineAtMs: options.deadlineAtMs } : {}
5610
+ }
5374
5611
  );
5375
5612
  if (expanded.length === 0) continue;
5613
+ if (deadlineExpired()) break;
5376
5614
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
5615
+ if (deadlineExpired()) break;
5377
5616
  if (seedSet.has(candidate.path)) continue;
5378
5617
  const memoryPath = path2.resolve(storage.dir, candidate.path);
5379
5618
  const memory = await storage.readMemoryByPath(memoryPath);
5619
+ if (deadlineExpired()) break;
5380
5620
  if (!memory) continue;
5381
5621
  if (isArtifactMemoryPath(memory.path)) continue;
5382
5622
  if (memory.frontmatter.status && memory.frontmatter.status !== "active")
@@ -7505,10 +7745,12 @@ ${formatted}`;
7505
7745
  return section;
7506
7746
  })()
7507
7747
  );
7508
- const recentBoxesPromise = this.isRecallSectionEnabled(
7509
- "memory-boxes",
7510
- this.config.memoryBoxesEnabled === true
7511
- ) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ? this.boxBuilderFor(profileStorage).readRecentBoxes(this.config.boxRecallDays).catch(() => []) : Promise.resolve([]);
7748
+ const recentBoxesPromise = observeEnrichmentPromise(
7749
+ this.isRecallSectionEnabled(
7750
+ "memory-boxes",
7751
+ this.config.memoryBoxesEnabled === true
7752
+ ) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ? this.boxBuilderFor(profileStorage).readRecentBoxes(this.config.boxRecallDays).catch(() => []) : Promise.resolve([])
7753
+ );
7512
7754
  this.profiler.startSpan("phase-1-parallel", profileTraceId);
7513
7755
  const phase1Start = Date.now();
7514
7756
  log.info(
@@ -7637,6 +7879,48 @@ ${formatted}`;
7637
7879
  }
7638
7880
  return finalizeEnrichmentOutcome(outcome);
7639
7881
  };
7882
+ const remainingEnrichmentAssemblyMs = () => enrichmentAssemblyDeadlineAtMs === null ? null : Math.max(0, enrichmentAssemblyDeadlineAtMs - Date.now());
7883
+ const awaitAssemblyStep = async (name, task, fallback) => {
7884
+ if (options.abortSignal?.aborted) {
7885
+ log.debug(
7886
+ `recall phase-1 assembly [${name}]: skipped after abort at +${Date.now() - phase1Start}ms`
7887
+ );
7888
+ return fallback;
7889
+ }
7890
+ const timeoutMs = remainingEnrichmentAssemblyMs();
7891
+ if (timeoutMs === 0) {
7892
+ log.debug(
7893
+ `recall phase-1 assembly [${name}]: skipped after shared ${enrichmentSectionDeadlineMs}ms budget expired at +${Date.now() - phase1Start}ms`
7894
+ );
7895
+ return fallback;
7896
+ }
7897
+ let timeoutHandle;
7898
+ try {
7899
+ const result = await (timeoutMs !== null ? Promise.race([
7900
+ task(),
7901
+ new Promise((resolve) => {
7902
+ timeoutHandle = setTimeout(
7903
+ () => resolve({ status: "timed_out" }),
7904
+ timeoutMs
7905
+ );
7906
+ })
7907
+ ]) : task());
7908
+ if (timeoutHandle) clearTimeout(timeoutHandle);
7909
+ if (typeof result === "object" && result !== null && "status" in result && result.status === "timed_out") {
7910
+ log.debug(
7911
+ `recall phase-1 assembly [${name}]: timed out within shared ${enrichmentSectionDeadlineMs}ms budget at +${Date.now() - phase1Start}ms`
7912
+ );
7913
+ return fallback;
7914
+ }
7915
+ return result;
7916
+ } catch (err) {
7917
+ if (timeoutHandle) clearTimeout(timeoutHandle);
7918
+ log.warn(
7919
+ `recall phase-1 assembly [${name}] failed open: ${err instanceof Error ? err.message : String(err)}`
7920
+ );
7921
+ return fallback;
7922
+ }
7923
+ };
7640
7924
  this.profiler.startSpan("assembly", profileTraceId);
7641
7925
  if (sharedCtx)
7642
7926
  this.appendRecallSection(sectionBuckets, "shared-context", sharedCtx);
@@ -7855,8 +8139,11 @@ ${lines.join("\n")}`
7855
8139
  );
7856
8140
  }
7857
8141
  {
7858
- const recentBoxes = await recentBoxesPromise;
7859
- if (recentBoxes.length > 0) {
8142
+ const recentBoxes = await awaitEnrichmentSection(
8143
+ "memory-boxes",
8144
+ recentBoxesPromise
8145
+ );
8146
+ if (recentBoxes && recentBoxes.length > 0) {
7860
8147
  const boxLines = recentBoxes.slice(0, 5).map((b) => {
7861
8148
  const sealedDate = b.sealedAt ? b.sealedAt.slice(0, 16).replace("T", " ") : "?";
7862
8149
  const traceNote = b.traceId ? ` [trace: ${b.traceId.slice(0, 12)}]` : "";
@@ -7986,6 +8273,7 @@ ${tmtNode.summary}`
7986
8273
  workProductsSection
7987
8274
  );
7988
8275
  }
8276
+ const qmdWasSettledBeforeAssemblyWait = qmdPromise.getSettledOutcome() !== void 0;
7989
8277
  const qmdResult = await awaitEnrichmentSection("qmd", qmdPromise);
7990
8278
  if (qmdResult) {
7991
8279
  const t0 = Date.now();
@@ -8032,48 +8320,69 @@ ${tmtNode.summary}`
8032
8320
  graphExpandedResultPaths.clear();
8033
8321
  } else {
8034
8322
  try {
8035
- const {
8036
- merged,
8037
- seedPaths,
8038
- expandedPaths,
8039
- seedResults = baselineMemoryResults
8040
- } = await this.expandResultsViaGraph({
8041
- memoryResults,
8042
- recallNamespaces,
8043
- recallResultLimit,
8044
- ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8045
- });
8046
- graphSnapshotStatus = "completed";
8047
- graphDecisionStatus = "completed";
8048
- graphDecisionReason = graphShadowEvalEnabled ? "graph shadow evaluation completed without altering injected context" : "graph expansion merged into recall ranking";
8049
- graphSnapshotReason = graphDecisionReason;
8050
- graphSnapshotSeedPaths = seedPaths;
8051
- graphSnapshotExpandedPaths = expandedPaths;
8052
- graphSnapshotSeedResults = this.buildGraphRecallRankedResults(
8053
- seedResults,
8054
- () => ["baseline"]
8055
- );
8056
- graphExpandedResultPaths.clear();
8057
- expandedPaths.forEach(
8058
- (entry) => graphExpandedResultPaths.add(entry.path)
8323
+ const graphExpansion = await awaitAssemblyStep(
8324
+ "graph-expansion",
8325
+ () => this.expandResultsViaGraph({
8326
+ memoryResults,
8327
+ recallNamespaces,
8328
+ recallResultLimit,
8329
+ deadlineAtMs: enrichmentAssemblyDeadlineAtMs,
8330
+ ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8331
+ }),
8332
+ null
8059
8333
  );
8060
- memoryResults = graphShadowEvalEnabled ? baselineMemoryResults : merged;
8061
- if (graphShadowEvalEnabled) {
8062
- const comparison = summarizeGraphShadowComparison(
8334
+ if (!graphExpansion) {
8335
+ graphSnapshotStatus = "aborted";
8336
+ graphDecisionStatus = "aborted";
8337
+ graphDecisionReason = options.abortSignal?.aborted ? "graph expansion skipped because recall assembly was aborted" : "graph expansion skipped because shared post-retrieval assembly budget expired";
8338
+ graphSnapshotReason = graphDecisionReason;
8339
+ graphSnapshotSeedPaths = baselineMemoryResults.slice(0, Math.max(1, recallResultLimit)).map((result) => result.path);
8340
+ graphSnapshotSeedResults = this.buildGraphRecallRankedResults(
8063
8341
  baselineMemoryResults,
8342
+ () => ["baseline"]
8343
+ );
8344
+ graphSnapshotExpandedPaths = [];
8345
+ graphExpandedResultPaths.clear();
8346
+ memoryResults = baselineMemoryResults;
8347
+ } else {
8348
+ const {
8064
8349
  merged,
8065
- recallResultLimit
8350
+ seedPaths,
8351
+ expandedPaths,
8352
+ seedResults = baselineMemoryResults
8353
+ } = graphExpansion;
8354
+ graphSnapshotStatus = "completed";
8355
+ graphDecisionStatus = "completed";
8356
+ graphDecisionReason = graphShadowEvalEnabled ? "graph shadow evaluation completed without altering injected context" : "graph expansion merged into recall ranking";
8357
+ graphSnapshotReason = graphDecisionReason;
8358
+ graphSnapshotSeedPaths = seedPaths;
8359
+ graphSnapshotExpandedPaths = expandedPaths;
8360
+ graphSnapshotSeedResults = this.buildGraphRecallRankedResults(
8361
+ seedResults,
8362
+ () => ["baseline"]
8066
8363
  );
8067
- graphSnapshotShadowComparison = comparison;
8068
- recordRecallSectionMetric({
8069
- section: "graphShadow",
8070
- priority: "enrichment",
8071
- durationMs: Date.now() - t0,
8072
- deadlineMs: enrichmentSectionDeadlineMs,
8073
- source: "fresh",
8074
- success: true,
8075
- timing: `on b=${comparison.baselineCount} g=${comparison.graphCount} ov=${comparison.overlapCount} (${comparison.overlapRatio.toFixed(2)}) avgDelta=${comparison.averageOverlapDelta.toFixed(3)}`
8076
- });
8364
+ graphExpandedResultPaths.clear();
8365
+ expandedPaths.forEach(
8366
+ (entry) => graphExpandedResultPaths.add(entry.path)
8367
+ );
8368
+ memoryResults = graphShadowEvalEnabled ? baselineMemoryResults : merged;
8369
+ if (graphShadowEvalEnabled) {
8370
+ const comparison = summarizeGraphShadowComparison(
8371
+ baselineMemoryResults,
8372
+ merged,
8373
+ recallResultLimit
8374
+ );
8375
+ graphSnapshotShadowComparison = comparison;
8376
+ recordRecallSectionMetric({
8377
+ section: "graphShadow",
8378
+ priority: "enrichment",
8379
+ durationMs: Date.now() - t0,
8380
+ deadlineMs: enrichmentSectionDeadlineMs,
8381
+ source: "fresh",
8382
+ success: true,
8383
+ timing: `on b=${comparison.baselineCount} g=${comparison.graphCount} ov=${comparison.overlapCount} (${comparison.overlapRatio.toFixed(2)}) avgDelta=${comparison.averageOverlapDelta.toFixed(3)}`
8384
+ });
8385
+ }
8077
8386
  }
8078
8387
  } catch (err) {
8079
8388
  graphSnapshotStatus = "aborted";
@@ -8092,12 +8401,31 @@ ${tmtNode.summary}`
8092
8401
  }
8093
8402
  }
8094
8403
  }
8095
- memoryResults = await this.boostSearchResults(
8404
+ const qmdBoostInput = await this.filterSearchResultsForRecall(
8096
8405
  memoryResults,
8097
- recallNamespaces,
8098
- retrievalQuery,
8099
8406
  void 0,
8100
- { asOfMs }
8407
+ {
8408
+ asOfMs,
8409
+ // If QMD had already settled before the ordered assembly reached it,
8410
+ // do not let unrelated slow enrichment turn those known results into
8411
+ // unchecked misses. QMD that only settles during its own wait remains
8412
+ // bounded by the shared post-retrieval assembly deadline.
8413
+ deadlineAtMs: qmdWasSettledBeforeAssemblyWait ? null : enrichmentAssemblyDeadlineAtMs,
8414
+ abortSignal: options.abortSignal,
8415
+ dropUnresolved: true,
8416
+ recallNamespaces
8417
+ }
8418
+ );
8419
+ memoryResults = await awaitAssemblyStep(
8420
+ "qmd-boost",
8421
+ () => this.boostSearchResults(
8422
+ qmdBoostInput.results,
8423
+ recallNamespaces,
8424
+ retrievalQuery,
8425
+ qmdBoostInput.memoryByPath,
8426
+ { asOfMs }
8427
+ ),
8428
+ qmdBoostInput.results
8101
8429
  );
8102
8430
  if (this.config.rerankEnabled && this.config.rerankProvider === "local") {
8103
8431
  const ranked = await rerankLocalOrNoop({
@@ -8224,39 +8552,45 @@ ${tmtNode.summary}`
8224
8552
  } else if (!confidenceGateRejected) {
8225
8553
  const queryAwarePrefilter = await queryAwarePrefilterPromise;
8226
8554
  if (queryAwarePrefilter.candidatePaths?.size !== 0) {
8227
- const embeddingResults = await this.searchEmbeddingFallback(
8228
- retrievalQuery,
8229
- embeddingFetchLimit
8230
- );
8231
- const prefilteredEmbeddingResults = applyQueryAwareCandidateFilter(
8232
- embeddingResults,
8233
- queryAwarePrefilter.candidatePaths
8234
- );
8235
- const scopedCandidates = filterRecallCandidates(
8236
- prefilteredEmbeddingResults,
8237
- {
8238
- namespacesEnabled: this.config.namespacesEnabled,
8239
- recallNamespaces,
8240
- resolveNamespace: (p) => this.namespaceFromPath(p),
8241
- limit: embeddingFetchLimit
8242
- }
8243
- );
8244
- const boostedScoped = await this.boostSearchResults(
8245
- scopedCandidates,
8246
- recallNamespaces,
8247
- retrievalQuery,
8248
- void 0,
8249
- { asOfMs }
8250
- );
8251
- xrayBranchPoolSize.hot_embedding = Math.max(
8252
- xrayBranchPoolSize.hot_embedding,
8253
- boostedScoped.length
8254
- );
8255
- const scoped = this.diversifyAndLimitRecallResults(
8256
- "memories",
8257
- boostedScoped,
8258
- recallResultLimit,
8259
- retrievalQuery
8555
+ const scoped = await awaitAssemblyStep(
8556
+ "embedding-fallback",
8557
+ async () => {
8558
+ const embeddingResults = await this.searchEmbeddingFallback(
8559
+ retrievalQuery,
8560
+ embeddingFetchLimit
8561
+ );
8562
+ const prefilteredEmbeddingResults = applyQueryAwareCandidateFilter(
8563
+ embeddingResults,
8564
+ queryAwarePrefilter.candidatePaths
8565
+ );
8566
+ const scopedCandidates = filterRecallCandidates(
8567
+ prefilteredEmbeddingResults,
8568
+ {
8569
+ namespacesEnabled: this.config.namespacesEnabled,
8570
+ recallNamespaces,
8571
+ resolveNamespace: (p) => this.namespaceFromPath(p),
8572
+ limit: embeddingFetchLimit
8573
+ }
8574
+ );
8575
+ const boostedScoped = await this.boostSearchResults(
8576
+ scopedCandidates,
8577
+ recallNamespaces,
8578
+ retrievalQuery,
8579
+ void 0,
8580
+ { asOfMs }
8581
+ );
8582
+ xrayBranchPoolSize.hot_embedding = Math.max(
8583
+ xrayBranchPoolSize.hot_embedding,
8584
+ boostedScoped.length
8585
+ );
8586
+ return this.diversifyAndLimitRecallResults(
8587
+ "memories",
8588
+ boostedScoped,
8589
+ recallResultLimit,
8590
+ retrievalQuery
8591
+ );
8592
+ },
8593
+ []
8260
8594
  );
8261
8595
  if (scoped.length > 0) {
8262
8596
  if (shouldPersistGraphSnapshot) {
@@ -8292,6 +8626,7 @@ ${tmtNode.summary}`
8292
8626
  queryAwarePrefilter,
8293
8627
  abortSignal: options.abortSignal,
8294
8628
  xrayPoolSizeSink: xrayColdPoolSink,
8629
+ deadlineAtMs: enrichmentAssemblyDeadlineAtMs,
8295
8630
  asOfMs,
8296
8631
  ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8297
8632
  });
@@ -8358,39 +8693,45 @@ ${tmtNode.summary}`
8358
8693
  } else if (recallResultLimit > 0 && !this.qmd.isAvailable()) {
8359
8694
  const queryAwarePrefilter = await queryAwarePrefilterPromise;
8360
8695
  if (queryAwarePrefilter.candidatePaths?.size !== 0) {
8361
- const embeddingResults = await this.searchEmbeddingFallback(
8362
- retrievalQuery,
8363
- embeddingFetchLimit
8364
- );
8365
- const prefilteredEmbeddingResults = applyQueryAwareCandidateFilter(
8366
- embeddingResults,
8367
- queryAwarePrefilter.candidatePaths
8368
- );
8369
- const scopedCandidates = filterRecallCandidates(
8370
- prefilteredEmbeddingResults,
8371
- {
8372
- namespacesEnabled: this.config.namespacesEnabled,
8373
- recallNamespaces,
8374
- resolveNamespace: (p) => this.namespaceFromPath(p),
8375
- limit: embeddingFetchLimit
8376
- }
8377
- );
8378
- const boostedScoped = await this.boostSearchResults(
8379
- scopedCandidates,
8380
- recallNamespaces,
8381
- retrievalQuery,
8382
- void 0,
8383
- { asOfMs }
8384
- );
8385
- xrayBranchPoolSize.hot_embedding = Math.max(
8386
- xrayBranchPoolSize.hot_embedding,
8387
- boostedScoped.length
8388
- );
8389
- const scoped = this.diversifyAndLimitRecallResults(
8390
- "memories",
8391
- boostedScoped,
8392
- recallResultLimit,
8393
- retrievalQuery
8696
+ const scoped = await awaitAssemblyStep(
8697
+ "embedding-fallback",
8698
+ async () => {
8699
+ const embeddingResults = await this.searchEmbeddingFallback(
8700
+ retrievalQuery,
8701
+ embeddingFetchLimit
8702
+ );
8703
+ const prefilteredEmbeddingResults = applyQueryAwareCandidateFilter(
8704
+ embeddingResults,
8705
+ queryAwarePrefilter.candidatePaths
8706
+ );
8707
+ const scopedCandidates = filterRecallCandidates(
8708
+ prefilteredEmbeddingResults,
8709
+ {
8710
+ namespacesEnabled: this.config.namespacesEnabled,
8711
+ recallNamespaces,
8712
+ resolveNamespace: (p) => this.namespaceFromPath(p),
8713
+ limit: embeddingFetchLimit
8714
+ }
8715
+ );
8716
+ const boostedScoped = await this.boostSearchResults(
8717
+ scopedCandidates,
8718
+ recallNamespaces,
8719
+ retrievalQuery,
8720
+ void 0,
8721
+ { asOfMs }
8722
+ );
8723
+ xrayBranchPoolSize.hot_embedding = Math.max(
8724
+ xrayBranchPoolSize.hot_embedding,
8725
+ boostedScoped.length
8726
+ );
8727
+ return this.diversifyAndLimitRecallResults(
8728
+ "memories",
8729
+ boostedScoped,
8730
+ recallResultLimit,
8731
+ retrievalQuery
8732
+ );
8733
+ },
8734
+ []
8394
8735
  );
8395
8736
  if (scoped.length > 0) {
8396
8737
  if (shouldPersistGraphSnapshot) {
@@ -8418,7 +8759,11 @@ ${tmtNode.summary}`
8418
8759
  xrayRecalledResults = scoped;
8419
8760
  impressionRecorded = true;
8420
8761
  } else {
8421
- const memories = await this.readAllMemoriesForNamespaces(recallNamespaces);
8762
+ const memories = await awaitAssemblyStep(
8763
+ "recent-memory-read",
8764
+ () => this.readAllMemoriesForNamespaces(recallNamespaces),
8765
+ []
8766
+ );
8422
8767
  if (memories.length > 0) {
8423
8768
  const supersessionOptions = {
8424
8769
  enabled: this.config.temporalSupersessionEnabled,
@@ -8449,6 +8794,7 @@ ${tmtNode.summary}`
8449
8794
  queryAwarePrefilter,
8450
8795
  abortSignal: options.abortSignal,
8451
8796
  xrayPoolSizeSink: xrayColdPoolSink,
8797
+ deadlineAtMs: enrichmentAssemblyDeadlineAtMs,
8452
8798
  asOfMs,
8453
8799
  ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8454
8800
  });
@@ -8473,36 +8819,42 @@ ${tmtNode.summary}`
8473
8819
  impressionRecorded = true;
8474
8820
  }
8475
8821
  } else {
8476
- const recentSorted = queryAwareScopedMemories.sort(
8477
- (a, b) => new Date(b.frontmatter.updated).getTime() - new Date(a.frontmatter.updated).getTime()
8478
- );
8479
- const preloadedMap = new Map(
8480
- queryAwareScopedMemories.filter((m) => m.path).map((m) => [m.path, m])
8481
- );
8482
- const recentAsResults = recentSorted.map(
8483
- (m, i) => ({
8484
- docid: m.frontmatter.id,
8485
- path: m.path,
8486
- snippet: m.content,
8487
- score: 1 - i / Math.max(recentSorted.length, 1)
8488
- })
8489
- );
8490
- const boostedRecent = (await this.boostSearchResults(
8491
- recentAsResults,
8492
- recallNamespaces,
8493
- retrievalQuery,
8494
- preloadedMap,
8495
- { asOfMs }
8496
- )).sort((a, b) => b.score - a.score);
8497
- xrayBranchPoolSize.recent_scan = Math.max(
8498
- xrayBranchPoolSize.recent_scan,
8499
- boostedRecent.length
8500
- );
8501
- const recent = this.diversifyAndLimitRecallResults(
8502
- "memories",
8503
- boostedRecent,
8504
- recallResultLimit,
8505
- retrievalQuery
8822
+ const recent = await awaitAssemblyStep(
8823
+ "recent-memory-scan",
8824
+ async () => {
8825
+ const recentSorted = queryAwareScopedMemories.sort(
8826
+ (a, b) => new Date(b.frontmatter.updated).getTime() - new Date(a.frontmatter.updated).getTime()
8827
+ );
8828
+ const preloadedMap = new Map(
8829
+ queryAwareScopedMemories.filter((m) => m.path).map((m) => [m.path, m])
8830
+ );
8831
+ const recentAsResults = recentSorted.map(
8832
+ (m, i) => ({
8833
+ docid: m.frontmatter.id,
8834
+ path: m.path,
8835
+ snippet: m.content,
8836
+ score: 1 - i / Math.max(recentSorted.length, 1)
8837
+ })
8838
+ );
8839
+ const boostedRecent = (await this.boostSearchResults(
8840
+ recentAsResults,
8841
+ recallNamespaces,
8842
+ retrievalQuery,
8843
+ preloadedMap,
8844
+ { asOfMs }
8845
+ )).sort((a, b) => b.score - a.score);
8846
+ xrayBranchPoolSize.recent_scan = Math.max(
8847
+ xrayBranchPoolSize.recent_scan,
8848
+ boostedRecent.length
8849
+ );
8850
+ return this.diversifyAndLimitRecallResults(
8851
+ "memories",
8852
+ boostedRecent,
8853
+ recallResultLimit,
8854
+ retrievalQuery
8855
+ );
8856
+ },
8857
+ []
8506
8858
  );
8507
8859
  if (recent.length > 0) {
8508
8860
  if (shouldPersistGraphSnapshot) {
@@ -8538,6 +8890,7 @@ ${tmtNode.summary}`
8538
8890
  queryAwarePrefilter,
8539
8891
  abortSignal: options.abortSignal,
8540
8892
  xrayPoolSizeSink: xrayColdPoolSink,
8893
+ deadlineAtMs: enrichmentAssemblyDeadlineAtMs,
8541
8894
  asOfMs,
8542
8895
  ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8543
8896
  });
@@ -8578,6 +8931,7 @@ ${tmtNode.summary}`
8578
8931
  queryAwarePrefilter,
8579
8932
  abortSignal: options.abortSignal,
8580
8933
  xrayPoolSizeSink: xrayColdPoolSink,
8934
+ deadlineAtMs: enrichmentAssemblyDeadlineAtMs,
8581
8935
  asOfMs,
8582
8936
  ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
8583
8937
  });
@@ -8872,6 +9226,7 @@ _Context: ${topQuestion.context}_`
8872
9226
  query: retrievalQuery,
8873
9227
  memoryIds: recalledMemoryIds,
8874
9228
  namespace: selfNamespace,
9229
+ recallNamespaces,
8875
9230
  traceId,
8876
9231
  plannerMode: recallMode,
8877
9232
  requestedMode,
@@ -12268,6 +12623,212 @@ ${lines.join("\n\n")}`;
12268
12623
  *
12269
12624
  * Callers must pass the full candidate pool (post-rerank, pre-slice).
12270
12625
  */
12626
+ qmdCollectionNamespaceFromPrefix(collectionPrefix) {
12627
+ const baseCollection = this.config.qmdCollection;
12628
+ if (collectionPrefix === baseCollection) return this.config.defaultNamespace;
12629
+ const namespaceSuffix = collectionPrefix.startsWith(`${baseCollection}--`) ? collectionPrefix.slice(baseCollection.length + 2) : "";
12630
+ if (!namespaceSuffix) return null;
12631
+ const decoded = namespaceIdentityFromToken(namespaceSuffix);
12632
+ if (decoded !== null) return decoded || this.config.defaultNamespace;
12633
+ if (namespaceSuffix.startsWith("ns--")) {
12634
+ const legacyNamespace = namespaceSuffix.slice("ns--".length).trim();
12635
+ return legacyNamespace || null;
12636
+ }
12637
+ return null;
12638
+ }
12639
+ async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
12640
+ const parts = qmdCollectionPathParts(resultPath);
12641
+ const storageDirFor = (storage) => typeof storage.dir === "string" && storage.dir ? storage.dir : null;
12642
+ const fallbackStorageDir = storageDirFor(fallbackStorage);
12643
+ const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
12644
+ if (parts && parts.collection === coldCollection) {
12645
+ const storages = [];
12646
+ const seenStorageDirs = /* @__PURE__ */ new Set();
12647
+ const addStorage = (storage) => {
12648
+ const storageDir = storageDirFor(storage);
12649
+ const storageKey = storageDir ? path2.resolve(storageDir) : `storage-without-dir-${storages.length}`;
12650
+ if (seenStorageDirs.has(storageKey)) return;
12651
+ seenStorageDirs.add(storageKey);
12652
+ storages.push(storage);
12653
+ };
12654
+ const fallbackNamespace = fallbackStorageDir !== null ? this.namespaceFromStorageDir(fallbackStorageDir) : this.config.defaultNamespace;
12655
+ if (recallNamespaces.length === 0 || !this.config.namespacesEnabled || recallNamespaces.includes(fallbackNamespace)) {
12656
+ addStorage(fallbackStorage);
12657
+ }
12658
+ if (recallNamespaces.length > 0) {
12659
+ for (const namespace of recallNamespaces) {
12660
+ try {
12661
+ addStorage(await this.storageRouter.storageFor(namespace));
12662
+ } catch (err) {
12663
+ log.debug("qmd cold result namespace storage lookup skipped", {
12664
+ path: resultPath,
12665
+ namespace,
12666
+ error: err.message
12667
+ });
12668
+ }
12669
+ }
12670
+ }
12671
+ for (const storage of storages) {
12672
+ const storageDir = storageDirFor(storage);
12673
+ if (!storageDir) {
12674
+ const memory = await storage.readMemoryByPath(resultPath);
12675
+ if (memory) return memory;
12676
+ continue;
12677
+ }
12678
+ try {
12679
+ const coldRoot = path2.join(storageDir, "cold");
12680
+ for (const candidate of qmdResultPathCandidates(
12681
+ coldRoot,
12682
+ parts.relativePath
12683
+ )) {
12684
+ const memory = await storage.readMemoryByPath(candidate);
12685
+ if (memory) return memory;
12686
+ }
12687
+ } catch (err) {
12688
+ if (err instanceof SecureStoreLockedError) throw err;
12689
+ log.debug("qmd cold result path lookup failed open", {
12690
+ path: resultPath,
12691
+ collection: coldCollection,
12692
+ error: err.message
12693
+ });
12694
+ }
12695
+ }
12696
+ return null;
12697
+ }
12698
+ const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
12699
+ if (parts && collectionNamespace) {
12700
+ try {
12701
+ const collectionStorage = await this.storageRouter.storageFor(collectionNamespace);
12702
+ for (const candidate of qmdResultPathCandidates(
12703
+ collectionStorage.dir,
12704
+ parts.relativePath
12705
+ )) {
12706
+ const memory = await collectionStorage.readMemoryByPath(candidate);
12707
+ if (memory) return memory;
12708
+ }
12709
+ return null;
12710
+ } catch (err) {
12711
+ if (err instanceof SecureStoreLockedError) throw err;
12712
+ log.debug("qmd result namespace path lookup failed open", {
12713
+ path: resultPath,
12714
+ namespace: collectionNamespace,
12715
+ error: err.message
12716
+ });
12717
+ return null;
12718
+ }
12719
+ }
12720
+ if (path2.isAbsolute(resultPath)) {
12721
+ if (!fallbackStorageDir) {
12722
+ return await fallbackStorage.readMemoryByPath(resultPath);
12723
+ }
12724
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
12725
+ resultPath,
12726
+ fallbackStorage,
12727
+ recallNamespaces
12728
+ );
12729
+ if (!ownerStorage) return null;
12730
+ for (const candidate of qmdResultPathCandidates(
12731
+ ownerStorage.dir,
12732
+ resultPath
12733
+ )) {
12734
+ const memory = await ownerStorage.storage.readMemoryByPath(candidate);
12735
+ if (memory) return memory;
12736
+ }
12737
+ return null;
12738
+ }
12739
+ if (!fallbackStorageDir) {
12740
+ return await fallbackStorage.readMemoryByPath(resultPath);
12741
+ }
12742
+ for (const candidate of qmdResultPathCandidates(
12743
+ fallbackStorageDir,
12744
+ resultPath
12745
+ )) {
12746
+ const memory = await fallbackStorage.readMemoryByPath(candidate);
12747
+ if (memory) return memory;
12748
+ }
12749
+ return null;
12750
+ }
12751
+ async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
12752
+ const memory = await this.readQmdResultMemory(
12753
+ result.path,
12754
+ fallbackStorage,
12755
+ recallNamespaces
12756
+ );
12757
+ if (!memory) return null;
12758
+ let ownerNamespace = null;
12759
+ if (path2.isAbsolute(memory.path)) {
12760
+ const ownerStorage = await this.storageForAbsoluteQmdResultPath(
12761
+ memory.path,
12762
+ fallbackStorage,
12763
+ recallNamespaces
12764
+ );
12765
+ ownerNamespace = ownerStorage?.namespace ?? null;
12766
+ if (!ownerNamespace && this.config.namespacesEnabled) return null;
12767
+ }
12768
+ ownerNamespace ??= this.namespaceFromPath(memory.path);
12769
+ if (recallNamespaces.length > 0 && !recallNamespaces.includes(ownerNamespace)) {
12770
+ return null;
12771
+ }
12772
+ return {
12773
+ namespace: ownerNamespace,
12774
+ result: {
12775
+ ...result,
12776
+ docid: result.docid || memory.frontmatter.id,
12777
+ path: memory.path,
12778
+ snippet: result.snippet || memory.content.slice(0, 400)
12779
+ }
12780
+ };
12781
+ }
12782
+ async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
12783
+ const resolvedPath = path2.resolve(resultPath);
12784
+ const memoryRoot = path2.resolve(this.config.memoryDir);
12785
+ const namespacesRoot = path2.join(memoryRoot, "namespaces");
12786
+ const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
12787
+ const matches = [];
12788
+ const seenDirs = /* @__PURE__ */ new Set();
12789
+ const maybeAddStorage = (storage, namespace) => {
12790
+ const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
12791
+ if (!storageDir) return;
12792
+ const candidateRoot = path2.resolve(storageDir);
12793
+ if (seenDirs.has(candidateRoot)) return;
12794
+ if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
12795
+ if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
12796
+ return;
12797
+ }
12798
+ seenDirs.add(candidateRoot);
12799
+ matches.push({ storage, dir: candidateRoot, namespace });
12800
+ };
12801
+ const fallbackNamespace = fallbackStorageDir !== null ? this.namespaceFromStorageDir(fallbackStorageDir) : this.config.defaultNamespace;
12802
+ maybeAddStorage(fallbackStorage, fallbackNamespace);
12803
+ const candidateNamespaces = /* @__PURE__ */ new Set();
12804
+ candidateNamespaces.add(this.config.defaultNamespace);
12805
+ candidateNamespaces.add(this.config.sharedNamespace);
12806
+ for (const ns of recallNamespaces) {
12807
+ candidateNamespaces.add(ns);
12808
+ }
12809
+ if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
12810
+ const relativeToNamespaces = path2.relative(namespacesRoot, resolvedPath);
12811
+ const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
12812
+ if (namespaceSegment) {
12813
+ candidateNamespaces.add(
12814
+ namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment
12815
+ );
12816
+ }
12817
+ }
12818
+ for (const policy of this.config.namespacePolicies ?? []) {
12819
+ candidateNamespaces.add(policy.name);
12820
+ }
12821
+ for (const ns of candidateNamespaces) {
12822
+ if (!ns) continue;
12823
+ try {
12824
+ maybeAddStorage(await this.storageRouter.storageFor(ns), ns);
12825
+ } catch {
12826
+ continue;
12827
+ }
12828
+ }
12829
+ matches.sort((a, b) => b.dir.length - a.dir.length);
12830
+ return matches[0] ?? null;
12831
+ }
12271
12832
  async applyMemoryWorthRerank(results, namespaces) {
12272
12833
  const counters = /* @__PURE__ */ new Map();
12273
12834
  const seenNamespaces = /* @__PURE__ */ new Set();
@@ -12312,7 +12873,7 @@ ${lines.join("\n\n")}`;
12312
12873
  if (reader) {
12313
12874
  for (const r of missing) {
12314
12875
  try {
12315
- const memory = await reader.readMemoryByPath(r.path);
12876
+ const memory = await this.readQmdResultMemory(r.path, reader, namespaces);
12316
12877
  if (!memory) continue;
12317
12878
  const fm = memory.frontmatter;
12318
12879
  if (fm.mw_success === void 0 && fm.mw_fail === void 0) continue;
@@ -12560,6 +13121,41 @@ ${lines.join("\n\n")}`;
12560
13121
  if (options.xrayPoolSizeSink) options.xrayPoolSizeSink.size = 0;
12561
13122
  return [];
12562
13123
  }
13124
+ const deadlineRemainingMs = () => typeof options.deadlineAtMs === "number" ? Math.max(0, options.deadlineAtMs - Date.now()) : null;
13125
+ const runColdStepWithinDeadline = async (label, fallback, task) => {
13126
+ throwIfRecallAborted(options.abortSignal);
13127
+ const remainingMs = deadlineRemainingMs();
13128
+ if (remainingMs === 0) {
13129
+ log.debug(`cold-tier recall ${label} skipped: shared assembly deadline expired`);
13130
+ return fallback;
13131
+ }
13132
+ if (remainingMs === null) return task();
13133
+ let timeoutHandle;
13134
+ let timedOut = false;
13135
+ const taskPromise = task().catch((err) => {
13136
+ if (timedOut) {
13137
+ log.debug(`cold-tier recall ${label} failed after deadline: ${err}`);
13138
+ return fallback;
13139
+ }
13140
+ throw err;
13141
+ });
13142
+ try {
13143
+ return await Promise.race([
13144
+ taskPromise,
13145
+ new Promise((resolve) => {
13146
+ timeoutHandle = setTimeout(() => {
13147
+ timedOut = true;
13148
+ log.debug(
13149
+ `cold-tier recall ${label} skipped: shared assembly deadline expired`
13150
+ );
13151
+ resolve(fallback);
13152
+ }, remainingMs);
13153
+ })
13154
+ ]);
13155
+ } finally {
13156
+ if (timeoutHandle) clearTimeout(timeoutHandle);
13157
+ }
13158
+ };
12563
13159
  const coldQmdEnabled = this.config.qmdColdTierEnabled === true;
12564
13160
  const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
12565
13161
  const coldMaxResults = this.config.qmdColdMaxResults ?? this.config.qmdMaxResults;
@@ -12575,19 +13171,23 @@ ${lines.join("\n\n")}`;
12575
13171
  false,
12576
13172
  0
12577
13173
  );
12578
- longTerm = await this.fetchQmdMemoryResultsWithArtifactTopUp(
12579
- options.prompt,
12580
- coldFetchLimit,
12581
- coldHybridLimit,
12582
- {
12583
- namespacesEnabled: this.config.namespacesEnabled,
12584
- recallNamespaces: options.recallNamespaces,
12585
- resolveNamespace: (p) => this.namespaceFromPath(p),
12586
- collection: coldCollection,
12587
- queryAwarePrefilter: options.queryAwarePrefilter,
12588
- searchOptions: this.buildConfiguredQmdSearchOptions(options.prompt),
12589
- abortSignal: options.abortSignal
12590
- }
13174
+ longTerm = await runColdStepWithinDeadline(
13175
+ "qmd lookup",
13176
+ [],
13177
+ () => this.fetchQmdMemoryResultsWithArtifactTopUp(
13178
+ options.prompt,
13179
+ coldFetchLimit,
13180
+ coldHybridLimit,
13181
+ {
13182
+ namespacesEnabled: this.config.namespacesEnabled,
13183
+ recallNamespaces: options.recallNamespaces,
13184
+ resolveNamespace: (p) => this.namespaceFromPath(p),
13185
+ collection: coldCollection,
13186
+ queryAwarePrefilter: options.queryAwarePrefilter,
13187
+ searchOptions: this.buildConfiguredQmdSearchOptions(options.prompt),
13188
+ abortSignal: options.abortSignal
13189
+ }
13190
+ )
12591
13191
  );
12592
13192
  if (longTerm.length > 0) {
12593
13193
  log.debug(
@@ -12597,12 +13197,16 @@ ${lines.join("\n\n")}`;
12597
13197
  }
12598
13198
  }
12599
13199
  if (longTerm.length === 0) {
12600
- longTerm = await this.searchLongTermArchiveFallback(
12601
- options.prompt,
12602
- options.recallNamespaces,
12603
- options.recallResultLimit,
12604
- options.queryAwarePrefilter,
12605
- options.abortSignal
13200
+ longTerm = await runColdStepWithinDeadline(
13201
+ "archive scan",
13202
+ [],
13203
+ () => this.searchLongTermArchiveFallback(
13204
+ options.prompt,
13205
+ options.recallNamespaces,
13206
+ options.recallResultLimit,
13207
+ options.queryAwarePrefilter,
13208
+ options.abortSignal
13209
+ )
12606
13210
  );
12607
13211
  if (longTerm.length > 0) {
12608
13212
  log.debug("cold-tier recall source=archive-scan");
@@ -12611,9 +13215,51 @@ ${lines.join("\n\n")}`;
12611
13215
  if (longTerm.length === 0) return [];
12612
13216
  let results = longTerm;
12613
13217
  if (this.config.namespacesEnabled) {
12614
- results = results.filter(
12615
- (r) => options.recallNamespaces.includes(this.namespaceFromPath(r.path))
12616
- );
13218
+ const recallRoots = [];
13219
+ const seenRecallRoots = /* @__PURE__ */ new Set();
13220
+ for (const namespace of options.recallNamespaces) {
13221
+ try {
13222
+ const storage = await this.storageRouter.storageFor(namespace);
13223
+ const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
13224
+ if (!storageDir) continue;
13225
+ const recallRoot = path2.resolve(storageDir);
13226
+ if (seenRecallRoots.has(recallRoot)) continue;
13227
+ seenRecallRoots.add(recallRoot);
13228
+ recallRoots.push(recallRoot);
13229
+ } catch (err) {
13230
+ log.debug("cold-tier recall namespace root lookup skipped", {
13231
+ namespace,
13232
+ error: err.message
13233
+ });
13234
+ }
13235
+ }
13236
+ const scopedResults = [];
13237
+ for (const result of results) {
13238
+ if (options.abortSignal?.aborted || deadlineRemainingMs() === 0) break;
13239
+ const parts = qmdCollectionPathParts(result.path);
13240
+ if (parts?.collection === coldCollection) {
13241
+ const resolvedCold = await this.resolveColdQmdResultForRecall(
13242
+ result,
13243
+ this.storage,
13244
+ options.recallNamespaces
13245
+ );
13246
+ if (resolvedCold) scopedResults.push(resolvedCold.result);
13247
+ continue;
13248
+ }
13249
+ if (path2.isAbsolute(result.path)) {
13250
+ const resolvedPath = path2.resolve(result.path);
13251
+ if (recallRoots.some(
13252
+ (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
13253
+ )) {
13254
+ scopedResults.push(result);
13255
+ }
13256
+ continue;
13257
+ }
13258
+ if (options.recallNamespaces.includes(this.namespaceFromPath(result.path))) {
13259
+ scopedResults.push(result);
13260
+ }
13261
+ }
13262
+ results = scopedResults;
12617
13263
  }
12618
13264
  results = results.filter((r) => !isArtifactMemoryPath(r.path));
12619
13265
  if (results.length === 0) return [];
@@ -12624,17 +13270,64 @@ ${lines.join("\n\n")}`;
12624
13270
  memoryResults: results,
12625
13271
  recallNamespaces: options.recallNamespaces,
12626
13272
  recallResultLimit: options.recallResultLimit,
13273
+ deadlineAtMs: options.deadlineAtMs,
12627
13274
  ...options.includeLowConfidence === true ? { includeLowConfidence: true } : {}
12628
13275
  });
12629
13276
  results = merged;
12630
13277
  }
12631
- results = await this.boostSearchResults(
13278
+ const boostInput = await this.filterSearchResultsForRecall(
12632
13279
  results,
12633
- options.recallNamespaces,
12634
- options.prompt,
12635
13280
  void 0,
12636
- { allowLifecycleFiltered: true, asOfMs: options.asOfMs }
13281
+ {
13282
+ allowLifecycleFiltered: true,
13283
+ asOfMs: options.asOfMs,
13284
+ deadlineAtMs: options.deadlineAtMs,
13285
+ abortSignal: options.abortSignal,
13286
+ dropUnresolved: true,
13287
+ recallNamespaces: options.recallNamespaces
13288
+ }
12637
13289
  );
13290
+ results = boostInput.results;
13291
+ const boostTimeoutMs = typeof options.deadlineAtMs === "number" ? Math.max(0, options.deadlineAtMs - Date.now()) : null;
13292
+ if (boostTimeoutMs !== 0) {
13293
+ let timeoutHandle;
13294
+ try {
13295
+ const boosted = await (boostTimeoutMs !== null ? Promise.race([
13296
+ this.boostSearchResults(
13297
+ boostInput.results,
13298
+ options.recallNamespaces,
13299
+ options.prompt,
13300
+ boostInput.memoryByPath,
13301
+ { allowLifecycleFiltered: true, asOfMs: options.asOfMs }
13302
+ ),
13303
+ new Promise((resolve) => {
13304
+ timeoutHandle = setTimeout(
13305
+ () => resolve({ status: "timed_out" }),
13306
+ boostTimeoutMs
13307
+ );
13308
+ })
13309
+ ]) : this.boostSearchResults(
13310
+ boostInput.results,
13311
+ options.recallNamespaces,
13312
+ options.prompt,
13313
+ boostInput.memoryByPath,
13314
+ { allowLifecycleFiltered: true, asOfMs: options.asOfMs }
13315
+ ));
13316
+ if (typeof boosted === "object" && boosted !== null && "status" in boosted && boosted.status === "timed_out") {
13317
+ log.debug("cold-tier recall boost skipped: shared assembly deadline expired");
13318
+ } else if (Array.isArray(boosted)) {
13319
+ results = boosted;
13320
+ } else {
13321
+ results = boostInput.results;
13322
+ }
13323
+ } catch (err) {
13324
+ log.debug(`cold-tier recall boost failed open: ${err}`);
13325
+ } finally {
13326
+ if (timeoutHandle) clearTimeout(timeoutHandle);
13327
+ }
13328
+ } else {
13329
+ log.debug("cold-tier recall boost skipped: shared assembly deadline already expired");
13330
+ }
12638
13331
  if (this.config.rerankEnabled && this.config.rerankProvider === "local") {
12639
13332
  const ranked = await rerankLocalOrNoop({
12640
13333
  query: options.prompt,
@@ -12755,64 +13448,101 @@ ${lines.join("\n\n")}`;
12755
13448
  this.accessTrackingBuffer.clear();
12756
13449
  log.debug(`flushed ${entries.length} access tracking entries`);
12757
13450
  }
12758
- /**
12759
- * Apply recency, access count, and importance boosting to QMD search results.
12760
- * Returns re-ranked results.
12761
- */
12762
- async boostSearchResults(results, _recallNamespaces, prompt, preloadedMemoryMap, options) {
12763
- if (results.length === 0) return results;
12764
- const now = Date.now();
13451
+ async loadSearchResultMemoryMap(results, preloadedMemoryMap, options) {
12765
13452
  const memoryByPath = preloadedMemoryMap ? new Map(preloadedMemoryMap) : /* @__PURE__ */ new Map();
12766
- const resultPaths = new Set(
12767
- results.map((r) => r.path).filter(Boolean)
12768
- );
12769
- let temporalFromDate = null;
12770
- let promptTags = [];
12771
- if (this.config.queryAwareIndexingEnabled && prompt) {
12772
- if (isTemporalQuery(prompt)) {
12773
- temporalFromDate = recencyWindowFromPrompt(prompt, now);
13453
+ const checkedPaths = /* @__PURE__ */ new Set();
13454
+ const unreadablePaths = /* @__PURE__ */ new Set();
13455
+ const markChecked = (result) => {
13456
+ if (result.path) checkedPaths.add(result.path);
13457
+ };
13458
+ const markUnreadable = (result, err) => {
13459
+ if (!result.path) return;
13460
+ checkedPaths.add(result.path);
13461
+ unreadablePaths.add(result.path);
13462
+ log.warn("recall safety filter dropped unreadable secure-store candidate", {
13463
+ path: result.path,
13464
+ error: err.message
13465
+ });
13466
+ };
13467
+ const deadlineExpired = () => typeof options?.deadlineAtMs === "number" && Date.now() >= options.deadlineAtMs;
13468
+ if (options?.deadlineAtMs == null) {
13469
+ const batchSize = options?.abortSignal ? 16 : results.length;
13470
+ for (let offset = 0; offset < results.length; offset += batchSize) {
13471
+ if (options?.abortSignal?.aborted) {
13472
+ return {
13473
+ memoryByPath,
13474
+ checkedPaths,
13475
+ unreadablePaths,
13476
+ completed: false
13477
+ };
13478
+ }
13479
+ await Promise.all(
13480
+ results.slice(offset, offset + batchSize).map(async (r) => {
13481
+ if (!r.path) return;
13482
+ if (memoryByPath.has(r.path)) {
13483
+ markChecked(r);
13484
+ return;
13485
+ }
13486
+ try {
13487
+ const mem = await this.readQmdResultMemory(
13488
+ r.path,
13489
+ this.storage,
13490
+ options?.recallNamespaces
13491
+ );
13492
+ markChecked(r);
13493
+ if (mem) memoryByPath.set(r.path, mem);
13494
+ } catch (err) {
13495
+ if (err instanceof SecureStoreLockedError) {
13496
+ markUnreadable(r, err);
13497
+ return;
13498
+ }
13499
+ throw err;
13500
+ }
13501
+ })
13502
+ );
12774
13503
  }
12775
- promptTags = extractTagsFromPrompt(prompt);
13504
+ return { memoryByPath, checkedPaths, unreadablePaths, completed: true };
12776
13505
  }
12777
- const [, rawTemporal, rawTags] = await Promise.all([
12778
- Promise.all(
12779
- results.map(async (r) => {
12780
- if (!r.path || memoryByPath.has(r.path)) return;
12781
- const mem = await this.storage.readMemoryByPath(r.path);
12782
- if (mem) memoryByPath.set(r.path, mem);
12783
- })
12784
- ),
12785
- temporalFromDate !== null ? queryByDateRangeAsync(this.config.memoryDir, temporalFromDate) : Promise.resolve(null),
12786
- promptTags.length > 0 ? queryByTagsAsync(this.config.memoryDir, promptTags) : Promise.resolve(null)
12787
- ]);
12788
- const queryIntent = this.config.intentRoutingEnabled && prompt ? inferIntentFromText(prompt) : null;
12789
- let temporalCandidates = null;
12790
- let tagCandidates = null;
12791
- if (this.config.queryAwareIndexingEnabled && prompt) {
12792
- const maxCandidates = this.config.queryAwareIndexingMaxCandidates;
12793
- const capSet = (s) => {
12794
- if (!s) return null;
12795
- const scoped = new Set(Array.from(s).filter((p) => resultPaths.has(p)));
12796
- if (maxCandidates === 0 || scoped.size <= maxCandidates)
12797
- return scoped;
12798
- return new Set(Array.from(scoped).slice(0, maxCandidates));
12799
- };
12800
- if (temporalFromDate !== null) {
12801
- temporalCandidates = capSet(rawTemporal);
13506
+ for (const result of results) {
13507
+ if (!result.path) continue;
13508
+ if (memoryByPath.has(result.path)) {
13509
+ markChecked(result);
13510
+ continue;
12802
13511
  }
12803
- if (promptTags.length > 0) {
12804
- tagCandidates = capSet(rawTags);
13512
+ if (options?.abortSignal?.aborted || deadlineExpired()) {
13513
+ return { memoryByPath, checkedPaths, unreadablePaths, completed: false };
13514
+ }
13515
+ try {
13516
+ const mem = await this.readQmdResultMemory(
13517
+ result.path,
13518
+ this.storage,
13519
+ options?.recallNamespaces
13520
+ );
13521
+ markChecked(result);
13522
+ if (mem) memoryByPath.set(result.path, mem);
13523
+ } catch (err) {
13524
+ if (err instanceof SecureStoreLockedError) {
13525
+ markUnreadable(result, err);
13526
+ continue;
13527
+ }
13528
+ throw err;
12805
13529
  }
12806
13530
  }
13531
+ return { memoryByPath, checkedPaths, unreadablePaths, completed: true };
13532
+ }
13533
+ filterSearchResultsByRecallSafety(results, memoryByPath, options) {
12807
13534
  let lifecycleFilteredCount = 0;
12808
13535
  let temporalSupersededFilteredCount = 0;
12809
13536
  let dedicatedSurfaceFilteredCount = 0;
12810
13537
  let forgottenFilteredCount = 0;
12811
- const boosted = [];
12812
- const recencyWeight = this.effectiveRecencyWeight();
13538
+ let blockedPathFilteredCount = 0;
13539
+ const filtered = [];
12813
13540
  for (const r of results) {
13541
+ if (r.path && options?.blockedPaths?.has(r.path)) {
13542
+ blockedPathFilteredCount += 1;
13543
+ continue;
13544
+ }
12814
13545
  const memory = memoryByPath.get(r.path);
12815
- let score = r.score;
12816
13546
  if (memory) {
12817
13547
  if (memory.frontmatter.status === "forgotten") {
12818
13548
  forgottenFilteredCount += 1;
@@ -12854,6 +13584,126 @@ ${lines.join("\n\n")}`;
12854
13584
  dedicatedSurfaceFilteredCount += 1;
12855
13585
  continue;
12856
13586
  }
13587
+ }
13588
+ filtered.push(r);
13589
+ }
13590
+ if (lifecycleFilteredCount > 0) {
13591
+ log.debug(
13592
+ `lifecycle retrieval filter removed ${lifecycleFilteredCount} stale/archived candidates`
13593
+ );
13594
+ }
13595
+ if (temporalSupersededFilteredCount > 0) {
13596
+ log.debug(
13597
+ `temporal supersession filter removed ${temporalSupersededFilteredCount} superseded candidates`
13598
+ );
13599
+ }
13600
+ if (dedicatedSurfaceFilteredCount > 0) {
13601
+ log.debug(
13602
+ `dedicated surface filter removed ${dedicatedSurfaceFilteredCount} dream/procedural candidates from generic recall`
13603
+ );
13604
+ }
13605
+ if (forgottenFilteredCount > 0) {
13606
+ log.debug(
13607
+ `forgotten status filter removed ${forgottenFilteredCount} candidates from recall`
13608
+ );
13609
+ }
13610
+ if (blockedPathFilteredCount > 0) {
13611
+ log.debug(
13612
+ `unreadable-path filter removed ${blockedPathFilteredCount} candidates from recall`
13613
+ );
13614
+ }
13615
+ return filtered;
13616
+ }
13617
+ async filterSearchResultsForRecall(results, preloadedMemoryMap, options) {
13618
+ if (results.length === 0) {
13619
+ return {
13620
+ results,
13621
+ memoryByPath: preloadedMemoryMap ? new Map(preloadedMemoryMap) : /* @__PURE__ */ new Map()
13622
+ };
13623
+ }
13624
+ const loaded = await this.loadSearchResultMemoryMap(
13625
+ results,
13626
+ preloadedMemoryMap,
13627
+ options
13628
+ );
13629
+ const candidateResults = loaded.completed ? results : results.filter((result) => !result.path || loaded.checkedPaths.has(result.path));
13630
+ if (!loaded.completed) {
13631
+ log.debug(
13632
+ `recall safety filter stopped before validating all candidates (${candidateResults.length}/${results.length} eligible)`
13633
+ );
13634
+ }
13635
+ const blockedPaths = new Set(loaded.unreadablePaths);
13636
+ if (options?.dropUnresolved === true) {
13637
+ for (const resultPath of loaded.checkedPaths) {
13638
+ if (!loaded.memoryByPath.has(resultPath)) {
13639
+ blockedPaths.add(resultPath);
13640
+ }
13641
+ }
13642
+ }
13643
+ return {
13644
+ results: this.filterSearchResultsByRecallSafety(
13645
+ candidateResults,
13646
+ loaded.memoryByPath,
13647
+ { ...options, blockedPaths }
13648
+ ),
13649
+ memoryByPath: loaded.memoryByPath
13650
+ };
13651
+ }
13652
+ /**
13653
+ * Apply recency, access count, and importance boosting to QMD search results.
13654
+ * Returns re-ranked results.
13655
+ */
13656
+ async boostSearchResults(results, _recallNamespaces, prompt, preloadedMemoryMap, options) {
13657
+ if (results.length === 0) return results;
13658
+ const safety = await this.filterSearchResultsForRecall(
13659
+ results,
13660
+ preloadedMemoryMap,
13661
+ { ...options, recallNamespaces: _recallNamespaces }
13662
+ );
13663
+ const safeResults = safety.results;
13664
+ const memoryByPath = safety.memoryByPath;
13665
+ if (safeResults.length === 0) return safeResults;
13666
+ const now = Date.now();
13667
+ const resultPaths = new Set(
13668
+ safeResults.map((r) => r.path).filter(Boolean)
13669
+ );
13670
+ let temporalFromDate = null;
13671
+ let promptTags = [];
13672
+ if (this.config.queryAwareIndexingEnabled && prompt) {
13673
+ if (isTemporalQuery(prompt)) {
13674
+ temporalFromDate = recencyWindowFromPrompt(prompt, now);
13675
+ }
13676
+ promptTags = extractTagsFromPrompt(prompt);
13677
+ }
13678
+ const [rawTemporal, rawTags] = await Promise.all([
13679
+ temporalFromDate !== null ? queryByDateRangeAsync(this.config.memoryDir, temporalFromDate) : Promise.resolve(null),
13680
+ promptTags.length > 0 ? queryByTagsAsync(this.config.memoryDir, promptTags) : Promise.resolve(null)
13681
+ ]);
13682
+ const queryIntent = this.config.intentRoutingEnabled && prompt ? inferIntentFromText(prompt) : null;
13683
+ let temporalCandidates = null;
13684
+ let tagCandidates = null;
13685
+ if (this.config.queryAwareIndexingEnabled && prompt) {
13686
+ const maxCandidates = this.config.queryAwareIndexingMaxCandidates;
13687
+ const capSet = (s) => {
13688
+ if (!s) return null;
13689
+ const scoped = new Set(Array.from(s).filter((p) => resultPaths.has(p)));
13690
+ if (maxCandidates === 0 || scoped.size <= maxCandidates)
13691
+ return scoped;
13692
+ return new Set(Array.from(scoped).slice(0, maxCandidates));
13693
+ };
13694
+ if (temporalFromDate !== null) {
13695
+ temporalCandidates = capSet(rawTemporal);
13696
+ }
13697
+ if (promptTags.length > 0) {
13698
+ tagCandidates = capSet(rawTags);
13699
+ }
13700
+ }
13701
+ const boosted = [];
13702
+ const recencyWeight = this.effectiveRecencyWeight();
13703
+ for (const r of safeResults) {
13704
+ const memory = memoryByPath.get(r.path);
13705
+ let score = r.score;
13706
+ if (memory) {
12857
13707
  if (recencyWeight > 0) {
12858
13708
  const createdAt = new Date(memory.frontmatter.created).getTime();
12859
13709
  const ageMs = now - createdAt;
@@ -12964,26 +13814,6 @@ ${lines.join("\n\n")}`;
12964
13814
  }
12965
13815
  boosted.push({ ...r, score });
12966
13816
  }
12967
- if (lifecycleFilteredCount > 0) {
12968
- log.debug(
12969
- `lifecycle retrieval filter removed ${lifecycleFilteredCount} stale/archived candidates`
12970
- );
12971
- }
12972
- if (temporalSupersededFilteredCount > 0) {
12973
- log.debug(
12974
- `temporal supersession filter removed ${temporalSupersededFilteredCount} superseded candidates`
12975
- );
12976
- }
12977
- if (dedicatedSurfaceFilteredCount > 0) {
12978
- log.debug(
12979
- `dedicated surface filter removed ${dedicatedSurfaceFilteredCount} dream/procedural candidates from generic recall`
12980
- );
12981
- }
12982
- if (forgottenFilteredCount > 0) {
12983
- log.debug(
12984
- `forgotten status filter removed ${forgottenFilteredCount} candidates from recall`
12985
- );
12986
- }
12987
13817
  return boosted.sort((a, b) => b.score - a.score);
12988
13818
  }
12989
13819
  /**
@@ -13121,8 +13951,37 @@ ${lines.join("\n\n")}`;
13121
13951
  reason: link.reason || void 0
13122
13952
  }));
13123
13953
  }
13954
+ async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
13955
+ const parts = qmdCollectionPathParts(result.path);
13956
+ if (parts) {
13957
+ const memory = await this.readQmdResultMemory(
13958
+ result.path,
13959
+ storage,
13960
+ recallNamespaces
13961
+ );
13962
+ return memory ? graphPathRelativeToStorage(storage.dir, memory.path) : null;
13963
+ }
13964
+ return graphPathRelativeToStorage(storage.dir, result.path);
13965
+ }
13966
+ async graphSeedPathsWithinDeadline(storage, results, deadlineAtMs, recallNamespaces = []) {
13967
+ const resolved = [];
13968
+ for (const result of results) {
13969
+ if (Date.now() >= deadlineAtMs) break;
13970
+ const seedPath = await this.graphSeedPathRelativeToStorage(
13971
+ storage,
13972
+ result,
13973
+ recallNamespaces
13974
+ );
13975
+ if (Date.now() >= deadlineAtMs) break;
13976
+ if (seedPath) resolved.push(seedPath);
13977
+ }
13978
+ return resolved;
13979
+ }
13124
13980
  namespaceFromPath(p) {
13125
13981
  if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
13982
+ const parts = qmdCollectionPathParts(p);
13983
+ const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
13984
+ if (collectionNamespace) return collectionNamespace;
13126
13985
  const m = p.match(/[\\/]+namespaces[\\/]+([^\\/]+)(?:[\\/]|$)/);
13127
13986
  if (!m?.[1]) return this.config.defaultNamespace;
13128
13987
  return namespaceIdentityFromToken(m[1]) ?? m[1];
@@ -13206,4 +14065,4 @@ export {
13206
14065
  resolvePersistedMemoryRelativePath,
13207
14066
  Orchestrator
13208
14067
  };
13209
- //# sourceMappingURL=chunk-TFICNXXU.js.map
14068
+ //# sourceMappingURL=chunk-2BHNQRE5.js.map