@remnic/core 9.30.0 → 9.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -10
  2. package/dist/access-admin-ops-surface.js +50 -44
  3. package/dist/access-authorization-probe.d.ts +10 -10
  4. package/dist/access-authorization-probe.js +51 -45
  5. package/dist/access-boundary.d.ts +13 -11
  6. package/dist/access-boundary.js +50 -44
  7. package/dist/access-cli.js +168 -123
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +119 -0
  10. package/dist/access-extraction-force-flush.js +166 -0
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +47 -13
  13. package/dist/access-http-lcm-compaction.js +7 -3
  14. package/dist/access-http-lifecycle-flush.d.ts +132 -0
  15. package/dist/access-http-lifecycle-flush.js +9 -0
  16. package/dist/access-http-lifecycle-flush.js.map +1 -0
  17. package/dist/access-http.d.ts +11 -10
  18. package/dist/access-http.js +66 -59
  19. package/dist/access-identity-continuity-surface.d.ts +8 -8
  20. package/dist/access-identity-continuity-surface.js +50 -44
  21. package/dist/access-lcm-surface.d.ts +10 -10
  22. package/dist/access-lcm-surface.js +50 -44
  23. package/dist/access-mcp-output-schemas.js +1 -1
  24. package/dist/access-mcp.d.ts +16 -10
  25. package/dist/access-mcp.js +58 -52
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-D4vW97H1.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +50 -44
  30. package/dist/access-observe-helpers.d.ts +22 -0
  31. package/dist/access-observe-helpers.js +10 -0
  32. package/dist/access-observe-helpers.js.map +1 -0
  33. package/dist/access-observe-write-surface.d.ts +51 -47
  34. package/dist/access-observe-write-surface.js +50 -44
  35. package/dist/access-operations-batch.js +53 -47
  36. package/dist/access-operations.d.ts +11 -11
  37. package/dist/access-operations.js +55 -49
  38. package/dist/access-recall-concurrency.d.ts +10 -10
  39. package/dist/access-recall-concurrency.js +50 -44
  40. package/dist/access-recall-response.d.ts +10 -10
  41. package/dist/access-recall-response.js +50 -44
  42. package/dist/access-recall-surface.d.ts +10 -10
  43. package/dist/access-recall-surface.js +50 -44
  44. package/dist/access-schema.d.ts +37 -7
  45. package/dist/access-schema.js +5 -3
  46. package/dist/{access-service-B5RwVsTV.d.ts → access-service-B6PZ_xUL.d.ts} +44 -20
  47. package/dist/access-service-helpers.d.ts +113 -0
  48. package/dist/access-service-helpers.js +8 -0
  49. package/dist/access-service-helpers.js.map +1 -0
  50. package/dist/access-service.d.ts +10 -10
  51. package/dist/access-service.js +50 -44
  52. package/dist/access-surface-catalog.d.ts +10 -10
  53. package/dist/access-surface-catalog.js +2 -0
  54. package/dist/access-surface-catalog.js.map +1 -1
  55. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  56. package/dist/action-confidence.d.ts +1 -1
  57. package/dist/active-memory-bridge.d.ts +1 -1
  58. package/dist/active-recall.d.ts +1 -1
  59. package/dist/active-recall.js +1 -1
  60. package/dist/adapters/index.js +7 -7
  61. package/dist/adapters/registry.js +3 -3
  62. package/dist/behavior-learner.d.ts +1 -1
  63. package/dist/behavior-signals.d.ts +1 -1
  64. package/dist/bootstrap.d.ts +8 -8
  65. package/dist/briefing.d.ts +2 -2
  66. package/dist/briefing.js +14 -14
  67. package/dist/buffer-surprise-report.d.ts +1 -1
  68. package/dist/buffer-turn-helpers.d.ts +5 -0
  69. package/dist/buffer-turn-helpers.js +24 -0
  70. package/dist/buffer-turn-helpers.js.map +1 -0
  71. package/dist/buffer.d.ts +17 -4
  72. package/dist/buffer.js +21 -1
  73. package/dist/bulk-import/index.d.ts +3 -3
  74. package/dist/calibration.d.ts +1 -1
  75. package/dist/capabilities.d.ts +1 -1
  76. package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
  77. package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
  78. package/dist/{capsule-merge-5KKJQBWQ.js → capsule-merge-2H2IUTBT.js} +4 -4
  79. package/dist/{catalog-V7inUQdp.d.ts → catalog-CGFYmTT8.d.ts} +1 -1
  80. package/dist/causal-behavior.d.ts +1 -1
  81. package/dist/causal-behavior.js +2 -2
  82. package/dist/causal-chain.js +2 -2
  83. package/dist/causal-consolidation.d.ts +1 -1
  84. package/dist/causal-consolidation.js +19 -19
  85. package/dist/causal-retrieval.js +2 -2
  86. package/dist/causal-trajectory-graph.d.ts +1 -1
  87. package/dist/causal-trajectory.js +1 -1
  88. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  89. package/dist/{chunk-GIBMDSJ2.js → chunk-27P5YVDU.js} +2 -2
  90. package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
  91. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  92. package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
  93. package/dist/chunk-3F2LKUMU.js.map +1 -0
  94. package/dist/chunk-3QL24R5Y.js +9 -0
  95. package/dist/chunk-3QL24R5Y.js.map +1 -0
  96. package/dist/chunk-4RNZMRAV.js +60 -0
  97. package/dist/chunk-4RNZMRAV.js.map +1 -0
  98. package/dist/{chunk-6U7F52DE.js → chunk-4XHR3I67.js} +60 -60
  99. package/dist/chunk-5IVLTFOV.js +65 -0
  100. package/dist/chunk-5IVLTFOV.js.map +1 -0
  101. package/dist/{chunk-2EUVEDF5.js → chunk-5XA7PQ5I.js} +2 -2
  102. package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
  103. package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
  104. package/dist/{chunk-HUHX2OCX.js → chunk-7DRETLP5.js} +1 -1
  105. package/dist/chunk-7DRETLP5.js.map +1 -0
  106. package/dist/{chunk-RGIWINDN.js → chunk-7G5MH4NT.js} +30 -30
  107. package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
  108. package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
  109. package/dist/{chunk-M3C2V3PV.js → chunk-AJEMDQNA.js} +12 -12
  110. package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
  111. package/dist/{chunk-ACXPX4AG.js → chunk-BR2K43MK.js} +2 -2
  112. package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
  113. package/dist/chunk-BUE5E2HL.js.map +1 -0
  114. package/dist/{chunk-CZRYLSSW.js → chunk-BUGVGH4N.js} +2 -2
  115. package/dist/{chunk-YTQNQ4KB.js → chunk-C4VQMFVM.js} +3 -3
  116. package/dist/{chunk-ZPSVBSOF.js → chunk-CIVDJD6P.js} +3 -3
  117. package/dist/{chunk-K5GB36ME.js → chunk-CZDOT5I2.js} +2 -2
  118. package/dist/{chunk-VI2JQPNQ.js → chunk-E4PWACUN.js} +2 -2
  119. package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
  120. package/dist/{chunk-P5PXWTW7.js → chunk-EJCAV3QZ.js} +3 -3
  121. package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
  122. package/dist/chunk-ER7W6H4T.js +112 -0
  123. package/dist/chunk-ER7W6H4T.js.map +1 -0
  124. package/dist/{chunk-6FUPCJUL.js → chunk-FI4F5X2V.js} +54 -54
  125. package/dist/chunk-FI4F5X2V.js.map +1 -0
  126. package/dist/{chunk-LGHKJABJ.js → chunk-GOUILH55.js} +40 -18
  127. package/dist/chunk-GOUILH55.js.map +1 -0
  128. package/dist/{chunk-G5R3D5UP.js → chunk-GTTAHHD3.js} +2 -2
  129. package/dist/{chunk-H5CPS5JP.js → chunk-H36LJIPD.js} +3 -3
  130. package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
  131. package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
  132. package/dist/{chunk-5W4ZLBEZ.js → chunk-JCFTIQBR.js} +2 -2
  133. package/dist/{chunk-XOZ4ALGB.js → chunk-KE353EWI.js} +3 -3
  134. package/dist/{chunk-W5EG6LE3.js → chunk-KIT6M7EB.js} +3 -3
  135. package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
  136. package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
  137. package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
  138. package/dist/chunk-N5Z4EVOR.js +123 -0
  139. package/dist/chunk-N5Z4EVOR.js.map +1 -0
  140. package/dist/{chunk-66772WBP.js → chunk-NFXQJHJD.js} +5 -5
  141. package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
  142. package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
  143. package/dist/{chunk-NHWB6HG2.js → chunk-NYCGIQRA.js} +2 -2
  144. package/dist/{chunk-4WKA6I65.js → chunk-OGCNZPKX.js} +1119 -309
  145. package/dist/chunk-OGCNZPKX.js.map +1 -0
  146. package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
  147. package/dist/{chunk-FDAMS4PK.js → chunk-PNPOWBGC.js} +2 -2
  148. package/dist/{chunk-IC6CBHCA.js → chunk-QGENAYVS.js} +2 -2
  149. package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
  150. package/dist/chunk-QIHIHZYC.js.map +1 -0
  151. package/dist/{chunk-PUS63Q3G.js → chunk-RUYJ7TWU.js} +517 -2011
  152. package/dist/chunk-RUYJ7TWU.js.map +1 -0
  153. package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
  154. package/dist/chunk-TL4TO3EA.js.map +1 -0
  155. package/dist/{chunk-SPJXKAVF.js → chunk-U52AKICI.js} +14 -13
  156. package/dist/chunk-U52AKICI.js.map +1 -0
  157. package/dist/chunk-ULARSG5Z.js +203 -0
  158. package/dist/chunk-ULARSG5Z.js.map +1 -0
  159. package/dist/{chunk-62U4J2GN.js → chunk-UR77VKF7.js} +2 -2
  160. package/dist/{chunk-JCBWCYEJ.js → chunk-VANLTS5F.js} +2 -2
  161. package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
  162. package/dist/chunk-VCD4PSK2.js.map +1 -0
  163. package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
  164. package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
  165. package/dist/chunk-WWUVONGW.js.map +1 -0
  166. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  167. package/dist/{chunk-TH2LSRMG.js → chunk-XHDIB4T4.js} +2 -2
  168. package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
  169. package/dist/{chunk-LBOD4U5B.js → chunk-YFOMN2II.js} +6 -6
  170. package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
  171. package/dist/chunk-YIAA2X3D.js.map +1 -0
  172. package/dist/chunk-YPC7W6GA.js +1604 -0
  173. package/dist/chunk-YPC7W6GA.js.map +1 -0
  174. package/dist/{chunk-I5NLEENJ.js → chunk-Z4SWV4VW.js} +3 -3
  175. package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
  176. package/dist/chunk-ZCPP5OW6.js.map +1 -0
  177. package/dist/{cli-C4GbETPC.d.ts → cli-BptUDTtp.d.ts} +5 -5
  178. package/dist/cli.d.ts +12 -12
  179. package/dist/cli.js +91 -84
  180. package/dist/compounding/engine.d.ts +2 -2
  181. package/dist/compounding/engine.js +14 -14
  182. package/dist/compounding/preference-consolidator.d.ts +1 -1
  183. package/dist/compression-optimizer.d.ts +1 -1
  184. package/dist/config.d.ts +1 -1
  185. package/dist/config.js +1 -1
  186. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  187. package/dist/connectors/codex-materialize-runner.js +14 -14
  188. package/dist/connectors/codex-materialize.d.ts +1 -1
  189. package/dist/connectors/index.d.ts +1 -1
  190. package/dist/connectors/index.js +17 -17
  191. package/dist/consolidation-provenance-check.d.ts +2 -2
  192. package/dist/consolidation-provenance-check.js +5 -5
  193. package/dist/consolidation-undo.d.ts +2 -2
  194. package/dist/consolidation-undo.js +3 -3
  195. package/dist/contradiction/index.d.ts +2 -2
  196. package/dist/contradiction/index.js +4 -4
  197. package/dist/conversation-index/backend.d.ts +1 -1
  198. package/dist/conversation-index/backend.js +2 -2
  199. package/dist/conversation-index/chunker.d.ts +1 -1
  200. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  201. package/dist/conversation-index/indexer.d.ts +1 -1
  202. package/dist/conversation-index/search.d.ts +1 -1
  203. package/dist/corpus-watermark.d.ts +1 -1
  204. package/dist/corpus-watermark.js +26 -26
  205. package/dist/day-summary.d.ts +1 -1
  206. package/dist/delinearize.d.ts +1 -1
  207. package/dist/direct-answer-wiring.d.ts +1 -1
  208. package/dist/direct-answer.d.ts +1 -1
  209. package/dist/embedding-fallback.d.ts +1 -1
  210. package/dist/enrichment/index.d.ts +1 -1
  211. package/dist/entity-retrieval.d.ts +2 -2
  212. package/dist/entity-retrieval.js +14 -14
  213. package/dist/entity-schema.d.ts +1 -1
  214. package/dist/explicit-capture.d.ts +8 -8
  215. package/dist/extraction-error-classification.d.ts +1 -1
  216. package/dist/extraction-faithfulness.d.ts +1 -1
  217. package/dist/extraction-judge-telemetry.d.ts +1 -1
  218. package/dist/extraction-judge-training.d.ts +1 -1
  219. package/dist/extraction-judge.d.ts +1 -1
  220. package/dist/extraction-liveness.d.ts +1 -1
  221. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  222. package/dist/extraction-source-grounding.d.ts +15 -2
  223. package/dist/extraction-source-grounding.js +10 -1
  224. package/dist/extraction.d.ts +2 -15
  225. package/dist/extraction.js +5 -4
  226. package/dist/fallback-llm.d.ts +1 -1
  227. package/dist/graph-dashboard-diff.d.ts +1 -1
  228. package/dist/graph-dashboard-key.d.ts +1 -1
  229. package/dist/graph-dashboard-parser.d.ts +1 -1
  230. package/dist/graph-edge-reinforcement.d.ts +1 -1
  231. package/dist/graph-snapshot.d.ts +1 -1
  232. package/dist/graph.d.ts +1 -1
  233. package/dist/importance.d.ts +1 -1
  234. package/dist/importers/index.d.ts +1 -1
  235. package/dist/in-flight-reads.d.ts +1 -1
  236. package/dist/index.d.ts +19 -19
  237. package/dist/index.js +215 -207
  238. package/dist/intent.d.ts +1 -1
  239. package/dist/lcm/engine.d.ts +1 -1
  240. package/dist/lcm/engine.js +3 -3
  241. package/dist/lcm/index.d.ts +1 -1
  242. package/dist/lcm/index.js +6 -6
  243. package/dist/lcm/tools.d.ts +1 -1
  244. package/dist/lifecycle.d.ts +1 -1
  245. package/dist/live-connectors-runner.d.ts +1 -1
  246. package/dist/local-llm-helpers.d.ts +7 -0
  247. package/dist/local-llm-helpers.js +16 -0
  248. package/dist/local-llm-helpers.js.map +1 -0
  249. package/dist/local-llm.d.ts +3 -6
  250. package/dist/local-llm.js +2 -1
  251. package/dist/local-model-endpoint.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.d.ts +1 -1
  253. package/dist/maintenance/memory-governance.js +14 -14
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
  256. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  257. package/dist/maintenance/rebuild-memory-projection.js +15 -15
  258. package/dist/{maintenance-CL30NWtc.d.ts → maintenance-b6f92bRz.d.ts} +3 -3
  259. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  260. package/dist/memory-action-policy.d.ts +1 -1
  261. package/dist/memory-cache.d.ts +1 -1
  262. package/dist/memory-corpus-version.js +2 -2
  263. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  264. package/dist/memory-projection-store.d.ts +1 -1
  265. package/dist/memory-provenance.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +24 -24
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +9 -9
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +14 -14
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-impression-drain.d.ts +1 -1
  277. package/dist/offline-sync-impression-drain.js +6 -5
  278. package/dist/operator-doctor-corpus.d.ts +1 -1
  279. package/dist/operator-doctor-corpus.js +29 -29
  280. package/dist/operator-doctor-replica.d.ts +1 -1
  281. package/dist/operator-doctor-replica.js +3 -3
  282. package/dist/operator-toolkit.d.ts +3 -3
  283. package/dist/operator-toolkit.js +38 -37
  284. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  285. package/dist/orchestration/maintenance.d.ts +4 -4
  286. package/dist/orchestration/maintenance.js +22 -21
  287. package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-3uGxC1qO.d.ts} +72 -34
  288. package/dist/orchestrator.d.ts +8 -8
  289. package/dist/orchestrator.js +167 -159
  290. package/dist/page-versioning.js +3 -3
  291. package/dist/patterns-cli.d.ts +1 -1
  292. package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-DepuNr-m.d.ts} +1 -1
  293. package/dist/policy-runtime.d.ts +1 -1
  294. package/dist/proactive-contention.d.ts +1 -1
  295. package/dist/provenance.d.ts +1 -1
  296. package/dist/{qmd-q9tg4dHp.d.ts → qmd-Dalr3Jby.d.ts} +1 -1
  297. package/dist/qmd-preflight.d.ts +2 -2
  298. package/dist/qmd-recall-cache.d.ts +1 -1
  299. package/dist/qmd.d.ts +2 -2
  300. package/dist/qmd.js +4 -4
  301. package/dist/recall-concurrency-config.d.ts +1 -1
  302. package/dist/recall-disclosure-escalation.d.ts +1 -1
  303. package/dist/recall-explain-renderer.d.ts +1 -1
  304. package/dist/recall-explain-renderer.js +3 -3
  305. package/dist/recall-memory-map.d.ts +1 -1
  306. package/dist/recall-planner-llm.d.ts +1 -1
  307. package/dist/recall-state.d.ts +1 -1
  308. package/dist/recall-tag-filter.d.ts +1 -1
  309. package/dist/recall-timings.d.ts +1 -1
  310. package/dist/recall-xray-cli.d.ts +1 -1
  311. package/dist/recall-xray-cli.js +4 -4
  312. package/dist/recall-xray-renderer.d.ts +1 -1
  313. package/dist/recall-xray-renderer.js +3 -3
  314. package/dist/recall-xray.d.ts +1 -1
  315. package/dist/recall-xray.js +2 -2
  316. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  317. package/dist/replay/normalizers/claude.d.ts +1 -1
  318. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  319. package/dist/replay/normalizers/shared.d.ts +1 -1
  320. package/dist/replay/runner.d.ts +1 -1
  321. package/dist/replay/types.d.ts +1 -1
  322. package/dist/replica-divergence.d.ts +1 -1
  323. package/dist/replica-divergence.js +2 -2
  324. package/dist/replica-peers-config.d.ts +1 -1
  325. package/dist/resolve-auth-token.d.ts +1 -1
  326. package/dist/resume-bundles.js +1 -1
  327. package/dist/retrieval-agents.d.ts +2 -2
  328. package/dist/retrieval-tiers.d.ts +1 -1
  329. package/dist/routing/engine.d.ts +1 -1
  330. package/dist/routing/store.d.ts +1 -1
  331. package/dist/salvage-envelope.d.ts +1 -1
  332. package/dist/{scope-profiles-CWDyglPM.d.ts → scope-profiles-BpiM5hTU.d.ts} +1 -1
  333. package/dist/search/embed-helper.d.ts +1 -1
  334. package/dist/search/factory.d.ts +1 -1
  335. package/dist/search/factory.js +8 -8
  336. package/dist/search/index.d.ts +1 -1
  337. package/dist/search/index.js +12 -12
  338. package/dist/search/lancedb-backend.d.ts +1 -1
  339. package/dist/search/meilisearch-backend.d.ts +1 -1
  340. package/dist/search/noop-backend.d.ts +1 -1
  341. package/dist/search/orama-backend.d.ts +1 -1
  342. package/dist/search/port.d.ts +1 -1
  343. package/dist/search/remote-backend.d.ts +1 -1
  344. package/dist/{semantic-consolidation-BUE3deLn.d.ts → semantic-consolidation-CMtVrf9f.d.ts} +1 -1
  345. package/dist/semantic-consolidation.d.ts +2 -2
  346. package/dist/semantic-consolidation.js +16 -16
  347. package/dist/semantic-rule-promotion.js +14 -14
  348. package/dist/semantic-rule-verifier.d.ts +1 -1
  349. package/dist/semantic-rule-verifier.js +14 -14
  350. package/dist/{service-CXgM0bQG.d.ts → service-DuAxwSgg.d.ts} +2 -2
  351. package/dist/session-observer-bands.d.ts +1 -1
  352. package/dist/session-observer-state.d.ts +1 -1
  353. package/dist/shared-context/manager.d.ts +1 -1
  354. package/dist/signal.d.ts +1 -1
  355. package/dist/{storage-DysJq-XH.d.ts → storage-CF0Ih8GP.d.ts} +1 -1
  356. package/dist/storage.d.ts +2 -2
  357. package/dist/storage.js +13 -13
  358. package/dist/summarizer.d.ts +1 -1
  359. package/dist/summarizer.js +3 -2
  360. package/dist/summary-snapshot.d.ts +1 -1
  361. package/dist/temporal-supersession.d.ts +2 -2
  362. package/dist/temporal-timeline-recall.d.ts +1 -1
  363. package/dist/temporal-validity.d.ts +1 -1
  364. package/dist/threading.d.ts +1 -1
  365. package/dist/tier-migration.d.ts +2 -2
  366. package/dist/tier-routing.d.ts +1 -1
  367. package/dist/tokens.js +2 -2
  368. package/dist/topics.d.ts +1 -1
  369. package/dist/transcript.d.ts +1 -1
  370. package/dist/transfer/backup.js +2 -2
  371. package/dist/transfer/capsule-export.js +2 -2
  372. package/dist/transfer/capsule-import.js +5 -5
  373. package/dist/trust-score-stage.d.ts +1 -1
  374. package/dist/trust-score.d.ts +1 -1
  375. package/dist/{types-aPPzhnjT.d.ts → types-BpaYvJ6v.d.ts} +22 -2
  376. package/dist/types.d.ts +1 -1
  377. package/dist/types.js +1 -1
  378. package/dist/utility-runtime.d.ts +1 -1
  379. package/dist/verified-recall.js +14 -14
  380. package/dist/write-envelope.d.ts +1 -1
  381. package/package.json +2 -2
  382. package/src/access-boundary.ts +3 -0
  383. package/src/access-cli.test.ts +93 -0
  384. package/src/access-cli.ts +56 -2
  385. package/src/access-extraction-force-flush.ts +177 -0
  386. package/src/access-http-extraction-force-flush.test.ts +132 -0
  387. package/src/access-http-lcm-compaction.ts +99 -22
  388. package/src/access-http-lifecycle-flush.ts +81 -0
  389. package/src/access-http.test.ts +227 -0
  390. package/src/access-http.ts +33 -40
  391. package/src/access-mcp-output-schemas.ts +6 -0
  392. package/src/access-mcp.test.ts +40 -0
  393. package/src/access-mcp.ts +32 -1
  394. package/src/access-observe-helpers.ts +180 -0
  395. package/src/access-observe-write-surface.ts +78 -19
  396. package/src/access-operations-batch.ts +2 -1
  397. package/src/access-schema-pi.test.ts +17 -0
  398. package/src/access-schema.ts +28 -11
  399. package/src/access-service-helpers.ts +46 -0
  400. package/src/access-service-observe-lcm-parity.test.ts +781 -31
  401. package/src/access-service-observe-scope.test.ts +88 -0
  402. package/src/access-service.ts +46 -128
  403. package/src/access-surface-catalog.test.ts +32 -0
  404. package/src/access-surface-catalog.ts +2 -0
  405. package/src/buffer-session.test.ts +148 -0
  406. package/src/buffer-turn-helpers.ts +152 -0
  407. package/src/buffer.ts +126 -201
  408. package/src/correction/correction-access-wiring.ts +79 -27
  409. package/src/correction/correction-executor.test.ts +542 -1
  410. package/src/correction/correction-executor.ts +309 -89
  411. package/src/correction/correction-planner.test.ts +35 -1
  412. package/src/correction/correction-planner.ts +50 -3
  413. package/src/correction/correction-service.ts +12 -7
  414. package/src/correction/correction-storage-integration.test.ts +172 -1
  415. package/src/correction/passive-capture.test.ts +35 -0
  416. package/src/correction/passive-capture.ts +17 -3
  417. package/src/extraction-source-grounding.ts +55 -1
  418. package/src/extraction-timeout.test.ts +51 -0
  419. package/src/extraction.ts +64 -90
  420. package/src/local-llm-headers-timeout.test.ts +48 -0
  421. package/src/local-llm-helpers.ts +58 -0
  422. package/src/local-llm.ts +62 -58
  423. package/src/orchestration/extraction-run-helpers.ts +309 -0
  424. package/src/orchestration/extraction-run.test.ts +350 -7
  425. package/src/orchestration/extraction-run.ts +327 -250
  426. package/src/orchestration/recall-internal-deps.ts +385 -0
  427. package/src/orchestration/recall-internal.ts +16 -375
  428. package/src/orchestration/session-context.ts +193 -18
  429. package/src/orchestration/turn-ingestion.ts +61 -11
  430. package/src/orchestrator-flush.test.ts +511 -5
  431. package/src/orchestrator.ts +8 -6
  432. package/src/types.ts +2 -2
  433. package/dist/chunk-4A6YGWQN.js.map +0 -1
  434. package/dist/chunk-4WKA6I65.js.map +0 -1
  435. package/dist/chunk-4Z4XNEWZ.js.map +0 -1
  436. package/dist/chunk-6FUPCJUL.js.map +0 -1
  437. package/dist/chunk-B6JDYXL7.js.map +0 -1
  438. package/dist/chunk-GBJ4RDFR.js.map +0 -1
  439. package/dist/chunk-HUHX2OCX.js.map +0 -1
  440. package/dist/chunk-IYZ5K7MU.js.map +0 -1
  441. package/dist/chunk-LGHKJABJ.js.map +0 -1
  442. package/dist/chunk-PHWUFPCO.js.map +0 -1
  443. package/dist/chunk-PUS63Q3G.js.map +0 -1
  444. package/dist/chunk-RPW2NOU6.js.map +0 -1
  445. package/dist/chunk-SPJXKAVF.js.map +0 -1
  446. package/dist/chunk-YTSNAUXN.js.map +0 -1
  447. /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
  448. /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
  449. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  450. /package/dist/{chunk-GIBMDSJ2.js.map → chunk-27P5YVDU.js.map} +0 -0
  451. /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
  452. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  453. /package/dist/{chunk-6U7F52DE.js.map → chunk-4XHR3I67.js.map} +0 -0
  454. /package/dist/{chunk-2EUVEDF5.js.map → chunk-5XA7PQ5I.js.map} +0 -0
  455. /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
  456. /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
  457. /package/dist/{chunk-RGIWINDN.js.map → chunk-7G5MH4NT.js.map} +0 -0
  458. /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
  459. /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
  460. /package/dist/{chunk-M3C2V3PV.js.map → chunk-AJEMDQNA.js.map} +0 -0
  461. /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  462. /package/dist/{chunk-ACXPX4AG.js.map → chunk-BR2K43MK.js.map} +0 -0
  463. /package/dist/{chunk-CZRYLSSW.js.map → chunk-BUGVGH4N.js.map} +0 -0
  464. /package/dist/{chunk-YTQNQ4KB.js.map → chunk-C4VQMFVM.js.map} +0 -0
  465. /package/dist/{chunk-ZPSVBSOF.js.map → chunk-CIVDJD6P.js.map} +0 -0
  466. /package/dist/{chunk-K5GB36ME.js.map → chunk-CZDOT5I2.js.map} +0 -0
  467. /package/dist/{chunk-VI2JQPNQ.js.map → chunk-E4PWACUN.js.map} +0 -0
  468. /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
  469. /package/dist/{chunk-P5PXWTW7.js.map → chunk-EJCAV3QZ.js.map} +0 -0
  470. /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
  471. /package/dist/{chunk-G5R3D5UP.js.map → chunk-GTTAHHD3.js.map} +0 -0
  472. /package/dist/{chunk-H5CPS5JP.js.map → chunk-H36LJIPD.js.map} +0 -0
  473. /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
  474. /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
  475. /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-JCFTIQBR.js.map} +0 -0
  476. /package/dist/{chunk-XOZ4ALGB.js.map → chunk-KE353EWI.js.map} +0 -0
  477. /package/dist/{chunk-W5EG6LE3.js.map → chunk-KIT6M7EB.js.map} +0 -0
  478. /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
  479. /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
  480. /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
  481. /package/dist/{chunk-66772WBP.js.map → chunk-NFXQJHJD.js.map} +0 -0
  482. /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
  483. /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
  484. /package/dist/{chunk-NHWB6HG2.js.map → chunk-NYCGIQRA.js.map} +0 -0
  485. /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
  486. /package/dist/{chunk-FDAMS4PK.js.map → chunk-PNPOWBGC.js.map} +0 -0
  487. /package/dist/{chunk-IC6CBHCA.js.map → chunk-QGENAYVS.js.map} +0 -0
  488. /package/dist/{chunk-62U4J2GN.js.map → chunk-UR77VKF7.js.map} +0 -0
  489. /package/dist/{chunk-JCBWCYEJ.js.map → chunk-VANLTS5F.js.map} +0 -0
  490. /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
  491. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  492. /package/dist/{chunk-TH2LSRMG.js.map → chunk-XHDIB4T4.js.map} +0 -0
  493. /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
  494. /package/dist/{chunk-LBOD4U5B.js.map → chunk-YFOMN2II.js.map} +0 -0
  495. /package/dist/{chunk-I5NLEENJ.js.map → chunk-Z4SWV4VW.js.map} +0 -0
@@ -29,8 +29,11 @@ import { tmpdir } from "node:os";
29
29
  import { join } from "node:path";
30
30
  import test from "node:test";
31
31
 
32
- import { EngramAccessService } from "./access-service.js";
32
+ import { EngramAccessInputError, EngramAccessService } from "./access-service.js";
33
+ import { EngramAccessForbiddenError } from "./access-errors.js";
33
34
  import { Orchestrator } from "./orchestrator.js";
35
+ import { ExtractionDeadlineError } from "./orchestration/extraction-run.js";
36
+ import { SessionOwnershipError } from "./orchestration/session-context.js";
34
37
  import type { EngramAccessObserveRequest } from "./access-service.js";
35
38
  import {
36
39
  combineNamespaces,
@@ -54,7 +57,25 @@ interface ParityProbe {
54
57
  sessionKeys: string[];
55
58
  writeNamespaceOverride?: string;
56
59
  principalOverride?: string;
60
+ sessionOwnerPrincipal?: string;
57
61
  }>;
62
+ lcmEngine: {
63
+ enabled: boolean;
64
+ waitForSessionObserveIdle?: (sessionKey: string) => Promise<void>;
65
+ };
66
+ extractionForceFlushCalls: ExtractionForceFlushCall[];
67
+ }
68
+
69
+ interface ExtractionForceFlushCall {
70
+ sessionKey: string;
71
+ options: {
72
+ reason: string;
73
+ extractionDeadlineMs?: number;
74
+ failOnExtractionFailure?: boolean;
75
+ abortSignal?: AbortSignal;
76
+ writeNamespaceOverride?: string;
77
+ principalOverride?: string;
78
+ };
58
79
  }
59
80
 
60
81
  /**
@@ -72,6 +93,7 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
72
93
  const searchSessionIds: Array<string | undefined> = [];
73
94
  const searchSessionPrefixes: Array<string | undefined> = [];
74
95
  const extractionCalls: ParityProbe["extractionCalls"] = [];
96
+ const extractionForceFlushCalls: ExtractionForceFlushCall[] = [];
75
97
 
76
98
  const config = {
77
99
  namespacesEnabled: true,
@@ -96,6 +118,35 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
96
118
  ...overrides,
97
119
  } as unknown as PluginConfig;
98
120
 
121
+ const lcmEngine = {
122
+ enabled: true,
123
+ enqueueObserveMessages: (sessionKey: string) => {
124
+ lcmWriteKeys.push(sessionKey);
125
+ },
126
+ waitForSessionObserveIdle: async (_sessionKey: string) => {},
127
+ preCompactionFlush: async (sessionKey: string) => {
128
+ compactionFlushKeys.push(sessionKey);
129
+ },
130
+ recordCompaction: async (
131
+ sessionKey: string,
132
+ _before: number,
133
+ _after: number,
134
+ ) => {
135
+ compactionRecordKeys.push(sessionKey);
136
+ },
137
+ searchContextFull: async (
138
+ _query: string,
139
+ _limit: number,
140
+ sessionId?: string,
141
+ sessionPrefix?: string,
142
+ ) => {
143
+ searchSessionIds.push(sessionId);
144
+ searchSessionPrefixes.push(sessionPrefix);
145
+ return [];
146
+ },
147
+ };
148
+
149
+
99
150
  const orch = {
100
151
  config,
101
152
  getCodingContextForSession: (sk: string | undefined) =>
@@ -110,45 +161,29 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
110
161
  Orchestrator.prototype.resolvePrincipal.call(orch, sk),
111
162
  resolveSelfNamespace: (sk?: string) =>
112
163
  Orchestrator.prototype.resolveSelfNamespace.call(orch, sk),
113
- lcmEngine: {
114
- enabled: true,
115
- enqueueObserveMessages: (sessionKey: string) => {
116
- lcmWriteKeys.push(sessionKey);
117
- },
118
- waitForSessionObserveIdle: async (_sessionKey: string) => {},
119
- preCompactionFlush: async (sessionKey: string) => {
120
- compactionFlushKeys.push(sessionKey);
121
- },
122
- recordCompaction: async (
123
- sessionKey: string,
124
- _before: number,
125
- _after: number,
126
- ) => {
127
- compactionRecordKeys.push(sessionKey);
128
- },
129
- searchContextFull: async (
130
- _query: string,
131
- _limit: number,
132
- sessionId?: string,
133
- sessionPrefix?: string,
134
- ) => {
135
- searchSessionIds.push(sessionId);
136
- searchSessionPrefixes.push(sessionPrefix);
137
- return [];
138
- },
139
- },
140
- // Capture extraction routing/identity so the provenance-principal tests can
141
- // assert what `observe` threads into `ingestReplayBatch`.
164
+ lcmEngine,
142
165
  ingestReplayBatch: async (
143
166
  turns: Array<{ sessionKey: string }>,
144
- options: { writeNamespaceOverride?: string; principalOverride?: string } = {},
167
+ options: {
168
+ writeNamespaceOverride?: string;
169
+ principalOverride?: string;
170
+ sessionOwnerPrincipal?: string;
171
+ abortSignal?: AbortSignal;
172
+ } = {},
145
173
  ) => {
146
174
  extractionCalls.push({
147
175
  sessionKeys: turns.map((t) => t.sessionKey),
148
176
  writeNamespaceOverride: options.writeNamespaceOverride,
149
177
  principalOverride: options.principalOverride,
178
+ sessionOwnerPrincipal: options.sessionOwnerPrincipal,
150
179
  });
151
180
  },
181
+ flushSession: async (
182
+ sessionKey: string,
183
+ options: ExtractionForceFlushCall["options"],
184
+ ) => {
185
+ extractionForceFlushCalls.push({ sessionKey, options });
186
+ },
152
187
  } as unknown as Orchestrator;
153
188
 
154
189
  return {
@@ -160,6 +195,8 @@ function makeParityProbe(overrides: Partial<PluginConfig> = {}): ParityProbe {
160
195
  searchSessionIds,
161
196
  searchSessionPrefixes,
162
197
  extractionCalls,
198
+ lcmEngine,
199
+ extractionForceFlushCalls,
163
200
  };
164
201
  }
165
202
 
@@ -339,6 +376,719 @@ test("#1505 thread 2 (c) projectTag: observe LCM write key == recall reader key
339
376
  assert.equal(probe.compactionRecordKeys[0], expectedKey, "record key");
340
377
  });
341
378
 
379
+ test("#2128: disabled LCM flush does not bind per-call project context", async () => {
380
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
381
+ const service = new EngramAccessService(probe.orch);
382
+ const sessionKey = "pi-geek:disabled-lcm-flush";
383
+ probe.lcmEngine.enabled = false;
384
+
385
+ const response = await service.lcmCompactionFlush({
386
+ sessionKey,
387
+ projectTag: "Acme/Webshop",
388
+ authenticatedPrincipal: "pi-geek",
389
+ });
390
+
391
+ assert.equal(response.enabled, false);
392
+ assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
393
+ assert.equal(probe.compactionFlushKeys.length, 0);
394
+ });
395
+
396
+ test("#2128: failed LCM flush rolls back a seeded project context", async () => {
397
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
398
+ const service = new EngramAccessService(probe.orch);
399
+ const sessionKey = "pi-geek:failed-lcm-flush";
400
+ probe.lcmEngine.waitForSessionObserveIdle = async () => {
401
+ throw new Error("idle wait failed");
402
+ };
403
+
404
+ await assert.rejects(
405
+ () =>
406
+ service.lcmCompactionFlush({
407
+ sessionKey,
408
+ projectTag: "Acme/Webshop",
409
+ authenticatedPrincipal: "pi-geek",
410
+ }),
411
+ /idle wait failed/,
412
+ );
413
+ assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
414
+ });
415
+
416
+ test("#2128: successful LCM flush does not bind per-call project context", async () => {
417
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
418
+ const service = new EngramAccessService(probe.orch);
419
+ const sessionKey = "pi-geek:successful-lcm-flush";
420
+
421
+ const response = await service.lcmCompactionFlush({
422
+ sessionKey,
423
+ projectTag: "Acme/Webshop",
424
+ authenticatedPrincipal: "pi-geek",
425
+ });
426
+
427
+ assert.equal(response.enabled, true);
428
+ assert.equal(response.flushed, true);
429
+ assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
430
+ assert.equal(probe.compactionFlushKeys.length, 1);
431
+ });
432
+
433
+ test("#2128: extraction force-flush uses observe's scoped target even when LCM is disabled", async () => {
434
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
435
+ const service = new EngramAccessService(probe.orch);
436
+ const deadlineMs = Date.now() + 10_000;
437
+ const abortController = new AbortController();
438
+ probe.lcmEngine.enabled = false;
439
+
440
+ const response = await service.extractionForceFlush({
441
+ sessionKey: "pi-geek:force-flush",
442
+ projectTag: "Acme/Webshop",
443
+ deadlineMs,
444
+ abortSignal: abortController.signal,
445
+ authenticatedPrincipal: "pi-geek",
446
+ });
447
+
448
+ const expectedNamespace = combineNamespaces(
449
+ "pi-geek",
450
+ projectNamespaceName(projectTagProjectId("Acme/Webshop")),
451
+ );
452
+ assert.equal(response.flushed, true);
453
+ assert.equal(response.effectiveNamespace, expectedNamespace);
454
+ assert.equal(probe.extractionForceFlushCalls.length, 1);
455
+ const [call] = probe.extractionForceFlushCalls;
456
+ assert.equal(call.sessionKey, "pi-geek:force-flush");
457
+ assert.equal(call.options.reason, "access_force_flush");
458
+ assert.equal(
459
+ Object.hasOwn(call.options, "bufferKey"),
460
+ false,
461
+ "force-flush must let the orchestrator discover all session buffer keys",
462
+ );
463
+ assert.equal(call.options.extractionDeadlineMs, deadlineMs);
464
+ assert.equal(call.options.failOnExtractionFailure, true);
465
+ assert.equal(call.options.abortSignal, abortController.signal);
466
+ assert.equal(call.options.writeNamespaceOverride, expectedNamespace);
467
+ assert.equal(
468
+ probe.orch.getCodingContextForSession("pi-geek:force-flush"),
469
+ null,
470
+ "successful extraction force-flush must clear per-call coding context",
471
+ );
472
+ assert.equal(call.options.principalOverride, "pi-geek");
473
+ assert.equal(
474
+ Object.hasOwn(call.options, "sessionOwnerPrincipal"),
475
+ false,
476
+ "force-flush must not claim ownership for opaque buffered turns",
477
+ );
478
+ });
479
+
480
+ test("#2128: single-store force-flush clears retained turns without an owner filter", async () => {
481
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
482
+ const cleanupOwners: Array<string | undefined> = [];
483
+ (probe.orch as unknown as {
484
+ buffer: {
485
+ clearRetainedTurnsForSession(
486
+ sessionKey: string,
487
+ ownerPrincipal?: string,
488
+ options?: { abortSignal?: AbortSignal; deadlineMs?: number },
489
+ ): Promise<void>;
490
+ };
491
+ }).buffer = {
492
+ clearRetainedTurnsForSession: async (_sessionKey, ownerPrincipal) => {
493
+ cleanupOwners.push(ownerPrincipal);
494
+ },
495
+ };
496
+ const service = new EngramAccessService(probe.orch);
497
+
498
+ await service.extractionForceFlush({
499
+ sessionKey: "single-store-session",
500
+ authenticatedPrincipal: "pi-geek",
501
+ });
502
+
503
+ assert.deepEqual(cleanupOwners, [undefined]);
504
+ });
505
+
506
+ test("#2128: force-flush waits for a pending observe extraction", async () => {
507
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
508
+ let resolveExtraction!: () => void;
509
+ const pendingExtraction = new Promise<void>((resolve) => {
510
+ resolveExtraction = resolve;
511
+ });
512
+ probe.orch.ingestReplayBatch = async () => pendingExtraction;
513
+ const service = new EngramAccessService(probe.orch);
514
+ const sessionKey = "pending-observe-extraction";
515
+
516
+ await service.observe(
517
+ observeRequest({
518
+ sessionKey,
519
+ skipExtraction: false,
520
+ }),
521
+ );
522
+
523
+ let settled = false;
524
+ const flushPromise = service.extractionForceFlush({ sessionKey });
525
+ void flushPromise.then(
526
+ () => {
527
+ settled = true;
528
+ },
529
+ () => {
530
+ settled = true;
531
+ },
532
+ );
533
+ await new Promise<void>((resolve) => setImmediate(resolve));
534
+ assert.equal(settled, false);
535
+
536
+ resolveExtraction();
537
+ const response = await flushPromise;
538
+ assert.equal(response.flushed, true);
539
+ });
540
+ test("#2128: pending extraction barriers stay isolated by authenticated principal", async () => {
541
+ const probe = makeParityProbe({
542
+ namespacePolicies: [
543
+ { name: "team", readPrincipals: ["alice", "bob"], writePrincipals: ["alice", "bob"] },
544
+ ],
545
+ } as Partial<PluginConfig>);
546
+ const pending = new Map<string, () => void>();
547
+ probe.orch.ingestReplayBatch = async (_turns, options = {}) =>
548
+ new Promise<void>((resolve) => {
549
+ pending.set(options.principalOverride ?? "", resolve);
550
+ });
551
+ const service = new EngramAccessService(probe.orch);
552
+ const sessionKey = "shared-session";
553
+
554
+ await service.observe(
555
+ observeRequest({
556
+ sessionKey,
557
+ namespace: "team",
558
+ authenticatedPrincipal: "alice",
559
+ skipExtraction: false,
560
+ }),
561
+ );
562
+ await service.observe(
563
+ observeRequest({
564
+ sessionKey,
565
+ namespace: "team",
566
+ authenticatedPrincipal: "bob",
567
+ skipExtraction: false,
568
+ }),
569
+ );
570
+ assert.deepEqual([...pending.keys()].sort(), ["alice", "bob"]);
571
+
572
+ const aliceFlush = service.extractionForceFlush({
573
+ sessionKey,
574
+ namespace: "team",
575
+ authenticatedPrincipal: "alice",
576
+ deadlineMs: Date.now() + 500,
577
+ });
578
+ await new Promise<void>((resolve) => setImmediate(resolve));
579
+ pending.get("alice")?.();
580
+ assert.equal((await aliceFlush).flushed, true);
581
+
582
+ const bobFlush = service.extractionForceFlush({
583
+ sessionKey,
584
+ namespace: "team",
585
+ authenticatedPrincipal: "bob",
586
+ deadlineMs: Date.now() + 500,
587
+ });
588
+ pending.get("bob")?.();
589
+ assert.equal((await bobFlush).flushed, true);
590
+ });
591
+
592
+ test("#2128: chained observes remain behind one force-flush barrier", async () => {
593
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
594
+ const resolvers: Array<() => void> = [];
595
+ probe.orch.ingestReplayBatch = async () =>
596
+ new Promise<void>((resolve) => {
597
+ resolvers.push(resolve);
598
+ });
599
+ const service = new EngramAccessService(probe.orch);
600
+ const sessionKey = "chained-observes";
601
+
602
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
603
+ const flushPromise = service.extractionForceFlush({ sessionKey, deadlineMs: Date.now() + 500 });
604
+ await new Promise<void>((resolve) => setImmediate(resolve));
605
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
606
+ assert.equal(resolvers.length, 2);
607
+
608
+ let settled = false;
609
+ void flushPromise.then(
610
+ () => {
611
+ settled = true;
612
+ },
613
+ () => {
614
+ settled = true;
615
+ },
616
+ );
617
+ resolvers[0]?.();
618
+ await new Promise<void>((resolve) => setImmediate(resolve));
619
+ assert.equal(settled, false);
620
+ resolvers[1]?.();
621
+ assert.equal((await flushPromise).flushed, true);
622
+ });
623
+
624
+ test("#2128: a failed observe extraction is consumed after force-flush reports it", async () => {
625
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
626
+ let rejectExtraction!: (error: Error) => void;
627
+ let extractionAttempt = 0;
628
+ probe.orch.ingestReplayBatch = async () => {
629
+ extractionAttempt += 1;
630
+ if (extractionAttempt > 1) return;
631
+ return new Promise<void>((_resolve, reject) => {
632
+ rejectExtraction = reject;
633
+ });
634
+ };
635
+ const service = new EngramAccessService(probe.orch);
636
+ const sessionKey = "failed-observe-extraction";
637
+ const failure = new Error("provider failed");
638
+
639
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
640
+ rejectExtraction(failure);
641
+ await assert.rejects(
642
+ service.extractionForceFlush({ sessionKey }),
643
+ (error: unknown) => error === failure,
644
+ );
645
+
646
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
647
+ await assert.doesNotReject(() => service.extractionForceFlush({ sessionKey }));
648
+ });
649
+
650
+ test("#2128: force-flush deadline cancels the pending observe extraction", async () => {
651
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
652
+ let extractionSignal: AbortSignal | undefined;
653
+ probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
654
+ extractionSignal = options.abortSignal;
655
+ return new Promise<void>((_resolve, reject) => {
656
+ options.abortSignal?.addEventListener(
657
+ "abort",
658
+ () => reject(new Error("extraction cancelled")),
659
+ { once: true },
660
+ );
661
+ });
662
+ };
663
+ const service = new EngramAccessService(probe.orch);
664
+ const sessionKey = "deadline-cancelled-extraction";
665
+
666
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
667
+ const keepAlive = setInterval(() => {}, 5);
668
+ try {
669
+ await assert.rejects(
670
+ service.extractionForceFlush({
671
+ sessionKey,
672
+ deadlineMs: Date.now() + 25,
673
+ }),
674
+ (error: unknown) =>
675
+ error instanceof EngramAccessInputError &&
676
+ error.message.includes("pending_observe_extraction"),
677
+ );
678
+ } finally {
679
+ clearInterval(keepAlive);
680
+ }
681
+ assert.equal(extractionSignal?.aborted, true);
682
+ });
683
+
684
+ test("#2128: force-flush abort signal cancels the pending observe extraction", async () => {
685
+ const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
686
+ let extractionSignal: AbortSignal | undefined;
687
+ probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
688
+ extractionSignal = options.abortSignal;
689
+ return new Promise<void>((_resolve, reject) => {
690
+ options.abortSignal?.addEventListener(
691
+ "abort",
692
+ () => reject(new Error("extraction cancelled")),
693
+ { once: true },
694
+ );
695
+ });
696
+ };
697
+ const service = new EngramAccessService(probe.orch);
698
+ const sessionKey = "abort-cancelled-extraction";
699
+ const abortController = new AbortController();
700
+
701
+ await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
702
+ const flushPromise = service.extractionForceFlush({
703
+ sessionKey,
704
+ abortSignal: abortController.signal,
705
+ });
706
+ await new Promise<void>((resolve) => setImmediate(resolve));
707
+ abortController.abort();
708
+ await assert.rejects(
709
+ flushPromise,
710
+ (error: unknown) => error instanceof Error && error.message === "extraction force-flush aborted",
711
+ );
712
+ assert.equal(extractionSignal?.aborted, true);
713
+ });
714
+
715
+ test("#2128: force-flush abort only cancels the resolved namespace barrier", async () => {
716
+ const probe = makeParityProbe({
717
+ namespacePolicies: [
718
+ { name: "project-a", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
719
+ { name: "project-b", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
720
+ ],
721
+ } as Partial<PluginConfig>);
722
+ const extractionSignals = new Map<string, AbortSignal | undefined>();
723
+ const extractionResolvers = new Map<string, () => void>();
724
+ probe.orch.ingestReplayBatch = async (_turns, options = {}) => {
725
+ const namespace = options.writeNamespaceOverride ?? "";
726
+ extractionSignals.set(namespace, options.abortSignal);
727
+ return new Promise<void>((resolve, reject) => {
728
+ extractionResolvers.set(namespace, resolve);
729
+ options.abortSignal?.addEventListener(
730
+ "abort",
731
+ () => reject(options.abortSignal?.reason ?? new Error("extraction cancelled")),
732
+ { once: true },
733
+ );
734
+ });
735
+ };
736
+ const service = new EngramAccessService(probe.orch);
737
+ const sessionKey = "opaque-shared-session";
738
+ const namespaceA = "project-a";
739
+ const namespaceB = "project-b";
740
+
741
+ await service.observe(
742
+ observeRequest({
743
+ sessionKey,
744
+ authenticatedPrincipal: "pi-geek",
745
+ namespace: namespaceA,
746
+ skipExtraction: false,
747
+ }),
748
+ );
749
+ await service.observe(
750
+ observeRequest({
751
+ sessionKey,
752
+ authenticatedPrincipal: "pi-geek",
753
+ namespace: namespaceB,
754
+ skipExtraction: false,
755
+ }),
756
+ );
757
+ assert.ok(extractionSignals.has(namespaceA));
758
+ assert.ok(extractionSignals.has(namespaceB));
759
+
760
+ const abortController = new AbortController();
761
+ const flushA = service.extractionForceFlush({
762
+ sessionKey,
763
+ authenticatedPrincipal: "pi-geek",
764
+ namespace: namespaceA,
765
+ abortSignal: abortController.signal,
766
+ });
767
+ await new Promise<void>((resolve) => setImmediate(resolve));
768
+ abortController.abort();
769
+ await assert.rejects(
770
+ flushA,
771
+ (error: unknown) => error instanceof Error && error.message === "extraction force-flush aborted",
772
+ );
773
+ assert.equal(extractionSignals.get(namespaceA)?.aborted, true);
774
+ assert.equal(extractionSignals.get(namespaceB)?.aborted, false);
775
+
776
+ extractionResolvers.get(namespaceB)?.();
777
+ await assert.doesNotReject(() =>
778
+ service.extractionForceFlush({
779
+ sessionKey,
780
+ authenticatedPrincipal: "pi-geek",
781
+ namespace: namespaceB,
782
+ }),
783
+ );
784
+ });
785
+
786
+ test("#2128: authenticated opaque sessions persist their trusted owner for force-flush", async () => {
787
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
788
+ const service = new EngramAccessService(probe.orch);
789
+ const sessionKey = "opaque-session-42";
790
+
791
+ await service.observe(
792
+ observeRequest({
793
+ sessionKey,
794
+ authenticatedPrincipal: "pi-geek",
795
+ skipExtraction: false,
796
+ }),
797
+ );
798
+
799
+ assert.equal(probe.extractionCalls[0]?.sessionOwnerPrincipal, "pi-geek");
800
+ const response = await service.extractionForceFlush({
801
+ sessionKey,
802
+ authenticatedPrincipal: "pi-geek",
803
+ projectTag: "Acme/Webshop",
804
+ });
805
+ assert.equal(response.flushed, true);
806
+ assert.equal(probe.extractionForceFlushCalls[0]?.options.principalOverride, "pi-geek");
807
+ assert.equal(
808
+ probe.orch.getCodingContextForSession(sessionKey),
809
+ null,
810
+ "opaque force-flush must not persist caller project context",
811
+ );
812
+ });
813
+
814
+
815
+ test("#2128: extraction force-flush rejects a session owned by another principal", async () => {
816
+ const probe = makeParityProbe({
817
+ ...withSelfPolicyPrefix("pi-geek"),
818
+ namespacePolicies: [
819
+ { name: "pi-geek", readPrincipals: ["pi-geek"], writePrincipals: ["pi-geek"] },
820
+ { name: "victim", readPrincipals: ["victim"], writePrincipals: ["victim"] },
821
+ ],
822
+ principalFromSessionKeyRules: [
823
+ { match: "pi-geek:", principal: "pi-geek" },
824
+ { match: "victim:", principal: "victim" },
825
+ ],
826
+ });
827
+ const service = new EngramAccessService(probe.orch);
828
+
829
+ await assert.rejects(
830
+ () =>
831
+ service.extractionForceFlush({
832
+ sessionKey: "victim:private-session",
833
+ authenticatedPrincipal: "pi-geek",
834
+ }),
835
+ /sessionKey is not owned by authenticated principal/,
836
+ );
837
+ assert.equal(probe.extractionForceFlushCalls.length, 0);
838
+ });
839
+
840
+ test("#2128: opaque ownership denial is surfaced as a forbidden access error", async () => {
841
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
842
+ probe.orch.flushSession = async () => {
843
+ throw new SessionOwnershipError("session opaque-session has buffered turns without trusted ownership");
844
+ };
845
+ const service = new EngramAccessService(probe.orch);
846
+
847
+ await assert.rejects(
848
+ () =>
849
+ service.extractionForceFlush({
850
+ sessionKey: "opaque-session",
851
+ authenticatedPrincipal: "pi-geek",
852
+ }),
853
+ (error: unknown) =>
854
+ error instanceof EngramAccessForbiddenError &&
855
+ error.message === "session opaque-session has buffered turns without trusted ownership",
856
+ );
857
+ });
858
+
859
+ test("#2128: explicit namespace force-flush does not bind unrelated project context", async () => {
860
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
861
+ const service = new EngramAccessService(probe.orch);
862
+ const sessionKey = "pi-geek:explicit-scope";
863
+
864
+ await service.extractionForceFlush({
865
+ sessionKey,
866
+ namespace: "pi-geek",
867
+ projectTag: "Acme/Webshop",
868
+ authenticatedPrincipal: "pi-geek",
869
+ });
870
+
871
+ assert.equal(probe.orch.getCodingContextForSession(sessionKey), null);
872
+ });
873
+ test("#2128: post-flush retained cleanup is best effort and receives lifecycle guards", async () => {
874
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
875
+ const abortController = new AbortController();
876
+ const cleanupCalls: Array<{
877
+ sessionKey: string;
878
+ ownerPrincipal?: string;
879
+ options?: { abortSignal?: AbortSignal; deadlineMs?: number };
880
+ }> = [];
881
+ (probe.orch as unknown as {
882
+ buffer: {
883
+ clearRetainedTurnsForSession(
884
+ sessionKey: string,
885
+ ownerPrincipal?: string,
886
+ options?: { abortSignal?: AbortSignal; deadlineMs?: number },
887
+ ): Promise<void>;
888
+ };
889
+ }).buffer = {
890
+ clearRetainedTurnsForSession: async (sessionKey, ownerPrincipal, options) => {
891
+ cleanupCalls.push({ sessionKey, ownerPrincipal, options });
892
+ throw new Error("retained cleanup unavailable");
893
+ },
894
+ };
895
+ const service = new EngramAccessService(probe.orch);
896
+ const deadlineMs = Date.now() + 10_000;
897
+
898
+ const response = await service.extractionForceFlush({
899
+ sessionKey: "pi-geek:cleanup-best-effort",
900
+ authenticatedPrincipal: "pi-geek",
901
+ abortSignal: abortController.signal,
902
+ deadlineMs,
903
+ });
904
+
905
+ assert.equal(response.flushed, true);
906
+ assert.deepEqual(cleanupCalls, [{
907
+ sessionKey: "pi-geek:cleanup-best-effort",
908
+ ownerPrincipal: "pi-geek",
909
+ options: { abortSignal: abortController.signal, deadlineMs },
910
+ }]);
911
+ });
912
+
913
+ test("#2128: post-flush retained cleanup stops on abort or deadline", async () => {
914
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
915
+ (probe.orch as unknown as {
916
+ buffer: {
917
+ clearRetainedTurnsForSession(
918
+ sessionKey: string,
919
+ ownerPrincipal?: string,
920
+ options?: { abortSignal?: AbortSignal; deadlineMs?: number },
921
+ ): Promise<void>;
922
+ };
923
+ }).buffer = {
924
+ clearRetainedTurnsForSession: async () => new Promise<void>(() => {}),
925
+ };
926
+ const service = new EngramAccessService(probe.orch);
927
+ const abortController = new AbortController();
928
+ setTimeout(() => abortController.abort(), 5).unref();
929
+
930
+ await assert.rejects(
931
+ () =>
932
+ Promise.race([
933
+ service.extractionForceFlush({
934
+ sessionKey: "pi-geek:cleanup-abort",
935
+ authenticatedPrincipal: "pi-geek",
936
+ abortSignal: abortController.signal,
937
+ }),
938
+ new Promise<never>((_resolve, reject) =>
939
+ setTimeout(() => reject(new Error("abort cleanup test timed out")), 100),
940
+ ),
941
+ ]),
942
+ /extraction force-flush aborted/,
943
+ );
944
+
945
+ await assert.rejects(
946
+ () =>
947
+ Promise.race([
948
+ service.extractionForceFlush({
949
+ sessionKey: "pi-geek:cleanup-deadline",
950
+ authenticatedPrincipal: "pi-geek",
951
+ deadlineMs: Date.now() + 5,
952
+ }),
953
+ new Promise<never>((_resolve, reject) =>
954
+ setTimeout(() => reject(new Error("deadline cleanup test timed out")), 100),
955
+ ),
956
+ ]),
957
+ /replay extraction deadline exceeded \(retained_turn_cleanup\)/,
958
+ );
959
+ });
960
+ test("#2128: aborted or expired extraction force-flush never touches a buffer", async () => {
961
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
962
+ const service = new EngramAccessService(probe.orch);
963
+ const abortController = new AbortController();
964
+ abortController.abort();
965
+
966
+ await assert.rejects(
967
+ () =>
968
+ service.extractionForceFlush({
969
+ sessionKey: "pi-geek:aborted-flush",
970
+ authenticatedPrincipal: "pi-geek",
971
+ abortSignal: abortController.signal,
972
+ }),
973
+ /extraction force-flush aborted/,
974
+ );
975
+ await assert.rejects(
976
+ () =>
977
+ service.extractionForceFlush({
978
+ sessionKey: "pi-geek:expired-flush",
979
+ authenticatedPrincipal: "pi-geek",
980
+ deadlineMs: Date.now() - 1,
981
+ }),
982
+ (error: unknown) =>
983
+ error instanceof EngramAccessInputError &&
984
+ error.message === "extraction force-flush deadline exceeded before buffer drain",
985
+ );
986
+ assert.equal(probe.extractionForceFlushCalls.length, 0);
987
+ });
988
+
989
+ test("#2128: self-deps wires force-flush cancellation into the observe tracker", async () => {
990
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
991
+ const service = new EngramAccessService(probe.orch);
992
+ const cancellations: Array<{
993
+ sessionKey: string;
994
+ principal?: string;
995
+ namespace?: string;
996
+ }> = [];
997
+ const surface = (service as unknown as {
998
+ accessObserveWriteSurface: {
999
+ cancelPendingObserveExtractions(
1000
+ sessionKey: string,
1001
+ principal?: string,
1002
+ namespace?: string,
1003
+ ): void;
1004
+ };
1005
+ }).accessObserveWriteSurface;
1006
+ surface.cancelPendingObserveExtractions = (sessionKey, principal, namespace) => {
1007
+ cancellations.push({ sessionKey, principal, namespace });
1008
+ };
1009
+
1010
+ await assert.rejects(
1011
+ () =>
1012
+ service.extractionForceFlush({
1013
+ sessionKey: "pi-geek:cancel-hook",
1014
+ namespace: "pi-geek",
1015
+ authenticatedPrincipal: "pi-geek",
1016
+ deadlineMs: Date.now() - 1,
1017
+ }),
1018
+ (error: unknown) =>
1019
+ error instanceof EngramAccessInputError &&
1020
+ error.message === "extraction force-flush deadline exceeded before buffer drain",
1021
+ );
1022
+ assert.deepEqual(cancellations, [{
1023
+ sessionKey: "pi-geek:cancel-hook",
1024
+ principal: "pi-geek",
1025
+ namespace: "pi-geek",
1026
+ }]);
1027
+ });
1028
+
1029
+ test("#2128: late extraction deadline is surfaced as an access input error", async () => {
1030
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
1031
+ probe.orch.flushSession = async () => {
1032
+ throw new ExtractionDeadlineError("during_extract");
1033
+ };
1034
+ const service = new EngramAccessService(probe.orch);
1035
+
1036
+ await assert.rejects(
1037
+ () =>
1038
+ service.extractionForceFlush({
1039
+ sessionKey: "pi-geek:late-deadline",
1040
+ authenticatedPrincipal: "pi-geek",
1041
+ deadlineMs: Date.now() + 10_000,
1042
+ }),
1043
+ (error: unknown) =>
1044
+ error instanceof EngramAccessInputError &&
1045
+ error.message === "replay extraction deadline exceeded (during_extract)",
1046
+ );
1047
+ });
1048
+
1049
+ test("#2128: force-flush scope resolution does not overwrite a concurrent observe context", async () => {
1050
+ const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
1051
+ const service = new EngramAccessService(probe.orch);
1052
+ const sessionKey = "pi-geek:concurrent-scope";
1053
+ let releaseFlush!: () => void;
1054
+ const flushBlocked = new Promise<void>((resolve) => {
1055
+ releaseFlush = resolve;
1056
+ });
1057
+ probe.orch.flushSession = async () => flushBlocked;
1058
+
1059
+ const flushPromise = service.extractionForceFlush({
1060
+ sessionKey,
1061
+ projectTag: "Acme/FlushProject",
1062
+ authenticatedPrincipal: "pi-geek",
1063
+ });
1064
+ await new Promise<void>((resolve) => setImmediate(resolve));
1065
+ assert.equal(
1066
+ probe.orch.getCodingContextForSession(sessionKey),
1067
+ null,
1068
+ "force-flush scope resolution must stay local while its drain is pending",
1069
+ );
1070
+
1071
+ await service.observe(
1072
+ observeRequest({
1073
+ sessionKey,
1074
+ projectTag: "Acme/ObserveProject",
1075
+ authenticatedPrincipal: "pi-geek",
1076
+ skipExtraction: true,
1077
+ }),
1078
+ );
1079
+ const observedContext = probe.orch.getCodingContextForSession(sessionKey);
1080
+ assert.ok(observedContext);
1081
+ assert.equal(observedContext.projectId, projectTagProjectId("Acme/ObserveProject"));
1082
+
1083
+ releaseFlush();
1084
+ await flushPromise;
1085
+ assert.equal(
1086
+ probe.orch.getCodingContextForSession(sessionKey)?.projectId,
1087
+ projectTagProjectId("Acme/ObserveProject"),
1088
+ "force-flush cleanup must not clear a context attached by the concurrent observe",
1089
+ );
1090
+ });
1091
+
342
1092
  test("#1505 thread 2 (b) cwd git repo: observe LCM write key == recall reader key == compaction keys", async () => {
343
1093
  const repoDir = mkdtempSync(join(tmpdir(), "remnic-lcm-parity-git-"));
344
1094
  const git = (...args: string[]) =>