@remnic/core 9.22.0 → 9.22.2

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 (402) hide show
  1. package/dist/access-admin-ops-surface.d.ts +15 -12
  2. package/dist/access-admin-ops-surface.js +25 -24
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-boundary.d.ts +13 -10
  5. package/dist/access-boundary.js +25 -24
  6. package/dist/access-cli.js +84 -82
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-http.d.ts +16 -9
  9. package/dist/access-http.js +33 -32
  10. package/dist/access-identity-continuity-surface.d.ts +9 -7
  11. package/dist/access-identity-continuity-surface.js +25 -24
  12. package/dist/access-lcm-surface.d.ts +12 -9
  13. package/dist/access-lcm-surface.js +25 -24
  14. package/dist/access-mcp-output-schemas.js +1 -1
  15. package/dist/access-mcp.d.ts +22 -10
  16. package/dist/access-mcp.js +31 -30
  17. package/dist/access-memory-search-fanout.d.ts +2 -2
  18. package/dist/{access-namespace-preflight-tmwQgCT6.d.ts → access-namespace-preflight-CmErR03h.d.ts} +1 -1
  19. package/dist/access-namespace-preflight.d.ts +3 -3
  20. package/dist/access-namespace-preflight.js +25 -24
  21. package/dist/access-observe-write-surface.d.ts +12 -9
  22. package/dist/access-observe-write-surface.js +25 -24
  23. package/dist/access-operations-batch.js +27 -26
  24. package/dist/access-operations.d.ts +16 -13
  25. package/dist/access-operations.js +28 -27
  26. package/dist/access-recall-concurrency.d.ts +12 -9
  27. package/dist/access-recall-concurrency.js +25 -24
  28. package/dist/access-recall-response.d.ts +12 -9
  29. package/dist/access-recall-response.js +25 -24
  30. package/dist/access-recall-surface.d.ts +14 -11
  31. package/dist/access-recall-surface.js +25 -24
  32. package/dist/access-schema.d.ts +76 -76
  33. package/dist/{access-service-BtxW52vv.d.ts → access-service-CKEROeFP.d.ts} +22 -11
  34. package/dist/access-service.d.ts +13 -10
  35. package/dist/access-service.js +25 -24
  36. package/dist/access-surface-catalog.d.ts +12 -9
  37. package/dist/access-surface-catalog.js +6 -0
  38. package/dist/access-surface-catalog.js.map +1 -1
  39. package/dist/access-wearables-meetings-surface.d.ts +78 -0
  40. package/dist/access-wearables-meetings-surface.js +22 -0
  41. package/dist/access-wearables-meetings-surface.js.map +1 -0
  42. package/dist/action-confidence.d.ts +1 -1
  43. package/dist/active-memory-bridge.d.ts +1 -1
  44. package/dist/active-recall.d.ts +1 -1
  45. package/dist/active-recall.js +2 -2
  46. package/dist/{auto-sync-UPTUVE4X.js → auto-sync-5OE5QOZB.js} +3 -3
  47. package/dist/behavior-learner.d.ts +1 -1
  48. package/dist/behavior-signals.d.ts +1 -1
  49. package/dist/bootstrap.d.ts +9 -7
  50. package/dist/briefing.d.ts +2 -2
  51. package/dist/briefing.js +5 -5
  52. package/dist/buffer-surprise-report.d.ts +1 -1
  53. package/dist/buffer.d.ts +2 -2
  54. package/dist/bulk-import/index.d.ts +3 -3
  55. package/dist/calibration.d.ts +1 -1
  56. package/dist/capabilities.d.ts +1 -1
  57. package/dist/{catalog-iWvWz61I.d.ts → catalog-BFTVo2Ez.d.ts} +1 -1
  58. package/dist/causal-behavior.d.ts +1 -1
  59. package/dist/causal-behavior.js +2 -2
  60. package/dist/causal-chain.js +2 -2
  61. package/dist/causal-consolidation.d.ts +1 -1
  62. package/dist/causal-consolidation.js +9 -9
  63. package/dist/causal-retrieval.js +2 -2
  64. package/dist/causal-trajectory-graph.d.ts +1 -1
  65. package/dist/causal-trajectory.js +1 -1
  66. package/dist/{chunk-GF22HWS2.js → chunk-2PHX3I5C.js} +7 -7
  67. package/dist/{chunk-JFDEYXF7.js → chunk-3NAHZQU3.js} +2 -2
  68. package/dist/{chunk-XBRPEGXF.js → chunk-3UOSVTFR.js} +5 -5
  69. package/dist/{chunk-TTKWTT72.js → chunk-3ZW6ZQO6.js} +3 -3
  70. package/dist/{chunk-UV72DEZD.js → chunk-4B77XSG5.js} +5 -5
  71. package/dist/{chunk-IC2TCZJ2.js → chunk-57QKLRBV.js} +3 -1
  72. package/dist/chunk-57QKLRBV.js.map +1 -0
  73. package/dist/{chunk-LMHDFOVV.js → chunk-5CPI2QWG.js} +3 -3
  74. package/dist/{chunk-P72WZMWQ.js → chunk-5FZQ74K5.js} +2 -2
  75. package/dist/{chunk-BRT7KEXU.js → chunk-6TWXQ4E2.js} +5 -5
  76. package/dist/{chunk-CV6ZYXK3.js → chunk-7I7AYIUQ.js} +3 -3
  77. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  78. package/dist/{chunk-MONWCSVL.js → chunk-7RAJ3GXO.js} +2 -1
  79. package/dist/chunk-7RAJ3GXO.js.map +1 -0
  80. package/dist/{chunk-SQEDDWAM.js → chunk-A2RFKL3V.js} +5 -34
  81. package/dist/chunk-A2RFKL3V.js.map +1 -0
  82. package/dist/{chunk-JN57HZCD.js → chunk-ATEAL5EI.js} +6 -6
  83. package/dist/{chunk-4PYLBXX6.js → chunk-AYAROCWD.js} +2 -2
  84. package/dist/chunk-BLDBT6HZ.js +39 -0
  85. package/dist/chunk-BLDBT6HZ.js.map +1 -0
  86. package/dist/{chunk-NB2P47N7.js → chunk-CUUY5CC4.js} +6 -6
  87. package/dist/{chunk-KL5Y6PEV.js → chunk-E3ZMFFQZ.js} +2 -2
  88. package/dist/{chunk-55FDQYPS.js → chunk-ES5IHQ6M.js} +2 -2
  89. package/dist/{chunk-N47ZWQBO.js → chunk-G2NSSQES.js} +2 -2
  90. package/dist/{chunk-GSWPU5CR.js → chunk-GD3QOBMB.js} +2 -2
  91. package/dist/{chunk-6ANPNUVL.js → chunk-IIXLB5E7.js} +58 -36
  92. package/dist/chunk-IIXLB5E7.js.map +1 -0
  93. package/dist/{chunk-SACPRJ7F.js → chunk-JNIJBXVK.js} +2 -2
  94. package/dist/{chunk-W3XT32W7.js → chunk-JVGUY2AU.js} +23 -13
  95. package/dist/chunk-JVGUY2AU.js.map +1 -0
  96. package/dist/{chunk-DGLON3AL.js → chunk-KNRG6ZGJ.js} +6 -6
  97. package/dist/{chunk-GEUDRENF.js → chunk-MMTG3SCJ.js} +2 -2
  98. package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
  99. package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
  100. package/dist/{chunk-QTO2FGBT.js → chunk-OUW4PAY4.js} +191 -117
  101. package/dist/chunk-OUW4PAY4.js.map +1 -0
  102. package/dist/{chunk-KQ2XCQYN.js → chunk-P2BLHUL2.js} +2 -2
  103. package/dist/{chunk-ACGGTPU4.js → chunk-QCKQEBIY.js} +17 -9
  104. package/dist/chunk-QCKQEBIY.js.map +1 -0
  105. package/dist/{chunk-6L775BUB.js → chunk-QE63OHLB.js} +2 -2
  106. package/dist/{chunk-ONHRRJZM.js → chunk-QJAQNXWI.js} +6 -6
  107. package/dist/{chunk-EQYBHXRR.js → chunk-ROUL7RZU.js} +385 -59
  108. package/dist/chunk-ROUL7RZU.js.map +1 -0
  109. package/dist/{chunk-N6M7MRVN.js → chunk-RT4TSR2C.js} +9034 -8726
  110. package/dist/chunk-RT4TSR2C.js.map +1 -0
  111. package/dist/{chunk-6NZ7U4R4.js → chunk-SCOT5DTA.js} +1 -1
  112. package/dist/chunk-SCOT5DTA.js.map +1 -0
  113. package/dist/{chunk-6RYWNBSA.js → chunk-SVZGA2MK.js} +2 -2
  114. package/dist/chunk-SYOIVK7K.js +63 -0
  115. package/dist/chunk-SYOIVK7K.js.map +1 -0
  116. package/dist/{chunk-DM5A4ZFL.js → chunk-TWCOYET2.js} +11 -1
  117. package/dist/chunk-TWCOYET2.js.map +1 -0
  118. package/dist/{chunk-7S5OMI76.js → chunk-WS32QRLO.js} +109 -44
  119. package/dist/chunk-WS32QRLO.js.map +1 -0
  120. package/dist/{chunk-OCMLGND7.js → chunk-WWZ35GWW.js} +5 -5
  121. package/dist/{chunk-QMGIQUBG.js → chunk-XWPFZX6S.js} +503 -139
  122. package/dist/chunk-XWPFZX6S.js.map +1 -0
  123. package/dist/{chunk-A5N6ISRK.js → chunk-ZN4UZWMT.js} +2 -2
  124. package/dist/{chunk-7M6APKJL.js → chunk-ZYU7ZFLT.js} +2 -2
  125. package/dist/{cli-D9vXgWwM.d.ts → cli-BrwT9YMD.d.ts} +5 -5
  126. package/dist/cli.d.ts +14 -11
  127. package/dist/cli.js +57 -56
  128. package/dist/compounding/engine.d.ts +2 -2
  129. package/dist/compounding/engine.js +5 -5
  130. package/dist/compounding/preference-consolidator.d.ts +1 -1
  131. package/dist/compression-optimizer.d.ts +1 -1
  132. package/dist/config.d.ts +1 -1
  133. package/dist/config.js +2 -2
  134. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  135. package/dist/connectors/codex-materialize-runner.js +5 -5
  136. package/dist/connectors/codex-materialize.d.ts +1 -1
  137. package/dist/connectors/index.d.ts +1 -1
  138. package/dist/connectors/index.js +5 -5
  139. package/dist/consolidation-provenance-check.d.ts +2 -2
  140. package/dist/consolidation-undo.d.ts +2 -2
  141. package/dist/contradiction/index.d.ts +2 -2
  142. package/dist/conversation-index/backend.d.ts +1 -1
  143. package/dist/conversation-index/chunker.d.ts +1 -1
  144. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  145. package/dist/conversation-index/indexer.d.ts +1 -1
  146. package/dist/conversation-index/search.d.ts +1 -1
  147. package/dist/day-summary.d.ts +1 -1
  148. package/dist/delinearize.d.ts +1 -1
  149. package/dist/direct-answer-wiring.d.ts +1 -1
  150. package/dist/direct-answer.d.ts +1 -1
  151. package/dist/embedding-fallback.d.ts +1 -1
  152. package/dist/enrichment/index.d.ts +1 -1
  153. package/dist/entity-retrieval.d.ts +2 -2
  154. package/dist/entity-retrieval.js +5 -5
  155. package/dist/entity-schema.d.ts +1 -1
  156. package/dist/explicit-capture.d.ts +9 -7
  157. package/dist/extraction-error-classification.d.ts +22 -0
  158. package/dist/extraction-error-classification.js +11 -0
  159. package/dist/extraction-error-classification.js.map +1 -0
  160. package/dist/extraction-faithfulness.d.ts +1 -1
  161. package/dist/extraction-judge-telemetry.d.ts +1 -1
  162. package/dist/extraction-judge-training.d.ts +1 -1
  163. package/dist/extraction-judge.d.ts +1 -1
  164. package/dist/extraction.d.ts +3 -17
  165. package/dist/extraction.js +5 -3
  166. package/dist/fallback-llm.d.ts +1 -1
  167. package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
  168. package/dist/graph-dashboard-diff.d.ts +1 -1
  169. package/dist/graph-dashboard-key.d.ts +1 -1
  170. package/dist/graph-dashboard-parser.d.ts +1 -1
  171. package/dist/graph-edge-reinforcement.d.ts +1 -1
  172. package/dist/graph-snapshot.d.ts +1 -1
  173. package/dist/graph.d.ts +1 -1
  174. package/dist/importance.d.ts +1 -1
  175. package/dist/importers/index.d.ts +1 -1
  176. package/dist/in-flight-reads.d.ts +1 -1
  177. package/dist/index.d.ts +713 -923
  178. package/dist/index.js +176 -140
  179. package/dist/intent.d.ts +1 -1
  180. package/dist/lcm/engine.d.ts +1 -1
  181. package/dist/lcm/engine.js +3 -3
  182. package/dist/lcm/index.d.ts +1 -1
  183. package/dist/lcm/index.js +11 -11
  184. package/dist/lcm/tools.d.ts +1 -1
  185. package/dist/lifecycle.d.ts +1 -1
  186. package/dist/live-connectors-runner.d.ts +1 -1
  187. package/dist/local-llm.d.ts +1 -1
  188. package/dist/local-model-endpoint.d.ts +1 -1
  189. package/dist/maintenance/memory-governance.d.ts +1 -1
  190. package/dist/maintenance/memory-governance.js +6 -6
  191. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  192. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  193. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  194. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  195. package/dist/maintenance-C98njYb8.d.ts +366 -0
  196. package/dist/mcp-memory-inspector-app.d.ts +12 -9
  197. package/dist/mcp-read-only-tools.js +1 -1
  198. package/dist/memory-action-policy.d.ts +1 -1
  199. package/dist/memory-cache.d.ts +1 -1
  200. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  201. package/dist/memory-projection-store.d.ts +1 -1
  202. package/dist/memory-provenance.d.ts +1 -1
  203. package/dist/memory-worth-outcomes.d.ts +2 -2
  204. package/dist/models-json.d.ts +1 -1
  205. package/dist/namespaces/migrate.d.ts +3 -3
  206. package/dist/namespaces/migrate.js +12 -12
  207. package/dist/namespaces/principal.d.ts +1 -1
  208. package/dist/namespaces/search.d.ts +1 -1
  209. package/dist/namespaces/search.js +6 -6
  210. package/dist/namespaces/storage.d.ts +3 -3
  211. package/dist/namespaces/storage.js +5 -5
  212. package/dist/native-knowledge.d.ts +1 -1
  213. package/dist/offline-sync-impression-drain.d.ts +1 -1
  214. package/dist/operator-toolkit.d.ts +2 -2
  215. package/dist/operator-toolkit.js +18 -18
  216. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  217. package/dist/orchestration/maintenance.d.ts +6 -223
  218. package/dist/orchestration/maintenance.js +12 -12
  219. package/dist/{orchestrator-DB93S48I.d.ts → orchestrator-C9ZVppNh.d.ts} +12 -481
  220. package/dist/orchestrator.d.ts +10 -8
  221. package/dist/orchestrator.js +84 -82
  222. package/dist/patterns-cli.d.ts +1 -1
  223. package/dist/{pipeline-DmGc-H66.d.ts → pipeline-id_-sqYm.d.ts} +1 -1
  224. package/dist/policy-runtime.d.ts +1 -1
  225. package/dist/proactive-contention.d.ts +1 -1
  226. package/dist/provenance.d.ts +1 -1
  227. package/dist/{qmd-cJT0crkF.d.ts → qmd-R6XaQOZK.d.ts} +1 -1
  228. package/dist/qmd-preflight.d.ts +2 -2
  229. package/dist/qmd-recall-cache.d.ts +1 -1
  230. package/dist/qmd.d.ts +2 -2
  231. package/dist/qmd.js +4 -4
  232. package/dist/recall-concurrency-config.d.ts +1 -1
  233. package/dist/recall-disclosure-escalation.d.ts +1 -1
  234. package/dist/recall-explain-renderer.d.ts +1 -1
  235. package/dist/recall-explain-renderer.js +3 -3
  236. package/dist/recall-memory-map.d.ts +1 -1
  237. package/dist/recall-planner-llm.d.ts +1 -1
  238. package/dist/recall-state.d.ts +1 -1
  239. package/dist/recall-tag-filter.d.ts +1 -1
  240. package/dist/recall-timings.d.ts +1 -1
  241. package/dist/recall-xray-cli.d.ts +1 -1
  242. package/dist/recall-xray-cli.js +4 -4
  243. package/dist/recall-xray-renderer.d.ts +1 -1
  244. package/dist/recall-xray-renderer.js +3 -3
  245. package/dist/recall-xray.d.ts +1 -1
  246. package/dist/recall-xray.js +2 -2
  247. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  248. package/dist/replay/normalizers/claude.d.ts +1 -1
  249. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  250. package/dist/replay/normalizers/shared.d.ts +1 -1
  251. package/dist/replay/runner.d.ts +1 -1
  252. package/dist/replay/types.d.ts +1 -1
  253. package/dist/resolve-auth-token.d.ts +1 -1
  254. package/dist/resume-bundles.js +4 -4
  255. package/dist/retrieval-agents.d.ts +2 -2
  256. package/dist/retrieval-tiers.d.ts +1 -1
  257. package/dist/routing/engine.d.ts +1 -1
  258. package/dist/routing/store.d.ts +1 -1
  259. package/dist/salvage-envelope.d.ts +1 -1
  260. package/dist/schemas.d.ts +76 -76
  261. package/dist/{scope-profiles-KG2nODX7.d.ts → scope-profiles-EhyuAKkd.d.ts} +1 -1
  262. package/dist/search/embed-helper.d.ts +1 -1
  263. package/dist/search/factory.d.ts +1 -1
  264. package/dist/search/factory.js +5 -5
  265. package/dist/search/index.d.ts +1 -1
  266. package/dist/search/index.js +9 -9
  267. package/dist/search/lancedb-backend.d.ts +1 -1
  268. package/dist/search/meilisearch-backend.d.ts +1 -1
  269. package/dist/search/noop-backend.d.ts +1 -1
  270. package/dist/search/orama-backend.d.ts +1 -1
  271. package/dist/search/port.d.ts +1 -1
  272. package/dist/search/remote-backend.d.ts +1 -1
  273. package/dist/{semantic-consolidation-BaZlg0D8.d.ts → semantic-consolidation-B2xo26UQ.d.ts} +1 -1
  274. package/dist/semantic-consolidation.d.ts +2 -2
  275. package/dist/semantic-consolidation.js +7 -7
  276. package/dist/semantic-rule-promotion.js +5 -5
  277. package/dist/semantic-rule-verifier.d.ts +1 -1
  278. package/dist/semantic-rule-verifier.js +6 -6
  279. package/dist/service-DgFWlZ-r.d.ts +835 -0
  280. package/dist/session-observer-bands.d.ts +1 -1
  281. package/dist/session-observer-state.d.ts +1 -1
  282. package/dist/shared-context/manager.d.ts +9 -9
  283. package/dist/signal.d.ts +1 -1
  284. package/dist/{storage-BKhHHnRo.d.ts → storage-XGawwqXE.d.ts} +131 -2
  285. package/dist/storage.d.ts +2 -2
  286. package/dist/storage.js +4 -4
  287. package/dist/summarizer.d.ts +1 -1
  288. package/dist/summary-snapshot.d.ts +1 -1
  289. package/dist/temporal-supersession.d.ts +2 -2
  290. package/dist/temporal-timeline-recall.d.ts +1 -1
  291. package/dist/temporal-validity.d.ts +1 -1
  292. package/dist/threading.d.ts +1 -1
  293. package/dist/tier-migration.d.ts +2 -2
  294. package/dist/tier-routing.d.ts +1 -1
  295. package/dist/topics.d.ts +1 -1
  296. package/dist/transcript.d.ts +1 -1
  297. package/dist/transfer/types.d.ts +66 -66
  298. package/dist/trust-score-stage.d.ts +1 -1
  299. package/dist/trust-score.d.ts +1 -1
  300. package/dist/{types-GBQZuT7l.d.ts → types-Bbs0qz6b.d.ts} +2 -3
  301. package/dist/types.d.ts +1 -1
  302. package/dist/types.js +1 -1
  303. package/dist/utility-runtime.d.ts +1 -1
  304. package/dist/verified-recall.js +6 -6
  305. package/dist/write-envelope.d.ts +1 -1
  306. package/package.json +2 -2
  307. package/src/access-boundary.ts +3 -0
  308. package/src/access-http.test.ts +63 -0
  309. package/src/access-http.ts +26 -37
  310. package/src/access-mcp-output-schemas.ts +10 -0
  311. package/src/access-mcp.ts +4 -121
  312. package/src/access-operations-batch.ts +10 -5
  313. package/src/access-service.ts +43 -46
  314. package/src/access-surface-catalog.ts +6 -0
  315. package/src/access-wearables-meetings-surface.ts +139 -0
  316. package/src/activity/digest.ts +1 -1
  317. package/src/activity/runner.test.ts +37 -0
  318. package/src/activity/runner.ts +12 -0
  319. package/src/activity/scheduler.test.ts +1 -0
  320. package/src/activity/sync-registration.ts +13 -0
  321. package/src/cli/meetings-commands.ts +70 -0
  322. package/src/cli.ts +7 -6
  323. package/src/extraction-error-classification.ts +52 -0
  324. package/src/extraction.ts +2 -50
  325. package/src/mcp-read-only-tools.ts +2 -0
  326. package/src/meetings/build-memory.test.ts +364 -0
  327. package/src/meetings/build-scheduler.test.ts +55 -0
  328. package/src/meetings/build-scheduler.ts +96 -0
  329. package/src/meetings/day-source.test.ts +275 -0
  330. package/src/meetings/day-source.ts +352 -0
  331. package/src/meetings/http-glue.ts +126 -0
  332. package/src/meetings/index.ts +5 -4
  333. package/src/meetings/manual-sync-flush.test.ts +72 -0
  334. package/src/meetings/mcp-tools.ts +65 -0
  335. package/src/meetings/memory-gen.test.ts +498 -0
  336. package/src/meetings/memory-gen.ts +549 -0
  337. package/src/meetings/memory-generator.ts +5 -0
  338. package/src/meetings/namespace-isolation.test.ts +159 -0
  339. package/src/meetings/service.test.ts +195 -0
  340. package/src/meetings/service.ts +157 -0
  341. package/src/meetings/summary-extractor.test.ts +287 -0
  342. package/src/meetings/summary-extractor.ts +264 -0
  343. package/src/orchestration/maintenance.ts +8 -0
  344. package/src/orchestration/orchestrator-init.ts +6 -1
  345. package/src/orchestration/workspace-ops.ts +172 -8
  346. package/src/orchestrator.ts +12 -13
  347. package/src/storage.ts +21 -0
  348. package/src/testing/subjects/meetings-namespace-harness.ts +159 -0
  349. package/src/testing/subjects/meetings-namespace.test.ts +93 -0
  350. package/src/types.ts +1 -2
  351. package/src/wearables/cli.ts +2 -1
  352. package/src/wearables/index.ts +1 -0
  353. package/src/wearables/mcp-tools.ts +143 -0
  354. package/src/wearables/registry.test.ts +11 -0
  355. package/src/wearables/registry.ts +13 -0
  356. package/src/wearables/service.test.ts +62 -1
  357. package/src/wearables/service.ts +30 -2
  358. package/src/wearables/transcript-search-namespace-isolation.test.ts +98 -0
  359. package/dist/chunk-6ANPNUVL.js.map +0 -1
  360. package/dist/chunk-6NZ7U4R4.js.map +0 -1
  361. package/dist/chunk-7S5OMI76.js.map +0 -1
  362. package/dist/chunk-ACGGTPU4.js.map +0 -1
  363. package/dist/chunk-DM5A4ZFL.js.map +0 -1
  364. package/dist/chunk-EQYBHXRR.js.map +0 -1
  365. package/dist/chunk-IC2TCZJ2.js.map +0 -1
  366. package/dist/chunk-MONWCSVL.js.map +0 -1
  367. package/dist/chunk-N6M7MRVN.js.map +0 -1
  368. package/dist/chunk-QMGIQUBG.js.map +0 -1
  369. package/dist/chunk-QTO2FGBT.js.map +0 -1
  370. package/dist/chunk-SQEDDWAM.js.map +0 -1
  371. package/dist/chunk-W3XT32W7.js.map +0 -1
  372. /package/dist/{auto-sync-UPTUVE4X.js.map → auto-sync-5OE5QOZB.js.map} +0 -0
  373. /package/dist/{chunk-GF22HWS2.js.map → chunk-2PHX3I5C.js.map} +0 -0
  374. /package/dist/{chunk-JFDEYXF7.js.map → chunk-3NAHZQU3.js.map} +0 -0
  375. /package/dist/{chunk-XBRPEGXF.js.map → chunk-3UOSVTFR.js.map} +0 -0
  376. /package/dist/{chunk-TTKWTT72.js.map → chunk-3ZW6ZQO6.js.map} +0 -0
  377. /package/dist/{chunk-UV72DEZD.js.map → chunk-4B77XSG5.js.map} +0 -0
  378. /package/dist/{chunk-LMHDFOVV.js.map → chunk-5CPI2QWG.js.map} +0 -0
  379. /package/dist/{chunk-P72WZMWQ.js.map → chunk-5FZQ74K5.js.map} +0 -0
  380. /package/dist/{chunk-BRT7KEXU.js.map → chunk-6TWXQ4E2.js.map} +0 -0
  381. /package/dist/{chunk-CV6ZYXK3.js.map → chunk-7I7AYIUQ.js.map} +0 -0
  382. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  383. /package/dist/{chunk-JN57HZCD.js.map → chunk-ATEAL5EI.js.map} +0 -0
  384. /package/dist/{chunk-4PYLBXX6.js.map → chunk-AYAROCWD.js.map} +0 -0
  385. /package/dist/{chunk-NB2P47N7.js.map → chunk-CUUY5CC4.js.map} +0 -0
  386. /package/dist/{chunk-KL5Y6PEV.js.map → chunk-E3ZMFFQZ.js.map} +0 -0
  387. /package/dist/{chunk-55FDQYPS.js.map → chunk-ES5IHQ6M.js.map} +0 -0
  388. /package/dist/{chunk-N47ZWQBO.js.map → chunk-G2NSSQES.js.map} +0 -0
  389. /package/dist/{chunk-GSWPU5CR.js.map → chunk-GD3QOBMB.js.map} +0 -0
  390. /package/dist/{chunk-SACPRJ7F.js.map → chunk-JNIJBXVK.js.map} +0 -0
  391. /package/dist/{chunk-DGLON3AL.js.map → chunk-KNRG6ZGJ.js.map} +0 -0
  392. /package/dist/{chunk-GEUDRENF.js.map → chunk-MMTG3SCJ.js.map} +0 -0
  393. /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
  394. /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
  395. /package/dist/{chunk-KQ2XCQYN.js.map → chunk-P2BLHUL2.js.map} +0 -0
  396. /package/dist/{chunk-6L775BUB.js.map → chunk-QE63OHLB.js.map} +0 -0
  397. /package/dist/{chunk-ONHRRJZM.js.map → chunk-QJAQNXWI.js.map} +0 -0
  398. /package/dist/{chunk-6RYWNBSA.js.map → chunk-SVZGA2MK.js.map} +0 -0
  399. /package/dist/{chunk-OCMLGND7.js.map → chunk-WWZ35GWW.js.map} +0 -0
  400. /package/dist/{chunk-A5N6ISRK.js.map → chunk-ZN4UZWMT.js.map} +0 -0
  401. /package/dist/{chunk-7M6APKJL.js.map → chunk-ZYU7ZFLT.js.map} +0 -0
  402. /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
@@ -31,12 +31,23 @@ import type { NamespaceMaintenanceSummary } from "../maintenance/namespace-plann
31
31
  import { type PatternReinforcementResult, runPatternReinforcement } from "../maintenance/pattern-reinforcement.js";
32
32
  import { evaluateMemoryActionPolicy } from "../memory-action-policy.js";
33
33
  import { NamespaceStorageRouter } from "../namespaces/storage.js";
34
+ import { namespaceCollectionName } from "../namespaces/search.js";
34
35
  import { parseMemoryActionEligibilityContext } from "../schemas.js";
35
36
  import type { SearchBackend } from "../search/port.js";
36
37
  import { type AccessTrackingEntry, type MemoryActionEvent, type MemoryFile, type PluginConfig, confidenceTier } from "../types.js";
37
38
  import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
38
39
  import { assertPathInsideRoot } from "../utils/path-containment.js";
39
40
  import { WearablesService } from "../wearables/service.js";
41
+ import { ActivityStore } from "../activity/store.js";
42
+ import { MeetingsBuilder } from "../meetings/build.js";
43
+ import { createMeetingMemoryGenerator, createMeetingMemoryWriter } from "../meetings/memory-gen.js";
44
+ import { createMeetingSummaryDeps } from "../meetings/summary-extractor.js";
45
+ import {
46
+ ActivityWearablesMeetingsDaySource,
47
+ storageWearableDayReader,
48
+ type MeetingsActivityReader,
49
+ } from "../meetings/day-source.js";
50
+ import { MeetingsService } from "../meetings/service.js";
40
51
  import { qmdCollectionPathParts, qmdResultPathCandidates } from "./qmd-result-resolver.js";
41
52
  import {
42
53
  Orchestrator,
@@ -48,6 +59,13 @@ import {
48
59
  type DaySummaryGatherOptions,
49
60
  } from "../orchestrator.js";
50
61
 
62
+ /**
63
+ * Trailing-edge coalescing window for post-sync meeting rebuilds (issue #1900).
64
+ * An activity tick and a wearable window sync often land within seconds; this
65
+ * folds the burst into one build per day.
66
+ */
67
+ const MEETINGS_BUILD_DEBOUNCE_MS = 5_000;
68
+
51
69
  export interface WorkspaceOpsDeps {
52
70
  readonly accessTrackingBuffer: Map<
53
71
  string,
@@ -95,7 +113,8 @@ export interface WorkspaceOpsDeps {
95
113
  }>;
96
114
  readonly storage: StorageManager;
97
115
  readonly storageRouter: NamespaceStorageRouter;
98
- wearablesServiceInstance: WearablesService | null;
116
+ readonly wearablesServiceByNamespace: Map<string, WearablesService>;
117
+ readonly meetingsServiceByNamespace: Map<string, MeetingsService>;
99
118
  }
100
119
 
101
120
  function matchesMemoryPath(candidatePath: string, requestedPath: string, memoryDir: string): boolean {
@@ -635,12 +654,12 @@ export class WorkspaceOpsCoordinator {
635
654
  * memory writes stay consistent. Writes are pinned to the same
636
655
  * deterministic namespace bulk-import uses.
637
656
  */
638
- getWearablesService(): WearablesService {
639
- if (!this.deps.wearablesServiceInstance) {
640
- this.deps.wearablesServiceInstance = new WearablesService({
657
+ getWearablesService(namespace: string): WearablesService {
658
+ let service = this.deps.wearablesServiceByNamespace.get(namespace);
659
+ if (!service) {
660
+ service = new WearablesService({
641
661
  config: this.deps.config.wearables,
642
- getStorage: async () =>
643
- await this.deps.getStorageForNamespace(this.deps.bulkImportWriteNamespace()),
662
+ getStorage: async () => await this.deps.getStorageForNamespace(namespace),
644
663
  extract: (turns) => this.deps.extraction.extract(turns),
645
664
  // Smart memoryMode runs candidates through the SAME extraction
646
665
  // judge (cache + defer counters included) the live extraction
@@ -662,7 +681,23 @@ export class WorkspaceOpsCoordinator {
662
681
  search: async (query, maxResults) => {
663
682
  if (!this.deps.qmd.isAvailable()) return null;
664
683
  try {
665
- const results = await this.deps.qmd.search(query, undefined, maxResults);
684
+ // Scope the indexed search to the CALLER namespace's collection so a
685
+ // non-default caller's transcript_search never returns root or
686
+ // other-namespace transcripts (#2123). Namespaces off, or the
687
+ // default/machine-owner namespace rooted at memoryDir, resolve to the
688
+ // base collection (unchanged); every other namespace to its own.
689
+ let collection: string | undefined;
690
+ if (resolveNamespaceCapabilities(this.deps.config).namespaces === true) {
691
+ const storage = await this.deps.getStorageForNamespace(namespace);
692
+ const useLegacy =
693
+ namespace === this.deps.config.defaultNamespace &&
694
+ storage.dir === this.deps.config.memoryDir;
695
+ collection = namespaceCollectionName(this.deps.config.qmdCollection, namespace, {
696
+ defaultNamespace: this.deps.config.defaultNamespace,
697
+ useLegacyDefaultCollection: useLegacy,
698
+ });
699
+ }
700
+ const results = await this.deps.qmd.search(query, collection, maxResults);
666
701
  return results.map((result) => ({
667
702
  path: result.path,
668
703
  score: result.score,
@@ -683,9 +718,138 @@ export class WorkspaceOpsCoordinator {
683
718
  // (#1904, Codex).
684
719
  await this.deps.qmd.update();
685
720
  },
721
+ // Meeting tail-step (issue #1900): schedule a debounced meeting rebuild
722
+ // for every day a wearable sync touched. Wired on the shared service so
723
+ // BOTH the auto-sync adapter and the manual HTTP/MCP/CLI sync path
724
+ // (EngramAccessService.wearablesSync -> getWearablesService().sync)
725
+ // rebuild affected meetings. Gated on meetings.enabled so a sync of
726
+ // other signals never spins up meeting building; a failure never fails
727
+ // the sync.
728
+ onDaysSynced: async (days) => {
729
+ if (!this.deps.config.meetings.enabled) return;
730
+ try {
731
+ const meetings = await this.getMeetingsService(namespace);
732
+ for (const day of days) meetings.requestBuild(day);
733
+ } catch (err) {
734
+ log.warn(
735
+ `meetings: failed to schedule post-wearable-sync build: ${
736
+ err instanceof Error ? err.message : String(err)
737
+ }`,
738
+ );
739
+ }
740
+ },
741
+ });
742
+ this.deps.wearablesServiceByNamespace.set(namespace, service);
743
+ }
744
+ return service;
745
+ }
746
+
747
+ /**
748
+ * Lazily-constructed meetings service (issue #1900). Owns the record store,
749
+ * the store-backed builder (fed by the concrete activity + wearable day
750
+ * source), and the debounced post-sync build scheduler. Every meeting surface
751
+ * — CLI, MCP tools, HTTP routes — shares this one instance. Writes are pinned
752
+ * to the same deterministic namespace bulk-import uses, so meeting records and
753
+ * episode memories land beside wearable/activity artifacts. Constructing it
754
+ * touches no disk while `meetings.enabled` is off — every entrypoint gates.
755
+ */
756
+ async getMeetingsService(namespace: string): Promise<MeetingsService> {
757
+ let service = this.deps.meetingsServiceByNamespace.get(namespace);
758
+ if (!service) {
759
+ const config = this.deps.config.meetings;
760
+ const memoryDir = this.deps.config.memoryDir;
761
+ const storage = await this.deps.getStorageForNamespace(namespace);
762
+ const store = storage.meetingRecordStore();
763
+ // Activity is machine-scoped (<memoryDir>/state/activity.sqlite) and is
764
+ // consumed ONLY by the machine-owner (default) namespace; every other
765
+ // caller namespace runs audio-only with no activity reader (issue #2123).
766
+ // A missing/unavailable store degrades to no screen context, never a fail.
767
+ const activity: MeetingsActivityReader | undefined =
768
+ namespace !== this.deps.config.defaultNamespace
769
+ ? undefined
770
+ : {
771
+ listSnapshotsForDay: (machine, startUtc, endUtc) => {
772
+ let activityStore: ActivityStore | undefined;
773
+ try {
774
+ activityStore = ActivityStore.open(memoryDir);
775
+ return activityStore.listSnapshotsForDay(machine, startUtc, endUtc);
776
+ } catch (err) {
777
+ log.warn(
778
+ `meetings: activity snapshots unavailable (${
779
+ err instanceof Error ? err.message : String(err)
780
+ }); building without screen context`,
781
+ );
782
+ return [];
783
+ } finally {
784
+ activityStore?.close();
785
+ }
786
+ },
787
+ };
788
+ const source = new ActivityWearablesMeetingsDaySource({
789
+ activity,
790
+ wearables: storageWearableDayReader(storage),
791
+ config,
792
+ timezone: this.deps.config.activity.timezone,
793
+ });
794
+ // Production trust-gated summary/fact deps (issue #1900). Built from the
795
+ // shared LLM clients + the SAME durability-judge closure the wearables
796
+ // service passes (verdict cache + defer counters included), so meeting
797
+ // facts inherit identical judge gating — no forked trust/judge/LLM path.
798
+ // Pure construction (no disk/network); the builder gates on summaryMode.
799
+ const fallbackLlm = new FallbackLlmClient(
800
+ this.deps.config.gatewayConfig,
801
+ fallbackLlmRuntimeContextFromConfig(this.deps.config),
802
+ );
803
+ const summary = createMeetingSummaryDeps({
804
+ localLlm: this.deps.localLlm,
805
+ fallbackLlm,
806
+ judgeFacts: (candidates) =>
807
+ judgeFactDurability(
808
+ candidates,
809
+ this.deps.config,
810
+ this.deps.localLlm,
811
+ fallbackLlm,
812
+ this.deps.judgeVerdictCache,
813
+ this.deps.judgeDeferCounts,
814
+ ),
815
+ });
816
+ const builder = new MeetingsBuilder({
817
+ source,
818
+ store,
819
+ config,
820
+ hooks: {
821
+ reindex: async () => {
822
+ // Meeting records live in the QMD collection root; reindex on change
823
+ // so `show`/search find them immediately (qmd.update clears its own
824
+ // result caches). Fired only when records changed; a failure is
825
+ // surfaced as a build warning, not a hard failure.
826
+ await this.deps.qmd.update();
827
+ },
828
+ },
829
+ // Memory generation behind the builder seam (issue #1900 decouple): the
830
+ // deterministic engine depends only on MeetingMemoryGenerator, never on
831
+ // memory-gen. The generator wraps the same sealed write path the wearables
832
+ // generator uses — createMeetingMemoryWriter adds the source-scoped
833
+ // dedup/retire the raw StorageManager lacks — plus the trust-gated
834
+ // summary/facts layer (extractor + shared durability judge). It gates on
835
+ // summaryMode internally, so `off` never invokes the extractor.
836
+ memoryGenerator: createMeetingMemoryGenerator(createMeetingMemoryWriter(storage), config, summary),
837
+ });
838
+ service = new MeetingsService({
839
+ config,
840
+ store,
841
+ builder,
842
+ buildDebounceMs: MEETINGS_BUILD_DEBOUNCE_MS,
843
+ onBuildError: (date, err) =>
844
+ log.warn(
845
+ `meetings: tail-step build for ${date} failed: ${
846
+ err instanceof Error ? err.message : String(err)
847
+ }`,
848
+ ),
686
849
  });
850
+ this.deps.meetingsServiceByNamespace.set(namespace, service);
687
851
  }
688
- return this.deps.wearablesServiceInstance;
852
+ return service;
689
853
  }
690
854
 
691
855
  async autoConsolidateIdentity(): Promise<void> {
@@ -404,6 +404,7 @@ import {
404
404
  import { normalizeReplaySessionKey, type ReplayTurn } from "./replay/types.js";
405
405
  import type { ImportTurn } from "./bulk-import/types.js";
406
406
  import { WearablesService } from "./wearables/service.js";
407
+ import { MeetingsService } from "./meetings/service.js";
407
408
  import {
408
409
  type AgentPersonaModelConfig,
409
410
  confidenceTier,
@@ -875,7 +876,8 @@ export class Orchestrator {
875
876
  private readonly consolidationObservers = new Set<
876
877
  (observation: ConsolidationObservation) => Promise<void> | void
877
878
  >();
878
- private wearablesServiceInstance: WearablesService | null = null;
879
+ private readonly wearablesServiceByNamespace = new Map<string, WearablesService>();
880
+ private readonly meetingsServiceByNamespace = new Map<string, MeetingsService>();
879
881
  private wearablesAutoSyncHandle: { stop(): Promise<void> } | null = null;
880
882
  private lastQmdReprobeAtMs = 0;
881
883
  private lastFileHygieneRunAtMs = 0;
@@ -955,6 +957,7 @@ export class Orchestrator {
955
957
  await this.wearablesAutoSyncHandle.stop();
956
958
  this.wearablesAutoSyncHandle = null;
957
959
  }
960
+ for (const svc of this.meetingsServiceByNamespace.values()) svc.dispose();
958
961
  await this.maintenanceScheduler.dispose();
959
962
  await drainRecallWrites(this);
960
963
  // PR #2016 finding 3: drain any deferred lock-timeout hash-index retries so a
@@ -1486,6 +1489,7 @@ export class Orchestrator {
1486
1489
  namespaceSearchRouter: this.namespaceSearchRouter,
1487
1490
  namespaceCatalog: this.namespaceCatalog,
1488
1491
  getStorage: () => this.storage, storageForNamespace: (namespace) => this.storageRouter.storageFor(namespace),
1492
+ onActivitySynced: (summary) => { if (!this.config.meetings.enabled) return; void this.getMeetingsService().then((s) => s.requestBuildForActivitySync(summary.ranAt, this.config.activity.timezone, summary.touchedDates)).catch((err) => log.warn(`meetings: activity tail-step build failed to schedule: ${err instanceof Error ? err.message : String(err)}`)); },
1489
1493
  });
1490
1494
  // Issue #1526: background extraction queue lives on its own coordinator.
1491
1495
  this.extractionQueueCoordinator = new ExtractionQueueCoordinator();
@@ -2091,8 +2095,7 @@ export class Orchestrator {
2091
2095
  }
2092
2096
 
2093
2097
  async maybeRunFileHygiene(): Promise<void> {
2094
- return this.workspaceOpsCoordinator.maybeRunFileHygiene(
2095
- );
2098
+ return this.workspaceOpsCoordinator.maybeRunFileHygiene();
2096
2099
  }
2097
2100
 
2098
2101
  async runBootstrap(options: BootstrapOptions): Promise<BootstrapResult> {
@@ -2270,8 +2273,7 @@ export class Orchestrator {
2270
2273
  }
2271
2274
 
2272
2275
  private async validateLocalLlmModel(): Promise<void> {
2273
- return this.workspaceOpsCoordinator.validateLocalLlmModel(
2274
- );
2276
+ return this.workspaceOpsCoordinator.validateLocalLlmModel();
2275
2277
  }
2276
2278
 
2277
2279
  private invokeRecall(
@@ -2996,10 +2998,9 @@ export class Orchestrator {
2996
2998
  return this.config.defaultNamespace;
2997
2999
  }
2998
3000
 
2999
- getWearablesService(): WearablesService {
3000
- return this.workspaceOpsCoordinator.getWearablesService(
3001
- );
3002
- }
3001
+ getWearablesService(namespace: string = this.config.defaultNamespace): WearablesService { return this.workspaceOpsCoordinator.getWearablesService(namespace); }
3002
+
3003
+ getMeetingsService(namespace: string = this.config.defaultNamespace): Promise<MeetingsService> { return this.workspaceOpsCoordinator.getMeetingsService(namespace); }
3003
3004
 
3004
3005
  async ingestBulkImportBatch(
3005
3006
  turns: ImportTurn[],
@@ -3303,8 +3304,7 @@ export class Orchestrator {
3303
3304
  static readonly IDENTITY_CONSOLIDATE_THRESHOLD = 8_000;
3304
3305
 
3305
3306
  private async autoConsolidateIdentity(): Promise<void> {
3306
- return this.workspaceOpsCoordinator.autoConsolidateIdentity(
3307
- );
3307
+ return this.workspaceOpsCoordinator.autoConsolidateIdentity();
3308
3308
  }
3309
3309
 
3310
3310
  // Issue #1526: recall result formatting moved to RecallResultFormatter. Thin
@@ -3683,8 +3683,7 @@ export class Orchestrator {
3683
3683
  }
3684
3684
 
3685
3685
  async flushAccessTracking(): Promise<void> {
3686
- return this.workspaceOpsCoordinator.flushAccessTracking(
3687
- );
3686
+ return this.workspaceOpsCoordinator.flushAccessTracking();
3688
3687
  }
3689
3688
 
3690
3689
  private async loadSearchResultMemoryMap(
package/src/storage.ts CHANGED
@@ -75,6 +75,7 @@ import { serializeFaithfulnessFields, parseFaithfulnessField } from "./extractio
75
75
  import { createVersion as createPageVersion, type VersioningConfig, type VersionTrigger } from "./page-versioning.js";
76
76
  import { isValidTranscriptDate, WEARABLES_DIR_NAME } from "./wearables/day-store.js";
77
77
  import { FusionArtifactStore } from "./wearables/fusion/index.js";
78
+ import { MeetingRecordStore } from "./meetings/store.js";
78
79
  import {
79
80
  SecureStoreLockedError,
80
81
  MAGIC_HEADER_SIZE,
@@ -2632,6 +2633,26 @@ export class StorageManager {
2632
2633
  }));
2633
2634
  }
2634
2635
 
2636
+ private _meetingRecordStore?: MeetingRecordStore;
2637
+
2638
+ /**
2639
+ * Meeting record IO (issue #1900). Records live under `<baseDir>/meetings/`
2640
+ * — inside the QMD collection root (full-text searchable) but outside the
2641
+ * memory scan roots — and inherit the same encrypted-at-rest + atomic-write +
2642
+ * symlink-containment semantics as memories via the shared secure IO port.
2643
+ */
2644
+ meetingRecordStore(): MeetingRecordStore {
2645
+ if (this._meetingRecordStore) return this._meetingRecordStore;
2646
+ return (this._meetingRecordStore = new MeetingRecordStore(this.baseDir, {
2647
+ writeFile: (p, c) => this.writeStorageSecureFile(p, c),
2648
+ readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
2649
+ readDir: (d) => readdir(d),
2650
+ deleteFile: (p) => unlink(p),
2651
+ realpath: (p) => realpath(p),
2652
+ lstat: (p) => lstat(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() })),
2653
+ }));
2654
+ }
2655
+
2635
2656
  /**
2636
2657
  * Locate a wearable-sourced memory by exact (trimmed) content,
2637
2658
  * ignoring the "[Attributes: ...]" suffix writeMemory appends for
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Shared harness for the caller-derived namespace-symmetry surface tests
3
+ * (issue #2123). Builds a real Orchestrator + EngramAccessService with
4
+ * namespaces enabled and a fake wearable connector, so wearablesSync +
5
+ * meetingsBuild exercise the full source-transcript -> detect -> record ->
6
+ * episode-memory path against per-namespace storage roots.
7
+ *
8
+ * Test-only: lives under testing/ so tsup (which entry-points only top-level
9
+ * src/*.ts) never bundles it. Imported by the two-principal isolation test and
10
+ * the meetings-namespace lifecycle-matrix subject.
11
+ */
12
+ import { mkdtemp, rm } from "node:fs/promises";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+
16
+ import { parseConfig } from "../../config.js";
17
+ import { Orchestrator } from "../../orchestrator.js";
18
+ import { EngramAccessService } from "../../access-service.js";
19
+ import { ActivityStore } from "../../activity/store.js";
20
+ import {
21
+ clearWearableConnectors,
22
+ registerWearableConnector,
23
+ } from "../../wearables/registry.js";
24
+ import type { WearableSourceConnector } from "../../wearables/types.js";
25
+
26
+ /** Connector id every harness meeting is sourced from. */
27
+ export const FAKE_WEARABLE_SOURCE = "faketest";
28
+
29
+ /**
30
+ * Register a deterministic fake wearable connector that returns one 30-minute
31
+ * conversation with two distinct non-wearer speakers for whatever day is
32
+ * requested — enough to fire audio-only meeting detection
33
+ * (>= audioOnlyMinMinutes, >= 2 distinct non-wearer speakers). Clears the
34
+ * registry first so repeated harness builds in one test process never collide.
35
+ */
36
+ export function registerFakeWearableConnector(): void {
37
+ clearWearableConnectors();
38
+ registerWearableConnector({
39
+ id: FAKE_WEARABLE_SOURCE,
40
+ displayName: "Fake Test Wearable",
41
+ factory: (): WearableSourceConnector => ({
42
+ id: FAKE_WEARABLE_SOURCE,
43
+ displayName: "Fake Test Wearable",
44
+ async verifyAuth() {
45
+ return { ok: true };
46
+ },
47
+ async fetchConversations(opts) {
48
+ const day = opts.date;
49
+ return {
50
+ conversations: [
51
+ {
52
+ id: `conv-${day}`,
53
+ source: FAKE_WEARABLE_SOURCE,
54
+ title: "Planning sync",
55
+ startIso: `${day}T14:00:00.000Z`,
56
+ endIso: `${day}T14:30:00.000Z`,
57
+ segments: [
58
+ { text: "hi team", speakerKey: "me", speakerName: "Me", isWearer: true, startIso: `${day}T14:00:00.000Z`, endIso: `${day}T14:00:30.000Z` },
59
+ { text: "the quarterly numbers look strong", speakerKey: "alice", speakerName: "Alice", isWearer: false, startIso: `${day}T14:05:00.000Z`, endIso: `${day}T14:06:00.000Z` },
60
+ { text: "agreed, let us ship it next week", speakerKey: "bob", speakerName: "Bob", isWearer: false, startIso: `${day}T14:20:00.000Z`, endIso: `${day}T14:21:00.000Z` },
61
+ { text: "sounds good to me", speakerKey: "alice", speakerName: "Alice", isWearer: false, startIso: `${day}T14:29:00.000Z`, endIso: `${day}T14:29:30.000Z` },
62
+ ],
63
+ },
64
+ ],
65
+ nextCursor: null,
66
+ };
67
+ },
68
+ }),
69
+ });
70
+ }
71
+
72
+ /** Namespaces enabled; `pA` owns `nsA`, `pB` owns `nsB` (both NON-default) with
73
+ * full read+write; `pWO` can WRITE `nsWO` but is omitted from its readPrincipals
74
+ * (write-only, for the meetingsBuild read-authorization regression, #2123); the
75
+ * default namespace is writable/readable by any authenticated principal, so
76
+ * `op` acts as the machine owner. */
77
+ function makeConfig(memoryDir: string): ReturnType<typeof parseConfig> {
78
+ return parseConfig({
79
+ openaiApiKey: "sk-test",
80
+ memoryDir,
81
+ workspaceDir: path.join(memoryDir, "workspace"),
82
+ qmdEnabled: false,
83
+ embeddingFallbackEnabled: false,
84
+ chunkingEnabled: false,
85
+ namespacesEnabled: true,
86
+ defaultNamespace: "default",
87
+ namespacePolicies: [
88
+ { name: "nsA", readPrincipals: ["pA"], writePrincipals: ["pA"] },
89
+ { name: "nsB", readPrincipals: ["pB"], writePrincipals: ["pB"] },
90
+ { name: "nsWO", readPrincipals: [], writePrincipals: ["pWO"] },
91
+ ],
92
+ wearables: {
93
+ enabled: true,
94
+ autoSyncEnabled: false,
95
+ sources: { [FAKE_WEARABLE_SOURCE]: { enabled: true, memoryMode: "off" } },
96
+ },
97
+ meetings: { enabled: true },
98
+ });
99
+ }
100
+
101
+ export interface MeetingsNamespaceHarness {
102
+ readonly orchestrator: Orchestrator;
103
+ readonly service: EngramAccessService;
104
+ readonly memoryDir: string;
105
+ /** Namespace-root storage (records/memories/transcripts live under `.dir`).
106
+ * Typed via ReturnType to avoid a direct storage.ts import (ratchet #1533). */
107
+ storageForNs(namespace: string): ReturnType<Orchestrator["getStorage"]>;
108
+ /** Seed the machine-global activity store (<memoryDir>/state/activity.sqlite). */
109
+ seedGlobalActivity(day: string): void;
110
+ /**
111
+ * Simulate a restart: tear down the live orchestrator and open a FRESH
112
+ * Orchestrator + EngramAccessService over the same on-disk memoryDir. Returns
113
+ * the new service; subsequent `storageForNs`/`cleanup` target the reopened
114
+ * instance.
115
+ */
116
+ reopen(): Promise<EngramAccessService>;
117
+ cleanup(): Promise<void>;
118
+ }
119
+
120
+ export async function buildMeetingsNamespaceHarness(): Promise<MeetingsNamespaceHarness> {
121
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-mtg-ns-"));
122
+ registerFakeWearableConnector();
123
+ let orchestrator = new Orchestrator(makeConfig(memoryDir));
124
+ let service = new EngramAccessService(orchestrator);
125
+ const harness: MeetingsNamespaceHarness = {
126
+ get orchestrator() {
127
+ return orchestrator;
128
+ },
129
+ get service() {
130
+ return service;
131
+ },
132
+ memoryDir,
133
+ storageForNs: (namespace) => orchestrator.getStorage(namespace),
134
+ seedGlobalActivity(day: string): void {
135
+ const store = ActivityStore.open(memoryDir);
136
+ try {
137
+ store.insertSnapshot({ machine: "m1", capturedAtUtc: `${day}T14:10:00.000Z`, app: "zoom.us", windowTitle: "Planning", text: "roadmap review", textSource: "ax", contentHash: `h-${day}-1` });
138
+ store.insertSnapshot({ machine: "m1", capturedAtUtc: `${day}T14:20:00.000Z`, app: "zoom.us", windowTitle: "Planning", text: "roadmap review 2", textSource: "ax", contentHash: `h-${day}-2` });
139
+ } finally {
140
+ store.close();
141
+ }
142
+ },
143
+ async reopen(): Promise<EngramAccessService> {
144
+ await orchestrator.destroy();
145
+ registerFakeWearableConnector();
146
+ orchestrator = new Orchestrator(makeConfig(memoryDir));
147
+ service = new EngramAccessService(orchestrator);
148
+ return service;
149
+ },
150
+ async cleanup(): Promise<void> {
151
+ await orchestrator.destroy();
152
+ clearWearableConnectors();
153
+ // maxRetries absorbs a rare ENOTEMPTY when a background flush writes a
154
+ // state file as the recursive walk removes the tree (issue #2123 test).
155
+ await rm(memoryDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
156
+ },
157
+ };
158
+ return harness;
159
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Meetings caller-namespace subject for the scenario-matrix harness (issue
3
+ * #2123). Exercises the caller-derived namespace meeting build/read path: a
4
+ * principal on a NON-default namespace syncs wearables and builds meetings, and
5
+ * the record must be readable in that caller namespace while a different
6
+ * namespace stays empty.
7
+ *
8
+ * Most canonical rows probe session/provider-identity/compaction/dedupe
9
+ * dimensions the meetings-namespace path has no honest analogue for — those are
10
+ * skipped via `appliesTo` (never faked). The two realized rows map cleanly:
11
+ * - explicit-provider-identity → a straight caller-namespace build;
12
+ * - restart-reload-recovery → reopen a fresh service over the same on-disk
13
+ * memoryDir and re-read the persisted caller-namespace record.
14
+ */
15
+ import assert from "node:assert/strict";
16
+
17
+ import {
18
+ buildMeetingsNamespaceHarness,
19
+ type MeetingsNamespaceHarness,
20
+ } from "./meetings-namespace-harness.js";
21
+ import {
22
+ type LifecycleSubject,
23
+ type MatrixRow,
24
+ runLifecycleMatrix,
25
+ } from "../lifecycle-matrix.js";
26
+
27
+ interface MeetingsNamespaceState {
28
+ harness: MeetingsNamespaceHarness;
29
+ date: string;
30
+ }
31
+
32
+ const CALLER = { namespace: "nsA", authenticatedPrincipal: "pA" } as const;
33
+ const OTHER = { namespace: "nsB", authenticatedPrincipal: "pB" } as const;
34
+
35
+ async function meetingCountFor(
36
+ harness: MeetingsNamespaceHarness,
37
+ scope: { namespace: string; authenticatedPrincipal: string },
38
+ date: string,
39
+ ): Promise<number> {
40
+ const list = await harness.service.meetingsList(date, scope);
41
+ return list.days[0]?.meetings.length ?? 0;
42
+ }
43
+
44
+ const subject: LifecycleSubject<MeetingsNamespaceState> = {
45
+ appliesTo(row: MatrixRow): boolean | string {
46
+ if (row.id === "explicit-provider-identity" || row.id === "restart-reload-recovery") {
47
+ return true;
48
+ }
49
+ return `meetings caller-namespace build has no ${row.id} semantics to realize`;
50
+ },
51
+
52
+ async setup(): Promise<MeetingsNamespaceState> {
53
+ const harness = await buildMeetingsNamespaceHarness();
54
+ return { harness, date: "2026-06-09" };
55
+ },
56
+
57
+ async exercise(state, row): Promise<void> {
58
+ await state.harness.service.wearablesSync({ date: state.date, ...CALLER });
59
+ const build = await state.harness.service.meetingsBuild(state.date, CALLER);
60
+ assert.equal(build.meetings.length, 1, "caller namespace detects one audio meeting");
61
+ // restart/reload row: reopen a fresh service over the same on-disk state.
62
+ if (row.dimensions.restart) {
63
+ await state.harness.reopen();
64
+ }
65
+ },
66
+
67
+ async invariants(state): Promise<void> {
68
+ // Caller namespace still reads its record (survives a restart when reopened).
69
+ assert.equal(
70
+ await meetingCountFor(state.harness, CALLER, state.date),
71
+ 1,
72
+ "caller namespace reads its own meeting record",
73
+ );
74
+ // A different namespace never observes the caller's meeting.
75
+ assert.equal(
76
+ await meetingCountFor(state.harness, OTHER, state.date),
77
+ 0,
78
+ "a different namespace stays isolated from the caller's meeting",
79
+ );
80
+ const storageOther = await state.harness.storageForNs("nsB");
81
+ assert.deepEqual(
82
+ await storageOther.meetingRecordStore().listMeetingDates(),
83
+ [],
84
+ "no meeting record physically under the other namespace root",
85
+ );
86
+ },
87
+
88
+ async teardown(state): Promise<void> {
89
+ await state.harness.cleanup();
90
+ },
91
+ };
92
+
93
+ runLifecycleMatrix("meetings-namespace", subject);
package/src/types.ts CHANGED
@@ -1218,8 +1218,7 @@ export interface PluginConfig extends BoundedJsonlStateConfig {
1218
1218
  */
1219
1219
  wearables: WearablesConfig;
1220
1220
  activity: ActivityConfig;
1221
- /**
1222
- * Retrospective meeting intelligence (issue #1900): detect + fuse meetings
1221
+ /** Retrospective meeting intelligence (issue #1900): detect + fuse meetings
1223
1222
  * from already-ingested audio + screen activity. Disabled by default.
1224
1223
  */
1225
1224
  meetings: MeetingsConfig;
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import { WearablesInputError } from "./errors.js";
12
+ import { builtInConnectorPackageSpecifier } from "./registry.js";
12
13
  import type { WearablesService } from "./service.js";
13
14
  import type { WearableSyncSummary } from "./types.js";
14
15
 
@@ -182,7 +183,7 @@ export async function runWearablesCliCommand(
182
183
  for (const source of status.sources) {
183
184
  io.stdout.write(
184
185
  ` ${source.source} (${source.displayName}): ${source.enabled ? "enabled" : "disabled"}, ` +
185
- `connector ${source.connectorInstalled ? "installed" : `MISSING — npm install @remnic/connector-${source.source}`}, ` +
186
+ `connector ${source.connectorInstalled ? "installed" : `MISSING — npm install ${builtInConnectorPackageSpecifier(source.source)}`}, ` +
186
187
  `memoryMode ${source.memoryMode}, ` +
187
188
  `${source.transcriptDays} transcript day${source.transcriptDays === 1 ? "" : "s"}, ` +
188
189
  `last sync ${source.lastSyncAt ?? "never"}\n`,
@@ -16,6 +16,7 @@ export {
16
16
  parseWearablesConfig,
17
17
  } from "./config.js";
18
18
  export {
19
+ builtInConnectorPackageSpecifier,
19
20
  registerWearableConnector,
20
21
  getWearableConnector,
21
22
  listWearableConnectors,