@remnic/core 9.63.4 → 9.63.5

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 (415) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +23 -23
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +24 -24
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +23 -23
  7. package/dist/access-cli.js +55 -55
  8. package/dist/access-coding-context-resolution.d.ts +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +11 -11
  10. package/dist/access-extraction-force-flush.js +23 -23
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +11 -11
  13. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  14. package/dist/access-http-offline-stream.d.ts +11 -11
  15. package/dist/access-http-query.d.ts +2 -2
  16. package/dist/access-http-query.js +25 -25
  17. package/dist/access-http.d.ts +12 -12
  18. package/dist/access-http.js +34 -34
  19. package/dist/access-identity-continuity-surface.d.ts +9 -9
  20. package/dist/access-identity-continuity-surface.js +23 -23
  21. package/dist/access-lcm-surface.d.ts +11 -11
  22. package/dist/access-lcm-surface.js +23 -23
  23. package/dist/access-mcp.d.ts +11 -11
  24. package/dist/access-mcp.js +28 -28
  25. package/dist/access-memory-search-fanout.d.ts +2 -2
  26. package/dist/{access-namespace-preflight-yO4LMGFH.d.ts → access-namespace-preflight-DB0zXFek.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +3 -3
  28. package/dist/access-namespace-preflight.js +23 -23
  29. package/dist/access-observe-write-surface.d.ts +11 -11
  30. package/dist/access-observe-write-surface.js +23 -23
  31. package/dist/access-offline-manifest.d.ts +9 -9
  32. package/dist/access-offline-manifest.js +3 -3
  33. package/dist/access-operations-batch.js +24 -24
  34. package/dist/access-operations.d.ts +11 -11
  35. package/dist/access-operations.js +27 -27
  36. package/dist/access-recall-concurrency.d.ts +11 -11
  37. package/dist/access-recall-concurrency.js +23 -23
  38. package/dist/access-recall-response.d.ts +11 -11
  39. package/dist/access-recall-response.js +23 -23
  40. package/dist/access-recall-surface.d.ts +11 -11
  41. package/dist/access-recall-surface.js +23 -23
  42. package/dist/{access-service-D-bi3r01.d.ts → access-service-cKQrte9Z.d.ts} +7 -7
  43. package/dist/access-service-helpers.d.ts +11 -11
  44. package/dist/access-service.d.ts +11 -11
  45. package/dist/access-service.js +23 -23
  46. package/dist/access-surface-catalog.d.ts +11 -11
  47. package/dist/access-surface-catalog.js +25 -25
  48. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  49. package/dist/action-confidence.d.ts +1 -1
  50. package/dist/active-memory-bridge.d.ts +1 -1
  51. package/dist/active-recall.d.ts +1 -1
  52. package/dist/ambient-provenance.d.ts +1 -1
  53. package/dist/artifact-search.d.ts +1 -1
  54. package/dist/behavior-learner.d.ts +1 -1
  55. package/dist/behavior-signals.d.ts +1 -1
  56. package/dist/bootstrap.d.ts +9 -9
  57. package/dist/briefing-window.d.ts +2 -2
  58. package/dist/briefing.d.ts +2 -2
  59. package/dist/briefing.js +11 -11
  60. package/dist/buffer-surprise-report.d.ts +1 -1
  61. package/dist/buffer-turn-helpers.d.ts +1 -1
  62. package/dist/buffer.d.ts +2 -2
  63. package/dist/buffer.js +4 -4
  64. package/dist/bulk-import/index.d.ts +3 -3
  65. package/dist/calibration.d.ts +1 -1
  66. package/dist/capabilities.d.ts +1 -1
  67. package/dist/{capsule-merge-HCJJMLPS.js → capsule-merge-SGIVB3WA.js} +5 -5
  68. package/dist/{catalog-BYIHQw1l.d.ts → catalog-CCzmf8IH.d.ts} +1 -1
  69. package/dist/causal-behavior.d.ts +1 -1
  70. package/dist/causal-consolidation.d.ts +1 -1
  71. package/dist/causal-consolidation.js +12 -12
  72. package/dist/causal-trajectory-graph.d.ts +1 -1
  73. package/dist/{chunk-XFCQIQQU.js → chunk-2UM6WHME.js} +3 -3
  74. package/dist/{chunk-CKWOMJDY.js → chunk-3Z5TGRFA.js} +8 -8
  75. package/dist/{chunk-JJX5XEIG.js → chunk-77QZW2D6.js} +4 -4
  76. package/dist/{chunk-X4MGNVOO.js → chunk-7AF243WZ.js} +1 -1
  77. package/dist/{chunk-2ASAS3CQ.js → chunk-7KQB4EBS.js} +2 -2
  78. package/dist/{chunk-3LJ2L3T3.js → chunk-7LF2OHIJ.js} +2 -2
  79. package/dist/{chunk-VAMQU4W7.js → chunk-AYVCKGA6.js} +2 -2
  80. package/dist/{chunk-GTRGH4ZT.js → chunk-BB2LH5JM.js} +2 -2
  81. package/dist/{chunk-XMMESCPD.js → chunk-C64XATK7.js} +17 -27
  82. package/dist/chunk-C64XATK7.js.map +1 -0
  83. package/dist/{chunk-DQV3LUQL.js → chunk-CUDSA46O.js} +2 -2
  84. package/dist/{chunk-PADG72LJ.js → chunk-DXDAQZ2K.js} +2 -2
  85. package/dist/{chunk-EJCN5ATI.js → chunk-DYZR3Z6D.js} +3 -3
  86. package/dist/{chunk-VN7IIQGS.js → chunk-E4KMY4KR.js} +2 -2
  87. package/dist/{chunk-ZQKXRKMR.js → chunk-EFKZT6AY.js} +2 -2
  88. package/dist/{chunk-DNRTKO2U.js → chunk-EJY3HJMT.js} +2 -2
  89. package/dist/{chunk-4EDAHS6D.js → chunk-ERPBRXVZ.js} +2 -2
  90. package/dist/{chunk-ZUZD2DRV.js → chunk-F6JYBVL6.js} +27 -57
  91. package/dist/{chunk-ZUZD2DRV.js.map → chunk-F6JYBVL6.js.map} +1 -1
  92. package/dist/{chunk-JWPG65LH.js → chunk-FHKXVTM5.js} +38 -39
  93. package/dist/chunk-FHKXVTM5.js.map +1 -0
  94. package/dist/{chunk-RPKJHYVE.js → chunk-FPEZ74F7.js} +2 -2
  95. package/dist/{chunk-Z334TJRB.js → chunk-GF7RQWXC.js} +2 -2
  96. package/dist/{chunk-6D7PZKCJ.js → chunk-GG4DN63W.js} +2 -2
  97. package/dist/{chunk-OR7KEGLR.js → chunk-GTD4Q62X.js} +2 -6
  98. package/dist/{chunk-QOMUE4FS.js → chunk-I5FLIB2J.js} +2 -2
  99. package/dist/{chunk-2JL7WPXL.js → chunk-IVXVLDNT.js} +12 -12
  100. package/dist/{chunk-NRFU5MVH.js → chunk-JOEJG4SD.js} +47 -1
  101. package/dist/chunk-JOEJG4SD.js.map +1 -0
  102. package/dist/{chunk-EJLTNPRY.js → chunk-KHCUVYCY.js} +3 -3
  103. package/dist/{chunk-QSIQVC32.js → chunk-KYTRF64R.js} +2 -2
  104. package/dist/{chunk-LNFYISZ6.js → chunk-LX4TNSAE.js} +4 -4
  105. package/dist/{chunk-H6ZXNH5I.js → chunk-MUJ4QFUQ.js} +3 -3
  106. package/dist/{chunk-JSH2TV34.js → chunk-NA56NSKL.js} +2 -2
  107. package/dist/{chunk-DFEYRCG2.js → chunk-NKB43PGI.js} +2 -2
  108. package/dist/{chunk-DLQQU4EG.js → chunk-NS5ETDYD.js} +2 -2
  109. package/dist/{chunk-VG6DC2GO.js → chunk-OETHJBAL.js} +53 -45
  110. package/dist/{chunk-VG6DC2GO.js.map → chunk-OETHJBAL.js.map} +1 -1
  111. package/dist/{chunk-BXOZALJ6.js → chunk-PB4WVYGC.js} +2 -2
  112. package/dist/{chunk-Q35XGIEM.js → chunk-PBRCYYO7.js} +2 -2
  113. package/dist/{chunk-QYN5PXDZ.js → chunk-PMVPCZJZ.js} +4 -4
  114. package/dist/{chunk-3USQWITL.js → chunk-QI5RDDEL.js} +3 -3
  115. package/dist/{chunk-I6OQCT3Y.js → chunk-QRWMS6SI.js} +2 -2
  116. package/dist/{chunk-ITYAXU4S.js → chunk-R6UMNP5C.js} +3 -3
  117. package/dist/{chunk-5W62VEFH.js → chunk-RWMSMTQP.js} +2 -2
  118. package/dist/{chunk-FKJVEW6O.js → chunk-SYVGVK4S.js} +2 -2
  119. package/dist/{chunk-GNKY5JEP.js → chunk-TSTI6A3A.js} +8 -8
  120. package/dist/{chunk-ISFUFLFM.js → chunk-UCLMKNHA.js} +2 -2
  121. package/dist/{chunk-ZMSZVISA.js → chunk-UFKPQBXH.js} +3 -3
  122. package/dist/{chunk-B2OOJCUX.js → chunk-UGHCZS6K.js} +2 -2
  123. package/dist/{chunk-RSLRGRBJ.js → chunk-V3KIRICY.js} +3 -3
  124. package/dist/{chunk-MRJ43KSG.js → chunk-VPHSMJ2E.js} +2 -2
  125. package/dist/{chunk-E2GYBTSP.js → chunk-VYEPACWY.js} +2 -2
  126. package/dist/{chunk-A4HXWNST.js → chunk-X7LEDA74.js} +2 -2
  127. package/dist/{chunk-KMAP7SNQ.js → chunk-XCB6QDL6.js} +2 -2
  128. package/dist/{chunk-WDUG2CH3.js → chunk-YEQCMA5L.js} +2 -2
  129. package/dist/{chunk-LZCSOUJ7.js → chunk-YFCEBB5P.js} +2 -2
  130. package/dist/{chunk-IKXUG6KC.js → chunk-YXMHUBN2.js} +2 -2
  131. package/dist/{chunk-GFNS3BHV.js → chunk-ZUPKNWRZ.js} +3 -3
  132. package/dist/{chunk-GSTIBXBW.js → chunk-ZVPVTPGI.js} +2 -2
  133. package/dist/{cli-DEoABKXH.d.ts → cli-BFBDYV0D.d.ts} +5 -5
  134. package/dist/cli.d.ts +13 -13
  135. package/dist/cli.js +45 -45
  136. package/dist/coding/pre-action-gate.d.ts +1 -1
  137. package/dist/compounding/engine.d.ts +2 -2
  138. package/dist/compounding/engine.js +11 -11
  139. package/dist/compounding/preference-consolidator.d.ts +1 -1
  140. package/dist/compression-optimizer.d.ts +1 -1
  141. package/dist/config.d.ts +1 -1
  142. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  143. package/dist/connectors/codex-materialize-runner.js +11 -11
  144. package/dist/connectors/codex-materialize.d.ts +1 -1
  145. package/dist/connectors/index.d.ts +1 -1
  146. package/dist/connectors/index.js +11 -11
  147. package/dist/consolidation-provenance-check.d.ts +2 -2
  148. package/dist/consolidation-provenance-check.js +5 -5
  149. package/dist/consolidation-undo.d.ts +2 -2
  150. package/dist/consolidation-undo.js +4 -4
  151. package/dist/contradiction/index.d.ts +2 -2
  152. package/dist/converge-config.d.ts +1 -1
  153. package/dist/convergence-refresh.d.ts +2 -2
  154. package/dist/convergence-refresh.js +13 -13
  155. package/dist/conversation-index/backend.d.ts +1 -1
  156. package/dist/conversation-index/chunker.d.ts +1 -1
  157. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  158. package/dist/conversation-index/indexer.d.ts +1 -1
  159. package/dist/conversation-index/search.d.ts +1 -1
  160. package/dist/corpus-watermark.d.ts +1 -1
  161. package/dist/corpus-watermark.js +13 -13
  162. package/dist/day-summary.d.ts +1 -1
  163. package/dist/delinearize.d.ts +1 -1
  164. package/dist/dependency-propagation-config.d.ts +1 -1
  165. package/dist/{dependency-propagation-delivery-BxhvAppj.d.ts → dependency-propagation-delivery-DiY5T63p.d.ts} +1 -1
  166. package/dist/direct-answer-wiring.d.ts +1 -1
  167. package/dist/direct-answer.d.ts +1 -1
  168. package/dist/embedding-fallback.d.ts +1 -1
  169. package/dist/enrichment/index.d.ts +1 -1
  170. package/dist/entity-origin-fields.d.ts +1 -1
  171. package/dist/entity-retrieval.d.ts +2 -2
  172. package/dist/entity-retrieval.js +11 -11
  173. package/dist/entity-schema.d.ts +1 -1
  174. package/dist/episodic-context.d.ts +1 -1
  175. package/dist/explicit-capture.d.ts +9 -9
  176. package/dist/explicit-capture.js +5 -5
  177. package/dist/external-wiki-access.d.ts +11 -11
  178. package/dist/external-wiki-access.js +24 -24
  179. package/dist/external-wiki-collection-registration.d.ts +1 -1
  180. package/dist/external-wiki-collection.d.ts +1 -1
  181. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  182. package/dist/extraction-error-classification.d.ts +1 -1
  183. package/dist/extraction-faithfulness.d.ts +1 -1
  184. package/dist/extraction-judge-telemetry.d.ts +1 -1
  185. package/dist/extraction-judge-training.d.ts +1 -1
  186. package/dist/extraction-judge.d.ts +1 -1
  187. package/dist/extraction-liveness.d.ts +1 -1
  188. package/dist/extraction-normalization.d.ts +1 -1
  189. package/dist/extraction-prompt.d.ts +1 -1
  190. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  191. package/dist/extraction-source-grounding.d.ts +1 -1
  192. package/dist/extraction.d.ts +1 -1
  193. package/dist/extraction.js +14 -14
  194. package/dist/fallback-llm.d.ts +1 -1
  195. package/dist/graph-dashboard-diff.d.ts +1 -1
  196. package/dist/graph-dashboard-key.d.ts +1 -1
  197. package/dist/graph-dashboard-parser.d.ts +1 -1
  198. package/dist/graph-edge-reinforcement.d.ts +1 -1
  199. package/dist/graph-path-reconstruction.d.ts +1 -1
  200. package/dist/graph-path-scoring.d.ts +1 -1
  201. package/dist/graph-snapshot.d.ts +1 -1
  202. package/dist/graph.d.ts +1 -1
  203. package/dist/harmonic-retrieval.js +1 -1
  204. package/dist/importance.d.ts +1 -1
  205. package/dist/importers/index.d.ts +1 -1
  206. package/dist/in-flight-reads.d.ts +1 -1
  207. package/dist/index.d.ts +21 -21
  208. package/dist/index.js +55 -55
  209. package/dist/intent.d.ts +1 -1
  210. package/dist/lcm/engine.d.ts +1 -1
  211. package/dist/lcm/index.d.ts +1 -1
  212. package/dist/lcm/tools.d.ts +1 -1
  213. package/dist/lifecycle.d.ts +1 -1
  214. package/dist/live-connectors-runner.d.ts +1 -1
  215. package/dist/local-llm.d.ts +1 -1
  216. package/dist/local-model-endpoint.d.ts +1 -1
  217. package/dist/maintenance/memory-governance.d.ts +1 -1
  218. package/dist/maintenance/memory-governance.js +11 -11
  219. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  220. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -11
  221. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  222. package/dist/maintenance/rebuild-memory-projection.js +12 -12
  223. package/dist/{maintenance-N5ur13Al.d.ts → maintenance-CaqA4z7V.d.ts} +3 -3
  224. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  225. package/dist/memory-action-policy.d.ts +1 -1
  226. package/dist/memory-cache.d.ts +1 -1
  227. package/dist/memory-cache.js +1 -1
  228. package/dist/memory-corpus-version.js +2 -2
  229. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  230. package/dist/memory-projection-store.d.ts +1 -1
  231. package/dist/memory-provenance.d.ts +1 -1
  232. package/dist/memory-snapshot.d.ts +1 -1
  233. package/dist/memory-worth-outcomes.d.ts +2 -2
  234. package/dist/models-json.d.ts +1 -1
  235. package/dist/namespaces/migrate.d.ts +3 -3
  236. package/dist/namespaces/migrate.js +12 -12
  237. package/dist/namespaces/principal.d.ts +1 -1
  238. package/dist/namespaces/search.d.ts +1 -1
  239. package/dist/namespaces/search.js +4 -4
  240. package/dist/namespaces/storage.d.ts +3 -3
  241. package/dist/namespaces/storage.js +11 -11
  242. package/dist/native-knowledge.d.ts +1 -1
  243. package/dist/offline-sync-impression-drain.d.ts +1 -1
  244. package/dist/operator-doctor-corpus.d.ts +1 -1
  245. package/dist/operator-doctor-corpus.js +14 -14
  246. package/dist/operator-doctor-replica.d.ts +1 -1
  247. package/dist/operator-toolkit.d.ts +3 -3
  248. package/dist/operator-toolkit.js +20 -20
  249. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  250. package/dist/orchestration/maintenance.d.ts +4 -4
  251. package/dist/orchestration/maintenance.js +17 -17
  252. package/dist/{orchestrator-ByLrpav4.d.ts → orchestrator-CSc9GfQv.d.ts} +8 -8
  253. package/dist/orchestrator.d.ts +9 -9
  254. package/dist/orchestrator.js +55 -55
  255. package/dist/page-versioning.js +4 -4
  256. package/dist/patterns-cli.d.ts +1 -1
  257. package/dist/{pipeline-BdF3ferY.d.ts → pipeline-X606GdRJ.d.ts} +1 -1
  258. package/dist/policy-runtime.d.ts +1 -1
  259. package/dist/proactive-contention.d.ts +1 -1
  260. package/dist/provenance.d.ts +1 -1
  261. package/dist/{public-http-DusietP2.d.ts → public-http-8PcrDIYi.d.ts} +1 -1
  262. package/dist/{qmd-CBSxevyb.d.ts → qmd-DCKeR-GX.d.ts} +1 -1
  263. package/dist/qmd-preflight.d.ts +2 -2
  264. package/dist/qmd-recall-cache.d.ts +1 -1
  265. package/dist/qmd.d.ts +2 -2
  266. package/dist/qmd.js +2 -2
  267. package/dist/recall-concurrency-config.d.ts +1 -1
  268. package/dist/recall-disclosure-escalation.d.ts +1 -1
  269. package/dist/recall-explain-renderer.d.ts +1 -1
  270. package/dist/recall-memory-map.d.ts +1 -1
  271. package/dist/recall-planner-llm.d.ts +1 -1
  272. package/dist/recall-state.d.ts +1 -1
  273. package/dist/recall-tag-filter.d.ts +1 -1
  274. package/dist/recall-timings.d.ts +1 -1
  275. package/dist/recall-xray-cli.d.ts +1 -1
  276. package/dist/recall-xray-renderer.d.ts +1 -1
  277. package/dist/recall-xray.d.ts +1 -1
  278. package/dist/reconcile/cursor.d.ts +1 -1
  279. package/dist/reconcile/manifest.d.ts +1 -1
  280. package/dist/reconcile/manifest.js +2 -2
  281. package/dist/reconcile/plan.d.ts +1 -1
  282. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  283. package/dist/replay/normalizers/claude.d.ts +1 -1
  284. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  285. package/dist/replay/normalizers/shared.d.ts +1 -1
  286. package/dist/replay/runner.d.ts +1 -1
  287. package/dist/replay/types.d.ts +1 -1
  288. package/dist/replica-divergence.d.ts +1 -1
  289. package/dist/replica-peers-config.d.ts +1 -1
  290. package/dist/resolve-auth-token.d.ts +1 -1
  291. package/dist/retrieval-agents.d.ts +2 -2
  292. package/dist/retrieval-tiers.d.ts +1 -1
  293. package/dist/routing/engine.d.ts +1 -1
  294. package/dist/routing/store.d.ts +1 -1
  295. package/dist/salvage-envelope.d.ts +1 -1
  296. package/dist/{scope-profiles-CeMv7pP0.d.ts → scope-profiles-_Y_RHCeE.d.ts} +1 -1
  297. package/dist/search/embed-helper.d.ts +1 -1
  298. package/dist/search/factory.d.ts +1 -1
  299. package/dist/search/factory.js +3 -3
  300. package/dist/search/index.d.ts +1 -1
  301. package/dist/search/index.js +3 -3
  302. package/dist/search/lancedb-backend.d.ts +1 -1
  303. package/dist/search/meilisearch-backend.d.ts +1 -1
  304. package/dist/search/noop-backend.d.ts +1 -1
  305. package/dist/search/orama-backend.d.ts +1 -1
  306. package/dist/search/port.d.ts +1 -1
  307. package/dist/search/remote-backend.d.ts +1 -1
  308. package/dist/{semantic-consolidation-B-85brYj.d.ts → semantic-consolidation-DT2VSrU0.d.ts} +1 -1
  309. package/dist/semantic-consolidation.d.ts +2 -2
  310. package/dist/semantic-consolidation.js +12 -12
  311. package/dist/semantic-rule-promotion.js +11 -11
  312. package/dist/semantic-rule-verifier.d.ts +1 -1
  313. package/dist/semantic-rule-verifier.js +11 -11
  314. package/dist/{service-CoO0HA2E.d.ts → service-BMo-gwDE.d.ts} +3 -3
  315. package/dist/session-observer-bands.d.ts +1 -1
  316. package/dist/session-observer-state.d.ts +1 -1
  317. package/dist/shared-context/manager.d.ts +1 -1
  318. package/dist/signal.d.ts +1 -1
  319. package/dist/source-agent-qualifier.d.ts +1 -1
  320. package/dist/source-agent-qualifier.js +13 -13
  321. package/dist/{storage-BVAVitkO.d.ts → storage-CGzJGUUu.d.ts} +49 -24
  322. package/dist/storage.d.ts +2 -2
  323. package/dist/storage.js +10 -10
  324. package/dist/summarizer.d.ts +1 -1
  325. package/dist/summary-snapshot.d.ts +1 -1
  326. package/dist/support-passport/index.d.ts +14 -14
  327. package/dist/support-passport/index.js +26 -26
  328. package/dist/temporal-supersession.d.ts +2 -2
  329. package/dist/temporal-timeline-recall.d.ts +1 -1
  330. package/dist/temporal-validity.d.ts +1 -1
  331. package/dist/threading.d.ts +1 -1
  332. package/dist/tier-migration.d.ts +2 -2
  333. package/dist/tier-routing.d.ts +1 -1
  334. package/dist/topics.d.ts +1 -1
  335. package/dist/transcript.d.ts +1 -1
  336. package/dist/transfer/capsule-import.js +5 -5
  337. package/dist/trust-score-stage.d.ts +1 -1
  338. package/dist/trust-score.d.ts +1 -1
  339. package/dist/{types-DWHOxlZP.d.ts → types-CBEAYU76.d.ts} +112 -128
  340. package/dist/types.d.ts +1 -1
  341. package/dist/utility-runtime.d.ts +1 -1
  342. package/dist/verified-recall.js +11 -11
  343. package/dist/write-envelope.d.ts +1 -1
  344. package/package.json +2 -2
  345. package/src/chat/chat-cli.test.ts +53 -0
  346. package/src/chat/chat-cli.ts +22 -58
  347. package/src/dedup/index.test.ts +65 -1
  348. package/src/dedup/index.ts +24 -2
  349. package/src/meetings/build.test.ts +20 -4
  350. package/src/meetings/build.ts +2 -2
  351. package/src/meetings/day-source.test.ts +3 -1
  352. package/src/meetings/day-source.ts +1 -12
  353. package/src/meetings/fuse.test.ts +64 -15
  354. package/src/meetings/fuse.ts +18 -12
  355. package/src/meetings/types.ts +4 -19
  356. package/src/memory-cache-derived.test.ts +90 -0
  357. package/src/memory-cache.ts +40 -42
  358. package/src/storage/content-hash-index.ts +54 -0
  359. package/src/storage-contract/content-hash.test.ts +59 -1
  360. package/src/storage-fact-hash-index-defer.test.ts +9 -9
  361. package/src/storage.ts +39 -40
  362. package/dist/chunk-JWPG65LH.js.map +0 -1
  363. package/dist/chunk-NRFU5MVH.js.map +0 -1
  364. package/dist/chunk-XMMESCPD.js.map +0 -1
  365. /package/dist/{capsule-merge-HCJJMLPS.js.map → capsule-merge-SGIVB3WA.js.map} +0 -0
  366. /package/dist/{chunk-XFCQIQQU.js.map → chunk-2UM6WHME.js.map} +0 -0
  367. /package/dist/{chunk-CKWOMJDY.js.map → chunk-3Z5TGRFA.js.map} +0 -0
  368. /package/dist/{chunk-JJX5XEIG.js.map → chunk-77QZW2D6.js.map} +0 -0
  369. /package/dist/{chunk-X4MGNVOO.js.map → chunk-7AF243WZ.js.map} +0 -0
  370. /package/dist/{chunk-2ASAS3CQ.js.map → chunk-7KQB4EBS.js.map} +0 -0
  371. /package/dist/{chunk-3LJ2L3T3.js.map → chunk-7LF2OHIJ.js.map} +0 -0
  372. /package/dist/{chunk-VAMQU4W7.js.map → chunk-AYVCKGA6.js.map} +0 -0
  373. /package/dist/{chunk-GTRGH4ZT.js.map → chunk-BB2LH5JM.js.map} +0 -0
  374. /package/dist/{chunk-DQV3LUQL.js.map → chunk-CUDSA46O.js.map} +0 -0
  375. /package/dist/{chunk-PADG72LJ.js.map → chunk-DXDAQZ2K.js.map} +0 -0
  376. /package/dist/{chunk-EJCN5ATI.js.map → chunk-DYZR3Z6D.js.map} +0 -0
  377. /package/dist/{chunk-VN7IIQGS.js.map → chunk-E4KMY4KR.js.map} +0 -0
  378. /package/dist/{chunk-ZQKXRKMR.js.map → chunk-EFKZT6AY.js.map} +0 -0
  379. /package/dist/{chunk-DNRTKO2U.js.map → chunk-EJY3HJMT.js.map} +0 -0
  380. /package/dist/{chunk-4EDAHS6D.js.map → chunk-ERPBRXVZ.js.map} +0 -0
  381. /package/dist/{chunk-RPKJHYVE.js.map → chunk-FPEZ74F7.js.map} +0 -0
  382. /package/dist/{chunk-Z334TJRB.js.map → chunk-GF7RQWXC.js.map} +0 -0
  383. /package/dist/{chunk-6D7PZKCJ.js.map → chunk-GG4DN63W.js.map} +0 -0
  384. /package/dist/{chunk-OR7KEGLR.js.map → chunk-GTD4Q62X.js.map} +0 -0
  385. /package/dist/{chunk-QOMUE4FS.js.map → chunk-I5FLIB2J.js.map} +0 -0
  386. /package/dist/{chunk-2JL7WPXL.js.map → chunk-IVXVLDNT.js.map} +0 -0
  387. /package/dist/{chunk-EJLTNPRY.js.map → chunk-KHCUVYCY.js.map} +0 -0
  388. /package/dist/{chunk-QSIQVC32.js.map → chunk-KYTRF64R.js.map} +0 -0
  389. /package/dist/{chunk-LNFYISZ6.js.map → chunk-LX4TNSAE.js.map} +0 -0
  390. /package/dist/{chunk-H6ZXNH5I.js.map → chunk-MUJ4QFUQ.js.map} +0 -0
  391. /package/dist/{chunk-JSH2TV34.js.map → chunk-NA56NSKL.js.map} +0 -0
  392. /package/dist/{chunk-DFEYRCG2.js.map → chunk-NKB43PGI.js.map} +0 -0
  393. /package/dist/{chunk-DLQQU4EG.js.map → chunk-NS5ETDYD.js.map} +0 -0
  394. /package/dist/{chunk-BXOZALJ6.js.map → chunk-PB4WVYGC.js.map} +0 -0
  395. /package/dist/{chunk-Q35XGIEM.js.map → chunk-PBRCYYO7.js.map} +0 -0
  396. /package/dist/{chunk-QYN5PXDZ.js.map → chunk-PMVPCZJZ.js.map} +0 -0
  397. /package/dist/{chunk-3USQWITL.js.map → chunk-QI5RDDEL.js.map} +0 -0
  398. /package/dist/{chunk-I6OQCT3Y.js.map → chunk-QRWMS6SI.js.map} +0 -0
  399. /package/dist/{chunk-ITYAXU4S.js.map → chunk-R6UMNP5C.js.map} +0 -0
  400. /package/dist/{chunk-5W62VEFH.js.map → chunk-RWMSMTQP.js.map} +0 -0
  401. /package/dist/{chunk-FKJVEW6O.js.map → chunk-SYVGVK4S.js.map} +0 -0
  402. /package/dist/{chunk-GNKY5JEP.js.map → chunk-TSTI6A3A.js.map} +0 -0
  403. /package/dist/{chunk-ISFUFLFM.js.map → chunk-UCLMKNHA.js.map} +0 -0
  404. /package/dist/{chunk-ZMSZVISA.js.map → chunk-UFKPQBXH.js.map} +0 -0
  405. /package/dist/{chunk-B2OOJCUX.js.map → chunk-UGHCZS6K.js.map} +0 -0
  406. /package/dist/{chunk-RSLRGRBJ.js.map → chunk-V3KIRICY.js.map} +0 -0
  407. /package/dist/{chunk-MRJ43KSG.js.map → chunk-VPHSMJ2E.js.map} +0 -0
  408. /package/dist/{chunk-E2GYBTSP.js.map → chunk-VYEPACWY.js.map} +0 -0
  409. /package/dist/{chunk-A4HXWNST.js.map → chunk-X7LEDA74.js.map} +0 -0
  410. /package/dist/{chunk-KMAP7SNQ.js.map → chunk-XCB6QDL6.js.map} +0 -0
  411. /package/dist/{chunk-WDUG2CH3.js.map → chunk-YEQCMA5L.js.map} +0 -0
  412. /package/dist/{chunk-LZCSOUJ7.js.map → chunk-YFCEBB5P.js.map} +0 -0
  413. /package/dist/{chunk-IKXUG6KC.js.map → chunk-YXMHUBN2.js.map} +0 -0
  414. /package/dist/{chunk-GFNS3BHV.js.map → chunk-ZUPKNWRZ.js.map} +0 -0
  415. /package/dist/{chunk-GSTIBXBW.js.map → chunk-ZVPVTPGI.js.map} +0 -0
@@ -4,7 +4,7 @@ import { tmpdir } from "node:os";
4
4
  import path from "node:path";
5
5
  import test from "node:test";
6
6
 
7
- import { findContradictions, findDuplicates } from "./index.js";
7
+ import { NEGATION_WORDS, findContradictions, findDuplicates } from "./index.js";
8
8
 
9
9
  test("findContradictions detects can versus cannot statements", async () => {
10
10
  const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-dedup-contradiction-"));
@@ -149,3 +149,67 @@ test("dedup scans reject symlinked category directories outside memoryDir", asyn
149
149
  await rm(outsideDir, { recursive: true, force: true });
150
150
  }
151
151
  });
152
+
153
+ test("strip-negation pattern is derived from NEGATION_WORDS", async () => {
154
+ NEGATION_WORDS.add("seldom");
155
+ const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-dedup-negation-"));
156
+
157
+ try {
158
+ const factsDir = path.join(memoryDir, "facts");
159
+ await mkdir(factsDir);
160
+ await writeFile(
161
+ path.join(factsDir, "plain.md"),
162
+ ["---", "id: mem-plain", "category: fact", "---", "The user enjoys morning runs."].join("\n"),
163
+ "utf8"
164
+ );
165
+ await writeFile(
166
+ path.join(factsDir, "seldom.md"),
167
+ ["---", "id: mem-seldom", "category: fact", "---", "The user seldom enjoys morning runs."].join("\n"),
168
+ "utf8"
169
+ );
170
+
171
+ const result = findContradictions({ memoryDir, categories: ["facts"] });
172
+
173
+ // "high" requires the stripped texts to match exactly, which only happens
174
+ // when the strip pattern honors the word the test added to the set.
175
+ assert.equal(result.contradictions.length, 1);
176
+ assert.equal(result.contradictions[0]?.severity, "high");
177
+ assert.equal(result.contradictions[0]?.reason, "Negated version of similar content");
178
+ } finally {
179
+ NEGATION_WORDS.delete("seldom");
180
+ await rm(memoryDir, { recursive: true, force: true });
181
+ }
182
+ });
183
+
184
+ test("strip-negation cache rebuilds on same-size vocabulary swap", async () => {
185
+ const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-dedup-negation-swap-"));
186
+
187
+ try {
188
+ const factsDir = path.join(memoryDir, "facts");
189
+ await mkdir(factsDir);
190
+ await writeFile(
191
+ path.join(factsDir, "plain.md"),
192
+ ["---", "id: mem-swap-plain", "category: fact", "---", "The user enjoys morning runs."].join("\n"),
193
+ "utf8"
194
+ );
195
+ await writeFile(
196
+ path.join(factsDir, "rarely.md"),
197
+ ["---", "id: mem-swap-rarely", "category: fact", "---", "The user rarely enjoys morning runs."].join("\n"),
198
+ "utf8"
199
+ );
200
+
201
+ // Warm the pattern cache with the current vocabulary (no "rarely" yet).
202
+ assert.equal(findContradictions({ memoryDir, categories: ["facts"] }).contradictions.length, 0);
203
+
204
+ // Same-size swap: the size-keyed cache would keep serving the stale pattern.
205
+ NEGATION_WORDS.delete("never");
206
+ NEGATION_WORDS.add("rarely");
207
+ const result = findContradictions({ memoryDir, categories: ["facts"] });
208
+ assert.equal(result.contradictions.length, 1);
209
+ assert.equal(result.contradictions[0]?.severity, "high");
210
+ } finally {
211
+ NEGATION_WORDS.delete("rarely");
212
+ NEGATION_WORDS.add("never");
213
+ await rm(memoryDir, { recursive: true, force: true });
214
+ }
215
+ });
@@ -245,7 +245,7 @@ function tokenizeForSimilarity(text: string): Set<string> {
245
245
 
246
246
  // ── Contradiction detection ──────────────────────────────────────────────────
247
247
 
248
- const NEGATION_WORDS = new Set([
248
+ export const NEGATION_WORDS = new Set([
249
249
  "not",
250
250
  "don't",
251
251
  "doesn't",
@@ -317,9 +317,31 @@ function containsNegation(text: string): boolean {
317
317
  return words.some((w) => NEGATION_WORDS.has(w));
318
318
  }
319
319
 
320
+ function escapeRegExp(value: string): string {
321
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
322
+ }
323
+
324
+ // Single vocabulary source: the strip pattern is derived from NEGATION_WORDS,
325
+ // never hand-maintained. Keyed on the alternation content so any vocabulary
326
+ // change (not just a size change) rebuilds the pattern.
327
+ let stripNegationPattern: RegExp | null = null;
328
+ let stripNegationPatternSource: string | null = null;
329
+
330
+ function stripNegationRegex(): RegExp {
331
+ const alternation = [...NEGATION_WORDS]
332
+ .sort((a, b) => b.length - a.length)
333
+ .map(escapeRegExp)
334
+ .join("|");
335
+ if (stripNegationPattern === null || stripNegationPatternSource !== alternation) {
336
+ stripNegationPattern = new RegExp(`\\b(?:${alternation})\\b`, "gi");
337
+ stripNegationPatternSource = alternation;
338
+ }
339
+ return stripNegationPattern;
340
+ }
341
+
320
342
  function stripNegation(text: string): string {
321
343
  return text
322
- .replace(/\b(not|don't|doesn't|isn't|aren't|won't|can't|cannot|never|no|none|neither|nor|nothing|nowhere)\b/gi, "")
344
+ .replace(stripNegationRegex(), "")
323
345
  .replace(/\s+/g, " ")
324
346
  .trim();
325
347
  }
@@ -5,12 +5,12 @@ import { MeetingsBuilder, type MeetingDayData, type MeetingsDayBuildSummary, typ
5
5
  import { DEFAULT_MEETINGS_CONFIG } from "./config.js";
6
6
  import { MeetingRecordStore, type MeetingRecordFileIo } from "./store.js";
7
7
  import type {
8
- MeetingActivitySnapshot,
9
8
  MeetingsConfig,
10
9
  MeetingAppSpan,
11
10
  MeetingAudioWindow,
12
11
  MeetingRecord,
13
12
  } from "./types.js";
13
+ import type { ActivitySnapshot } from "../activity/types.js";
14
14
  import type { FusionConversationInput, FusionSegmentInput } from "../wearables/fusion/types.js";
15
15
  import type { MeetingMemoryGenerator, MeetingMemoryOutcome } from "./memory-generator.js";
16
16
 
@@ -174,9 +174,25 @@ test("degradation — audio only yields a record with no screen-context section"
174
174
  });
175
175
 
176
176
  test("full — app+audio with activity fuses transcript and screen context", async () => {
177
- const activity: MeetingActivitySnapshot[] = [
178
- { tsUtc: "2026-03-10T14:05:00.000Z", app: "Preview", title: "Q3-roadmap.pdf" },
179
- { tsUtc: "2026-03-10T14:30:00.000Z", app: "Zoom", text: "meeting chat" },
177
+ const activity: ActivitySnapshot[] = [
178
+ {
179
+ machine: "workstation",
180
+ capturedAtUtc: "2026-03-10T14:05:00.000Z",
181
+ app: "Preview",
182
+ windowTitle: "Q3-roadmap.pdf",
183
+ text: "",
184
+ textSource: "ax",
185
+ contentHash: "snap-1",
186
+ },
187
+ {
188
+ machine: "workstation",
189
+ capturedAtUtc: "2026-03-10T14:30:00.000Z",
190
+ app: "Zoom",
191
+ windowTitle: "",
192
+ text: "meeting chat",
193
+ textSource: "ax",
194
+ contentHash: "snap-2",
195
+ },
180
196
  ];
181
197
  const { builder: b, store } = builder(
182
198
  {
@@ -22,10 +22,10 @@ import type {
22
22
  MeetingMemoryOutcome,
23
23
  MeetingsDayFactGenResult,
24
24
  } from "./memory-generator.js";
25
+ import type { ActivitySnapshot } from "../activity/types.js";
25
26
  import type { FusionConversationInput } from "../wearables/fusion/types.js";
26
27
  import type {
27
28
  DetectedMeeting,
28
- MeetingActivitySnapshot,
29
29
  MeetingRecord,
30
30
  MeetingsConfig,
31
31
  MeetingsDetectionInput,
@@ -38,7 +38,7 @@ export interface MeetingDayData {
38
38
  /** Fusion conversation inputs across all wearable sources for the day. */
39
39
  conversations: FusionConversationInput[];
40
40
  /** Screen-activity snapshots for the day. */
41
- activity?: MeetingActivitySnapshot[];
41
+ activity?: ActivitySnapshot[];
42
42
  }
43
43
 
44
44
  /** Supplies a day's signals. Backed by fixtures in tests; by the activity +
@@ -127,7 +127,9 @@ test("loadDayData assembles detection + activity for the requested day, keyed to
127
127
  assert.equal(data.detection.appSpans[0]?.app, "Zoom");
128
128
  assert.deepEqual(data.detection.audioWindows, [], "no wearable transcripts → no audio windows");
129
129
  assert.equal(data.activity?.length, 2);
130
- assert.equal(data.activity?.[0]?.title, "Standup");
130
+ // Activity is the raw ActivitySnapshot list now — no rename mapper in between.
131
+ assert.equal(data.activity?.[0]?.windowTitle, "Standup");
132
+ assert.equal(data.activity?.[0]?.capturedAtUtc, "2026-03-10T14:00:00.000Z");
131
133
  assert.equal(data.conversations.length, 0);
132
134
  });
133
135
 
@@ -28,7 +28,6 @@ import type { FusionConversationInput, FusionSegmentInput } from "../wearables/f
28
28
  import type { MeetingDayData, MeetingsDaySource } from "./build.js";
29
29
  import { MeetingsInputError } from "./errors.js";
30
30
  import type {
31
- MeetingActivitySnapshot,
32
31
  MeetingAppSpan,
33
32
  MeetingAudioWindow,
34
33
  MeetingsConfig,
@@ -97,15 +96,6 @@ export function storageWearableDayReader(store: WearableDayTranscriptStore): Mee
97
96
  };
98
97
  }
99
98
 
100
- /** Map an activity snapshot to the redaction-safe screen snapshot fusion sees. */
101
- function toMeetingActivitySnapshot(snapshot: ActivitySnapshot): MeetingActivitySnapshot {
102
- const out: MeetingActivitySnapshot = { tsUtc: snapshot.capturedAtUtc, app: snapshot.app };
103
- if (snapshot.windowTitle.length > 0) out.title = snapshot.windowTitle;
104
- if (snapshot.browserUrl !== undefined && snapshot.browserUrl.length > 0) out.url = snapshot.browserUrl;
105
- if (snapshot.text.length > 0) out.text = snapshot.text;
106
- return out;
107
- }
108
-
109
99
  /**
110
100
  * Fallback dwell for a lone trailing meeting-app tick on a machine that
111
101
  * captured no other snapshot to estimate a cadence from. Five minutes keeps
@@ -341,12 +331,11 @@ export class ActivityWearablesMeetingsDaySource implements MeetingsDaySource {
341
331
  const snapshots = this.deps.activity
342
332
  ? await this.deps.activity.listSnapshotsForDay(null, startUtc, endUtc)
343
333
  : [];
344
- const activity = snapshots.map(toMeetingActivitySnapshot);
345
334
  const appSpans = deriveAppSpans(snapshots, this.deps.config.appPatterns);
346
335
  const bodies = await this.deps.wearables.readDayBodies(date);
347
336
  const tzBySource = new Map(bodies.map((b) => [b.source, b.timezone ?? ""] as const));
348
337
  const conversations = shiftFusionInputsToUtc(reconstructFusionInputs(date, bodies), tzBySource);
349
338
  const audioWindows = buildAudioWindows(conversations);
350
- return { detection: { date, appSpans, audioWindows }, conversations, activity };
339
+ return { detection: { date, appSpans, audioWindows }, conversations, activity: snapshots };
351
340
  }
352
341
  }
@@ -1,13 +1,12 @@
1
1
  import assert from "node:assert/strict";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
2
4
  import { test } from "node:test";
3
5
 
4
6
  import { DEFAULT_MEETINGS_CONFIG } from "./config.js";
5
7
  import { fuseMeeting } from "./fuse.js";
6
- import type {
7
- DetectedMeeting,
8
- MeetingActivitySnapshot,
9
- MeetingsConfig,
10
- } from "./types.js";
8
+ import type { ActivitySnapshot } from "../activity/types.js";
9
+ import type { DetectedMeeting, MeetingsConfig } from "./types.js";
11
10
  import type { FusionConversationInput, FusionSegmentInput } from "../wearables/fusion/types.js";
12
11
 
13
12
  const DATE = "2026-03-10";
@@ -51,8 +50,17 @@ function conv(
51
50
  return { source, conversationId: id, startIso, endIso, segments };
52
51
  }
53
52
 
54
- function snap(overrides: Partial<MeetingActivitySnapshot> & { tsUtc: string; app: string }): MeetingActivitySnapshot {
55
- return { ...overrides };
53
+ function snap(
54
+ overrides: Partial<ActivitySnapshot> & { capturedAtUtc: string; app: string },
55
+ ): ActivitySnapshot {
56
+ return {
57
+ machine: "workstation",
58
+ windowTitle: "",
59
+ text: "",
60
+ textSource: "ax",
61
+ contentHash: "snap-hash",
62
+ ...overrides,
63
+ };
56
64
  }
57
65
 
58
66
  test("fusion prefers the higher-trust source in overlap regions and records corroboratedBy without duplicating text", () => {
@@ -97,10 +105,10 @@ test("screen context includes a >=20s dwell and omits a 5s alt-tab; meeting-app
97
105
  ]),
98
106
  ],
99
107
  activity: [
100
- snap({ tsUtc: "2026-03-10T14:05:00.000Z", app: "Preview", title: "Q3-roadmap.pdf", text: "Q3 roadmap draft" }),
101
- snap({ tsUtc: "2026-03-10T14:05:25.000Z", app: "Notes", title: "scratch" }), // Preview dwell 25s → include; Notes starts
102
- snap({ tsUtc: "2026-03-10T14:05:30.000Z", app: "Preview", title: "Q3-roadmap.pdf" }), // Notes dwell 5s → exclude
103
- snap({ tsUtc: "2026-03-10T14:10:00.000Z", app: "Zoom", text: "Jane: agenda item one" }), // meeting-app → excerpt
108
+ snap({ capturedAtUtc: "2026-03-10T14:05:00.000Z", app: "Preview", windowTitle: "Q3-roadmap.pdf", text: "Q3 roadmap draft" }),
109
+ snap({ capturedAtUtc: "2026-03-10T14:05:25.000Z", app: "Notes", windowTitle: "scratch" }), // Preview dwell 25s → include; Notes starts
110
+ snap({ capturedAtUtc: "2026-03-10T14:05:30.000Z", app: "Preview", windowTitle: "Q3-roadmap.pdf" }), // Notes dwell 5s → exclude
111
+ snap({ capturedAtUtc: "2026-03-10T14:10:00.000Z", app: "Zoom", text: "Jane: agenda item one" }), // meeting-app → excerpt
104
112
  ],
105
113
  },
106
114
  config(),
@@ -122,9 +130,9 @@ test("context excerpts respect maxContextChars", () => {
122
130
  meeting: meeting(),
123
131
  conversations: [],
124
132
  activity: [
125
- snap({ tsUtc: "2026-03-10T14:01:00.000Z", app: "Zoom", text: "aaaa" }),
126
- snap({ tsUtc: "2026-03-10T14:02:00.000Z", app: "Zoom", text: "bbbb" }),
127
- snap({ tsUtc: "2026-03-10T14:03:00.000Z", app: "Zoom", text: "cccc" }),
133
+ snap({ capturedAtUtc: "2026-03-10T14:01:00.000Z", app: "Zoom", text: "aaaa" }),
134
+ snap({ capturedAtUtc: "2026-03-10T14:02:00.000Z", app: "Zoom", text: "bbbb" }),
135
+ snap({ capturedAtUtc: "2026-03-10T14:03:00.000Z", app: "Zoom", text: "cccc" }),
128
136
  ],
129
137
  },
130
138
  config({ maxContextChars: 8 }),
@@ -199,10 +207,51 @@ test("a lone trailing other-app snapshot is not inflated to the meeting end", ()
199
207
  ],
200
208
  // A single Notes snapshot 1 min before the window end. With no later
201
209
  // snapshot, the trailing run must NOT count dwell up to the meeting end.
202
- activity: [snap({ tsUtc: "2026-03-10T14:29:00.000Z", app: "Notes", title: "scratch" })],
210
+ activity: [snap({ capturedAtUtc: "2026-03-10T14:29:00.000Z", app: "Notes", windowTitle: "scratch" })],
203
211
  },
204
212
  config(),
205
213
  );
206
214
  assert.equal(fused.snapshotCount, 1);
207
215
  assert.deepEqual(fused.screenContext, [], "a lone trailing snapshot has zero observed dwell");
208
216
  });
217
+
218
+ test("fusion reads ActivitySnapshot fields — capturedAtUtc, browserUrl runs, windowTitle fallback", () => {
219
+ const fused = fuseMeeting(
220
+ {
221
+ meeting: meeting(),
222
+ conversations: [],
223
+ activity: [
224
+ snap({ capturedAtUtc: "2026-03-10T14:05:00.000Z", app: "Chrome", browserUrl: "https://github.com/org/repo/pull/1" }),
225
+ snap({ capturedAtUtc: "2026-03-10T14:06:00.000Z", app: "Chrome", browserUrl: "https://github.com/org/repo/pull/1" }),
226
+ // Different URL on the same app → a separate dwell run.
227
+ snap({ capturedAtUtc: "2026-03-10T14:06:30.000Z", app: "Chrome", browserUrl: "https://example.com/doc" }),
228
+ snap({ capturedAtUtc: "2026-03-10T14:07:00.000Z", app: "Chrome", browserUrl: "https://example.com/doc" }),
229
+ // Empty browserUrl falls back to the window title for key and label.
230
+ snap({ capturedAtUtc: "2026-03-10T14:07:30.000Z", app: "Chrome", windowTitle: "Spec v2" }),
231
+ snap({ capturedAtUtc: "2026-03-10T14:08:00.000Z", app: "Chrome", windowTitle: "Spec v2" }),
232
+ ],
233
+ },
234
+ config(),
235
+ );
236
+ assert.equal(fused.snapshotCount, 6);
237
+ assert.deepEqual(
238
+ fused.screenContext.map((e) => e.label),
239
+ [
240
+ "Chrome: github.com/org/repo/pull/1",
241
+ "Chrome: example.com/doc",
242
+ "Chrome: Spec v2",
243
+ ],
244
+ );
245
+ // Run dwell ends at the next different-key snapshot (90s, 60s) or, for the
246
+ // trailing run, at its own last snapshot (30s).
247
+ assert.deepEqual(fused.screenContext.map((e) => e.dwellSeconds), [90, 60, 30]);
248
+ });
249
+
250
+ test("MeetingActivitySnapshot and its rename mapper are gone", () => {
251
+ const here = import.meta.dirname;
252
+ for (const file of ["types.ts", "fuse.ts", "day-source.ts", "build.ts"]) {
253
+ const src = readFileSync(join(here, file), "utf8");
254
+ assert.ok(!src.includes("MeetingActivitySnapshot"), `${file} must not reference MeetingActivitySnapshot`);
255
+ assert.ok(!src.includes("toMeetingActivitySnapshot"), `${file} must not reference toMeetingActivitySnapshot`);
256
+ }
257
+ });
@@ -23,9 +23,9 @@ import type {
23
23
  FusionConversationInput,
24
24
  FusionSegmentInput,
25
25
  } from "../wearables/fusion/types.js";
26
+ import type { ActivitySnapshot } from "../activity/types.js";
26
27
  import type {
27
28
  FusedMeeting,
28
- MeetingActivitySnapshot,
29
29
  MeetingBuildInput,
30
30
  MeetingScreenContextEvent,
31
31
  MeetingsConfig,
@@ -119,20 +119,22 @@ function shortenUrl(url: string): string {
119
119
  return url.replace(/^[a-z]+:\/\//i, "");
120
120
  }
121
121
 
122
- function contextLabel(snap: MeetingActivitySnapshot): string {
123
- if (snap.url !== undefined && snap.url.length > 0) return `${snap.app}: ${shortenUrl(snap.url)}`;
124
- if (snap.title !== undefined && snap.title.length > 0) return `${snap.app}: ${snap.title}`;
122
+ function contextLabel(snap: ActivitySnapshot): string {
123
+ if (snap.browserUrl !== undefined && snap.browserUrl.length > 0) {
124
+ return `${snap.app}: ${shortenUrl(snap.browserUrl)}`;
125
+ }
126
+ if (snap.windowTitle.length > 0) return `${snap.app}: ${snap.windowTitle}`;
125
127
  return snap.app;
126
128
  }
127
129
 
128
130
  /** True when a snapshot is the meeting app itself (captions/chat/participants),
129
131
  * not other context. Matches the meeting's app or any configured app pattern. */
130
132
  function isMeetingAppSnapshot(
131
- snap: MeetingActivitySnapshot,
133
+ snap: ActivitySnapshot,
132
134
  meetingApp: string | undefined,
133
135
  appPatterns: readonly string[],
134
136
  ): boolean {
135
- const hay = `${snap.app} ${snap.title ?? ""} ${snap.url ?? ""}`.toLowerCase();
137
+ const hay = `${snap.app} ${snap.windowTitle} ${snap.browserUrl ?? ""}`.toLowerCase();
136
138
  if (meetingApp !== undefined && meetingApp.length > 0 && hay.includes(meetingApp.toLowerCase())) {
137
139
  return true;
138
140
  }
@@ -159,21 +161,25 @@ interface ScreenContextResult {
159
161
  * kept. Meeting-app snapshots never enter the timeline but feed excerpts.
160
162
  */
161
163
  function buildScreenContext(
162
- activity: readonly MeetingActivitySnapshot[],
164
+ activity: readonly ActivitySnapshot[],
163
165
  windowStartMs: number,
164
166
  windowEndMs: number,
165
167
  meetingApp: string | undefined,
166
168
  config: MeetingsConfig,
167
169
  ): ScreenContextResult {
168
170
  const win = activity
169
- .map((snap) => ({ snap, ms: Date.parse(snap.tsUtc) }))
171
+ .map((snap) => ({ snap, ms: Date.parse(snap.capturedAtUtc) }))
170
172
  .filter((entry) => Number.isFinite(entry.ms) && entry.ms >= windowStartMs && entry.ms < windowEndMs)
171
173
  .sort((a, b) => a.ms - b.ms || SORT_STR(a.snap.app, b.snap.app));
172
174
 
173
- const keyOf = (snap: MeetingActivitySnapshot): string =>
175
+ /** Run key detail: the URL when present, else the window title. */
176
+ const keyDetail = (snap: ActivitySnapshot): string =>
177
+ snap.browserUrl !== undefined && snap.browserUrl.length > 0 ? snap.browserUrl : snap.windowTitle;
178
+
179
+ const keyOf = (snap: ActivitySnapshot): string =>
174
180
  isMeetingAppSnapshot(snap, meetingApp, config.appPatterns)
175
181
  ? MEETING_APP_KEY
176
- : `${snap.app}\u0000${snap.url ?? snap.title ?? ""}`;
182
+ : `${snap.app}\u0000${keyDetail(snap)}`;
177
183
 
178
184
  const events: MeetingScreenContextEvent[] = [];
179
185
  const includedText: string[] = [];
@@ -197,7 +203,7 @@ function buildScreenContext(
197
203
  // Captions / chat / participant text visible on the meeting app itself.
198
204
  for (let i = runStartIdx; i < runEndIdx; i++) {
199
205
  const text = win[i]!.snap.text;
200
- if (text !== undefined && text.trim().length > 0) includedText.push(text.trim());
206
+ if (text.trim().length > 0) includedText.push(text.trim());
201
207
  }
202
208
  } else if (dwellSeconds >= config.contextDwellSeconds) {
203
209
  events.push({
@@ -209,7 +215,7 @@ function buildScreenContext(
209
215
  });
210
216
  for (let i = runStartIdx; i < runEndIdx; i++) {
211
217
  const text = win[i]!.snap.text;
212
- if (text !== undefined && text.trim().length > 0) includedText.push(text.trim());
218
+ if (text.trim().length > 0) includedText.push(text.trim());
213
219
  }
214
220
  }
215
221
  runStartIdx = runEndIdx;
@@ -8,6 +8,7 @@
8
8
  * timestamps are UTC ISO-8601; windows are half-open [startUtc, endUtc).
9
9
  */
10
10
 
11
+ import type { ActivitySnapshot } from "../activity/types.js";
11
12
  import type {
12
13
  FusedSegment,
13
14
  FusedSpeaker,
@@ -81,23 +82,6 @@ export interface MeetingsDetectionConfig {
81
82
  mergeGapMinutes: number;
82
83
  }
83
84
 
84
- /**
85
- * One screen-activity snapshot fed into meeting fusion (assembled from the
86
- * activity store by a later wiring slice; injected directly in tests). Text is
87
- * already post-redaction — meeting fusion never sees raw capture.
88
- */
89
- export interface MeetingActivitySnapshot {
90
- /** ISO 8601 UTC instant the snapshot was captured. */
91
- tsUtc: string;
92
- /** Foreground application label (e.g. "Preview", "Chrome", "Zoom"). */
93
- app: string;
94
- /** Window title, when known. */
95
- title?: string;
96
- /** Browser URL, when known. */
97
- url?: string;
98
- /** Extracted on-screen text excerpt, when known. */
99
- text?: string;
100
- }
101
85
 
102
86
  /** One entry in a meeting's screen-context timeline (an other-app dwell). */
103
87
  export interface MeetingScreenContextEvent {
@@ -144,8 +128,9 @@ export interface MeetingBuildInput {
144
128
  * is fine (they are clipped in `fuseMeeting`).
145
129
  */
146
130
  conversations: FusionConversationInput[];
147
- /** Day screen-activity snapshots (filtered to the window in `fuseMeeting`). */
148
- activity?: MeetingActivitySnapshot[];
131
+ /** Day screen-activity snapshots (filtered to the window in `fuseMeeting`).
132
+ * Already post-redaction — meeting fusion never sees raw capture. */
133
+ activity?: ActivitySnapshot[];
149
134
  }
150
135
 
151
136
  /** The fused, screen-aware view of a meeting produced by `fuseMeeting`. */
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Issue #2481 — the derived cache layers (episode map, rule memories) share
3
+ * one getVersionedCacheEntry read gate with the hot layer. These pin the
4
+ * per-layer contracts that must keep holding after that dedup: version-keyed
5
+ * round-trip, version-mismatch miss, keyId mismatch miss, and TTL expiry
6
+ * miss on EACH layer. (Hot-layer equivalents live in memory-cache-hot.test.ts.)
7
+ */
8
+
9
+ import assert from "node:assert/strict";
10
+ import test from "node:test";
11
+
12
+ import {
13
+ clearMemoryCache,
14
+ getCachedEpisodeMap,
15
+ getCachedRuleMemories,
16
+ setCachedEpisodeMap,
17
+ setCachedRuleMemories,
18
+ } from "./memory-cache.js";
19
+ import type { MemoryFile } from "./types.js";
20
+
21
+ function mem(path: string, id: string, category = "fact", memoryKind?: string): MemoryFile {
22
+ return {
23
+ path,
24
+ frontmatter: { id, category, ...(memoryKind ? { memoryKind } : {}) },
25
+ content: "x",
26
+ } as unknown as MemoryFile;
27
+ }
28
+
29
+ const EPISODE = mem("a.md", "ep-1", "fact", "episode");
30
+
31
+ test("episode map: matching version hits; version or keyId mismatch misses", () => {
32
+ const dir = "/tmp/remnic-derived-ep-ver";
33
+ clearMemoryCache();
34
+ setCachedEpisodeMap(dir, [EPISODE], 7, true, "key:1");
35
+ const got = getCachedEpisodeMap(dir, 7, "key:1");
36
+ assert.ok(got, "expected a hit at the matching version and keyId");
37
+ assert.deepEqual([...got.keys()], ["ep-1"]);
38
+ assert.equal(getCachedEpisodeMap(dir, 8, "key:1"), null, "a bumped version must miss");
39
+ assert.equal(getCachedEpisodeMap(dir, 7, "key:2"), null, "a mismatched keyId must miss");
40
+ clearMemoryCache();
41
+ });
42
+
43
+ test("episode map: TTL expiry misses; ttl=0 disables expiry", (t) => {
44
+ const dir = "/tmp/remnic-derived-ep-ttl";
45
+ clearMemoryCache();
46
+ t.mock.timers.enable({ apis: ["Date"] });
47
+ try {
48
+ setCachedEpisodeMap(dir, [EPISODE], 9);
49
+ assert.ok(getCachedEpisodeMap(dir, 9, "", 60_000), "fresh entry within TTL hits");
50
+ t.mock.timers.tick(120_000);
51
+ assert.equal(getCachedEpisodeMap(dir, 9, "", 60_000), null, "entry older than ttl is a miss");
52
+ setCachedEpisodeMap(dir, [EPISODE], 9);
53
+ t.mock.timers.tick(600_000);
54
+ assert.ok(getCachedEpisodeMap(dir, 9, "", 0), "ttl=0 disables expiry");
55
+ } finally {
56
+ t.mock.timers.reset();
57
+ clearMemoryCache();
58
+ }
59
+ });
60
+
61
+ test("rule memories: matching version hits; version or keyId mismatch misses", () => {
62
+ const dir = "/tmp/remnic-derived-rule-ver";
63
+ clearMemoryCache();
64
+ setCachedRuleMemories(dir, [mem("r.md", "r-1", "rule"), mem("f.md", "f-1", "fact")], 7, true, "key:1");
65
+ const got = getCachedRuleMemories(dir, 7, "key:1");
66
+ assert.ok(got, "expected a hit at the matching version and keyId");
67
+ assert.deepEqual(got.all.map((m) => m.frontmatter.id), ["r-1"], "only rule-category memories in all");
68
+ assert.ok(got.byId.has("f-1"), "byId indexes every memory");
69
+ assert.equal(getCachedRuleMemories(dir, 8, "key:1"), null, "a bumped version must miss");
70
+ assert.equal(getCachedRuleMemories(dir, 7, "key:2"), null, "a mismatched keyId must miss");
71
+ clearMemoryCache();
72
+ });
73
+
74
+ test("rule memories: TTL expiry misses; ttl=0 disables expiry", (t) => {
75
+ const dir = "/tmp/remnic-derived-rule-ttl";
76
+ clearMemoryCache();
77
+ t.mock.timers.enable({ apis: ["Date"] });
78
+ try {
79
+ setCachedRuleMemories(dir, [mem("r.md", "r-1", "rule")], 9);
80
+ assert.ok(getCachedRuleMemories(dir, 9, "", 60_000), "fresh entry within TTL hits");
81
+ t.mock.timers.tick(120_000);
82
+ assert.equal(getCachedRuleMemories(dir, 9, "", 60_000), null, "entry older than ttl is a miss");
83
+ setCachedRuleMemories(dir, [mem("r.md", "r-1", "rule")], 9);
84
+ t.mock.timers.tick(600_000);
85
+ assert.ok(getCachedRuleMemories(dir, 9, "", 0), "ttl=0 disables expiry");
86
+ } finally {
87
+ t.mock.timers.reset();
88
+ clearMemoryCache();
89
+ }
90
+ });