@remnic/core 9.65.7 → 9.65.8

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 (512) hide show
  1. package/dist/access-admin-ops-surface.d.ts +15 -13
  2. package/dist/access-admin-ops-surface.js +42 -42
  3. package/dist/access-authorization-probe.d.ts +15 -13
  4. package/dist/access-authorization-probe.js +43 -43
  5. package/dist/access-boundary.d.ts +15 -13
  6. package/dist/access-boundary.js +42 -42
  7. package/dist/access-cli.js +143 -140
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +2 -1
  10. package/dist/access-extraction-force-flush.d.ts +15 -13
  11. package/dist/access-extraction-force-flush.js +42 -42
  12. package/dist/access-health-types.d.ts +2 -1
  13. package/dist/access-http-lcm-compaction.d.ts +15 -13
  14. package/dist/access-http-lifecycle-flush.d.ts +15 -13
  15. package/dist/access-http-offline-stream.d.ts +15 -13
  16. package/dist/access-http-query.d.ts +3 -2
  17. package/dist/access-http-query.js +44 -44
  18. package/dist/access-http.d.ts +16 -14
  19. package/dist/access-http.js +59 -59
  20. package/dist/access-identity-continuity-surface.d.ts +13 -11
  21. package/dist/access-identity-continuity-surface.js +42 -42
  22. package/dist/access-lcm-surface.d.ts +15 -13
  23. package/dist/access-lcm-surface.js +42 -42
  24. package/dist/access-mcp.d.ts +15 -13
  25. package/dist/access-mcp.js +49 -49
  26. package/dist/access-memory-search-fanout.d.ts +3 -2
  27. package/dist/{access-namespace-preflight-8VYKmRX0.d.ts → access-namespace-preflight-CpAOrS-9.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +4 -3
  29. package/dist/access-namespace-preflight.js +42 -42
  30. package/dist/access-observe-write-surface.d.ts +15 -13
  31. package/dist/access-observe-write-surface.js +42 -42
  32. package/dist/access-offline-manifest.d.ts +13 -11
  33. package/dist/access-offline-manifest.js +6 -6
  34. package/dist/access-operations-batch.js +45 -45
  35. package/dist/access-operations.d.ts +20 -18
  36. package/dist/access-operations.js +48 -48
  37. package/dist/access-recall-concurrency.d.ts +15 -13
  38. package/dist/access-recall-concurrency.js +42 -42
  39. package/dist/access-recall-response.d.ts +15 -13
  40. package/dist/access-recall-response.js +42 -42
  41. package/dist/access-recall-surface.d.ts +15 -13
  42. package/dist/access-recall-surface.js +42 -42
  43. package/dist/access-schema.d.ts +83 -83
  44. package/dist/{access-service-Crk__Git.d.ts → access-service-Diu61Cfv.d.ts} +71 -71
  45. package/dist/access-service-helpers.d.ts +15 -13
  46. package/dist/access-service.d.ts +15 -13
  47. package/dist/access-service.js +42 -42
  48. package/dist/access-surface-catalog.d.ts +15 -13
  49. package/dist/access-surface-catalog.js +44 -44
  50. package/dist/access-wearables-meetings-surface.d.ts +6 -3
  51. package/dist/action-confidence.d.ts +2 -1
  52. package/dist/active-context-config.d.ts +27 -0
  53. package/dist/active-context-config.js +14 -0
  54. package/dist/active-context-transform.d.ts +267 -0
  55. package/dist/active-context-transform.js +31 -0
  56. package/dist/active-context-transform.js.map +1 -0
  57. package/dist/active-memory-bridge.d.ts +2 -1
  58. package/dist/active-recall.d.ts +2 -1
  59. package/dist/active-recall.js +10 -9
  60. package/dist/active-recall.js.map +1 -1
  61. package/dist/adapters/index.js +7 -7
  62. package/dist/adapters/registry.js +3 -3
  63. package/dist/ambient-provenance.d.ts +2 -1
  64. package/dist/artifact-search.d.ts +2 -1
  65. package/dist/{auto-sync-XVMLL2RH.js → auto-sync-2YPITIWN.js} +6 -6
  66. package/dist/behavior-learner.d.ts +2 -1
  67. package/dist/behavior-signals.d.ts +2 -1
  68. package/dist/bootstrap.d.ts +13 -11
  69. package/dist/briefing-window.d.ts +5 -2
  70. package/dist/briefing.d.ts +5 -2
  71. package/dist/briefing.js +23 -23
  72. package/dist/buffer-surprise-report.d.ts +2 -1
  73. package/dist/buffer-turn-helpers.d.ts +2 -1
  74. package/dist/buffer.d.ts +5 -2
  75. package/dist/buffer.js +6 -6
  76. package/dist/bulk-import/index.d.ts +4 -3
  77. package/dist/calibration.d.ts +2 -1
  78. package/dist/capabilities.d.ts +2 -1
  79. package/dist/{catalog-DybwVNW3.d.ts → catalog-9f-vEQLS.d.ts} +1 -1
  80. package/dist/causal-behavior.d.ts +4 -3
  81. package/dist/causal-consolidation.d.ts +2 -1
  82. package/dist/causal-consolidation.js +24 -24
  83. package/dist/causal-trajectory-graph.d.ts +2 -1
  84. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  85. package/dist/{chunk-S3K2CIK5.js → chunk-3A2NJP2U.js} +2 -2
  86. package/dist/{chunk-OPGL46PX.js → chunk-3PKAS6VL.js} +2 -2
  87. package/dist/{chunk-GTSVEEP3.js → chunk-3SZD4CYO.js} +3 -3
  88. package/dist/chunk-43HUVDTD.js +114 -0
  89. package/dist/chunk-43HUVDTD.js.map +1 -0
  90. package/dist/{chunk-YKWFK7XA.js → chunk-4F4AQFWL.js} +7 -7
  91. package/dist/{chunk-RGCF4XNH.js → chunk-4QEYREAV.js} +9 -9
  92. package/dist/{chunk-46WM6JX2.js → chunk-4ZWCQJNM.js} +5 -5
  93. package/dist/{chunk-DVYRD4HY.js → chunk-5ACCD4L7.js} +30 -1
  94. package/dist/chunk-5ACCD4L7.js.map +1 -0
  95. package/dist/{chunk-3RI5Y7KU.js → chunk-5DHKCO52.js} +2 -2
  96. package/dist/{chunk-VKCAHCBI.js → chunk-5RWZH6PH.js} +2 -2
  97. package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
  98. package/dist/{chunk-A32YEQAM.js → chunk-76DIF5KT.js} +2 -2
  99. package/dist/{chunk-OPPBTPUU.js → chunk-7KQB4EBS.js} +4 -4
  100. package/dist/{chunk-I2HTKOOP.js → chunk-7VZFRUQU.js} +3 -3
  101. package/dist/{chunk-D4QVPP3G.js → chunk-7WOWGRAU.js} +10 -6
  102. package/dist/chunk-7WOWGRAU.js.map +1 -0
  103. package/dist/{chunk-JCWY73FK.js → chunk-AHPIFKNG.js} +2 -2
  104. package/dist/{chunk-IP4ZNT4U.js → chunk-AZMLH5UT.js} +2 -2
  105. package/dist/chunk-B32WYRXX.js +77 -0
  106. package/dist/chunk-B32WYRXX.js.map +1 -0
  107. package/dist/{chunk-JOEJG4SD.js → chunk-BEC4YBNA.js} +4 -4
  108. package/dist/{chunk-VXVZ2GM3.js → chunk-CAMNRAJF.js} +2 -2
  109. package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
  110. package/dist/{chunk-YOXVZJFM.js → chunk-CFVTRUR3.js} +2 -2
  111. package/dist/{chunk-SVSRPG6M.js → chunk-CPA5NBHN.js} +2 -2
  112. package/dist/{chunk-7BEPVIH3.js → chunk-CRML27CO.js} +3 -3
  113. package/dist/{chunk-IY7UXD3J.js → chunk-DA7ITC5Z.js} +2 -2
  114. package/dist/{chunk-AFR6AIM4.js → chunk-DEACDKE3.js} +3 -3
  115. package/dist/{chunk-NG3MBQV4.js → chunk-DPCXDG7G.js} +2 -2
  116. package/dist/{chunk-HZNYJN77.js → chunk-F3NVYTTA.js} +2 -2
  117. package/dist/{chunk-PDDSFELN.js → chunk-F7XUD3PL.js} +2 -2
  118. package/dist/{chunk-YWSQD2IB.js → chunk-GTO56JY5.js} +2 -2
  119. package/dist/{chunk-RAIUTAZZ.js → chunk-H2YSH3DG.js} +2 -2
  120. package/dist/{chunk-F6QHHRWP.js → chunk-HMZKGHMD.js} +2 -2
  121. package/dist/{chunk-ZIJDI4CP.js → chunk-HRHO3ZNG.js} +2 -2
  122. package/dist/{chunk-SDEPLF7V.js → chunk-IBJ6U753.js} +2 -2
  123. package/dist/{chunk-T3JQTCCO.js → chunk-JI7U6AS3.js} +4 -4
  124. package/dist/{chunk-TR7DGXGI.js → chunk-JOZUBF4A.js} +5 -5
  125. package/dist/{chunk-I7EX6KSH.js → chunk-JYSN42VN.js} +55 -55
  126. package/dist/{chunk-ZPUIRTIZ.js → chunk-KOLJJN5G.js} +12 -75
  127. package/dist/chunk-KOLJJN5G.js.map +1 -0
  128. package/dist/{chunk-FMQ4MOQO.js → chunk-KZIF6XHX.js} +14 -14
  129. package/dist/chunk-LB7WCZHY.js +553 -0
  130. package/dist/chunk-LB7WCZHY.js.map +1 -0
  131. package/dist/{chunk-RIAM7DND.js → chunk-LDKPDODJ.js} +2 -2
  132. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  133. package/dist/{chunk-LLQCM2U2.js → chunk-LKYIOCWL.js} +101 -101
  134. package/dist/{chunk-5S4LQOPE.js → chunk-LOXHYCVS.js} +2 -2
  135. package/dist/{chunk-ANJXPFRS.js → chunk-LPNCR4QK.js} +8 -8
  136. package/dist/{chunk-GEPACVWN.js → chunk-MDD2RINF.js} +2 -2
  137. package/dist/{chunk-H63EDPFJ.js → chunk-MI2OTWV5.js} +15 -2
  138. package/dist/{chunk-H63EDPFJ.js.map → chunk-MI2OTWV5.js.map} +1 -1
  139. package/dist/{chunk-LBFFNDFM.js → chunk-MINHJ55X.js} +1 -1
  140. package/dist/chunk-MINHJ55X.js.map +1 -0
  141. package/dist/{chunk-6CPUQ5D6.js → chunk-MY2BC6UE.js} +13 -13
  142. package/dist/{chunk-CFGU52XJ.js → chunk-NPFUNWNX.js} +2 -2
  143. package/dist/{chunk-MFOSZUIT.js → chunk-NPIBN2VL.js} +2 -2
  144. package/dist/{chunk-5DH6PG4B.js → chunk-OA2O2GJ4.js} +3 -3
  145. package/dist/{chunk-JAQXUGLN.js → chunk-ODU2CNNX.js} +2 -2
  146. package/dist/{chunk-RQE4TITU.js → chunk-OXRRJXPR.js} +32 -32
  147. package/dist/{chunk-SEA6M7SS.js → chunk-P36Z4JRA.js} +2 -2
  148. package/dist/{chunk-Z4U3UN56.js → chunk-PU56CXZA.js} +6 -6
  149. package/dist/{chunk-5VPQSRQO.js → chunk-S5XOSTYM.js} +3 -3
  150. package/dist/{chunk-SVVIASVX.js → chunk-SEEJOGQX.js} +5 -5
  151. package/dist/{chunk-7TCGNUVP.js → chunk-SNOIKAHM.js} +2 -2
  152. package/dist/{chunk-7F27PCSN.js → chunk-T6ILXUAH.js} +2 -2
  153. package/dist/{chunk-EOHKUWXW.js → chunk-T7XP6IZE.js} +2 -2
  154. package/dist/{chunk-7WR462EM.js → chunk-TFR3HG4K.js} +3 -3
  155. package/dist/{chunk-YRVAKONL.js → chunk-TUHBYJXL.js} +1 -1
  156. package/dist/{chunk-F635GAL7.js → chunk-U7EW2W4W.js} +10 -10
  157. package/dist/{chunk-VFYRYFLL.js → chunk-UEBDCMOO.js} +2 -2
  158. package/dist/{chunk-WTOZBZNN.js → chunk-UENKPWCS.js} +4 -4
  159. package/dist/{chunk-AAXJNINV.js → chunk-UL4MKZHI.js} +2 -2
  160. package/dist/{chunk-R2MZCYA6.js → chunk-UNUMFURP.js} +3 -3
  161. package/dist/{chunk-ACOC27BB.js → chunk-UPFNQJC7.js} +2 -2
  162. package/dist/{chunk-W4BMEGQA.js → chunk-UTQUEHC7.js} +2 -2
  163. package/dist/{chunk-I32NKXE2.js → chunk-V4IDF3EZ.js} +2 -2
  164. package/dist/{chunk-BJTHRFFC.js → chunk-W2BAGGEW.js} +51 -19
  165. package/dist/chunk-W2BAGGEW.js.map +1 -0
  166. package/dist/{chunk-ZAOHJDKH.js → chunk-WNXYT4MK.js} +3 -3
  167. package/dist/{chunk-T42L3S6A.js → chunk-XBGHAAKR.js} +2 -2
  168. package/dist/{chunk-I4343FIA.js → chunk-XNWXSGHS.js} +4 -4
  169. package/dist/{chunk-THG4GYIE.js → chunk-YEUXERJ6.js} +5 -5
  170. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  171. package/dist/{chunk-5HERQ5FX.js → chunk-Z3YEGSR4.js} +10 -10
  172. package/dist/{cli-B322UMvB.d.ts → cli-O3F-ht3i.d.ts} +5 -5
  173. package/dist/cli.d.ts +17 -15
  174. package/dist/cli.js +92 -91
  175. package/dist/coding/pre-action-gate.d.ts +2 -1
  176. package/dist/compounding/engine.d.ts +5 -2
  177. package/dist/compounding/engine.js +24 -24
  178. package/dist/compounding/preference-consolidator.d.ts +4 -3
  179. package/dist/compression-optimizer.d.ts +2 -1
  180. package/dist/config-security.js +2 -2
  181. package/dist/config.d.ts +2 -1
  182. package/dist/config.js +10 -9
  183. package/dist/connectors/codex-materialize-runner.d.ts +2 -1
  184. package/dist/connectors/codex-materialize-runner.js +23 -23
  185. package/dist/connectors/codex-materialize.d.ts +2 -1
  186. package/dist/connectors/index.d.ts +2 -1
  187. package/dist/connectors/index.js +23 -23
  188. package/dist/consolidation-provenance-check.d.ts +5 -2
  189. package/dist/consolidation-provenance-check.js +2 -2
  190. package/dist/consolidation-undo.d.ts +5 -2
  191. package/dist/context-summary.d.ts +43 -0
  192. package/dist/context-summary.js +14 -0
  193. package/dist/context-summary.js.map +1 -0
  194. package/dist/contradiction/index.d.ts +6 -3
  195. package/dist/contradiction/index.js +5 -5
  196. package/dist/converge-config.d.ts +2 -1
  197. package/dist/convergence-refresh.d.ts +5 -2
  198. package/dist/convergence-refresh.js +26 -26
  199. package/dist/conversation-index/backend.d.ts +2 -1
  200. package/dist/conversation-index/backend.js +2 -2
  201. package/dist/conversation-index/chunker.d.ts +2 -1
  202. package/dist/conversation-index/faiss-adapter.d.ts +2 -1
  203. package/dist/conversation-index/indexer.d.ts +2 -1
  204. package/dist/conversation-index/search.d.ts +2 -1
  205. package/dist/corpus-watermark.d.ts +2 -1
  206. package/dist/corpus-watermark.js +25 -25
  207. package/dist/cross-lingual-recall.d.ts +2 -1
  208. package/dist/dashboard-runtime.js +2 -2
  209. package/dist/day-summary.d.ts +2 -1
  210. package/dist/delinearize.d.ts +2 -1
  211. package/dist/dependency-propagation-config.d.ts +2 -1
  212. package/dist/{dependency-propagation-delivery-BGcNairQ.d.ts → dependency-propagation-delivery-CL6RWXTA.d.ts} +1 -1
  213. package/dist/direct-answer-wiring.d.ts +2 -1
  214. package/dist/direct-answer.d.ts +2 -1
  215. package/dist/embedding-fallback.d.ts +2 -1
  216. package/dist/enrichment/index.d.ts +2 -1
  217. package/dist/entity-origin-fields.d.ts +2 -1
  218. package/dist/entity-retrieval.d.ts +5 -2
  219. package/dist/entity-retrieval.js +24 -24
  220. package/dist/entity-schema.d.ts +2 -1
  221. package/dist/episodic-context.d.ts +2 -1
  222. package/dist/eval-trajectory-contracts.d.ts +2 -1
  223. package/dist/eval-trajectory-store.d.ts +2 -1
  224. package/dist/eval-trajectory.d.ts +2 -1
  225. package/dist/event-order-recall.js +3 -3
  226. package/dist/explicit-capture.d.ts +13 -11
  227. package/dist/explicit-capture.js +6 -6
  228. package/dist/external-wiki-access.d.ts +15 -13
  229. package/dist/external-wiki-access.js +43 -43
  230. package/dist/external-wiki-collection-registration.d.ts +2 -1
  231. package/dist/external-wiki-collection.d.ts +2 -1
  232. package/dist/external-wiki-mcp-tools.d.ts +15 -13
  233. package/dist/extraction-error-classification.d.ts +2 -1
  234. package/dist/extraction-faithfulness.d.ts +2 -1
  235. package/dist/extraction-judge-telemetry.d.ts +2 -1
  236. package/dist/extraction-judge-training.d.ts +2 -1
  237. package/dist/extraction-judge.d.ts +2 -1
  238. package/dist/extraction-liveness.d.ts +2 -1
  239. package/dist/extraction-normalization.d.ts +2 -1
  240. package/dist/extraction-prompt.d.ts +2 -1
  241. package/dist/extraction-source-grounding-rules.d.ts +2 -1
  242. package/dist/extraction-source-grounding.d.ts +2 -1
  243. package/dist/extraction.d.ts +2 -1
  244. package/dist/extraction.js +31 -31
  245. package/dist/fallback-llm.d.ts +2 -1
  246. package/dist/{forget-SZ2BXDGF.js → forget-2AE4MDK3.js} +3 -3
  247. package/dist/graph-dashboard-diff.d.ts +2 -1
  248. package/dist/graph-dashboard-key.d.ts +2 -1
  249. package/dist/graph-dashboard-parser.d.ts +2 -1
  250. package/dist/graph-edge-reinforcement.d.ts +2 -1
  251. package/dist/graph-path-reconstruction.d.ts +2 -1
  252. package/dist/graph-path-scoring.d.ts +2 -1
  253. package/dist/graph-snapshot.d.ts +2 -1
  254. package/dist/graph.d.ts +2 -1
  255. package/dist/harmonic-retrieval.js +1 -1
  256. package/dist/importance.d.ts +2 -1
  257. package/dist/importers/index.d.ts +2 -1
  258. package/dist/in-flight-reads.d.ts +2 -1
  259. package/dist/{index-By2QUAMh.d.ts → index-C7Xep6S9.d.ts} +2 -2
  260. package/dist/index.d.ts +703 -701
  261. package/dist/index.js +225 -196
  262. package/dist/intent.d.ts +2 -1
  263. package/dist/lcm/engine.d.ts +3 -2
  264. package/dist/lcm/engine.js +5 -4
  265. package/dist/lcm/index.d.ts +4 -2
  266. package/dist/lcm/index.js +12 -11
  267. package/dist/lcm/summarizer.d.ts +4 -6
  268. package/dist/lcm/summarizer.js +2 -1
  269. package/dist/lcm/tools.d.ts +4 -3
  270. package/dist/lifecycle.d.ts +2 -1
  271. package/dist/live-connectors-runner.d.ts +2 -1
  272. package/dist/local-llm.d.ts +2 -1
  273. package/dist/local-model-endpoint.d.ts +2 -1
  274. package/dist/maintenance/memory-governance.d.ts +2 -1
  275. package/dist/maintenance/memory-governance.js +24 -24
  276. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +5 -2
  277. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +23 -23
  278. package/dist/maintenance/rebuild-memory-projection.d.ts +5 -2
  279. package/dist/maintenance/rebuild-memory-projection.js +25 -25
  280. package/dist/{maintenance-Dm2McrIx.d.ts → maintenance-CJ-xqFp0.d.ts} +3 -3
  281. package/dist/mcp-memory-inspector-app.d.ts +15 -13
  282. package/dist/memory-action-policy.d.ts +18 -2
  283. package/dist/memory-action-policy.js +3 -1
  284. package/dist/memory-cache.d.ts +2 -1
  285. package/dist/memory-controller.d.ts +2 -1
  286. package/dist/memory-controller.js +2 -2
  287. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  288. package/dist/memory-projection-store.d.ts +2 -1
  289. package/dist/memory-provenance.d.ts +2 -1
  290. package/dist/memory-snapshot.d.ts +2 -1
  291. package/dist/memory-subject-cli.d.ts +15 -13
  292. package/dist/memory-subject.d.ts +15 -13
  293. package/dist/memory-subject.js +3 -3
  294. package/dist/memory-worth-outcomes.d.ts +5 -2
  295. package/dist/models-json.d.ts +2 -1
  296. package/dist/namespaces/migrate.d.ts +6 -3
  297. package/dist/namespaces/migrate.js +24 -24
  298. package/dist/namespaces/principal.d.ts +2 -1
  299. package/dist/namespaces/search.d.ts +2 -1
  300. package/dist/namespaces/search.js +9 -9
  301. package/dist/namespaces/storage.d.ts +6 -3
  302. package/dist/namespaces/storage.js +23 -23
  303. package/dist/native-knowledge.d.ts +2 -1
  304. package/dist/offline-sync-impression-drain.d.ts +2 -1
  305. package/dist/offline-sync-impression-drain.js +2 -2
  306. package/dist/operator-doctor-corpus.d.ts +2 -1
  307. package/dist/operator-doctor-corpus.js +26 -26
  308. package/dist/operator-doctor-replica.d.ts +2 -1
  309. package/dist/operator-toolkit.d.ts +6 -3
  310. package/dist/operator-toolkit.js +38 -37
  311. package/dist/orchestration/compression-guideline-coordinator.d.ts +5 -2
  312. package/dist/orchestration/maintenance.d.ts +7 -4
  313. package/dist/orchestration/maintenance.js +31 -31
  314. package/dist/{orchestrator-Co1DyfuP.d.ts → orchestrator-BsntWxLy.d.ts} +8 -8
  315. package/dist/orchestrator.d.ts +13 -11
  316. package/dist/orchestrator.js +143 -140
  317. package/dist/patterns-cli.d.ts +2 -1
  318. package/dist/{pipeline-DotMnb6y.d.ts → pipeline-CVoysPm2.d.ts} +1 -1
  319. package/dist/policy-runtime.d.ts +2 -1
  320. package/dist/proactive-contention.d.ts +2 -1
  321. package/dist/provenance.d.ts +2 -1
  322. package/dist/{public-http-PJRtnSi-.d.ts → public-http-CuOxlTC2.d.ts} +1 -1
  323. package/dist/{qmd-BP0n11fR.d.ts → qmd-DWMAGA5l.d.ts} +1 -1
  324. package/dist/qmd-preflight.d.ts +3 -2
  325. package/dist/qmd-recall-cache.d.ts +2 -1
  326. package/dist/qmd.d.ts +3 -2
  327. package/dist/qmd.js +4 -4
  328. package/dist/recall-concurrency-config.d.ts +2 -1
  329. package/dist/recall-disclosure-escalation.d.ts +2 -1
  330. package/dist/recall-explain-renderer.d.ts +2 -1
  331. package/dist/recall-explain-renderer.js +3 -3
  332. package/dist/recall-memory-map.d.ts +2 -1
  333. package/dist/recall-planner-llm.d.ts +2 -1
  334. package/dist/recall-state.d.ts +2 -1
  335. package/dist/recall-tag-filter.d.ts +2 -1
  336. package/dist/recall-timings.d.ts +2 -1
  337. package/dist/recall-xray-cli.d.ts +2 -1
  338. package/dist/recall-xray-cli.js +4 -4
  339. package/dist/recall-xray-renderer.d.ts +2 -1
  340. package/dist/recall-xray-renderer.js +3 -3
  341. package/dist/recall-xray.d.ts +2 -1
  342. package/dist/recall-xray.js +2 -2
  343. package/dist/reconcile/cursor.d.ts +2 -1
  344. package/dist/reconcile/manifest.d.ts +2 -1
  345. package/dist/reconcile/manifest.js +3 -3
  346. package/dist/reconcile/plan.d.ts +2 -1
  347. package/dist/replay/normalizers/chatgpt.d.ts +2 -1
  348. package/dist/replay/normalizers/claude.d.ts +2 -1
  349. package/dist/replay/normalizers/openclaw.d.ts +2 -1
  350. package/dist/replay/normalizers/shared.d.ts +2 -1
  351. package/dist/replay/runner.d.ts +2 -1
  352. package/dist/replay/types.d.ts +2 -1
  353. package/dist/replica-divergence.d.ts +2 -1
  354. package/dist/replica-peers-config.d.ts +2 -1
  355. package/dist/{resolution-4552BNRV.js → resolution-XWBPKYFB.js} +6 -6
  356. package/dist/resolution-XWBPKYFB.js.map +1 -0
  357. package/dist/resolve-auth-token.d.ts +2 -1
  358. package/dist/resume-bundles.js +11 -10
  359. package/dist/retrieval-agents.d.ts +3 -2
  360. package/dist/retrieval-tiers.d.ts +2 -1
  361. package/dist/routing/engine.d.ts +2 -1
  362. package/dist/routing/store.d.ts +2 -1
  363. package/dist/salvage-envelope.d.ts +2 -1
  364. package/dist/salvage-envelope.js +5 -5
  365. package/dist/schemas.d.ts +124 -124
  366. package/dist/{scope-profiles-6ChZKTy-.d.ts → scope-profiles-CPWkW_dI.d.ts} +1 -1
  367. package/dist/search/embed-helper.d.ts +2 -1
  368. package/dist/search/factory.d.ts +2 -1
  369. package/dist/search/factory.js +8 -8
  370. package/dist/search/index.d.ts +2 -1
  371. package/dist/search/index.js +14 -14
  372. package/dist/search/lancedb-backend.d.ts +2 -1
  373. package/dist/search/meilisearch-backend.d.ts +2 -1
  374. package/dist/search/noop-backend.d.ts +2 -1
  375. package/dist/search/orama-backend.d.ts +2 -1
  376. package/dist/search/port.d.ts +2 -1
  377. package/dist/search/remote-backend.d.ts +2 -1
  378. package/dist/{semantic-consolidation-DziYcW5J.d.ts → semantic-consolidation-CNFVBXFc.d.ts} +1 -1
  379. package/dist/semantic-consolidation.d.ts +3 -2
  380. package/dist/semantic-consolidation.js +29 -29
  381. package/dist/semantic-rule-promotion.js +23 -23
  382. package/dist/semantic-rule-verifier.d.ts +2 -1
  383. package/dist/semantic-rule-verifier.js +23 -23
  384. package/dist/{service-C7rIBuK_.d.ts → service-Bb-JIdQ0.d.ts} +2 -2
  385. package/dist/session-observer-bands.d.ts +2 -1
  386. package/dist/session-observer-state.d.ts +2 -1
  387. package/dist/shared-context/manager.d.ts +8 -7
  388. package/dist/signal.d.ts +2 -1
  389. package/dist/source-agent-qualifier.d.ts +2 -1
  390. package/dist/source-agent-qualifier.js +27 -27
  391. package/dist/{storage-B1hEx8Xg.d.ts → storage-CukrlNKk.d.ts} +4 -1
  392. package/dist/storage.d.ts +5 -2
  393. package/dist/storage.js +22 -22
  394. package/dist/subject-config.d.ts +2 -1
  395. package/dist/subject-config.js +4 -4
  396. package/dist/summarizer.d.ts +2 -1
  397. package/dist/summary-snapshot.d.ts +2 -1
  398. package/dist/support-passport/index.d.ts +18 -16
  399. package/dist/support-passport/index.js +45 -45
  400. package/dist/temporal-supersession.d.ts +3 -2
  401. package/dist/temporal-timeline-recall.d.ts +2 -1
  402. package/dist/temporal-validity.d.ts +2 -1
  403. package/dist/threading.d.ts +2 -1
  404. package/dist/tier-migration.d.ts +5 -2
  405. package/dist/tier-routing.d.ts +2 -1
  406. package/dist/topics.d.ts +2 -1
  407. package/dist/transcript.d.ts +2 -1
  408. package/dist/transfer/types.d.ts +78 -78
  409. package/dist/trust-score-stage.d.ts +2 -1
  410. package/dist/trust-score.d.ts +2 -1
  411. package/dist/{types-BHDNxGTT.d.ts → types-djxQlxJ7.d.ts} +2 -1
  412. package/dist/types.d.ts +2 -1
  413. package/dist/types.js +1 -1
  414. package/dist/utility-runtime.d.ts +2 -1
  415. package/dist/verified-recall.js +23 -23
  416. package/dist/who-knows-cli.d.ts +15 -13
  417. package/dist/who-knows-cli.js +24 -24
  418. package/dist/who-knows.d.ts +15 -13
  419. package/dist/who-knows.js +23 -23
  420. package/dist/write-envelope.d.ts +2 -1
  421. package/dist/write-envelope.js +4 -4
  422. package/package.json +22 -2
  423. package/src/active-context-config.ts +98 -0
  424. package/src/active-context-transform.test.ts +533 -0
  425. package/src/active-context-transform.ts +981 -0
  426. package/src/config.ts +3 -5
  427. package/src/context-summary.ts +182 -0
  428. package/src/index.ts +4 -11
  429. package/src/lcm/summarizer.ts +14 -93
  430. package/src/memory-action-policy.ts +28 -0
  431. package/src/storage/context-transform-ledger.ts +39 -0
  432. package/src/storage/secure-line-reader.ts +50 -1
  433. package/src/storage.ts +4 -1
  434. package/src/types.ts +2 -3
  435. package/dist/chunk-BJTHRFFC.js.map +0 -1
  436. package/dist/chunk-D4QVPP3G.js.map +0 -1
  437. package/dist/chunk-DVYRD4HY.js.map +0 -1
  438. package/dist/chunk-LBFFNDFM.js.map +0 -1
  439. package/dist/chunk-ZPUIRTIZ.js.map +0 -1
  440. /package/dist/{resolution-4552BNRV.js.map → active-context-config.js.map} +0 -0
  441. /package/dist/{auto-sync-XVMLL2RH.js.map → auto-sync-2YPITIWN.js.map} +0 -0
  442. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  443. /package/dist/{chunk-S3K2CIK5.js.map → chunk-3A2NJP2U.js.map} +0 -0
  444. /package/dist/{chunk-OPGL46PX.js.map → chunk-3PKAS6VL.js.map} +0 -0
  445. /package/dist/{chunk-GTSVEEP3.js.map → chunk-3SZD4CYO.js.map} +0 -0
  446. /package/dist/{chunk-YKWFK7XA.js.map → chunk-4F4AQFWL.js.map} +0 -0
  447. /package/dist/{chunk-RGCF4XNH.js.map → chunk-4QEYREAV.js.map} +0 -0
  448. /package/dist/{chunk-46WM6JX2.js.map → chunk-4ZWCQJNM.js.map} +0 -0
  449. /package/dist/{chunk-3RI5Y7KU.js.map → chunk-5DHKCO52.js.map} +0 -0
  450. /package/dist/{chunk-VKCAHCBI.js.map → chunk-5RWZH6PH.js.map} +0 -0
  451. /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
  452. /package/dist/{chunk-A32YEQAM.js.map → chunk-76DIF5KT.js.map} +0 -0
  453. /package/dist/{chunk-OPPBTPUU.js.map → chunk-7KQB4EBS.js.map} +0 -0
  454. /package/dist/{chunk-I2HTKOOP.js.map → chunk-7VZFRUQU.js.map} +0 -0
  455. /package/dist/{chunk-JCWY73FK.js.map → chunk-AHPIFKNG.js.map} +0 -0
  456. /package/dist/{chunk-IP4ZNT4U.js.map → chunk-AZMLH5UT.js.map} +0 -0
  457. /package/dist/{chunk-JOEJG4SD.js.map → chunk-BEC4YBNA.js.map} +0 -0
  458. /package/dist/{chunk-VXVZ2GM3.js.map → chunk-CAMNRAJF.js.map} +0 -0
  459. /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
  460. /package/dist/{chunk-YOXVZJFM.js.map → chunk-CFVTRUR3.js.map} +0 -0
  461. /package/dist/{chunk-SVSRPG6M.js.map → chunk-CPA5NBHN.js.map} +0 -0
  462. /package/dist/{chunk-7BEPVIH3.js.map → chunk-CRML27CO.js.map} +0 -0
  463. /package/dist/{chunk-IY7UXD3J.js.map → chunk-DA7ITC5Z.js.map} +0 -0
  464. /package/dist/{chunk-AFR6AIM4.js.map → chunk-DEACDKE3.js.map} +0 -0
  465. /package/dist/{chunk-NG3MBQV4.js.map → chunk-DPCXDG7G.js.map} +0 -0
  466. /package/dist/{chunk-HZNYJN77.js.map → chunk-F3NVYTTA.js.map} +0 -0
  467. /package/dist/{chunk-PDDSFELN.js.map → chunk-F7XUD3PL.js.map} +0 -0
  468. /package/dist/{chunk-YWSQD2IB.js.map → chunk-GTO56JY5.js.map} +0 -0
  469. /package/dist/{chunk-RAIUTAZZ.js.map → chunk-H2YSH3DG.js.map} +0 -0
  470. /package/dist/{chunk-F6QHHRWP.js.map → chunk-HMZKGHMD.js.map} +0 -0
  471. /package/dist/{chunk-ZIJDI4CP.js.map → chunk-HRHO3ZNG.js.map} +0 -0
  472. /package/dist/{chunk-SDEPLF7V.js.map → chunk-IBJ6U753.js.map} +0 -0
  473. /package/dist/{chunk-T3JQTCCO.js.map → chunk-JI7U6AS3.js.map} +0 -0
  474. /package/dist/{chunk-TR7DGXGI.js.map → chunk-JOZUBF4A.js.map} +0 -0
  475. /package/dist/{chunk-I7EX6KSH.js.map → chunk-JYSN42VN.js.map} +0 -0
  476. /package/dist/{chunk-FMQ4MOQO.js.map → chunk-KZIF6XHX.js.map} +0 -0
  477. /package/dist/{chunk-RIAM7DND.js.map → chunk-LDKPDODJ.js.map} +0 -0
  478. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  479. /package/dist/{chunk-LLQCM2U2.js.map → chunk-LKYIOCWL.js.map} +0 -0
  480. /package/dist/{chunk-5S4LQOPE.js.map → chunk-LOXHYCVS.js.map} +0 -0
  481. /package/dist/{chunk-ANJXPFRS.js.map → chunk-LPNCR4QK.js.map} +0 -0
  482. /package/dist/{chunk-GEPACVWN.js.map → chunk-MDD2RINF.js.map} +0 -0
  483. /package/dist/{chunk-6CPUQ5D6.js.map → chunk-MY2BC6UE.js.map} +0 -0
  484. /package/dist/{chunk-CFGU52XJ.js.map → chunk-NPFUNWNX.js.map} +0 -0
  485. /package/dist/{chunk-MFOSZUIT.js.map → chunk-NPIBN2VL.js.map} +0 -0
  486. /package/dist/{chunk-5DH6PG4B.js.map → chunk-OA2O2GJ4.js.map} +0 -0
  487. /package/dist/{chunk-JAQXUGLN.js.map → chunk-ODU2CNNX.js.map} +0 -0
  488. /package/dist/{chunk-RQE4TITU.js.map → chunk-OXRRJXPR.js.map} +0 -0
  489. /package/dist/{chunk-SEA6M7SS.js.map → chunk-P36Z4JRA.js.map} +0 -0
  490. /package/dist/{chunk-Z4U3UN56.js.map → chunk-PU56CXZA.js.map} +0 -0
  491. /package/dist/{chunk-5VPQSRQO.js.map → chunk-S5XOSTYM.js.map} +0 -0
  492. /package/dist/{chunk-SVVIASVX.js.map → chunk-SEEJOGQX.js.map} +0 -0
  493. /package/dist/{chunk-7TCGNUVP.js.map → chunk-SNOIKAHM.js.map} +0 -0
  494. /package/dist/{chunk-7F27PCSN.js.map → chunk-T6ILXUAH.js.map} +0 -0
  495. /package/dist/{chunk-EOHKUWXW.js.map → chunk-T7XP6IZE.js.map} +0 -0
  496. /package/dist/{chunk-7WR462EM.js.map → chunk-TFR3HG4K.js.map} +0 -0
  497. /package/dist/{chunk-YRVAKONL.js.map → chunk-TUHBYJXL.js.map} +0 -0
  498. /package/dist/{chunk-F635GAL7.js.map → chunk-U7EW2W4W.js.map} +0 -0
  499. /package/dist/{chunk-VFYRYFLL.js.map → chunk-UEBDCMOO.js.map} +0 -0
  500. /package/dist/{chunk-WTOZBZNN.js.map → chunk-UENKPWCS.js.map} +0 -0
  501. /package/dist/{chunk-AAXJNINV.js.map → chunk-UL4MKZHI.js.map} +0 -0
  502. /package/dist/{chunk-R2MZCYA6.js.map → chunk-UNUMFURP.js.map} +0 -0
  503. /package/dist/{chunk-ACOC27BB.js.map → chunk-UPFNQJC7.js.map} +0 -0
  504. /package/dist/{chunk-W4BMEGQA.js.map → chunk-UTQUEHC7.js.map} +0 -0
  505. /package/dist/{chunk-I32NKXE2.js.map → chunk-V4IDF3EZ.js.map} +0 -0
  506. /package/dist/{chunk-ZAOHJDKH.js.map → chunk-WNXYT4MK.js.map} +0 -0
  507. /package/dist/{chunk-T42L3S6A.js.map → chunk-XBGHAAKR.js.map} +0 -0
  508. /package/dist/{chunk-I4343FIA.js.map → chunk-XNWXSGHS.js.map} +0 -0
  509. /package/dist/{chunk-THG4GYIE.js.map → chunk-YEUXERJ6.js.map} +0 -0
  510. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  511. /package/dist/{chunk-5HERQ5FX.js.map → chunk-Z3YEGSR4.js.map} +0 -0
  512. /package/dist/{forget-SZ2BXDGF.js.map → forget-2AE4MDK3.js.map} +0 -0
@@ -0,0 +1,981 @@
1
+ /**
2
+ * Host-agnostic active-context SUMMARY/FILTER plans (issue #2347).
3
+ *
4
+ * Core receives a short message list, checks the trusted scope first,
5
+ * then IDs and limits, and returns a content-addressed plan. Core never
6
+ * mutates host state or saved memory: the host adapter owns save, apply,
7
+ * and undo; it reports back through {@link ActiveContextApplyReceipt}.
8
+ * Plans and telemetry carry hashes and counts only — never raw message
9
+ * text, keep rules, or summary output.
10
+ *
11
+ * Paper basis: AgeMem (arXiv:2601.01885v3) §3.1/A.1 eq. (14) Summary and
12
+ * eq. (15) Filter. Selection is host-bounded (explicit IDs or one closed
13
+ * span); `all` / last-N spans are never inferred. Filter keeps messages
14
+ * with `score >= threshold` using a caller-supplied fixed score rule — an
15
+ * LLM never picks drop IDs. Event counts back the design; no ship claim.
16
+ */
17
+ import { createHash } from "node:crypto";
18
+ import { DEFAULT_ACTIVE_CONTEXT_CAPS, type ActiveContextCapabilitySet } from "./active-context-config.js";
19
+ import {
20
+ ContextSummaryUnavailableError,
21
+ summarizeContextPure,
22
+ type SummarizeFn,
23
+ } from "./context-summary.js";
24
+ import { evaluateActiveContextTransformPolicy } from "./memory-action-policy.js";
25
+
26
+ export const ACTIVE_CONTEXT_ALGORITHM_VERSION = "active-context-transform/1";
27
+ export const ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION = 1;
28
+ export const ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION = 1;
29
+ export const ACTIVE_CONTEXT_RECEIPT_SCHEMA_VERSION = 1;
30
+ export const ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION = 1;
31
+
32
+ export type ActiveContextOperation = "SUMMARY" | "FILTER";
33
+ export type ActiveContextPhase = "plan" | "prepare";
34
+ export type ActiveContextMessageRole = "system" | "developer" | "user" | "assistant" | "tool";
35
+
36
+ export type ActiveContextErrorCode =
37
+ | "feature_disabled"
38
+ | "scope_mismatch"
39
+ | "invalid_request"
40
+ | "stale_context"
41
+ | "plan_conflict"
42
+ | "preserve_conflict"
43
+ | "filter_unavailable"
44
+ | "summary_unavailable"
45
+ | "unsupported"
46
+ | "retention_unavailable"
47
+ | "retention_expired"
48
+ | "invalid_receipt"
49
+ | "host_error";
50
+
51
+ /** Roles that can never be removed by any operation or selector. */
52
+ const PROTECTED_ROLES: Record<string, true> = { system: true, developer: true };
53
+
54
+ export interface ActiveContextMessage {
55
+ id: string;
56
+ /** Snapshot order; plans sort by it and never reorder sources. */
57
+ ordinal: number;
58
+ role: ActiveContextMessageRole;
59
+ content: string;
60
+ /** Caller-marked protection; equivalent to a preserve-listed ID. */
61
+ protected?: boolean;
62
+ }
63
+
64
+ export interface ActiveContextSnapshot {
65
+ schemaVersion: 1;
66
+ sessionKey: string;
67
+ /** Data routing only — never authorization. */
68
+ namespace: string;
69
+ /** Host revision/turn identifier the plan binds as a precondition. */
70
+ revision: string | number;
71
+ messages: ActiveContextMessage[];
72
+ }
73
+
74
+ /**
75
+ * Trusted scope resolved by the access layer BEFORE any plan work
76
+ * (mirrors `ResolvedIdentity` from adapters/types.ts). Core never treats
77
+ * `snapshot.namespace` as auth.
78
+ */
79
+ export interface ActiveContextResolvedScope {
80
+ sessionKey: string;
81
+ namespace: string;
82
+ principal: string;
83
+ adapterId: string;
84
+ }
85
+
86
+ /** Fixed, caller-supplied score rule. Must return a finite score in [0,1]. */
87
+ export type ActiveContextScoreMessageFn = (message: ActiveContextMessage) => number | undefined;
88
+
89
+ export interface ActiveContextTransformDeps {
90
+ resolvedScope: ActiveContextResolvedScope;
91
+ /** Filter score rule — required for FILTER plans. */
92
+ scoreMessage?: ActiveContextScoreMessageFn;
93
+ /** Model seam for SUMMARY; the same pure seam LCM uses. */
94
+ summarize?: SummarizeFn;
95
+ /** Config-projected caps; defaults are conservative (see capabilities.ts). */
96
+ caps?: ActiveContextCapabilitySet;
97
+ /** Gate override; defaults to `caps.activeContextTransforms`. */
98
+ actionsEnabled?: boolean;
99
+ /** Clock seam for deterministic expiry tests. */
100
+ now?: () => Date;
101
+ }
102
+
103
+ export interface ActiveContextSpanSelector {
104
+ /** Closed span: inclusive start (by snapshot order). */
105
+ startMessageId: string;
106
+ /** Closed span: inclusive end (by snapshot order). */
107
+ endMessageId: string;
108
+ }
109
+
110
+ export interface ActiveContextTransformRequest {
111
+ schemaVersion: 1;
112
+ operation: ActiveContextOperation;
113
+ phase: ActiveContextPhase;
114
+ snapshot: ActiveContextSnapshot;
115
+ /** Exactly one of `messageIds` or `span`. */
116
+ selector: { messageIds?: string[]; span?: ActiveContextSpanSelector };
117
+ preserve?: {
118
+ messageIds?: string[];
119
+ roles?: ActiveContextMessageRole[];
120
+ minRetainedMessages?: number;
121
+ };
122
+ summary?: { method: "deterministic" | "llm" | "auto"; targetTokens?: number };
123
+ filter?: { keepCriterion: string; threshold: number };
124
+ expectedRevision?: string | number;
125
+ requestId?: string;
126
+ sourcePromptHash?: string;
127
+ }
128
+
129
+ export interface ActiveContextScoreRow {
130
+ messageId: string;
131
+ score: number;
132
+ decision: "keep" | "drop";
133
+ }
134
+
135
+ export interface ActiveContextPlanReplacement {
136
+ messageId: string;
137
+ /** Filled by prepare — plans never carry raw text. */
138
+ contentHash?: string;
139
+ sourceMessageIds: string[];
140
+ method: "deterministic" | "llm";
141
+ /** Whether prepare may degrade to deterministic output (auto mode only). */
142
+ fallbackPolicy: "allowed" | "none";
143
+ targetTokens: number;
144
+ modelUsed?: string;
145
+ fallback?: boolean;
146
+ }
147
+
148
+ export interface ActiveContextTransformPlan {
149
+ schemaVersion: 1;
150
+ planId: string;
151
+ planHash: string;
152
+ operation: ActiveContextOperation;
153
+ status: "ready" | "rejected";
154
+ errorCode?: ActiveContextErrorCode;
155
+ precondition: {
156
+ principal: string;
157
+ sessionKey: string;
158
+ namespace: string;
159
+ adapterId: string;
160
+ snapshotRevision: string | number;
161
+ expiresAt: string;
162
+ };
163
+ /** Selected sources in snapshot order. */
164
+ selectedMessageIds: string[];
165
+ /** Messages that stay after the plan applies. */
166
+ retainedMessageIds: string[];
167
+ /** Removable IDs the plan proposes to drop or fold into a replacement. */
168
+ proposedRemovalIds: string[];
169
+ scoreRows?: ActiveContextScoreRow[];
170
+ replacement?: ActiveContextPlanReplacement;
171
+ preserve: { protectedMessageIds: string[]; minimumRetainedMessages: number };
172
+ inverse: {
173
+ kind: "restore-source-message-ids";
174
+ sourceMessageIds: string[];
175
+ removeReplacementMessageId?: string;
176
+ expectedAppliedPlanHash?: string;
177
+ };
178
+ retention: {
179
+ planId: string;
180
+ mode: "adapter-local";
181
+ expiresAt: string;
182
+ maxBytes: number;
183
+ snapshotContentHash: string;
184
+ };
185
+ provenance: {
186
+ algorithmVersion: string;
187
+ selectorHash: string;
188
+ snapshotContentHash: string;
189
+ criterionHash?: string;
190
+ sourcePromptHash?: string;
191
+ generatedAt: string;
192
+ };
193
+ policy: { decision: "allow" | "deny"; rationale: string };
194
+ }
195
+
196
+ export interface ActiveContextHostCapability {
197
+ capabilityId: string;
198
+ trustedScope: ActiveContextResolvedScope;
199
+ hostRevision: string | number;
200
+ operations: ActiveContextOperation[];
201
+ expiresAt: string;
202
+ }
203
+
204
+ export interface ActiveContextApplyReceipt {
205
+ schemaVersion: 1;
206
+ planId: string;
207
+ planHash: string;
208
+ adapterId: string;
209
+ outcome: "applied" | "skipped" | "failed";
210
+ errorCode?: ActiveContextErrorCode;
211
+ hostRevisionBefore?: string | number;
212
+ hostRevisionAfter?: string | number;
213
+ appliedMessageIds?: string[];
214
+ removedMessageIds?: string[];
215
+ replacementMessageId?: string;
216
+ retentionExpiresAt?: string;
217
+ appliedAt: string;
218
+ }
219
+
220
+ /** Discriminated ledger record appended to `state/memory-actions.jsonl`. */
221
+ export interface ContextTransformTelemetryRecord {
222
+ recordKind: "context_transform";
223
+ schemaVersion: 1;
224
+ timestamp: string;
225
+ /** Plan ID doubles as the record action ID. */
226
+ actionId: string;
227
+ action: "summarize_context" | "filter_context";
228
+ outcome: "applied" | "skipped" | "failed";
229
+ status: "validated" | "applied" | "rejected";
230
+ actor?: string;
231
+ subsystem: string;
232
+ namespace: string;
233
+ sourceSessionKey: string;
234
+ planHash: string;
235
+ snapshotRevision: string | number;
236
+ adapterId?: string;
237
+ algorithmVersion?: string;
238
+ selectedCount: number;
239
+ retainedCount: number;
240
+ proposedRemovalCount: number;
241
+ receiptOutcome?: "applied" | "skipped" | "failed";
242
+ selectorHash: string;
243
+ snapshotContentHash: string;
244
+ criterionHash?: string;
245
+ sourcePromptHash?: string;
246
+ replacementContentHash?: string;
247
+ policyDecision?: "allow" | "defer" | "deny";
248
+ policyRationale?: string;
249
+ telemetryRecorded?: boolean;
250
+ }
251
+
252
+ export interface ActiveContextPreparedReplacement {
253
+ messageId: string;
254
+ text: string;
255
+ contentHash: string;
256
+ method: "deterministic" | "llm";
257
+ modelUsed?: string;
258
+ fallback: boolean;
259
+ sourceMessageIds: string[];
260
+ }
261
+
262
+ export interface ActiveContextPreparedTransform {
263
+ status: "ready" | "rejected" | "failed";
264
+ plan: ActiveContextTransformPlan;
265
+ replacement?: ActiveContextPreparedReplacement;
266
+ errorCode?: ActiveContextErrorCode;
267
+ }
268
+
269
+ // ── hashing ────────────────────────────────────────────────────────────────
270
+
271
+ function sha256Hex(value: string): string {
272
+ return createHash("sha256").update(value, "utf8").digest("hex");
273
+ }
274
+
275
+ /** Deterministic JSON: sorted keys, so field order never changes a hash. */
276
+ function canonicalJson(value: unknown): string {
277
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
278
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
279
+ const entries = Object.entries(value as Record<string, unknown>)
280
+ .filter(([, v]) => v !== undefined)
281
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
282
+ .map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
283
+ return `{${entries.join(",")}}`;
284
+ }
285
+
286
+ function hashSnapshot(snapshot: ActiveContextSnapshot): string {
287
+ return sha256Hex(
288
+ canonicalJson({
289
+ namespace: snapshot.namespace,
290
+ revision: snapshot.revision,
291
+ sessionKey: snapshot.sessionKey,
292
+ messages: snapshot.messages.map((m) => ({
293
+ contentHash: sha256Hex(m.content),
294
+ id: m.id,
295
+ ordinal: m.ordinal,
296
+ role: m.role,
297
+ })),
298
+ }),
299
+ );
300
+ }
301
+
302
+ // ── shared validation ──────────────────────────────────────────────────────
303
+
304
+ interface PlanContext {
305
+ caps: ActiveContextCapabilitySet;
306
+ scope: ActiveContextResolvedScope;
307
+ snapshotRevision: string | number;
308
+ byId: Map<string, ActiveContextMessage>;
309
+ ordered: ActiveContextMessage[];
310
+ snapshotContentHash: string;
311
+ generatedAt: string;
312
+ expiresAt: string;
313
+ }
314
+
315
+ const VALID_PHASES: Record<string, true> = { plan: true, prepare: true };
316
+ const VALID_ROLES: Record<string, true> = {
317
+ system: true,
318
+ developer: true,
319
+ user: true,
320
+ assistant: true,
321
+ tool: true,
322
+ };
323
+
324
+ function rejectedPlan(
325
+ operation: ActiveContextOperation,
326
+ errorCode: ActiveContextErrorCode,
327
+ context: PlanContext | null,
328
+ policy: { decision: "allow" | "deny"; rationale: string },
329
+ ): ActiveContextTransformPlan {
330
+ const planId = `actx-rejected-${sha256Hex(`${operation}:${errorCode}:${policy.rationale}`).slice(0, 12)}`;
331
+ return {
332
+ schemaVersion: ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION,
333
+ planId,
334
+ planHash: sha256Hex(canonicalJson({ planId, errorCode, operation })),
335
+ operation,
336
+ status: "rejected",
337
+ errorCode,
338
+ precondition: context
339
+ ? {
340
+ principal: context.scope.principal,
341
+ sessionKey: context.scope.sessionKey,
342
+ namespace: context.scope.namespace,
343
+ adapterId: context.scope.adapterId,
344
+ snapshotRevision: context.snapshotRevision,
345
+ expiresAt: context.expiresAt,
346
+ }
347
+ : {
348
+ principal: "",
349
+ sessionKey: "",
350
+ namespace: "",
351
+ adapterId: "",
352
+ snapshotRevision: "",
353
+ expiresAt: "",
354
+ },
355
+ selectedMessageIds: [],
356
+ retainedMessageIds: [],
357
+ proposedRemovalIds: [],
358
+ preserve: { protectedMessageIds: [], minimumRetainedMessages: 0 },
359
+ inverse: { kind: "restore-source-message-ids", sourceMessageIds: [] },
360
+ retention: {
361
+ planId,
362
+ mode: "adapter-local",
363
+ expiresAt: "",
364
+ maxBytes: 0,
365
+ snapshotContentHash: context?.snapshotContentHash ?? "",
366
+ },
367
+ provenance: {
368
+ algorithmVersion: ACTIVE_CONTEXT_ALGORITHM_VERSION,
369
+ selectorHash: "",
370
+ snapshotContentHash: context?.snapshotContentHash ?? "",
371
+ generatedAt: context?.generatedAt ?? new Date().toISOString(),
372
+ },
373
+ policy,
374
+ };
375
+ }
376
+
377
+ /** Scope + snapshot validation shared by plan and prepare. Throws PlanReject. */
378
+ class PlanReject extends Error {
379
+ constructor(readonly code: ActiveContextErrorCode) {
380
+ super(code);
381
+ }
382
+ }
383
+
384
+ function buildContext(
385
+ request: ActiveContextTransformRequest,
386
+ deps: ActiveContextTransformDeps,
387
+ ): PlanContext {
388
+ const caps = deps.caps ?? {
389
+ ...DEFAULT_ACTIVE_CONTEXT_CAPS,
390
+ activeContextTransforms: true,
391
+ activeContextLlm: false,
392
+ };
393
+ const scope = deps.resolvedScope;
394
+ if (!scope || !scope.sessionKey || !scope.namespace || !scope.principal || !scope.adapterId) {
395
+ throw new PlanReject("scope_mismatch");
396
+ }
397
+ // Trusted-scope checks run before any ID selection or model work.
398
+ if (request.snapshot.sessionKey !== scope.sessionKey) throw new PlanReject("scope_mismatch");
399
+ if (request.snapshot.namespace !== scope.namespace) throw new PlanReject("scope_mismatch");
400
+
401
+ const snapshot = request.snapshot;
402
+ if (snapshot.schemaVersion !== ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION) {
403
+ throw new PlanReject("invalid_request");
404
+ }
405
+ if (!Array.isArray(snapshot.messages) || snapshot.messages.length === 0) {
406
+ throw new PlanReject("invalid_request");
407
+ }
408
+ const byId = new Map<string, ActiveContextMessage>();
409
+ let totalChars = 0;
410
+ for (const message of snapshot.messages) {
411
+ if (
412
+ typeof message?.id !== "string" ||
413
+ message.id.length === 0 ||
414
+ typeof message.content !== "string" ||
415
+ VALID_ROLES[message.role] !== true
416
+ ) {
417
+ throw new PlanReject("invalid_request");
418
+ }
419
+ if (byId.has(message.id)) throw new PlanReject("invalid_request"); // duplicate IDs
420
+ byId.set(message.id, message);
421
+ totalChars += message.content.length;
422
+ }
423
+ if (snapshot.messages.length > caps.activeContextMaxMessages) throw new PlanReject("invalid_request");
424
+ if (totalChars > caps.activeContextMaxSnapshotChars) throw new PlanReject("invalid_request");
425
+
426
+ const now = (deps.now ?? (() => new Date()))();
427
+ const generatedAt = now.toISOString();
428
+ const expiresAt = new Date(now.getTime() + caps.activeContextPlanTtlMinutes * 60_000).toISOString();
429
+ return {
430
+ caps,
431
+ scope,
432
+ snapshotRevision: snapshot.revision,
433
+ byId,
434
+ ordered: [...snapshot.messages].sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id)),
435
+ snapshotContentHash: hashSnapshot(snapshot),
436
+ generatedAt,
437
+ expiresAt,
438
+ };
439
+ }
440
+
441
+ /** Resolve the selector to ordered source messages. Exactly one form allowed. */
442
+ function resolveSelection(
443
+ request: ActiveContextTransformRequest,
444
+ context: PlanContext,
445
+ ): ActiveContextMessage[] {
446
+ const messageIds = request.selector?.messageIds;
447
+ const span = request.selector?.span;
448
+ const hasIds = Array.isArray(messageIds) && messageIds.length > 0;
449
+ if (hasIds === (span !== undefined)) throw new PlanReject("invalid_request"); // both or neither
450
+
451
+ if (hasIds && messageIds) {
452
+ const seen = new Set<string>();
453
+ const picked: ActiveContextMessage[] = [];
454
+ for (const id of messageIds) {
455
+ if (seen.has(id)) throw new PlanReject("invalid_request"); // duplicate IDs
456
+ seen.add(id);
457
+ const message = context.byId.get(id);
458
+ if (!message) throw new PlanReject("invalid_request"); // unknown IDs
459
+ picked.push(message);
460
+ }
461
+ return picked.sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id)); // snapshot order
462
+ }
463
+
464
+ if (!span) throw new PlanReject("invalid_request");
465
+ const { startMessageId, endMessageId } = span;
466
+ const start = context.byId.get(startMessageId);
467
+ const end = context.byId.get(endMessageId);
468
+ if (!start || !end) throw new PlanReject("invalid_request");
469
+ if (start.ordinal > end.ordinal) throw new PlanReject("invalid_request"); // inverted span
470
+ const inSpan = context.ordered.filter(
471
+ (m) => m.ordinal >= start.ordinal && m.ordinal <= end.ordinal, // closed and full
472
+ );
473
+ if (inSpan.length === 0) throw new PlanReject("invalid_request"); // empty span
474
+ return inSpan;
475
+ }
476
+
477
+ function protectedIdSet(
478
+ request: ActiveContextTransformRequest,
479
+ context: PlanContext,
480
+ ): Set<string> {
481
+ const protectedIds = new Set<string>();
482
+ for (const message of context.ordered) {
483
+ if (PROTECTED_ROLES[message.role] === true || message.protected === true) {
484
+ protectedIds.add(message.id);
485
+ }
486
+ }
487
+ for (const role of request.preserve?.roles ?? []) {
488
+ if (PROTECTED_ROLES[role] === true) continue;
489
+ for (const message of context.ordered) {
490
+ if (message.role === role) protectedIds.add(message.id);
491
+ }
492
+ }
493
+ for (const id of request.preserve?.messageIds ?? []) {
494
+ if (context.byId.has(id)) protectedIds.add(id);
495
+ }
496
+ return protectedIds;
497
+ }
498
+
499
+ // ── plan ───────────────────────────────────────────────────────────────────
500
+
501
+ /**
502
+ * Build one bounded, content-addressed SUMMARY or FILTER plan. Returns a
503
+ * rejected plan (with a stable error code) instead of throwing on bad
504
+ * input — bad input is never hidden behind a no-op. `planHash` binds the
505
+ * scope, revision, and every selected/removal/replacement ID; replay
506
+ * across principal, session, namespace, adapter, or revision therefore
507
+ * fails the adapter's comparisons before retain, apply, or undo.
508
+ */
509
+ export function planActiveContextTransform(
510
+ request: ActiveContextTransformRequest,
511
+ deps: ActiveContextTransformDeps,
512
+ ): ActiveContextTransformPlan {
513
+ const caps =
514
+ deps.caps ?? { ...DEFAULT_ACTIVE_CONTEXT_CAPS, activeContextTransforms: true, activeContextLlm: false };
515
+ const policy = evaluateActiveContextTransformPolicy({
516
+ actionsEnabled: deps.actionsEnabled ?? caps.activeContextTransforms,
517
+ operation: request.operation,
518
+ });
519
+ if (policy.decision === "deny") {
520
+ // feature_disabled — evaluated before scope or selection work.
521
+ return rejectedPlan(request.operation, "feature_disabled", null, policy);
522
+ }
523
+ let context: PlanContext | null = null;
524
+ try {
525
+ if (request.schemaVersion !== ACTIVE_CONTEXT_SNAPSHOT_SCHEMA_VERSION) {
526
+ throw new PlanReject("invalid_request");
527
+ }
528
+ if (request.operation !== "SUMMARY" && request.operation !== "FILTER") {
529
+ throw new PlanReject("invalid_request");
530
+ }
531
+ if (VALID_PHASES[request.phase] !== true) throw new PlanReject("invalid_request");
532
+ context = buildContext(request, deps);
533
+
534
+ if (
535
+ request.expectedRevision !== undefined &&
536
+ request.expectedRevision !== request.snapshot.revision
537
+ ) {
538
+ throw new PlanReject("stale_context");
539
+ }
540
+
541
+ const selected = resolveSelection(request, context);
542
+ const protectedIds = protectedIdSet(request, context);
543
+ const removable = selected.filter((m) => !protectedIds.has(m.id));
544
+ if (removable.length === 0) {
545
+ throw new PlanReject("preserve_conflict"); // nothing chosen is removable
546
+ }
547
+
548
+ const minimumRetained = Math.max(
549
+ 1,
550
+ request.preserve?.minRetainedMessages ?? caps.activeContextMinRetainedMessages,
551
+ );
552
+ const idList = (messages: ActiveContextMessage[]) => messages.map((m) => m.id);
553
+ const allIds = idList(context.ordered);
554
+ const selectorHash = sha256Hex(canonicalJson(request.selector ?? {}));
555
+
556
+ if (request.operation === "FILTER") {
557
+ return buildFilterPlan(request, deps, context, {
558
+ selected,
559
+ removable,
560
+ protectedIds,
561
+ minimumRetained,
562
+ allIds,
563
+ selectorHash,
564
+ policy,
565
+ });
566
+ }
567
+ return buildSummaryPlan(request, deps, context, {
568
+ selected,
569
+ removable,
570
+ protectedIds,
571
+ minimumRetained,
572
+ allIds,
573
+ selectorHash,
574
+ policy,
575
+ });
576
+ } catch (err) {
577
+ if (err instanceof PlanReject) {
578
+ return rejectedPlan(request.operation, err.code, context, policy);
579
+ }
580
+ throw err;
581
+ }
582
+ }
583
+
584
+ interface SelectionBundle {
585
+ selected: ActiveContextMessage[];
586
+ removable: ActiveContextMessage[];
587
+ protectedIds: Set<string>;
588
+ minimumRetained: number;
589
+ allIds: string[];
590
+ selectorHash: string;
591
+ policy: { decision: "allow" | "deny"; rationale: string };
592
+ }
593
+
594
+ function finalizePlan(
595
+ operation: ActiveContextOperation,
596
+ context: PlanContext,
597
+ bundle: SelectionBundle,
598
+ proposedRemovalIds: string[],
599
+ extras: {
600
+ scoreRows?: ActiveContextScoreRow[];
601
+ replacement?: ActiveContextPlanReplacement;
602
+ criterionHash?: string;
603
+ sourcePromptHash?: string;
604
+ },
605
+ ): ActiveContextTransformPlan {
606
+ const retainedIds = bundle.allIds.filter((id) => !proposedRemovalIds.includes(id));
607
+ if (retainedIds.length < bundle.minimumRetained) {
608
+ throw new PlanReject("preserve_conflict"); // below keep floor / no safe message left
609
+ }
610
+ const sourceMessageIds = bundle.removable.map((m) => m.id);
611
+ const precondition = {
612
+ principal: context.scope.principal,
613
+ sessionKey: context.scope.sessionKey,
614
+ namespace: context.scope.namespace,
615
+ adapterId: context.scope.adapterId,
616
+ snapshotRevision: context.snapshotRevision,
617
+ expiresAt: context.expiresAt,
618
+ };
619
+ const provenance = {
620
+ algorithmVersion: ACTIVE_CONTEXT_ALGORITHM_VERSION,
621
+ selectorHash: bundle.selectorHash,
622
+ snapshotContentHash: context.snapshotContentHash,
623
+ ...(extras.criterionHash ? { criterionHash: extras.criterionHash } : {}),
624
+ ...(extras.sourcePromptHash ? { sourcePromptHash: extras.sourcePromptHash } : {}),
625
+ generatedAt: context.generatedAt,
626
+ };
627
+ const planId = `actx-${sha256Hex(
628
+ canonicalJson({
629
+ adapterId: precondition.adapterId,
630
+ criterionHash: extras.criterionHash,
631
+ namespace: precondition.namespace,
632
+ operation,
633
+ principal: precondition.principal,
634
+ selectorHash: bundle.selectorHash,
635
+ sessionKey: precondition.sessionKey,
636
+ snapshotContentHash: context.snapshotContentHash,
637
+ }),
638
+ ).slice(0, 16)}`;
639
+ const planBody = {
640
+ operation,
641
+ planId,
642
+ precondition,
643
+ proposedRemovalIds,
644
+ replacementMessageId: extras.replacement?.messageId,
645
+ replacementSourceIds: extras.replacement?.sourceMessageIds,
646
+ retainedIds,
647
+ selectedIds: bundle.selected.map((m) => m.id),
648
+ };
649
+ const planHash = sha256Hex(canonicalJson(planBody));
650
+ return {
651
+ schemaVersion: ACTIVE_CONTEXT_PLAN_SCHEMA_VERSION,
652
+ planId,
653
+ planHash,
654
+ operation,
655
+ status: "ready",
656
+ precondition,
657
+ selectedMessageIds: planBody.selectedIds,
658
+ retainedMessageIds: retainedIds,
659
+ proposedRemovalIds,
660
+ ...(extras.scoreRows ? { scoreRows: extras.scoreRows } : {}),
661
+ ...(extras.replacement ? { replacement: extras.replacement } : {}),
662
+ preserve: {
663
+ protectedMessageIds: [...bundle.protectedIds],
664
+ minimumRetainedMessages: bundle.minimumRetained,
665
+ },
666
+ inverse: {
667
+ kind: "restore-source-message-ids",
668
+ sourceMessageIds,
669
+ ...(extras.replacement ? { removeReplacementMessageId: extras.replacement.messageId } : {}),
670
+ expectedAppliedPlanHash: planHash,
671
+ },
672
+ retention: {
673
+ planId,
674
+ mode: "adapter-local",
675
+ expiresAt: context.expiresAt,
676
+ maxBytes: context.caps.activeContextRetentionMaxBytes,
677
+ snapshotContentHash: context.snapshotContentHash,
678
+ },
679
+ provenance,
680
+ policy: bundle.policy,
681
+ };
682
+ }
683
+
684
+ function buildFilterPlan(
685
+ request: ActiveContextTransformRequest,
686
+ deps: ActiveContextTransformDeps,
687
+ context: PlanContext,
688
+ bundle: SelectionBundle,
689
+ ): ActiveContextTransformPlan {
690
+ const filter = request.filter;
691
+ if (!filter || typeof filter.keepCriterion !== "string" || filter.keepCriterion.length === 0) {
692
+ throw new PlanReject("invalid_request"); // Filter needs keepCriterion
693
+ }
694
+ const threshold = filter.threshold;
695
+ if (typeof threshold !== "number" || !Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
696
+ throw new PlanReject("invalid_request"); // fixed limit in [0,1], never defaulted
697
+ }
698
+ if (!deps.scoreMessage) {
699
+ throw new PlanReject("filter_unavailable"); // Filter needs a score function
700
+ }
701
+
702
+ const scoreRows: ActiveContextScoreRow[] = [];
703
+ const removalIds: string[] = [];
704
+ for (const message of bundle.removable) {
705
+ const score = deps.scoreMessage(message);
706
+ if (typeof score !== "number" || !Number.isFinite(score) || score < 0 || score > 1) {
707
+ throw new PlanReject("filter_unavailable"); // missing / NaN / out of range
708
+ }
709
+ const decision = score >= threshold ? "keep" : "drop"; // fixed keep rule
710
+ scoreRows.push({ messageId: message.id, score, decision });
711
+ if (decision === "drop") removalIds.push(message.id);
712
+ }
713
+
714
+ return finalizePlan("FILTER", context, bundle, removalIds, {
715
+ scoreRows,
716
+ criterionHash: sha256Hex(filter.keepCriterion), // hash, never the rule text
717
+ sourcePromptHash: request.sourcePromptHash,
718
+ });
719
+ }
720
+
721
+ function buildSummaryPlan(
722
+ request: ActiveContextTransformRequest,
723
+ deps: ActiveContextTransformDeps,
724
+ context: PlanContext,
725
+ bundle: SelectionBundle,
726
+ ): ActiveContextTransformPlan {
727
+ const requested = request.summary?.method ?? "deterministic";
728
+ const llmEnabled = context.caps.activeContextLlm;
729
+ let method: "deterministic" | "llm";
730
+ let fallbackPolicy: "allowed" | "none";
731
+ if (requested === "deterministic") {
732
+ method = "deterministic";
733
+ fallbackPolicy = "none";
734
+ } else if (requested === "llm") {
735
+ if (!llmEnabled) throw new PlanReject("unsupported"); // explicit llm behind a closed gate
736
+ method = "llm";
737
+ fallbackPolicy = "none"; // fallback only in auto mode
738
+ } else {
739
+ // auto: prefer the LLM seam when allowed; deterministic otherwise.
740
+ method = llmEnabled && deps.summarize ? "llm" : "deterministic";
741
+ fallbackPolicy = method === "llm" ? "allowed" : "none";
742
+ }
743
+
744
+ const requestedTokens = request.summary?.targetTokens ?? context.caps.activeContextSummaryMaxTokens;
745
+ if (
746
+ typeof requestedTokens !== "number" ||
747
+ !Number.isFinite(requestedTokens) ||
748
+ requestedTokens <= 0 ||
749
+ requestedTokens > context.caps.activeContextSummaryMaxTokens
750
+ ) {
751
+ throw new PlanReject("invalid_request");
752
+ }
753
+ const targetTokens = Math.floor(requestedTokens);
754
+
755
+ // planId is derived inside finalizePlan; the replacement ID must be stable
756
+ // relative to it, so derive from the same stable inputs.
757
+ const replacementSeed = sha256Hex(
758
+ canonicalJson({
759
+ operation: "SUMMARY",
760
+ selectorHash: bundle.selectorHash,
761
+ snapshotContentHash: context.snapshotContentHash,
762
+ sessionKey: context.scope.sessionKey,
763
+ namespace: context.scope.namespace,
764
+ principal: context.scope.principal,
765
+ adapterId: context.scope.adapterId,
766
+ }),
767
+ );
768
+ const replacement: ActiveContextPlanReplacement = {
769
+ messageId: `actxr-${replacementSeed.slice(0, 16)}`,
770
+ sourceMessageIds: bundle.removable.map((m) => m.id),
771
+ method,
772
+ fallbackPolicy,
773
+ targetTokens,
774
+ };
775
+
776
+ const plan = finalizePlan("SUMMARY", context, bundle, [...replacement.sourceMessageIds], {
777
+ replacement,
778
+ sourcePromptHash: request.sourcePromptHash,
779
+ });
780
+ return plan;
781
+ }
782
+
783
+ // ── prepare ────────────────────────────────────────────────────────────────
784
+
785
+ /**
786
+ * Produce the SUMMARY replacement text for a ready plan through the pure
787
+ * summary seam (context-summary.ts). Never calls `LcmSummarizer`. FILTER
788
+ * plans pass through unchanged after revalidation. The caller must supply
789
+ * the same snapshot the plan was built from; a changed transcript fence
790
+ * rejects with `plan_conflict`.
791
+ */
792
+ export async function prepareActiveContextTransform(
793
+ plan: ActiveContextTransformPlan,
794
+ deps: ActiveContextTransformDeps & { snapshot: ActiveContextSnapshot },
795
+ ): Promise<ActiveContextPreparedTransform> {
796
+ if (plan.status !== "ready") {
797
+ return { status: "rejected", plan, errorCode: plan.errorCode ?? "invalid_request" };
798
+ }
799
+
800
+ const scope = deps.resolvedScope;
801
+ const p = plan.precondition;
802
+ if (
803
+ !scope ||
804
+ scope.principal !== p.principal ||
805
+ scope.sessionKey !== p.sessionKey ||
806
+ scope.namespace !== p.namespace ||
807
+ scope.adapterId !== p.adapterId
808
+ ) {
809
+ return { status: "rejected", plan, errorCode: "scope_mismatch" };
810
+ }
811
+ const now = deps.now?.() ?? new Date();
812
+ if (now.getTime() >= new Date(plan.retention.expiresAt).getTime()) {
813
+ return { status: "rejected", plan, errorCode: "stale_context" }; // expired plan
814
+ }
815
+ if (deps.snapshot.sessionKey !== p.sessionKey || deps.snapshot.namespace !== p.namespace) {
816
+ return { status: "rejected", plan, errorCode: "scope_mismatch" };
817
+ }
818
+ const fenceHash = hashSnapshot(deps.snapshot);
819
+ if (fenceHash !== plan.provenance.snapshotContentHash) {
820
+ return { status: "rejected", plan, errorCode: "plan_conflict" }; // changed fence
821
+ }
822
+
823
+ if (plan.operation === "FILTER") {
824
+ return { status: "ready", plan };
825
+ }
826
+
827
+ const replacement = plan.replacement;
828
+ if (!replacement) {
829
+ return { status: "failed", plan, errorCode: "invalid_request" };
830
+ }
831
+ const byId = new Map(deps.snapshot.messages.map((m) => [m.id, m] as const));
832
+ const sourceText = replacement.sourceMessageIds
833
+ .map((id) => byId.get(id))
834
+ .filter((m): m is ActiveContextMessage => m !== undefined)
835
+ .sort((a, b) => a.ordinal - b.ordinal || a.id.localeCompare(b.id))
836
+ .map((m) => m.content)
837
+ .join("\n\n"); // exact order, exact text
838
+
839
+ const method =
840
+ replacement.method === "deterministic"
841
+ ? "deterministic"
842
+ : replacement.fallbackPolicy === "allowed"
843
+ ? "auto"
844
+ : "llm";
845
+ try {
846
+ const result = await summarizeContextPure(sourceText, replacement.targetTokens, method, {
847
+ llm: deps.summarize,
848
+ deterministicMaxTokens: deps.caps?.activeContextSummaryMaxTokens ?? replacement.targetTokens,
849
+ });
850
+ if (result.text.trim().length === 0) {
851
+ return { status: "failed", plan, errorCode: "summary_unavailable" }; // bad model text
852
+ }
853
+ return {
854
+ status: "ready",
855
+ plan,
856
+ replacement: {
857
+ messageId: replacement.messageId,
858
+ text: result.text,
859
+ contentHash: sha256Hex(result.text),
860
+ method: result.method,
861
+ ...(result.modelUsed ? { modelUsed: result.modelUsed } : {}),
862
+ fallback: result.fallback,
863
+ sourceMessageIds: replacement.sourceMessageIds,
864
+ },
865
+ };
866
+ } catch (err) {
867
+ if (err instanceof ContextSummaryUnavailableError) {
868
+ return { status: "failed", plan, errorCode: "summary_unavailable" };
869
+ }
870
+ throw err;
871
+ }
872
+ }
873
+
874
+ // ── receipts and telemetry ─────────────────────────────────────────────────
875
+
876
+ /**
877
+ * Validate a host receipt against the plan's bindings and append one
878
+ * context record to the ledger. Order of checks: scope → hash → revision →
879
+ * shape. One-time use is enforced by the adapter's persisted apply/undo
880
+ * markers (retention store); this recorder appends only. A ledger write
881
+ * failure returns `recorded: false` and never fabricates an apply.
882
+ */
883
+ export async function recordActiveContextApplyReceipt(
884
+ plan: ActiveContextTransformPlan,
885
+ receipt: ActiveContextApplyReceipt,
886
+ trustedScope: ActiveContextResolvedScope,
887
+ recorder: {
888
+ append(record: ContextTransformTelemetryRecord): Promise<boolean>;
889
+ },
890
+ ): Promise<{ recorded: boolean; event: ContextTransformTelemetryRecord }> {
891
+ const p = plan.precondition;
892
+ const scopeMatch =
893
+ trustedScope.principal === p.principal &&
894
+ trustedScope.sessionKey === p.sessionKey &&
895
+ trustedScope.namespace === p.namespace &&
896
+ trustedScope.adapterId === p.adapterId &&
897
+ receipt.adapterId === trustedScope.adapterId;
898
+ if (!scopeMatch) throw new PlanReject("scope_mismatch");
899
+ if (receipt.planHash !== plan.planHash) throw new PlanReject("plan_conflict"); // bad hash
900
+ if (receipt.hostRevisionBefore === undefined || receipt.hostRevisionBefore !== p.snapshotRevision) {
901
+ throw new PlanReject("stale_context"); // old plan / bad revision
902
+ }
903
+ const shapeOk =
904
+ receipt.schemaVersion === ACTIVE_CONTEXT_RECEIPT_SCHEMA_VERSION &&
905
+ receipt.planId === plan.planId &&
906
+ (receipt.outcome === "applied" || receipt.outcome === "skipped" || receipt.outcome === "failed") &&
907
+ typeof receipt.appliedAt === "string" &&
908
+ !Number.isNaN(Date.parse(receipt.appliedAt));
909
+ if (!shapeOk) throw new PlanReject("invalid_receipt");
910
+
911
+ const event: ContextTransformTelemetryRecord = {
912
+ recordKind: "context_transform",
913
+ schemaVersion: ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION,
914
+ timestamp: receipt.appliedAt,
915
+ actionId: plan.planId,
916
+ action: plan.operation === "SUMMARY" ? "summarize_context" : "filter_context",
917
+ outcome: receipt.outcome,
918
+ status: receipt.outcome === "applied" ? "applied" : receipt.outcome === "failed" ? "rejected" : "validated",
919
+ subsystem: "active-context",
920
+ namespace: p.namespace,
921
+ sourceSessionKey: p.sessionKey,
922
+ planHash: plan.planHash,
923
+ snapshotRevision: p.snapshotRevision,
924
+ adapterId: receipt.adapterId,
925
+ algorithmVersion: plan.provenance.algorithmVersion,
926
+ selectedCount: plan.selectedMessageIds.length,
927
+ retainedCount: plan.retainedMessageIds.length,
928
+ proposedRemovalCount: plan.proposedRemovalIds.length,
929
+ receiptOutcome: receipt.outcome,
930
+ selectorHash: plan.provenance.selectorHash,
931
+ snapshotContentHash: plan.provenance.snapshotContentHash,
932
+ ...(plan.provenance.criterionHash ? { criterionHash: plan.provenance.criterionHash } : {}),
933
+ ...(plan.provenance.sourcePromptHash ? { sourcePromptHash: plan.provenance.sourcePromptHash } : {}),
934
+ policyDecision: plan.policy.decision,
935
+ policyRationale: plan.policy.rationale,
936
+ };
937
+
938
+ let recorded = false;
939
+ try {
940
+ recorded = await recorder.append(event);
941
+ } catch {
942
+ recorded = false; // ledger errors surface in the result, never as an apply
943
+ }
944
+ return { recorded, event: { ...event, telemetryRecorded: recorded } };
945
+ }
946
+
947
+ /**
948
+ * Build a plan-stage ledger record (plan produced, rejected, skipped, or
949
+ * failed before host apply). Receipt-backed applies use
950
+ * {@link recordActiveContextApplyReceipt} instead.
951
+ */
952
+ export function buildContextTransformPlanEvent(
953
+ plan: ActiveContextTransformPlan,
954
+ outcome: "skipped" | "failed",
955
+ ): ContextTransformTelemetryRecord {
956
+ return {
957
+ recordKind: "context_transform",
958
+ schemaVersion: ACTIVE_CONTEXT_RECORD_SCHEMA_VERSION,
959
+ timestamp: plan.provenance.generatedAt,
960
+ actionId: plan.planId,
961
+ action: plan.operation === "SUMMARY" ? "summarize_context" : "filter_context",
962
+ outcome,
963
+ status: plan.status === "ready" ? "validated" : "rejected",
964
+ subsystem: "active-context",
965
+ namespace: plan.precondition.namespace,
966
+ sourceSessionKey: plan.precondition.sessionKey,
967
+ planHash: plan.planHash,
968
+ snapshotRevision: plan.precondition.snapshotRevision,
969
+ algorithmVersion: plan.provenance.algorithmVersion,
970
+ selectedCount: plan.selectedMessageIds.length,
971
+ retainedCount: plan.retainedMessageIds.length,
972
+ proposedRemovalCount: plan.proposedRemovalIds.length,
973
+ selectorHash: plan.provenance.selectorHash,
974
+ snapshotContentHash: plan.provenance.snapshotContentHash,
975
+ ...(plan.provenance.criterionHash ? { criterionHash: plan.provenance.criterionHash } : {}),
976
+ ...(plan.provenance.sourcePromptHash ? { sourcePromptHash: plan.provenance.sourcePromptHash } : {}),
977
+ policyDecision: plan.policy.decision,
978
+ policyRationale: plan.policy.rationale,
979
+ telemetryRecorded: true,
980
+ };
981
+ }