@remnic/core 9.15.3 → 9.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/dist/access-admin-ops-surface.d.ts +8 -8
  2. package/dist/access-admin-ops-surface.js +7 -7
  3. package/dist/access-boundary.d.ts +8 -8
  4. package/dist/access-boundary.js +7 -7
  5. package/dist/access-cli.js +31 -30
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-http.d.ts +8 -8
  8. package/dist/access-http.js +11 -11
  9. package/dist/access-identity-continuity-surface.d.ts +6 -6
  10. package/dist/access-identity-continuity-surface.js +7 -7
  11. package/dist/access-lcm-surface.d.ts +8 -8
  12. package/dist/access-lcm-surface.js +7 -7
  13. package/dist/access-mcp.d.ts +8 -8
  14. package/dist/access-mcp.js +10 -10
  15. package/dist/access-memory-search-fanout.d.ts +2 -2
  16. package/dist/{access-namespace-preflight-B9e5GnyZ.d.ts → access-namespace-preflight-DwhEFYy3.d.ts} +1 -1
  17. package/dist/access-namespace-preflight.d.ts +3 -3
  18. package/dist/access-namespace-preflight.js +7 -7
  19. package/dist/access-observe-write-surface.d.ts +8 -8
  20. package/dist/access-observe-write-surface.js +7 -7
  21. package/dist/access-operations-batch.js +8 -8
  22. package/dist/access-operations.d.ts +8 -8
  23. package/dist/access-operations.js +9 -9
  24. package/dist/access-recall-concurrency.d.ts +8 -8
  25. package/dist/access-recall-concurrency.js +7 -7
  26. package/dist/access-recall-response.d.ts +8 -8
  27. package/dist/access-recall-response.js +7 -7
  28. package/dist/access-recall-surface.d.ts +8 -8
  29. package/dist/access-recall-surface.js +7 -7
  30. package/dist/{access-service-DgmJd_A-.d.ts → access-service-CSq1Wp2Z.d.ts} +6 -6
  31. package/dist/access-service.d.ts +8 -8
  32. package/dist/access-service.js +7 -7
  33. package/dist/access-surface-catalog.d.ts +8 -8
  34. package/dist/action-confidence.d.ts +1 -1
  35. package/dist/active-memory-bridge.d.ts +1 -1
  36. package/dist/active-recall.d.ts +1 -1
  37. package/dist/active-recall.js +2 -1
  38. package/dist/active-recall.js.map +1 -1
  39. package/dist/behavior-learner.d.ts +1 -1
  40. package/dist/behavior-signals.d.ts +1 -1
  41. package/dist/bootstrap.d.ts +6 -6
  42. package/dist/briefing.d.ts +2 -2
  43. package/dist/briefing.js +3 -3
  44. package/dist/buffer-surprise-report.d.ts +1 -1
  45. package/dist/buffer.d.ts +2 -2
  46. package/dist/bulk-import/index.d.ts +3 -3
  47. package/dist/calibration.d.ts +1 -1
  48. package/dist/capabilities.d.ts +1 -1
  49. package/dist/{catalog-g_dfT6oL.d.ts → catalog-B9uga4sG.d.ts} +1 -1
  50. package/dist/causal-behavior.d.ts +1 -1
  51. package/dist/causal-consolidation.d.ts +1 -1
  52. package/dist/causal-consolidation.js +4 -4
  53. package/dist/causal-trajectory-graph.d.ts +1 -1
  54. package/dist/{chunk-IRX5UCGN.js → chunk-2OH3ZRYH.js} +3 -3
  55. package/dist/{chunk-YXTSUIXC.js → chunk-5EKOBRCA.js} +6 -1
  56. package/dist/chunk-5EKOBRCA.js.map +1 -0
  57. package/dist/{chunk-42DJZZUB.js → chunk-7LXSPIVG.js} +2 -2
  58. package/dist/{chunk-47WFEKT7.js → chunk-7PK4W4RN.js} +2 -2
  59. package/dist/{chunk-O7ACJAHR.js → chunk-7YJLCNPF.js} +2 -2
  60. package/dist/{chunk-6EJL2O3G.js → chunk-AFH7PIFU.js} +2 -2
  61. package/dist/{chunk-JN4N2TMQ.js → chunk-ANGUOE2N.js} +7 -7
  62. package/dist/{chunk-GQOKO77V.js → chunk-AWT7SCWQ.js} +2 -2
  63. package/dist/{chunk-PXJEL55X.js → chunk-BIRPR5N7.js} +2 -2
  64. package/dist/{chunk-NAY25BGS.js → chunk-BTK2PIFL.js} +6 -6
  65. package/dist/{chunk-SYCVU556.js → chunk-C2RMQRPN.js} +3 -3
  66. package/dist/{chunk-T4EAQPQQ.js → chunk-G2WCVFDC.js} +2 -2
  67. package/dist/{chunk-UJIBXOJA.js → chunk-GEDBTSYU.js} +5 -5
  68. package/dist/{chunk-CXFVZ3PK.js → chunk-GRJ5UOFO.js} +84 -658
  69. package/dist/chunk-GRJ5UOFO.js.map +1 -0
  70. package/dist/chunk-GSQASASV.js +429 -0
  71. package/dist/chunk-GSQASASV.js.map +1 -0
  72. package/dist/{chunk-WIKOHCQZ.js → chunk-I6ODVWQB.js} +2 -2
  73. package/dist/{chunk-H4MDUPER.js → chunk-IZHXSLO7.js} +2 -2
  74. package/dist/{chunk-RRS5CDB6.js → chunk-JOCXI2O5.js} +2 -2
  75. package/dist/{chunk-EEUZQQRJ.js → chunk-KGKYTCDO.js} +2 -2
  76. package/dist/{chunk-JTW4TGPV.js → chunk-L3HAUO7K.js} +2 -2
  77. package/dist/{chunk-P53HGVJS.js → chunk-LMVAIZR5.js} +2 -2
  78. package/dist/{chunk-KLXG4BBO.js → chunk-M6TZQDTX.js} +2 -2
  79. package/dist/{chunk-FJ5IQ3SI.js → chunk-N7DK67GZ.js} +1 -1
  80. package/dist/chunk-N7DK67GZ.js.map +1 -0
  81. package/dist/{chunk-U6QWUFSM.js → chunk-OXT5TQDS.js} +2 -2
  82. package/dist/{chunk-T4OTDMX4.js → chunk-QDTEH6BS.js} +2 -2
  83. package/dist/{chunk-5MDE5MIC.js → chunk-SESF64QR.js} +2 -2
  84. package/dist/{chunk-4E5H4FPC.js → chunk-TUNI4GB3.js} +3 -3
  85. package/dist/{chunk-XJT6LNLY.js → chunk-V6LYAXGW.js} +834 -25
  86. package/dist/chunk-V6LYAXGW.js.map +1 -0
  87. package/dist/{chunk-5HFIHWOF.js → chunk-VLIY55Q5.js} +17 -17
  88. package/dist/{chunk-BNH2VVWP.js → chunk-WIS5JTJR.js} +2 -2
  89. package/dist/{chunk-OOGGUXAG.js → chunk-WQ2I6ODB.js} +2 -2
  90. package/dist/{cli-BXCd2cgK.d.ts → cli-DYLGXxuu.d.ts} +5 -5
  91. package/dist/cli.d.ts +10 -10
  92. package/dist/cli.js +25 -24
  93. package/dist/compounding/engine.d.ts +2 -2
  94. package/dist/compounding/engine.js +3 -3
  95. package/dist/compounding/preference-consolidator.d.ts +1 -1
  96. package/dist/compression-optimizer.d.ts +1 -1
  97. package/dist/config.d.ts +1 -1
  98. package/dist/config.js +2 -1
  99. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  100. package/dist/connectors/codex-materialize-runner.js +3 -3
  101. package/dist/connectors/codex-materialize.d.ts +1 -1
  102. package/dist/connectors/index.d.ts +1 -1
  103. package/dist/connectors/index.js +3 -3
  104. package/dist/consolidation-provenance-check.d.ts +2 -2
  105. package/dist/consolidation-undo.d.ts +2 -2
  106. package/dist/contradiction/index.d.ts +2 -2
  107. package/dist/conversation-index/backend.d.ts +1 -1
  108. package/dist/conversation-index/chunker.d.ts +1 -1
  109. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  110. package/dist/conversation-index/indexer.d.ts +1 -1
  111. package/dist/conversation-index/search.d.ts +1 -1
  112. package/dist/day-summary.d.ts +1 -1
  113. package/dist/delinearize.d.ts +1 -1
  114. package/dist/direct-answer-wiring.d.ts +1 -1
  115. package/dist/direct-answer.d.ts +1 -1
  116. package/dist/embedding-fallback.d.ts +1 -1
  117. package/dist/enrichment/index.d.ts +1 -1
  118. package/dist/entity-retrieval.d.ts +2 -2
  119. package/dist/entity-retrieval.js +3 -3
  120. package/dist/entity-schema.d.ts +1 -1
  121. package/dist/explicit-capture.d.ts +6 -6
  122. package/dist/extraction-faithfulness.d.ts +1 -1
  123. package/dist/extraction-judge-telemetry.d.ts +1 -1
  124. package/dist/extraction-judge-training.d.ts +1 -1
  125. package/dist/extraction-judge.d.ts +1 -1
  126. package/dist/extraction.d.ts +1 -1
  127. package/dist/fallback-llm.d.ts +1 -1
  128. package/dist/graph-dashboard-diff.d.ts +1 -1
  129. package/dist/graph-dashboard-key.d.ts +1 -1
  130. package/dist/graph-dashboard-parser.d.ts +1 -1
  131. package/dist/graph-edge-reinforcement.d.ts +1 -1
  132. package/dist/graph-snapshot.d.ts +1 -1
  133. package/dist/graph.d.ts +1 -1
  134. package/dist/importance.d.ts +1 -1
  135. package/dist/importers/index.d.ts +1 -1
  136. package/dist/in-flight-reads.d.ts +1 -1
  137. package/dist/index.d.ts +289 -99
  138. package/dist/index.js +70 -45
  139. package/dist/intent.d.ts +1 -1
  140. package/dist/lcm/engine.d.ts +1 -1
  141. package/dist/lcm/index.d.ts +1 -1
  142. package/dist/lcm/tools.d.ts +1 -1
  143. package/dist/lifecycle.d.ts +1 -1
  144. package/dist/live-connectors-runner.d.ts +1 -1
  145. package/dist/local-llm.d.ts +1 -1
  146. package/dist/local-model-endpoint.d.ts +1 -1
  147. package/dist/maintenance/memory-governance.d.ts +1 -1
  148. package/dist/maintenance/memory-governance.js +3 -3
  149. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  150. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  151. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  152. package/dist/mcp-memory-inspector-app.d.ts +8 -8
  153. package/dist/memory-action-policy.d.ts +1 -1
  154. package/dist/memory-cache.d.ts +1 -1
  155. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  156. package/dist/memory-projection-store.d.ts +1 -1
  157. package/dist/memory-provenance.d.ts +1 -1
  158. package/dist/memory-worth-outcomes.d.ts +2 -2
  159. package/dist/models-json.d.ts +1 -1
  160. package/dist/namespaces/migrate.d.ts +3 -3
  161. package/dist/namespaces/migrate.js +4 -4
  162. package/dist/namespaces/principal.d.ts +1 -1
  163. package/dist/namespaces/search.d.ts +1 -1
  164. package/dist/namespaces/storage.d.ts +3 -3
  165. package/dist/namespaces/storage.js +3 -3
  166. package/dist/native-knowledge.d.ts +1 -1
  167. package/dist/offline-sync-impression-drain.d.ts +1 -1
  168. package/dist/operator-toolkit.d.ts +2 -2
  169. package/dist/operator-toolkit.js +9 -8
  170. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  171. package/dist/orchestration/maintenance.d.ts +10 -7
  172. package/dist/orchestration/maintenance.js +7 -6
  173. package/dist/{orchestrator-BHfWtvEJ.d.ts → orchestrator-BHx-DWCa.d.ts} +7 -5
  174. package/dist/orchestrator.d.ts +6 -6
  175. package/dist/orchestrator.js +31 -30
  176. package/dist/patterns-cli.d.ts +1 -1
  177. package/dist/{pipeline-CBYcnmDC.d.ts → pipeline-DDHSE876.d.ts} +1 -1
  178. package/dist/policy-runtime.d.ts +1 -1
  179. package/dist/proactive-contention.d.ts +1 -1
  180. package/dist/provenance.d.ts +1 -1
  181. package/dist/{qmd-BIq-jrV4.d.ts → qmd-C4WVh6BM.d.ts} +1 -1
  182. package/dist/qmd-preflight.d.ts +2 -2
  183. package/dist/qmd-recall-cache.d.ts +1 -1
  184. package/dist/qmd.d.ts +2 -2
  185. package/dist/recall-concurrency-config.d.ts +1 -1
  186. package/dist/recall-disclosure-escalation.d.ts +1 -1
  187. package/dist/recall-explain-renderer.d.ts +1 -1
  188. package/dist/recall-explain-renderer.js +3 -3
  189. package/dist/recall-memory-map.d.ts +1 -1
  190. package/dist/recall-planner-llm.d.ts +1 -1
  191. package/dist/recall-state.d.ts +1 -1
  192. package/dist/recall-tag-filter.d.ts +1 -1
  193. package/dist/recall-timings.d.ts +1 -1
  194. package/dist/recall-xray-cli.d.ts +1 -1
  195. package/dist/recall-xray-cli.js +4 -4
  196. package/dist/recall-xray-renderer.d.ts +1 -1
  197. package/dist/recall-xray-renderer.js +3 -3
  198. package/dist/recall-xray.d.ts +1 -1
  199. package/dist/recall-xray.js +2 -2
  200. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  201. package/dist/replay/normalizers/claude.d.ts +1 -1
  202. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  203. package/dist/replay/normalizers/shared.d.ts +1 -1
  204. package/dist/replay/runner.d.ts +1 -1
  205. package/dist/replay/types.d.ts +1 -1
  206. package/dist/resolve-auth-token.d.ts +1 -1
  207. package/dist/resume-bundles.js +3 -2
  208. package/dist/retrieval-agents.d.ts +2 -2
  209. package/dist/retrieval-tiers.d.ts +1 -1
  210. package/dist/routing/engine.d.ts +1 -1
  211. package/dist/routing/store.d.ts +1 -1
  212. package/dist/salvage-envelope.d.ts +1 -1
  213. package/dist/{scope-profiles-DDno-uvy.d.ts → scope-profiles-EqMXwzCz.d.ts} +1 -1
  214. package/dist/search/embed-helper.d.ts +1 -1
  215. package/dist/search/factory.d.ts +1 -1
  216. package/dist/search/index.d.ts +1 -1
  217. package/dist/search/lancedb-backend.d.ts +1 -1
  218. package/dist/search/meilisearch-backend.d.ts +1 -1
  219. package/dist/search/noop-backend.d.ts +1 -1
  220. package/dist/search/orama-backend.d.ts +1 -1
  221. package/dist/search/port.d.ts +1 -1
  222. package/dist/search/remote-backend.d.ts +1 -1
  223. package/dist/{semantic-consolidation-7RIJFDwY.d.ts → semantic-consolidation-CYpvwmQc.d.ts} +1 -1
  224. package/dist/semantic-consolidation.d.ts +2 -2
  225. package/dist/semantic-consolidation.js +4 -4
  226. package/dist/semantic-rule-promotion.js +3 -3
  227. package/dist/semantic-rule-verifier.d.ts +1 -1
  228. package/dist/semantic-rule-verifier.js +3 -3
  229. package/dist/session-observer-bands.d.ts +1 -1
  230. package/dist/session-observer-state.d.ts +1 -1
  231. package/dist/shared-context/manager.d.ts +1 -1
  232. package/dist/signal.d.ts +1 -1
  233. package/dist/{storage-DkphZiOJ.d.ts → storage-Dxd7zVZH.d.ts} +1 -1
  234. package/dist/storage.d.ts +2 -2
  235. package/dist/storage.js +2 -2
  236. package/dist/summarizer.d.ts +1 -1
  237. package/dist/summary-snapshot.d.ts +1 -1
  238. package/dist/temporal-supersession.d.ts +2 -2
  239. package/dist/temporal-timeline-recall.d.ts +1 -1
  240. package/dist/temporal-validity.d.ts +1 -1
  241. package/dist/threading.d.ts +1 -1
  242. package/dist/tier-migration.d.ts +2 -2
  243. package/dist/tier-routing.d.ts +1 -1
  244. package/dist/topics.d.ts +1 -1
  245. package/dist/transcript.d.ts +1 -1
  246. package/dist/trust-score-stage.d.ts +1 -1
  247. package/dist/trust-score.d.ts +1 -1
  248. package/dist/{types-2q_MRFcM.d.ts → types-OUCJALBK.d.ts} +98 -1
  249. package/dist/types.d.ts +1 -1
  250. package/dist/types.js +1 -1
  251. package/dist/utility-runtime.d.ts +1 -1
  252. package/dist/verified-recall.js +3 -3
  253. package/dist/write-envelope.d.ts +1 -1
  254. package/package.json +2 -2
  255. package/src/activity/config.test.ts +113 -0
  256. package/src/activity/config.ts +111 -0
  257. package/src/activity/digest.ts +2 -2
  258. package/src/activity/index.ts +6 -0
  259. package/src/activity/pipeline.test.ts +379 -0
  260. package/src/activity/pipeline.ts +223 -0
  261. package/src/activity/reindex.test.ts +97 -0
  262. package/src/activity/reindex.ts +40 -0
  263. package/src/activity/runner.test.ts +452 -0
  264. package/src/activity/runner.ts +237 -0
  265. package/src/activity/scheduler.test.ts +303 -0
  266. package/src/activity/scheduler.ts +147 -0
  267. package/src/activity/source-client.test.ts +208 -0
  268. package/src/activity/source-client.ts +159 -0
  269. package/src/activity/sync-registration.test.ts +134 -0
  270. package/src/activity/sync-registration.ts +139 -0
  271. package/src/activity/types.ts +17 -0
  272. package/src/config.test.ts +19 -0
  273. package/src/config.ts +3 -0
  274. package/src/orchestration/maintenance.test.ts +42 -42
  275. package/src/orchestration/maintenance.ts +37 -5
  276. package/src/orchestration/orchestrator-helpers.ts +36 -1
  277. package/src/orchestration/recall-internal.ts +6 -6
  278. package/src/orchestration/recall-search-pipeline.ts +15 -7
  279. package/src/orchestrator-background-writes.test.ts +2 -2
  280. package/src/orchestrator.ts +3 -3
  281. package/src/types.ts +4 -1
  282. package/dist/chunk-CXFVZ3PK.js.map +0 -1
  283. package/dist/chunk-FJ5IQ3SI.js.map +0 -1
  284. package/dist/chunk-XJT6LNLY.js.map +0 -1
  285. package/dist/chunk-YXTSUIXC.js.map +0 -1
  286. /package/dist/{chunk-IRX5UCGN.js.map → chunk-2OH3ZRYH.js.map} +0 -0
  287. /package/dist/{chunk-42DJZZUB.js.map → chunk-7LXSPIVG.js.map} +0 -0
  288. /package/dist/{chunk-47WFEKT7.js.map → chunk-7PK4W4RN.js.map} +0 -0
  289. /package/dist/{chunk-O7ACJAHR.js.map → chunk-7YJLCNPF.js.map} +0 -0
  290. /package/dist/{chunk-6EJL2O3G.js.map → chunk-AFH7PIFU.js.map} +0 -0
  291. /package/dist/{chunk-JN4N2TMQ.js.map → chunk-ANGUOE2N.js.map} +0 -0
  292. /package/dist/{chunk-GQOKO77V.js.map → chunk-AWT7SCWQ.js.map} +0 -0
  293. /package/dist/{chunk-PXJEL55X.js.map → chunk-BIRPR5N7.js.map} +0 -0
  294. /package/dist/{chunk-NAY25BGS.js.map → chunk-BTK2PIFL.js.map} +0 -0
  295. /package/dist/{chunk-SYCVU556.js.map → chunk-C2RMQRPN.js.map} +0 -0
  296. /package/dist/{chunk-T4EAQPQQ.js.map → chunk-G2WCVFDC.js.map} +0 -0
  297. /package/dist/{chunk-UJIBXOJA.js.map → chunk-GEDBTSYU.js.map} +0 -0
  298. /package/dist/{chunk-WIKOHCQZ.js.map → chunk-I6ODVWQB.js.map} +0 -0
  299. /package/dist/{chunk-H4MDUPER.js.map → chunk-IZHXSLO7.js.map} +0 -0
  300. /package/dist/{chunk-RRS5CDB6.js.map → chunk-JOCXI2O5.js.map} +0 -0
  301. /package/dist/{chunk-EEUZQQRJ.js.map → chunk-KGKYTCDO.js.map} +0 -0
  302. /package/dist/{chunk-JTW4TGPV.js.map → chunk-L3HAUO7K.js.map} +0 -0
  303. /package/dist/{chunk-P53HGVJS.js.map → chunk-LMVAIZR5.js.map} +0 -0
  304. /package/dist/{chunk-KLXG4BBO.js.map → chunk-M6TZQDTX.js.map} +0 -0
  305. /package/dist/{chunk-U6QWUFSM.js.map → chunk-OXT5TQDS.js.map} +0 -0
  306. /package/dist/{chunk-T4OTDMX4.js.map → chunk-QDTEH6BS.js.map} +0 -0
  307. /package/dist/{chunk-5MDE5MIC.js.map → chunk-SESF64QR.js.map} +0 -0
  308. /package/dist/{chunk-4E5H4FPC.js.map → chunk-TUNI4GB3.js.map} +0 -0
  309. /package/dist/{chunk-5HFIHWOF.js.map → chunk-VLIY55Q5.js.map} +0 -0
  310. /package/dist/{chunk-BNH2VVWP.js.map → chunk-WIS5JTJR.js.map} +0 -0
  311. /package/dist/{chunk-OOGGUXAG.js.map → chunk-WQ2I6ODB.js.map} +0 -0
package/src/config.ts CHANGED
@@ -51,6 +51,7 @@ import {
51
51
  resolveNamespaceCatalogEnabled,
52
52
  } from "./emit-legacy-tools.js";
53
53
  import { parseWearablesConfig } from "./wearables/config.js";
54
+ import { parseActivityConfig } from "./activity/config.js";
54
55
  import { parseProvenanceConfig } from "./provenance.js";
55
56
  import { parseBoundedJsonlStateConfig } from "./bounded-jsonl-state.js";
56
57
  import { parseCodingKnowledgeConfig } from "./coding/coding-knowledge-config.js";
@@ -1172,6 +1173,7 @@ export function parseConfig(
1172
1173
 
1173
1174
  // Wearable transcript ingestion (Limitless / Bee / Omi) — delegated to the wearables module.
1174
1175
  const wearables = parseWearablesConfig(cfg.wearables);
1176
+ const activity = parseActivityConfig(cfg.activity);
1175
1177
 
1176
1178
  const provenance = parseProvenanceConfig(cfg.provenance);
1177
1179
  // Coding-agent project/branch scoping (issue #569)
@@ -2335,6 +2337,7 @@ export function parseConfig(
2335
2337
  dreamsPhases,
2336
2338
  procedural,
2337
2339
  wearables,
2340
+ activity,
2338
2341
  provenance,
2339
2342
  // At-rest encryption (issue #690 PR 3/4)
2340
2343
  // coerceBool handles CLI string inputs: `--config secureStoreEnabled=true`
@@ -162,7 +162,7 @@ test("runQmdMaintenance updates and embeds cataloged dynamic namespaces (NGnei)"
162
162
  assert.equal(embedCalls.length, 1, "QMD embed must batch all selected namespaces into one router call");
163
163
  assert.deepEqual(new Set(embedCalls[0]), new Set(["default", "shared", dynamicNamespace]));
164
164
  } finally {
165
- scheduler.dispose();
165
+ await scheduler.dispose();
166
166
  await rm(memoryDir, { recursive: true, force: true });
167
167
  }
168
168
  });
@@ -218,7 +218,7 @@ test("runQmdMaintenance tracks namespace embed cadence across budget rotation",
218
218
  "a global embed timestamp must not suppress embeddings for newly budgeted namespaces",
219
219
  );
220
220
  } finally {
221
- scheduler.dispose();
221
+ await scheduler.dispose();
222
222
  await rm(memoryDir, { recursive: true, force: true });
223
223
  }
224
224
  });
@@ -285,7 +285,7 @@ test("runQmdMaintenance skips cataloged dynamic namespaces whose live root is un
285
285
  "cataloged dynamic namespaces are skipped when the live router root differs from the catalog-sanitized root",
286
286
  );
287
287
  } finally {
288
- scheduler.dispose();
288
+ await scheduler.dispose();
289
289
  await rm(memoryDir, { recursive: true, force: true });
290
290
  await rm(outsideDir, { recursive: true, force: true });
291
291
  }
@@ -337,7 +337,7 @@ test("runQmdMaintenance treats zero namespace updates as failed maintenance", as
337
337
  assert.equal(markMaintenanceCalls, 0);
338
338
  assert.equal(embedCalls, 0);
339
339
  } finally {
340
- scheduler.dispose();
340
+ await scheduler.dispose();
341
341
  await rm(memoryDir, { recursive: true, force: true });
342
342
  }
343
343
  });
@@ -393,7 +393,7 @@ test("runQmdMaintenance treats partial namespace update eligibility as failed ma
393
393
  assert.equal(markMaintenanceCalls, 0);
394
394
  assert.equal(embedCalls, 0);
395
395
  } finally {
396
- scheduler.dispose();
396
+ await scheduler.dispose();
397
397
  await rm(memoryDir, { recursive: true, force: true });
398
398
  }
399
399
  });
@@ -442,7 +442,7 @@ test("runQmdMaintenance treats namespace embed errors as failed maintenance", as
442
442
  );
443
443
  assert.equal(markMaintenanceCalls, 0);
444
444
  } finally {
445
- scheduler.dispose();
445
+ await scheduler.dispose();
446
446
  await rm(memoryDir, { recursive: true, force: true });
447
447
  }
448
448
  });
@@ -515,7 +515,7 @@ test("runQmdMaintenance records QMD min-interval throttles as skipped maintenanc
515
515
  assert.equal(markMaintenanceCalls, 0);
516
516
  assert.equal(embedCalls, 0);
517
517
  } finally {
518
- scheduler.dispose();
518
+ await scheduler.dispose();
519
519
  await rm(memoryDir, { recursive: true, force: true });
520
520
  }
521
521
  });
@@ -578,7 +578,7 @@ test("runQmdMaintenance still embeds when due update is throttled", async () =>
578
578
  );
579
579
  assert.equal(markMaintenanceCalls, 0);
580
580
  } finally {
581
- scheduler.dispose();
581
+ await scheduler.dispose();
582
582
  await rm(memoryDir, { recursive: true, force: true });
583
583
  }
584
584
  });
@@ -637,7 +637,7 @@ test("runQmdMaintenance treats strict namespace update errors as failed maintena
637
637
  assert.equal(markMaintenanceCalls, 0);
638
638
  assert.equal(embedCalls, 0);
639
639
  } finally {
640
- scheduler.dispose();
640
+ await scheduler.dispose();
641
641
  await rm(memoryDir, { recursive: true, force: true });
642
642
  }
643
643
  });
@@ -682,7 +682,7 @@ test("runQmdMaintenance falls back to configured namespaces when the catalog is
682
682
  "a disabled catalog covers exactly the configured set",
683
683
  );
684
684
  } finally {
685
- scheduler.dispose();
685
+ await scheduler.dispose();
686
686
  await rm(memoryDir, { recursive: true, force: true });
687
687
  }
688
688
  });
@@ -747,7 +747,7 @@ test("MaintenanceScheduler reads a runtime-swapped qmd backend via getQmd (regre
747
747
  "after the swap to NoopSearchBackend, requestQmdMaintenance must short-circuit (isAvailable===false) and never touch the disposed backend",
748
748
  );
749
749
  } finally {
750
- scheduler.dispose();
750
+ await scheduler.dispose();
751
751
  }
752
752
  });
753
753
 
@@ -825,7 +825,7 @@ test("auto-compaction shrinks an oversized ledger and writes a verbatim backup",
825
825
  try {
826
826
  await scheduler.maybeCompactMemoryLifecycleLedger();
827
827
  } finally {
828
- scheduler.dispose();
828
+ await scheduler.dispose();
829
829
  }
830
830
 
831
831
  const afterSize = (await stat(ledgerPath)).size;
@@ -897,7 +897,7 @@ alpha
897
897
  try {
898
898
  await scheduler.maybeCompactMemoryLifecycleLedger();
899
899
  } finally {
900
- scheduler.dispose();
900
+ await scheduler.dispose();
901
901
  }
902
902
 
903
903
  const rebuilt = (await readFile(ledgerPath, "utf-8"))
@@ -934,7 +934,7 @@ test("auto-compaction is disabled when memoryLifecycleLedgerCompactBytes is 0",
934
934
  try {
935
935
  await scheduler.maybeCompactMemoryLifecycleLedger();
936
936
  } finally {
937
- scheduler.dispose();
937
+ await scheduler.dispose();
938
938
  }
939
939
  assert.equal(await readFile(ledgerPath, "utf-8"), before, "disabled: ledger untouched");
940
940
  await assert.rejects(() => readdir(path.join(memoryDir, "archive", "memory-lifecycle-ledger")));
@@ -967,7 +967,7 @@ test("auto-compaction min-interval throttle prevents a second run within the win
967
967
  assert.equal((await stat(ledgerPath)).size, regrownSize, "throttled: ledger not recompacted");
968
968
  assert.ok(regrownSize > compactedSize);
969
969
  } finally {
970
- scheduler.dispose();
970
+ await scheduler.dispose();
971
971
  }
972
972
  } finally {
973
973
  await rm(memoryDir, { recursive: true, force: true });
@@ -988,7 +988,7 @@ test("auto-compaction is a no-op when the ledger is below the threshold", async
988
988
  try {
989
989
  await scheduler.maybeCompactMemoryLifecycleLedger();
990
990
  } finally {
991
- scheduler.dispose();
991
+ await scheduler.dispose();
992
992
  }
993
993
  assert.equal(await readFile(ledgerPath, "utf-8"), before, "under threshold: ledger untouched");
994
994
  } finally {
@@ -1064,7 +1064,7 @@ test("auto-compaction singleflight: two requests racing through the over-cap pro
1064
1064
  assert.equal(stamps.length, 1, "only one compaction backup exists");
1065
1065
  assert.ok((await stat(ledgerPath)).size < 4096, "ledger was compacted once");
1066
1066
  } finally {
1067
- scheduler.dispose();
1067
+ await scheduler.dispose();
1068
1068
  }
1069
1069
  } finally {
1070
1070
  await rm(memoryDir, { recursive: true, force: true });
@@ -1120,7 +1120,7 @@ test("auto-compaction leaves the throttle un-advanced after a failed run so it r
1120
1120
  "still-eligible retry compacts once the failure clears",
1121
1121
  );
1122
1122
  } finally {
1123
- scheduler.dispose();
1123
+ await scheduler.dispose();
1124
1124
  }
1125
1125
  } finally {
1126
1126
  await rm(memoryDir, { recursive: true, force: true });
@@ -1147,7 +1147,7 @@ test("auto-compaction rewrites the ledger encrypted at rest under a secure store
1147
1147
  try {
1148
1148
  await scheduler.maybeCompactMemoryLifecycleLedger();
1149
1149
  } finally {
1150
- scheduler.dispose();
1150
+ await scheduler.dispose();
1151
1151
  }
1152
1152
  // The rewritten ledger is encrypted at rest and smaller than the plaintext
1153
1153
  // original, and decrypts back to the rebuilt events via the same key.
@@ -1215,7 +1215,7 @@ test("auto-compaction re-encrypts an ENCRYPTED ledger's backup for the archive p
1215
1215
  try {
1216
1216
  await scheduler.maybeCompactMemoryLifecycleLedger();
1217
1217
  } finally {
1218
- scheduler.dispose();
1218
+ await scheduler.dispose();
1219
1219
  }
1220
1220
 
1221
1221
  assert.ok(isEncryptedFile(await readFile(ledgerPath)), "compacted ledger stays encrypted at rest");
@@ -1314,7 +1314,7 @@ test("mixed pass: a deferred encrypted target keeps the throttle un-armed so unt
1314
1314
  "deferred target left the throttle un-armed: the second in-window pass recompacts",
1315
1315
  );
1316
1316
  } finally {
1317
- scheduler.dispose();
1317
+ await scheduler.dispose();
1318
1318
  }
1319
1319
  } finally {
1320
1320
  await rm(root, { recursive: true, force: true });
@@ -1351,7 +1351,7 @@ test("maintenance drains a pending lifecycle-append spill even when compaction i
1351
1351
  try {
1352
1352
  await scheduler.maybeCompactMemoryLifecycleLedger();
1353
1353
  } finally {
1354
- scheduler.dispose();
1354
+ await scheduler.dispose();
1355
1355
  }
1356
1356
 
1357
1357
  const ids = (await storage.readAllMemoryLifecycleEvents()).map((e) => e.eventId);
@@ -1433,7 +1433,7 @@ test("maintenance drains a namespace pending spill created after the throttle ar
1433
1433
  );
1434
1434
  await assert.rejects(() => stat(spillPath), /ENOENT/, "namespace spill file removed after drain");
1435
1435
  } finally {
1436
- scheduler.dispose();
1436
+ await scheduler.dispose();
1437
1437
  }
1438
1438
  } finally {
1439
1439
  await rm(root, { recursive: true, force: true });
@@ -1487,7 +1487,7 @@ test("auto-compaction bounds per-namespace ledgers, not just the root state path
1487
1487
  try {
1488
1488
  await scheduler.maybeCompactMemoryLifecycleLedger();
1489
1489
  } finally {
1490
- scheduler.dispose();
1490
+ await scheduler.dispose();
1491
1491
  }
1492
1492
  assert.ok((await stat(nsLedger)).size < beforeSize, "namespace ledger must be compacted");
1493
1493
  const rebuilt = (await readFile(nsLedger, "utf-8")).trim().split("\n").map((l) => JSON.parse(l));
@@ -1529,7 +1529,7 @@ test("catalog-disabled fallback never downgrades an encrypted namespace ledger t
1529
1529
  try {
1530
1530
  await scheduler.maybeCompactMemoryLifecycleLedger();
1531
1531
  } finally {
1532
- scheduler.dispose();
1532
+ await scheduler.dispose();
1533
1533
  }
1534
1534
  // Skipped, not rewritten: the encrypted ledger must be byte-for-byte intact.
1535
1535
  assert.deepEqual(
@@ -1635,7 +1635,7 @@ test("catalog-disabled fallback compacts an encrypted over-cap namespace ledger
1635
1635
  "encrypted fallback ledger compacts through the keyed store, never deferred forever",
1636
1636
  );
1637
1637
  } finally {
1638
- scheduler.dispose();
1638
+ await scheduler.dispose();
1639
1639
  }
1640
1640
 
1641
1641
  // On disk: rewritten, still encrypted at rest (no plaintext downgrade), and
@@ -1755,7 +1755,7 @@ test("catalog-disabled fallback decodes a long tokenized namespace dir so an enc
1755
1755
  "encrypted over-cap ledger for a long namespace compacts through the keyed store, never deferred forever",
1756
1756
  );
1757
1757
  } finally {
1758
- scheduler.dispose();
1758
+ await scheduler.dispose();
1759
1759
  }
1760
1760
 
1761
1761
  assert.notDeepEqual(
@@ -1867,7 +1867,7 @@ test("catalog-disabled fallback resolves a LEGACY RAW namespace dir (not a ns- t
1867
1867
  "encrypted over-cap ledger under a legacy raw namespace dir compacts through the keyed store, never deferred forever",
1868
1868
  );
1869
1869
  } finally {
1870
- scheduler.dispose();
1870
+ await scheduler.dispose();
1871
1871
  }
1872
1872
 
1873
1873
  assert.notDeepEqual(await readFile(nsLedger), encrypted, "ledger was rewritten (not deferred)");
@@ -1996,7 +1996,7 @@ test("catalog-disabled fallback routes a LEGACY RAW namespace dir through the PR
1996
1996
  "encrypted over-cap ledger under a legacy raw namespace dir compacts through the production-resolved keyed store, never deferred forever",
1997
1997
  );
1998
1998
  } finally {
1999
- scheduler.dispose();
1999
+ await scheduler.dispose();
2000
2000
  }
2001
2001
 
2002
2002
  assert.notDeepEqual(await readFile(nsLedger), encrypted, "ledger was rewritten (not deferred)");
@@ -2128,7 +2128,7 @@ test("catalog-disabled fallback refuses a symlinked namespaces scan root (#2033)
2128
2128
  try {
2129
2129
  await scheduler.maybeCompactMemoryLifecycleLedger();
2130
2130
  } finally {
2131
- scheduler.dispose();
2131
+ await scheduler.dispose();
2132
2132
  }
2133
2133
  assert.equal(
2134
2134
  await readFile(nsLedger, "utf-8"),
@@ -2175,7 +2175,7 @@ test("maintenance request triggers lifecycle compaction even when QMD is unavail
2175
2175
  "lifecycle compaction must be triggered from the maintenance request when QMD is unavailable",
2176
2176
  );
2177
2177
  } finally {
2178
- scheduler.dispose();
2178
+ await scheduler.dispose();
2179
2179
  }
2180
2180
  } finally {
2181
2181
  await rm(memoryDir, { recursive: true, force: true });
@@ -2215,7 +2215,7 @@ test("auto-compaction bounds per-namespace ledgers via filesystem fallback when
2215
2215
  try {
2216
2216
  await scheduler.maybeCompactMemoryLifecycleLedger();
2217
2217
  } finally {
2218
- scheduler.dispose();
2218
+ await scheduler.dispose();
2219
2219
  }
2220
2220
  assert.ok(
2221
2221
  (await stat(nsLedger)).size < beforeSize,
@@ -2286,7 +2286,7 @@ test("auto-compaction bounds a large append-only history under the read/decrypt
2286
2286
  "throttle armed after an effective bounded compaction: second in-window pass is a no-op",
2287
2287
  );
2288
2288
  } finally {
2289
- scheduler.dispose();
2289
+ await scheduler.dispose();
2290
2290
  }
2291
2291
  } finally {
2292
2292
  await rm(memoryDir, { recursive: true, force: true });
@@ -2328,7 +2328,7 @@ test("filesystem-fallback compaction drains a pending lifecycle append even when
2328
2328
  try {
2329
2329
  await scheduler.maybeCompactMemoryLifecycleLedger();
2330
2330
  } finally {
2331
- scheduler.dispose();
2331
+ await scheduler.dispose();
2332
2332
  }
2333
2333
 
2334
2334
  const ledger = await readFile(nsLedger, "utf-8");
@@ -2388,7 +2388,7 @@ test("filesystem-fallback compaction recovers a crash-orphaned *.claimed spill w
2388
2388
  try {
2389
2389
  await scheduler.maybeCompactMemoryLifecycleLedger();
2390
2390
  } finally {
2391
- scheduler.dispose();
2391
+ await scheduler.dispose();
2392
2392
  }
2393
2393
 
2394
2394
  const ledger = await readFile(nsLedger, "utf-8");
@@ -2454,7 +2454,7 @@ test("catalog-disabled fallback drain re-probes encryption UNDER the lock and de
2454
2454
  try {
2455
2455
  await scheduler.maybeCompactMemoryLifecycleLedger();
2456
2456
  } finally {
2457
- scheduler.dispose();
2457
+ await scheduler.dispose();
2458
2458
  }
2459
2459
 
2460
2460
  // nsA: encrypted spill deferred — byte-for-byte intact, the ledger never got
@@ -2514,7 +2514,7 @@ test("auto-compaction triggers on an encrypted ledger at/above the decrypt cap e
2514
2514
  try {
2515
2515
  await scheduler.maybeCompactMemoryLifecycleLedger();
2516
2516
  } finally {
2517
- scheduler.dispose();
2517
+ await scheduler.dispose();
2518
2518
  }
2519
2519
  const afterSize = (await stat(ledgerPath)).size;
2520
2520
  assert.ok(afterSize < beforeSize, "over-cap encrypted ledger must compact despite the larger threshold");
@@ -2572,7 +2572,7 @@ test("auto-compaction bypasses the min-interval throttle for an over-cap encrypt
2572
2572
  try {
2573
2573
  await bypassScheduler.maybeCompactMemoryLifecycleLedger();
2574
2574
  } finally {
2575
- bypassScheduler.dispose();
2575
+ await bypassScheduler.dispose();
2576
2576
  }
2577
2577
  const bypassAfter = (await stat(bypassLedger)).size;
2578
2578
  assert.ok(
@@ -2598,7 +2598,7 @@ test("auto-compaction bypasses the min-interval throttle for an over-cap encrypt
2598
2598
  try {
2599
2599
  await throttledScheduler.maybeCompactMemoryLifecycleLedger();
2600
2600
  } finally {
2601
- throttledScheduler.dispose();
2601
+ await throttledScheduler.dispose();
2602
2602
  }
2603
2603
  assert.equal(
2604
2604
  (await stat(throttledLedger)).size,
@@ -2684,7 +2684,7 @@ test("auto-compaction reserves the secure-store envelope so an encrypted rewrite
2684
2684
  "throttle armed after an effective encrypted compaction: second in-window pass is a no-op",
2685
2685
  );
2686
2686
  } finally {
2687
- scheduler.dispose();
2687
+ await scheduler.dispose();
2688
2688
  }
2689
2689
  } finally {
2690
2690
  await rm(memoryDir, { recursive: true, force: true });
@@ -2762,7 +2762,7 @@ test("auto-compaction reserves the envelope when a PLAINTEXT ledger will be rewr
2762
2762
  "throttle armed after an effective compaction: second in-window pass is a no-op",
2763
2763
  );
2764
2764
  } finally {
2765
- scheduler.dispose();
2765
+ await scheduler.dispose();
2766
2766
  }
2767
2767
  } finally {
2768
2768
  await rm(memoryDir, { recursive: true, force: true });
@@ -2819,7 +2819,7 @@ test("catalog-disabled fallback pending drain skips unsafe spill entries (symlin
2819
2819
  // (caught by the test timeout) and following the symlink would escape.
2820
2820
  await scheduler.maybeCompactMemoryLifecycleLedger();
2821
2821
  } finally {
2822
- scheduler.dispose();
2822
+ await scheduler.dispose();
2823
2823
  }
2824
2824
 
2825
2825
  const ledger = await readFile(nsLedger, "utf-8");
@@ -57,6 +57,7 @@ import {
57
57
  type LifecyclePendingIo,
58
58
  } from "../storage/memory-lifecycle-ledger-access.js";
59
59
  import { STATE_FILE_MAX_DECRYPT_BYTES } from "../storage/secure-line-reader.js";
60
+ import { ActivitySyncRegistrar } from "../activity/sync-registration.js";
60
61
  import { resolveHomeDir } from "../runtime/env.js";
61
62
  import { log } from "../logger.js";
62
63
  import { isErrnoCode } from "../utils/errno.js";
@@ -133,7 +134,20 @@ export class MaintenanceScheduler {
133
134
  // fixture.
134
135
  private lifecycleLedgerMaxBytes = STATE_FILE_MAX_DECRYPT_BYTES;
135
136
 
136
- constructor(private readonly deps: MaintenanceSchedulerDeps) {}
137
+ // ── Activity (screen-capture) sync scheduler (issue #1900) ──
138
+ // The full arm/re-arm/teardown lifecycle lives in ActivitySyncRegistrar.
139
+ private readonly activityRegistrar: ActivitySyncRegistrar;
140
+
141
+ constructor(private readonly deps: MaintenanceSchedulerDeps) {
142
+ this.activityRegistrar = new ActivitySyncRegistrar({
143
+ config: deps.config.activity,
144
+ memoryDir: deps.config.memoryDir,
145
+ qmdCollection: deps.config.qmdCollection,
146
+ secureStoreEnabled: resolveRecallAuxiliaryCapabilities(deps.config).secureStore,
147
+ getQmd: () => deps.getQmd(),
148
+ requestReindexRetry: () => this.requestQmdMaintenanceForTool("activity-reindex-retry"),
149
+ });
150
+ }
137
151
 
138
152
  // ───────────────────────────────────────────────────────────────────────
139
153
  // Cron auto-registration
@@ -148,7 +162,7 @@ export class MaintenanceScheduler {
148
162
  * Returns when all eligible registrations have completed so callers that
149
163
  * `await deferredReady` can rely on jobs.json being current.
150
164
  */
151
- async autoRegisterCrons(_signal: AbortSignal): Promise<void> {
165
+ async autoRegisterCrons(signal: AbortSignal): Promise<void> {
152
166
  if (resolveRecallAuxiliaryCapabilities(this.deps.config).daySummary) {
153
167
  try {
154
168
  await this.autoRegisterDaySummaryCron();
@@ -191,6 +205,11 @@ export class MaintenanceScheduler {
191
205
  log.debug(`graph edge decay cron auto-register failed (non-fatal): ${err}`);
192
206
  }
193
207
  }
208
+
209
+ // Activity (screen-capture) in-process sync scheduler (issue #1900),
210
+ // master default-off. The registrar owns the arm/re-arm/teardown contract
211
+ // (stop-prior, abort/teardown guards, secure-store refusal, retry latch).
212
+ await this.activityRegistrar.register(signal);
194
213
  }
195
214
 
196
215
  async autoRegisterDaySummaryCron(): Promise<void> {
@@ -1125,10 +1144,23 @@ export class MaintenanceScheduler {
1125
1144
  // ───────────────────────────────────────────────────────────────────────
1126
1145
 
1127
1146
  /**
1128
- * Clear any pending debounce timer. Called from the orchestrator's
1129
- * destroy() so a late tick does not fire on a torn-down instance.
1147
+ * Clear any pending debounce timer and drain the activity sync scheduler.
1148
+ * Called from the orchestrator's destroy() so a late tick does not fire on a
1149
+ * torn-down instance and no in-flight activity tick keeps writing after
1150
+ * teardown. Async: awaits the scheduler's abort+drain before resolving.
1130
1151
  */
1131
- dispose(): void {
1152
+ async dispose(): Promise<void> {
1153
+ // The registrar latches teardown first (so a draining tick's onRun cannot
1154
+ // re-arm QMD maintenance) and aborts+drains the sync. Capture its drain and
1155
+ // await it last so the rest of teardown runs while the aborted tick unwinds.
1156
+ const activityDrain = this.activityRegistrar.dispose();
1157
+ if (this.qmdMaintenanceTimer) {
1158
+ clearTimeout(this.qmdMaintenanceTimer);
1159
+ this.qmdMaintenanceTimer = null;
1160
+ }
1161
+ this.qmdMaintenancePending = false;
1162
+ await activityDrain;
1163
+ // Belt-and-suspenders: clear anything a late tick armed before the latch.
1132
1164
  if (this.qmdMaintenanceTimer) {
1133
1165
  clearTimeout(this.qmdMaintenanceTimer);
1134
1166
  this.qmdMaintenanceTimer = null;
@@ -601,6 +601,39 @@ export function isArtifactMemoryPath(filePath: string): boolean {
601
601
  return /(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(filePath);
602
602
  }
603
603
 
604
+ /** Exactly `activity/<YYYY-MM-DD>.md`, at the top level of a memory root. */
605
+ const ACTIVITY_DIGEST_TOPLEVEL = /^activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
606
+ /** The digest FILE shape anywhere in a path (root-unaware best-effort). */
607
+ const ACTIVITY_DIGEST_ANYWHERE = /(?:^|[\\/])activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
608
+
609
+ /**
610
+ * Activity day-digests live at `<memoryRoot>/activity/<YYYY-MM-DD>.md` — a
611
+ * dedicated searchable surface (explicit activity search), never generic recall.
612
+ * Captured screen text must not auto-inject into ordinary prompts (issue #1899).
613
+ * Keyed on the path (parseFrontmatter drops the digest's `kind` marker).
614
+ *
615
+ * Root-aware: when `memoryRoot` is given, the path is resolved relative to it and
616
+ * must be the TOP-LEVEL `activity/<date>.md`, so an ordinary memory nested under
617
+ * a category (e.g. `facts/proj/activity/<date>.md`) stays recallable. Without a
618
+ * root, falls back to the digest file shape anywhere (best-effort).
619
+ */
620
+ export function isActivityDigestPath(filePath: string, memoryRoot?: string): boolean {
621
+ if (memoryRoot !== undefined && memoryRoot.length > 0) {
622
+ const relative = path.relative(memoryRoot, path.resolve(memoryRoot, filePath));
623
+ return ACTIVITY_DIGEST_TOPLEVEL.test(relative);
624
+ }
625
+ return ACTIVITY_DIGEST_ANYWHERE.test(filePath);
626
+ }
627
+
628
+ /**
629
+ * Paths that dedicated surfaces own and generic recall must never inject:
630
+ * artifacts and activity digests. Explicit search paths (memory_search,
631
+ * activity search) do not apply this filter, so those surfaces still read them.
632
+ */
633
+ export function isGenericRecallExcludedPath(filePath: string, memoryRoot?: string): boolean {
634
+ return isArtifactMemoryPath(filePath) || isActivityDigestPath(filePath, memoryRoot);
635
+ }
636
+
604
637
  export function buildCompressionGuidelinesMarkdown(
605
638
  events: MemoryActionEvent[],
606
639
  generatedAtIso: string = new Date().toISOString(),
@@ -615,6 +648,8 @@ export function filterRecallCandidates(
615
648
  recallNamespaces: string[];
616
649
  resolveNamespace: (path: string) => string;
617
650
  limit: number;
651
+ /** Memory root for top-level activity-digest detection. */
652
+ memoryRoot?: string;
618
653
  },
619
654
  ): QmdSearchResult[] {
620
655
  const scopedByNamespace = options.namespacesEnabled
@@ -623,7 +658,7 @@ export function filterRecallCandidates(
623
658
  )
624
659
  : candidates;
625
660
  return scopedByNamespace
626
- .filter((r) => !isArtifactMemoryPath(r.path))
661
+ .filter((r) => !isGenericRecallExcludedPath(r.path, options.memoryRoot))
627
662
  .slice(0, Math.max(0, options.limit));
628
663
  }
629
664
 
@@ -84,7 +84,6 @@ import {
84
84
  computeArtifactRecallLimit,
85
85
  computeQmdHybridFetchLimit,
86
86
  defaultWorkspaceDir,
87
- isArtifactMemoryPath,
88
87
  raceRecallAbort,
89
88
  resolveRecallModeDecision,
90
89
  resolveRecallModeDecisionAsync,
@@ -97,6 +96,7 @@ import {
97
96
  type QueryAwarePrefilter,
98
97
  type RecallInvocationOptions,
99
98
  } from "../orchestrator.js";
99
+ import { isGenericRecallExcludedPath } from "./orchestrator-helpers.js";
100
100
 
101
101
  import type {
102
102
  RecallSectionAppendOptions,
@@ -4161,10 +4161,8 @@ export class RecallInternalCoordinator {
4161
4161
  memoryResults = memoryResults.filter((r) =>
4162
4162
  recallNamespaces.includes(r.namespace ?? this.deps.namespaceFromPath(r.path)));
4163
4163
  }
4164
- // Artifacts are injected through dedicated verbatim recall flow only.
4165
- memoryResults = memoryResults.filter(
4166
- (r) => !isArtifactMemoryPath(r.path),
4167
- );
4164
+ // Artifacts + activity digests are dedicated surfaces, never generic recall.
4165
+ memoryResults = memoryResults.filter((r) => !isGenericRecallExcludedPath(r.path, this.deps.config.memoryDir));
4168
4166
 
4169
4167
  const isFullModeGraphAssist =
4170
4168
  graphCaps.multiGraphMemory &&
@@ -4552,6 +4550,7 @@ export class RecallInternalCoordinator {
4552
4550
  recallNamespaces,
4553
4551
  resolveNamespace: (p) => this.deps.namespaceFromPath(p),
4554
4552
  limit: embeddingFetchLimit,
4553
+ memoryRoot: this.deps.config.memoryDir,
4555
4554
  },
4556
4555
  );
4557
4556
  const boostedScoped = await this.deps.boostSearchResults(
@@ -4749,6 +4748,7 @@ export class RecallInternalCoordinator {
4749
4748
  recallNamespaces,
4750
4749
  resolveNamespace: (p) => this.deps.namespaceFromPath(p),
4751
4750
  limit: embeddingFetchLimit,
4751
+ memoryRoot: this.deps.config.memoryDir,
4752
4752
  },
4753
4753
  );
4754
4754
  const boostedScoped = await this.deps.boostSearchResults(
@@ -4871,7 +4871,7 @@ export class RecallInternalCoordinator {
4871
4871
  typeof asOfMs === "number" && Number.isFinite(asOfMs);
4872
4872
  const activeMemories = memories.filter(
4873
4873
  (m) => {
4874
- if (isArtifactMemoryPath(m.path)) return false;
4874
+ if (isGenericRecallExcludedPath(m.path, this.deps.config.memoryDir)) return false;
4875
4875
  const status = m.frontmatter.status;
4876
4876
  if (!status || status === "active") return true;
4877
4877
  if (status === "superseded") {
@@ -54,12 +54,12 @@ import {
54
54
  shouldFilterLifecycleRecallCandidate,
55
55
  computeQmdHybridFetchLimit,
56
56
  filterRecallCandidates,
57
- isArtifactMemoryPath,
58
57
  throwIfRecallAborted,
59
58
  tokenizeRecallQuery,
60
59
  type QmdRecallSnapshot,
61
60
  type QueryAwarePrefilter,
62
61
  } from "../orchestrator.js";
62
+ import { isActivityDigestPath, isGenericRecallExcludedPath } from "./orchestrator-helpers.js";
63
63
 
64
64
  export interface RecallSearchPipelineDeps {
65
65
  applyMemoryWorthRerank(
@@ -466,6 +466,7 @@ export class RecallSearchPipelineCoordinator {
466
466
  recallNamespaces: options.recallNamespaces,
467
467
  resolveNamespace: options.resolveNamespace,
468
468
  limit: qmdFetchLimit,
469
+ memoryRoot: this.deps.config.memoryDir,
469
470
  });
470
471
  const emitDebugSnapshot = async (
471
472
  results: QmdSearchResult[],
@@ -610,6 +611,7 @@ export class RecallSearchPipelineCoordinator {
610
611
  recallNamespaces: options.recallNamespaces,
611
612
  resolveNamespace: options.resolveNamespace,
612
613
  limit: fetchLimit,
614
+ memoryRoot: this.deps.config.memoryDir,
613
615
  });
614
616
 
615
617
  if (filteredResults.length >= qmdFetchLimit) {
@@ -693,7 +695,7 @@ export class RecallSearchPipelineCoordinator {
693
695
  : [];
694
696
  if (scopedSeedResults.length >= cappedLimit) {
695
697
  return scopedSeedResults
696
- .filter((result) => !isArtifactMemoryPath(result.path))
698
+ .filter((result) => !isGenericRecallExcludedPath(result.path, this.deps.config.memoryDir))
697
699
  .slice(0, cappedLimit);
698
700
  }
699
701
 
@@ -726,7 +728,7 @@ export class RecallSearchPipelineCoordinator {
726
728
  [...scopedSeedResults, ...scored],
727
729
  this.deps.namespaceFromPath,
728
730
  cappedLimit,
729
- { filter: (result) => !isArtifactMemoryPath(result.path) },
731
+ { filter: (result) => !isGenericRecallExcludedPath(result.path, this.deps.config.memoryDir) },
730
732
  );
731
733
  }
732
734
 
@@ -974,8 +976,9 @@ export class RecallSearchPipelineCoordinator {
974
976
  }
975
977
  results = scopedResults;
976
978
  }
977
- // Artifact isolation contract: generic recall paths must exclude artifacts.
978
- results = results.filter((r) => !isArtifactMemoryPath(r.path));
979
+ // Dedicated-surface isolation: generic recall must exclude artifacts and
980
+ // activity digests (both remain readable via explicit search).
981
+ results = results.filter((r) => !isGenericRecallExcludedPath(r.path, this.deps.config.memoryDir));
979
982
  if (results.length === 0) return [];
980
983
 
981
984
  const isFullModeGraphAssist =
@@ -1351,10 +1354,15 @@ export class RecallSearchPipelineCoordinator {
1351
1354
  continue;
1352
1355
  }
1353
1356
 
1357
+ // Activity day-digests are a dedicated searchable surface (explicit
1358
+ // activity search), never generic recall — captured screen text must not
1359
+ // auto-inject into ordinary prompts (issue #1899). Keyed on the PATH:
1360
+ // the digest's `kind` frontmatter marker does not survive parseFrontmatter.
1354
1361
  if (
1355
1362
  options?.allowDedicatedSurface !== true &&
1356
1363
  (memory.frontmatter.memoryKind === "dream" ||
1357
- memory.frontmatter.memoryKind === "procedural")
1364
+ memory.frontmatter.memoryKind === "procedural" ||
1365
+ isActivityDigestPath(memory.path, this.deps.config.memoryDir))
1358
1366
  ) {
1359
1367
  dedicatedSurfaceFilteredCount += 1;
1360
1368
  continue;
@@ -1379,7 +1387,7 @@ export class RecallSearchPipelineCoordinator {
1379
1387
  }
1380
1388
  if (dedicatedSurfaceFilteredCount > 0) {
1381
1389
  log.debug(
1382
- `dedicated surface filter removed ${dedicatedSurfaceFilteredCount} dream/procedural candidates from generic recall`,
1390
+ `dedicated surface filter removed ${dedicatedSurfaceFilteredCount} dream/procedural/activity-digest candidates from generic recall`,
1383
1391
  );
1384
1392
  }
1385
1393
  if (forgottenFilteredCount > 0) {
@@ -21,13 +21,13 @@ test("destroy cancels maintenance and waits for tracked writes before disposing
21
21
  compoundingEnabled: false,
22
22
  })
23
23
  );
24
- const maintenanceScheduler = (orchestrator as unknown as { maintenanceScheduler: { dispose(): void } })
24
+ const maintenanceScheduler = (orchestrator as unknown as { maintenanceScheduler: { dispose(): Promise<void> } })
25
25
  .maintenanceScheduler;
26
26
  const originalMaintenanceDispose = maintenanceScheduler.dispose.bind(maintenanceScheduler);
27
27
  let maintenanceDisposed = false;
28
28
  maintenanceScheduler.dispose = () => {
29
29
  maintenanceDisposed = true;
30
- originalMaintenanceDispose();
30
+ return originalMaintenanceDispose();
31
31
  };
32
32
  const writeGate = Promise.withResolvers<void>();
33
33
  let destroySettled = false;