@remnic/core 9.66.1 → 9.66.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/dist/access-admin-ops-surface.d.ts +1 -1
  2. package/dist/access-admin-ops-surface.js +26 -26
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +1 -1
  5. package/dist/access-authorization-probe.js +27 -27
  6. package/dist/access-boundary.d.ts +1 -1
  7. package/dist/access-boundary.js +26 -26
  8. package/dist/access-cli.js +90 -88
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.js +26 -26
  12. package/dist/access-http-lcm-compaction.d.ts +1 -1
  13. package/dist/access-http-lifecycle-flush.d.ts +1 -1
  14. package/dist/access-http-offline-stream.d.ts +1 -1
  15. package/dist/access-http-query.js +28 -28
  16. package/dist/access-http.d.ts +2 -2
  17. package/dist/access-http.js +41 -41
  18. package/dist/access-identity-continuity-surface.js +26 -26
  19. package/dist/access-lcm-surface.d.ts +1 -1
  20. package/dist/access-lcm-surface.js +26 -26
  21. package/dist/access-mcp.d.ts +1 -1
  22. package/dist/access-mcp.js +33 -33
  23. package/dist/access-namespace-preflight.js +26 -26
  24. package/dist/access-observe-write-surface.d.ts +1 -1
  25. package/dist/access-observe-write-surface.js +26 -26
  26. package/dist/access-operations-batch.js +28 -28
  27. package/dist/access-operations.d.ts +6 -6
  28. package/dist/access-operations.js +32 -32
  29. package/dist/access-recall-concurrency.d.ts +1 -1
  30. package/dist/access-recall-concurrency.js +26 -26
  31. package/dist/access-recall-response.d.ts +1 -1
  32. package/dist/access-recall-response.js +26 -26
  33. package/dist/access-recall-surface.d.ts +1 -1
  34. package/dist/access-recall-surface.js +26 -26
  35. package/dist/access-schema.d.ts +89 -89
  36. package/dist/access-service-helpers.d.ts +1 -1
  37. package/dist/access-service.d.ts +1 -1
  38. package/dist/access-service.js +26 -26
  39. package/dist/access-surface-catalog.d.ts +1 -1
  40. package/dist/access-surface-catalog.js +28 -28
  41. package/dist/active-recall.js +3 -3
  42. package/dist/adapters/index.js +4 -4
  43. package/dist/adapters/registry.js +2 -2
  44. package/dist/briefing.js +10 -10
  45. package/dist/buffer.js +4 -4
  46. package/dist/causal-behavior.js +2 -2
  47. package/dist/causal-chain.js +2 -2
  48. package/dist/causal-consolidation.js +13 -13
  49. package/dist/causal-retrieval.js +2 -2
  50. package/dist/causal-trajectory-graph.js +2 -2
  51. package/dist/causal-trajectory.js +1 -1
  52. package/dist/{chunk-LYUUA6QB.js → chunk-25OLNWYG.js} +2 -2
  53. package/dist/{chunk-2X6BGKQL.js → chunk-2QSGJTDG.js} +10 -10
  54. package/dist/{chunk-ZZZWEDF4.js → chunk-2VZHB5US.js} +2 -2
  55. package/dist/{chunk-JKTV3JNX.js → chunk-36HJ36FK.js} +3 -3
  56. package/dist/{chunk-XKNHFDTT.js → chunk-3A2Z4OOS.js} +2 -2
  57. package/dist/{chunk-TCF4MU7L.js → chunk-47WWTCJY.js} +1001 -101
  58. package/dist/chunk-47WWTCJY.js.map +1 -0
  59. package/dist/{chunk-RDGKVH6T.js → chunk-4NKIGSJM.js} +2 -2
  60. package/dist/{chunk-QBNE55VA.js → chunk-4PG2CKI6.js} +2 -2
  61. package/dist/{chunk-S4CDUXQY.js → chunk-6545JDIM.js} +2 -2
  62. package/dist/{chunk-2FA7U5XY.js → chunk-65HXVEVG.js} +2 -2
  63. package/dist/{chunk-U6NGKS32.js → chunk-6BYJQ3L2.js} +8 -8
  64. package/dist/{chunk-OMX6TKXH.js → chunk-6PUF7LUO.js} +2 -2
  65. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  66. package/dist/{chunk-VG4SSPAW.js → chunk-AI5M4FVQ.js} +2 -2
  67. package/dist/{chunk-MUEGIKKY.js → chunk-B4B3QDV3.js} +21 -20
  68. package/dist/chunk-B4B3QDV3.js.map +1 -0
  69. package/dist/{chunk-YMOPYG3K.js → chunk-BIJAWZYW.js} +6 -6
  70. package/dist/{chunk-M5ERTI4I.js → chunk-BLHKR4GJ.js} +2 -2
  71. package/dist/chunk-BLUYQFRH.js +36 -0
  72. package/dist/chunk-BLUYQFRH.js.map +1 -0
  73. package/dist/{chunk-CEH2AFXG.js → chunk-C24UZSFW.js} +6 -6
  74. package/dist/{chunk-EH65UV2Z.js → chunk-C3ZYZKDJ.js} +2 -2
  75. package/dist/{chunk-NFP4KPTA.js → chunk-CDLPF3PX.js} +2 -2
  76. package/dist/{chunk-FFUMTH27.js → chunk-CQ6IWZDI.js} +2 -2
  77. package/dist/{chunk-KWIGDKM2.js → chunk-D2YNNDML.js} +2 -2
  78. package/dist/{chunk-65JOGLIS.js → chunk-D3DUA64S.js} +2 -2
  79. package/dist/{chunk-2ITZ74A6.js → chunk-DSEHPUID.js} +11 -11
  80. package/dist/chunk-E4X2YX2F.js +22 -0
  81. package/dist/chunk-E4X2YX2F.js.map +1 -0
  82. package/dist/{chunk-AF5H7TKI.js → chunk-EH7BNIUN.js} +2 -2
  83. package/dist/{chunk-IGZCAHFL.js → chunk-EQRD4NMH.js} +2 -2
  84. package/dist/{chunk-CX4OLNIH.js → chunk-ER2UPUMG.js} +2 -2
  85. package/dist/{chunk-SZMYGDSM.js → chunk-F2JXJABQ.js} +2 -2
  86. package/dist/{chunk-CHGG74CY.js → chunk-F4W5HTED.js} +2 -2
  87. package/dist/{chunk-H2IRSXZN.js → chunk-FFWONAAW.js} +3 -3
  88. package/dist/chunk-FYDW33ZB.js +13 -0
  89. package/dist/chunk-FYDW33ZB.js.map +1 -0
  90. package/dist/{chunk-TNGH4ZYI.js → chunk-GNWLTCKC.js} +2 -2
  91. package/dist/{chunk-OJUEUQDJ.js → chunk-JJ6ZEFXC.js} +2 -2
  92. package/dist/{chunk-U65VJSCJ.js → chunk-JMXHVJ2V.js} +10 -10
  93. package/dist/{chunk-NACLNNFQ.js → chunk-KSZKQTZS.js} +2 -2
  94. package/dist/{chunk-TCQRIIIN.js → chunk-LSR5LQXN.js} +2 -2
  95. package/dist/chunk-MAG6M3B6.js +51 -0
  96. package/dist/chunk-MAG6M3B6.js.map +1 -0
  97. package/dist/{chunk-B4AOWRYF.js → chunk-NTFXBILO.js} +4 -4
  98. package/dist/{chunk-2PSX5BJU.js → chunk-NZPFCP5A.js} +2 -2
  99. package/dist/{chunk-C5IUOBCN.js → chunk-OERZXNSK.js} +2 -2
  100. package/dist/{chunk-ZPS724LT.js → chunk-OIDICRH7.js} +2 -2
  101. package/dist/{chunk-LTBKKSCX.js → chunk-OLBZ2WGG.js} +2 -2
  102. package/dist/{chunk-PD66CVSD.js → chunk-OUKBMQ2O.js} +2 -2
  103. package/dist/{chunk-GPFZFCRN.js → chunk-PP7R754B.js} +1 -1
  104. package/dist/{chunk-GAJK3DQ5.js → chunk-PRRUK2ZH.js} +2 -2
  105. package/dist/{chunk-TBCDF556.js → chunk-PW3GKWH3.js} +3 -3
  106. package/dist/chunk-Q3SHEAXR.js +80 -0
  107. package/dist/chunk-Q3SHEAXR.js.map +1 -0
  108. package/dist/{chunk-KI64TTBL.js → chunk-R2Q6FTOX.js} +2 -2
  109. package/dist/{chunk-KJXCD7VR.js → chunk-RCPKBW7K.js} +4 -4
  110. package/dist/{chunk-INUBU6I5.js → chunk-RH3XLQG4.js} +2 -2
  111. package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
  112. package/dist/{chunk-NSTNGMSS.js → chunk-U4HZEW2B.js} +5 -5
  113. package/dist/{chunk-XOHYGIWF.js → chunk-UHQE37NI.js} +2 -2
  114. package/dist/{chunk-D3UXGE5D.js → chunk-UMZUKOJU.js} +7 -7
  115. package/dist/{chunk-S4Z2OBTX.js → chunk-UVYL5G7A.js} +3 -3
  116. package/dist/{chunk-4XLTUR6R.js → chunk-VKDBDJIX.js} +3 -3
  117. package/dist/{chunk-UW4RYPWC.js → chunk-VSMSYDIH.js} +2 -2
  118. package/dist/{chunk-LJABGXC4.js → chunk-W5IYHQA5.js} +3 -3
  119. package/dist/{chunk-7UOXCCCI.js → chunk-WKWY7YF3.js} +2 -2
  120. package/dist/{chunk-YWPLOJ7T.js → chunk-Y2YM4C75.js} +2 -2
  121. package/dist/{chunk-NUF7VSEX.js → chunk-YZ5VC2JJ.js} +2 -2
  122. package/dist/{chunk-EWKVYCFP.js → chunk-ZBIEX4XN.js} +1 -1
  123. package/dist/{chunk-GBEOUCBB.js → chunk-ZMVW2HJJ.js} +2 -2
  124. package/dist/{chunk-RPIS5FQ7.js → chunk-ZXROBS53.js} +44 -44
  125. package/dist/{cli-CsfFMe6n.d.ts → cli-BOuEb4Ia.d.ts} +1 -1
  126. package/dist/cli.d.ts +2 -2
  127. package/dist/cli.js +61 -61
  128. package/dist/coding/export-okf-codegraph.js +10 -10
  129. package/dist/coding/pre-action-gate.js +2 -2
  130. package/dist/compounding/engine.js +10 -10
  131. package/dist/config.js +3 -3
  132. package/dist/connectors/codex-materialize-runner.js +10 -10
  133. package/dist/connectors/index.js +10 -10
  134. package/dist/convergence-refresh.js +12 -12
  135. package/dist/corpus-watermark.js +12 -12
  136. package/dist/entity-retrieval.js +10 -10
  137. package/dist/external-wiki-access.d.ts +1 -1
  138. package/dist/external-wiki-access.js +27 -27
  139. package/dist/external-wiki-mcp-tools.d.ts +1 -1
  140. package/dist/extraction-span-wire.d.ts +17 -0
  141. package/dist/extraction-span-wire.js +13 -0
  142. package/dist/extraction-span-wire.js.map +1 -0
  143. package/dist/extraction-span.d.ts +17 -0
  144. package/dist/extraction-span.js +8 -0
  145. package/dist/extraction.js +13 -13
  146. package/dist/{graph-edge-decay-A4SDFMMS.js → graph-edge-decay-FXGELBFA.js} +4 -4
  147. package/dist/graph-edge-decay-FXGELBFA.js.map +1 -0
  148. package/dist/graph-snapshot.js +3 -3
  149. package/dist/graph.js +3 -3
  150. package/dist/harmonic-retrieval.js +1 -1
  151. package/dist/index.d.ts +887 -681
  152. package/dist/index.js +161 -108
  153. package/dist/lcm/engine.js +3 -3
  154. package/dist/lcm/index.js +11 -11
  155. package/dist/location/index.js +12 -12
  156. package/dist/maintenance/memory-governance.js +10 -10
  157. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  158. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  159. package/dist/mcp-memory-inspector-app.d.ts +1 -1
  160. package/dist/memory-subject-cli.d.ts +1 -1
  161. package/dist/memory-subject.d.ts +1 -1
  162. package/dist/namespaces/migrate.js +11 -11
  163. package/dist/namespaces/search.js +6 -6
  164. package/dist/namespaces/storage.js +10 -10
  165. package/dist/operator-doctor-corpus.js +13 -13
  166. package/dist/operator-toolkit.js +23 -23
  167. package/dist/orchestration/maintenance.js +18 -18
  168. package/dist/orchestrator.js +90 -88
  169. package/dist/{public-http-Cwvl4QZr.d.ts → public-http-CmQRjQCD.d.ts} +1 -1
  170. package/dist/qmd.js +4 -4
  171. package/dist/recall-deep-access.d.ts +30 -0
  172. package/dist/recall-deep-access.js +50 -0
  173. package/dist/recall-deep-access.js.map +1 -0
  174. package/dist/recall-deep-render.d.ts +11 -0
  175. package/dist/recall-deep-render.js +28 -0
  176. package/dist/recall-deep-render.js.map +1 -0
  177. package/dist/recall-deep.js +6 -73
  178. package/dist/recall-deep.js.map +1 -1
  179. package/dist/recall-navigate.js +6 -42
  180. package/dist/recall-navigate.js.map +1 -1
  181. package/dist/recall-state-view-render.d.ts +18 -0
  182. package/dist/recall-state-view-render.js +22 -0
  183. package/dist/recall-state-view-render.js.map +1 -0
  184. package/dist/recall-state-view-widen.d.ts +13 -0
  185. package/dist/recall-state-view-widen.js +11 -0
  186. package/dist/recall-state-view-widen.js.map +1 -0
  187. package/dist/recall-state-view-wire.d.ts +3 -4
  188. package/dist/recall-state-view-wire.js +2 -1
  189. package/dist/resume-bundles.js +4 -4
  190. package/dist/schemas.d.ts +176 -176
  191. package/dist/search/factory.js +5 -5
  192. package/dist/search/index.js +9 -9
  193. package/dist/semantic-consolidation.js +11 -11
  194. package/dist/semantic-rule-promotion.js +10 -10
  195. package/dist/semantic-rule-verifier.js +10 -10
  196. package/dist/shared-context/manager.d.ts +6 -6
  197. package/dist/source-agent-qualifier.js +12 -12
  198. package/dist/storage.js +9 -9
  199. package/dist/support-passport/index.d.ts +4 -4
  200. package/dist/support-passport/index.js +29 -29
  201. package/dist/transfer/export-okf.js +11 -11
  202. package/dist/transfer/types.d.ts +78 -78
  203. package/dist/verified-recall.js +10 -10
  204. package/dist/who-knows-cli.d.ts +1 -1
  205. package/dist/who-knows-cli.js +11 -11
  206. package/dist/who-knows.d.ts +1 -1
  207. package/dist/who-knows.js +10 -10
  208. package/package.json +2 -2
  209. package/src/activity/index.ts +3 -0
  210. package/src/activity/journal-vault-read.test.ts +153 -0
  211. package/src/activity/journal-vault-read.ts +214 -0
  212. package/src/activity/journal.ts +1 -1
  213. package/src/activity/timeline/analysis-batch.test.ts +56 -0
  214. package/src/activity/timeline/analysis-batch.ts +45 -0
  215. package/src/activity/timeline/analysis.test.ts +413 -0
  216. package/src/activity/timeline/analysis.ts +362 -0
  217. package/src/activity/timeline/index.ts +5 -0
  218. package/src/activity/timeline/journal-recap-persist.test.ts +148 -0
  219. package/src/activity/timeline/journal-recap-persist.ts +37 -0
  220. package/src/activity/timeline/weekly-persist.test.ts +121 -0
  221. package/src/activity/timeline/weekly-persist.ts +103 -0
  222. package/src/activity/vault-path.test.ts +38 -0
  223. package/src/activity/vault-path.ts +59 -0
  224. package/src/activity/vault-publish.test.ts +102 -0
  225. package/src/activity/vault-publish.ts +92 -13
  226. package/src/dedup/merge-on-write-wire.test.ts +101 -0
  227. package/src/dedup/merge-on-write-wire.ts +34 -0
  228. package/src/extraction-span-wire.test.ts +20 -0
  229. package/src/extraction-span-wire.ts +17 -0
  230. package/src/extraction-span.test.ts +59 -0
  231. package/src/extraction-span.ts +39 -0
  232. package/src/index.ts +1 -0
  233. package/src/recall-deep-access.test.ts +58 -0
  234. package/src/recall-deep-access.ts +71 -0
  235. package/src/recall-deep-render.test.ts +68 -0
  236. package/src/recall-deep-render.ts +32 -0
  237. package/src/recall-state-view-render.test.ts +94 -0
  238. package/src/recall-state-view-render.ts +24 -0
  239. package/src/recall-state-view-widen.test.ts +66 -0
  240. package/src/recall-state-view-widen.ts +49 -0
  241. package/src/recall-state-view-wire.ts +6 -16
  242. package/src/shared-context/staleness.test.ts +36 -0
  243. package/src/shared-context/staleness.ts +38 -0
  244. package/src/shared-context/trajectories.test.ts +77 -0
  245. package/src/shared-context/trajectories.ts +49 -0
  246. package/dist/chunk-MUEGIKKY.js.map +0 -1
  247. package/dist/chunk-TCF4MU7L.js.map +0 -1
  248. package/dist/chunk-WFCWP4XU.js +0 -17
  249. package/dist/chunk-WFCWP4XU.js.map +0 -1
  250. package/dist/{access-service-C2tV2-uL.d.ts → access-service-Dz6I9AZ-.d.ts} +64 -64
  251. /package/dist/{chunk-LYUUA6QB.js.map → chunk-25OLNWYG.js.map} +0 -0
  252. /package/dist/{chunk-2X6BGKQL.js.map → chunk-2QSGJTDG.js.map} +0 -0
  253. /package/dist/{chunk-ZZZWEDF4.js.map → chunk-2VZHB5US.js.map} +0 -0
  254. /package/dist/{chunk-JKTV3JNX.js.map → chunk-36HJ36FK.js.map} +0 -0
  255. /package/dist/{chunk-XKNHFDTT.js.map → chunk-3A2Z4OOS.js.map} +0 -0
  256. /package/dist/{chunk-RDGKVH6T.js.map → chunk-4NKIGSJM.js.map} +0 -0
  257. /package/dist/{chunk-QBNE55VA.js.map → chunk-4PG2CKI6.js.map} +0 -0
  258. /package/dist/{chunk-S4CDUXQY.js.map → chunk-6545JDIM.js.map} +0 -0
  259. /package/dist/{chunk-2FA7U5XY.js.map → chunk-65HXVEVG.js.map} +0 -0
  260. /package/dist/{chunk-U6NGKS32.js.map → chunk-6BYJQ3L2.js.map} +0 -0
  261. /package/dist/{chunk-OMX6TKXH.js.map → chunk-6PUF7LUO.js.map} +0 -0
  262. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  263. /package/dist/{chunk-VG4SSPAW.js.map → chunk-AI5M4FVQ.js.map} +0 -0
  264. /package/dist/{chunk-YMOPYG3K.js.map → chunk-BIJAWZYW.js.map} +0 -0
  265. /package/dist/{chunk-M5ERTI4I.js.map → chunk-BLHKR4GJ.js.map} +0 -0
  266. /package/dist/{chunk-CEH2AFXG.js.map → chunk-C24UZSFW.js.map} +0 -0
  267. /package/dist/{chunk-EH65UV2Z.js.map → chunk-C3ZYZKDJ.js.map} +0 -0
  268. /package/dist/{chunk-NFP4KPTA.js.map → chunk-CDLPF3PX.js.map} +0 -0
  269. /package/dist/{chunk-FFUMTH27.js.map → chunk-CQ6IWZDI.js.map} +0 -0
  270. /package/dist/{chunk-KWIGDKM2.js.map → chunk-D2YNNDML.js.map} +0 -0
  271. /package/dist/{chunk-65JOGLIS.js.map → chunk-D3DUA64S.js.map} +0 -0
  272. /package/dist/{chunk-2ITZ74A6.js.map → chunk-DSEHPUID.js.map} +0 -0
  273. /package/dist/{chunk-AF5H7TKI.js.map → chunk-EH7BNIUN.js.map} +0 -0
  274. /package/dist/{chunk-IGZCAHFL.js.map → chunk-EQRD4NMH.js.map} +0 -0
  275. /package/dist/{chunk-CX4OLNIH.js.map → chunk-ER2UPUMG.js.map} +0 -0
  276. /package/dist/{chunk-SZMYGDSM.js.map → chunk-F2JXJABQ.js.map} +0 -0
  277. /package/dist/{chunk-CHGG74CY.js.map → chunk-F4W5HTED.js.map} +0 -0
  278. /package/dist/{chunk-H2IRSXZN.js.map → chunk-FFWONAAW.js.map} +0 -0
  279. /package/dist/{chunk-TNGH4ZYI.js.map → chunk-GNWLTCKC.js.map} +0 -0
  280. /package/dist/{chunk-OJUEUQDJ.js.map → chunk-JJ6ZEFXC.js.map} +0 -0
  281. /package/dist/{chunk-U65VJSCJ.js.map → chunk-JMXHVJ2V.js.map} +0 -0
  282. /package/dist/{chunk-NACLNNFQ.js.map → chunk-KSZKQTZS.js.map} +0 -0
  283. /package/dist/{chunk-TCQRIIIN.js.map → chunk-LSR5LQXN.js.map} +0 -0
  284. /package/dist/{chunk-B4AOWRYF.js.map → chunk-NTFXBILO.js.map} +0 -0
  285. /package/dist/{chunk-2PSX5BJU.js.map → chunk-NZPFCP5A.js.map} +0 -0
  286. /package/dist/{chunk-C5IUOBCN.js.map → chunk-OERZXNSK.js.map} +0 -0
  287. /package/dist/{chunk-ZPS724LT.js.map → chunk-OIDICRH7.js.map} +0 -0
  288. /package/dist/{chunk-LTBKKSCX.js.map → chunk-OLBZ2WGG.js.map} +0 -0
  289. /package/dist/{chunk-PD66CVSD.js.map → chunk-OUKBMQ2O.js.map} +0 -0
  290. /package/dist/{chunk-GPFZFCRN.js.map → chunk-PP7R754B.js.map} +0 -0
  291. /package/dist/{chunk-GAJK3DQ5.js.map → chunk-PRRUK2ZH.js.map} +0 -0
  292. /package/dist/{chunk-TBCDF556.js.map → chunk-PW3GKWH3.js.map} +0 -0
  293. /package/dist/{chunk-KI64TTBL.js.map → chunk-R2Q6FTOX.js.map} +0 -0
  294. /package/dist/{chunk-KJXCD7VR.js.map → chunk-RCPKBW7K.js.map} +0 -0
  295. /package/dist/{chunk-INUBU6I5.js.map → chunk-RH3XLQG4.js.map} +0 -0
  296. /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
  297. /package/dist/{chunk-NSTNGMSS.js.map → chunk-U4HZEW2B.js.map} +0 -0
  298. /package/dist/{chunk-XOHYGIWF.js.map → chunk-UHQE37NI.js.map} +0 -0
  299. /package/dist/{chunk-D3UXGE5D.js.map → chunk-UMZUKOJU.js.map} +0 -0
  300. /package/dist/{chunk-S4Z2OBTX.js.map → chunk-UVYL5G7A.js.map} +0 -0
  301. /package/dist/{chunk-4XLTUR6R.js.map → chunk-VKDBDJIX.js.map} +0 -0
  302. /package/dist/{chunk-UW4RYPWC.js.map → chunk-VSMSYDIH.js.map} +0 -0
  303. /package/dist/{chunk-LJABGXC4.js.map → chunk-W5IYHQA5.js.map} +0 -0
  304. /package/dist/{chunk-7UOXCCCI.js.map → chunk-WKWY7YF3.js.map} +0 -0
  305. /package/dist/{chunk-YWPLOJ7T.js.map → chunk-Y2YM4C75.js.map} +0 -0
  306. /package/dist/{chunk-NUF7VSEX.js.map → chunk-YZ5VC2JJ.js.map} +0 -0
  307. /package/dist/{chunk-EWKVYCFP.js.map → chunk-ZBIEX4XN.js.map} +0 -0
  308. /package/dist/{chunk-GBEOUCBB.js.map → chunk-ZMVW2HJJ.js.map} +0 -0
  309. /package/dist/{chunk-RPIS5FQ7.js.map → chunk-ZXROBS53.js.map} +0 -0
  310. /package/dist/{graph-edge-decay-A4SDFMMS.js.map → extraction-span.js.map} +0 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Isolated span-offset parser (issue #2333 first slice).
3
+ *
4
+ * Default off. Extraction wiring waits on the Phase A bench gate.
5
+ */
6
+
7
+ export interface SpanOffsets {
8
+ start: number;
9
+ end: number;
10
+ }
11
+
12
+ export interface ParsedSpan {
13
+ text: string;
14
+ start?: number;
15
+ end?: number;
16
+ }
17
+
18
+ export function parseSpanOffsets(
19
+ text: string,
20
+ offsets: SpanOffsets,
21
+ spanModeEnabled: boolean | 0 | 1 = false,
22
+ ): ParsedSpan {
23
+ if (spanModeEnabled !== true && spanModeEnabled !== 1) {
24
+ return { text };
25
+ }
26
+
27
+ const { start, end } = offsets;
28
+ if (!Number.isInteger(start) || !Number.isInteger(end)) {
29
+ throw new RangeError("invalid span: out of range");
30
+ }
31
+ if (start > end) {
32
+ throw new RangeError("invalid span: reversed");
33
+ }
34
+ if (start < 0 || end > text.length) {
35
+ throw new RangeError("invalid span: out of range");
36
+ }
37
+
38
+ return { text: text.slice(start, end), start, end };
39
+ }
package/src/index.ts CHANGED
@@ -1458,3 +1458,4 @@ export * from "./maintenance/atomic-file.js";
1458
1458
  export * from "./eval-trajectory.js";
1459
1459
  export { MemoryControllerCoordinator, chooseAction, computeEvidenceReportHash, controllerConfigHash, evaluateActiveGates, hashControllerState, verifyEvidenceReport } from "./memory-controller.js";
1460
1460
  export type { ActiveContextAdapter, ActiveContextMessage, ActiveContextPlan, MemoryControllerActionFamily, MemoryControllerChoice, MemoryControllerConfig, MemoryControllerDeps, MemoryControllerEvent, MemoryControllerEvidence, MemoryControllerEvidenceReport, MemoryControllerExecutors, MemoryControllerMode, MemoryControllerPairedSeedEvidence, MemoryControllerReceipt, MemoryControllerRecorder, MemoryControllerReportReader, MemoryControllerRunResult, MemoryControllerState } from "./memory-controller.js";
1461
+ export * from "./recall-navigate.js";
@@ -0,0 +1,58 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { runDeepRecallAccess } from "./recall-deep-access.js";
5
+
6
+ const QUERY = "who met at the cafe";
7
+
8
+ test("budget 0 stops immediately with a tagged refusal", () => {
9
+ const result = runDeepRecallAccess({ query: QUERY, budget: 0, policyName: "expand-once" });
10
+ assert.equal(result.ok, false);
11
+ assert.deepEqual(result.refusal, { tag: "budget_exhausted" });
12
+ assert.equal(result.trace.length, 1);
13
+ assert.equal(result.trace[0]?.action, "stop");
14
+ assert.equal(result.state.budget, 0);
15
+ assert.equal(result.state.query, QUERY);
16
+ assert.deepEqual(result.state.workingSet, []);
17
+ assert.deepEqual(result.state.frontier, []);
18
+ assert.equal(result.traceJson, JSON.stringify(result.trace));
19
+ });
20
+
21
+ test("unknown policyName is rejected", () => {
22
+ assert.throws(
23
+ () => runDeepRecallAccess({ query: QUERY, budget: 2, policyName: "refine-twice" }),
24
+ /unknown deep recall access policy/,
25
+ );
26
+ assert.throws(
27
+ () => runDeepRecallAccess({ query: QUERY, budget: 2, policyName: "refine-twice" }),
28
+ /stop, expand-once/,
29
+ );
30
+ });
31
+
32
+ test("stop policy ends without expanding", () => {
33
+ const result = runDeepRecallAccess({ query: QUERY, budget: 3, policyName: "stop" });
34
+ assert.equal(result.ok, true);
35
+ assert.equal(result.refusal, undefined);
36
+ assert.equal(result.trace.length, 1);
37
+ assert.equal(result.trace[0]?.action, "stop");
38
+ assert.equal(result.state.budget, 3);
39
+ assert.deepEqual(result.state.workingSet, []);
40
+ });
41
+
42
+ test("expand-once expands once then stops", () => {
43
+ const result = runDeepRecallAccess({ query: QUERY, budget: 3, policyName: "expand-once" });
44
+ assert.equal(result.ok, true);
45
+ assert.deepEqual(
46
+ result.trace.map((step) => step.action),
47
+ ["expand", "stop"],
48
+ );
49
+ assert.equal(result.state.budget, 2);
50
+ });
51
+
52
+ test("same input produces the same trace JSON", () => {
53
+ const input = { query: QUERY, budget: 4, policyName: "expand-once" as const };
54
+ const first = runDeepRecallAccess(input);
55
+ const second = runDeepRecallAccess(input);
56
+ assert.equal(first.traceJson, second.traceJson);
57
+ assert.equal(first.traceJson, JSON.stringify(first.trace));
58
+ });
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Named-policy access facade for the deep-recall stepper (issue #2332 leftover).
3
+ *
4
+ * Not the hot path. Surfaces and parseConfig wait. Policy names are
5
+ * allow-listed. Budget 0 returns a tagged refusal without a policy call.
6
+ */
7
+
8
+ import { runDeepRecall, type DeepRecallResult, type DeepRecallState } from "./recall-deep.js";
9
+
10
+ export const DEEP_RECALL_ACCESS_POLICIES = ["stop", "expand-once"] as const;
11
+
12
+ export type DeepRecallAccessPolicyName = (typeof DEEP_RECALL_ACCESS_POLICIES)[number];
13
+
14
+ export interface DeepRecallAccessInput {
15
+ query: string;
16
+ budget: number;
17
+ policyName: string;
18
+ }
19
+
20
+ export interface DeepRecallAccessRefusal {
21
+ tag: "budget_exhausted";
22
+ }
23
+
24
+ export interface DeepRecallAccessResult {
25
+ ok: boolean;
26
+ refusal?: DeepRecallAccessRefusal;
27
+ state: DeepRecallState;
28
+ trace: DeepRecallResult["trace"];
29
+ traceJson: string;
30
+ }
31
+
32
+ export function isDeepRecallAccessPolicyName(value: unknown): value is DeepRecallAccessPolicyName {
33
+ return typeof value === "string" && (DEEP_RECALL_ACCESS_POLICIES as readonly string[]).includes(value);
34
+ }
35
+
36
+ export function runDeepRecallAccess(input: DeepRecallAccessInput): DeepRecallAccessResult {
37
+ if (!isDeepRecallAccessPolicyName(input.policyName)) {
38
+ throw new Error(
39
+ `unknown deep recall access policy: ${JSON.stringify(input.policyName)}. Valid: ${DEEP_RECALL_ACCESS_POLICIES.join(", ")}`,
40
+ );
41
+ }
42
+
43
+ const start: DeepRecallState = { query: input.query, workingSet: [], frontier: [], budget: input.budget };
44
+ if (!Number.isFinite(input.budget) || input.budget <= 0) {
45
+ const result = runDeepRecall(start, () => {
46
+ throw new Error("policy must not run when budget is 0");
47
+ });
48
+ return {
49
+ ok: false,
50
+ refusal: { tag: "budget_exhausted" },
51
+ state: result.state,
52
+ trace: result.trace,
53
+ traceJson: JSON.stringify(result.trace),
54
+ };
55
+ }
56
+
57
+ let expanded = false;
58
+ const result = runDeepRecall(start, () => {
59
+ if (input.policyName === "expand-once" && !expanded) {
60
+ expanded = true;
61
+ return "expand";
62
+ }
63
+ return "stop";
64
+ });
65
+ return {
66
+ ok: true,
67
+ state: result.state,
68
+ trace: result.trace,
69
+ traceJson: JSON.stringify(result.trace),
70
+ };
71
+ }
@@ -0,0 +1,68 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import {
5
+ runDeepRecall,
6
+ type DeepRecallState,
7
+ } from "./recall-deep.js";
8
+ import { renderDeepRecallTrace } from "./recall-deep-render.js";
9
+
10
+ function seed(extra: Partial<DeepRecallState> = {}): DeepRecallState {
11
+ return {
12
+ query: "who met at the cafe",
13
+ workingSet: [],
14
+ frontier: ["m-b", "m-c"],
15
+ budget: 2,
16
+ ...extra,
17
+ };
18
+ }
19
+
20
+ test("empty working set prints (empty)", () => {
21
+ const result = runDeepRecall(seed({ budget: 0 }), () => {
22
+ throw new Error("policy must not run when budget is 0");
23
+ });
24
+ assert.equal(
25
+ renderDeepRecallTrace(result),
26
+ [
27
+ "# Deep recall",
28
+ "",
29
+ "- query: who met at the cafe",
30
+ "- budget: 0",
31
+ "- stop: budget exhausted",
32
+ "",
33
+ "## Steps",
34
+ "",
35
+ "1. stop budget=0 workingSet=(empty) frontier=m-b, m-c",
36
+ "",
37
+ ].join("\n"),
38
+ );
39
+ });
40
+
41
+ test("expand then stop snapshot", () => {
42
+ const result = runDeepRecall(seed({ workingSet: ["m-seed"], budget: 2 }), (state) =>
43
+ state.workingSet.includes("m-b") ? "stop" : "expand",
44
+ );
45
+ assert.equal(
46
+ renderDeepRecallTrace(result),
47
+ [
48
+ "# Deep recall",
49
+ "",
50
+ "- query: who met at the cafe",
51
+ "- budget: 1",
52
+ "- stop: stop",
53
+ "",
54
+ "## Steps",
55
+ "",
56
+ "1. expand budget=1 workingSet=m-seed, m-b frontier=m-c",
57
+ "2. stop budget=1 workingSet=m-seed, m-b frontier=m-c",
58
+ "",
59
+ ].join("\n"),
60
+ );
61
+ });
62
+
63
+ test("same result renders the same bytes", () => {
64
+ const policy = () => "stop";
65
+ const first = renderDeepRecallTrace(runDeepRecall(seed({ budget: 3 }), policy));
66
+ const second = renderDeepRecallTrace(runDeepRecall(seed({ budget: 3 }), policy));
67
+ assert.equal(first, second);
68
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Markdown renderer for a deep-recall trace (issue #2332 leftover).
3
+ *
4
+ * Deterministic. Surfaces wait. Empty working set prints (empty).
5
+ */
6
+
7
+ import type { DeepRecallResult } from "./recall-deep.js";
8
+
9
+ export function renderDeepRecallTrace(result: DeepRecallResult): string {
10
+ const last = result.trace[result.trace.length - 1];
11
+ const stop = !last ? "none" : last.budget <= 0 ? "budget exhausted" : last.action;
12
+ const steps =
13
+ result.trace.length === 0
14
+ ? ["(empty)"]
15
+ : result.trace.map((step, index) => {
16
+ const workingSet = step.workingSet.length === 0 ? "(empty)" : step.workingSet.join(", ");
17
+ const frontier = step.frontier.length === 0 ? "(empty)" : step.frontier.join(", ");
18
+ return `${index + 1}. ${step.action} budget=${step.budget} workingSet=${workingSet} frontier=${frontier}`;
19
+ });
20
+ return [
21
+ "# Deep recall",
22
+ "",
23
+ `- query: ${result.state.query}`,
24
+ `- budget: ${result.state.budget}`,
25
+ `- stop: ${stop}`,
26
+ "",
27
+ "## Steps",
28
+ "",
29
+ ...steps,
30
+ "",
31
+ ].join("\n");
32
+ }
@@ -0,0 +1,94 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { renderStateViewLine } from "./recall-state-view-render.js";
5
+
6
+ const TEXT = "Was a baker";
7
+ const DATE = "2026-03-01";
8
+ const SUCCESSOR = "new-job";
9
+
10
+ test("historical line gets the superseded prefix", () => {
11
+ const line = renderStateViewLine(
12
+ {
13
+ id: "old-job",
14
+ text: TEXT,
15
+ stateLabel: "historical",
16
+ supersededAt: DATE,
17
+ supersededBy: SUCCESSOR,
18
+ },
19
+ { enabled: true },
20
+ );
21
+ assert.equal(line, `[superseded ${DATE} by ${SUCCESSOR}] ${TEXT}`);
22
+ });
23
+
24
+ test("transition line gets the superseded prefix", () => {
25
+ const line = renderStateViewLine(
26
+ {
27
+ id: "mid-job",
28
+ text: TEXT,
29
+ stateLabel: "transition",
30
+ supersededAt: DATE,
31
+ supersededBy: SUCCESSOR,
32
+ },
33
+ { enabled: true },
34
+ );
35
+ assert.equal(line, `[superseded ${DATE} by ${SUCCESSOR}] ${TEXT}`);
36
+ });
37
+
38
+ test("current line is identity text", () => {
39
+ assert.equal(
40
+ renderStateViewLine(
41
+ {
42
+ id: "new-job",
43
+ text: TEXT,
44
+ stateLabel: "current",
45
+ supersededAt: DATE,
46
+ supersededBy: SUCCESSOR,
47
+ },
48
+ { enabled: true },
49
+ ),
50
+ TEXT,
51
+ );
52
+ });
53
+
54
+ test("missing date is identity text", () => {
55
+ assert.equal(
56
+ renderStateViewLine(
57
+ {
58
+ id: "old-job",
59
+ text: TEXT,
60
+ stateLabel: "historical",
61
+ supersededBy: SUCCESSOR,
62
+ },
63
+ { enabled: true },
64
+ ),
65
+ TEXT,
66
+ );
67
+ });
68
+
69
+ test("missing successor is identity text", () => {
70
+ assert.equal(
71
+ renderStateViewLine(
72
+ {
73
+ id: "old-job",
74
+ text: TEXT,
75
+ stateLabel: "historical",
76
+ supersededAt: DATE,
77
+ },
78
+ { enabled: true },
79
+ ),
80
+ TEXT,
81
+ );
82
+ });
83
+
84
+ test("enabled false is identity text", () => {
85
+ const historical = {
86
+ id: "old-job",
87
+ text: TEXT,
88
+ stateLabel: "historical" as const,
89
+ supersededAt: DATE,
90
+ supersededBy: SUCCESSOR,
91
+ };
92
+ assert.equal(renderStateViewLine(historical), TEXT);
93
+ assert.equal(renderStateViewLine(historical, { enabled: false }), TEXT);
94
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Recall inject-line renderer for state views (issue #1952).
3
+ *
4
+ * Historical and transition rows get `[superseded <date> by <id>]` when both
5
+ * supersededAt and supersededBy are present. Current rows and a disabled
6
+ * flag are identity.
7
+ */
8
+ import { formatSupersededPrefix, type StateViewResult } from "./recall-state-view.js";
9
+
10
+ export type StateViewLineResult = StateViewResult & { text?: string };
11
+
12
+ export function renderStateViewLine(
13
+ result: StateViewLineResult,
14
+ options: { enabled?: boolean } = {},
15
+ ): string {
16
+ const text = typeof result.text === "string" ? result.text : "";
17
+ if (options.enabled !== true) return text;
18
+ const label = result.stateLabel;
19
+ if (label !== "historical" && label !== "transition") return text;
20
+ const date = result.supersededAt;
21
+ const successor = result.supersededBy;
22
+ if (!date || !successor) return text;
23
+ return `${formatSupersededPrefix(date, successor)} ${text}`;
24
+ }
@@ -0,0 +1,66 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { applyRecallStateViews } from "./recall-state-view-wire.js";
5
+ import { widenRecallStateViews } from "./recall-state-view-widen.js";
6
+ import type { StateViewResult } from "./recall-state-view.js";
7
+
8
+ function fact(id: string, extra: Partial<StateViewResult> = {}): StateViewResult {
9
+ return { id, ...extra };
10
+ }
11
+
12
+ const CURRENT = fact("new-job", { status: "active" });
13
+ const HISTORICAL = fact("old-job", {
14
+ status: "superseded",
15
+ supersededBy: "new-job",
16
+ supersededAt: "2026-03-01",
17
+ });
18
+ const ORPHAN = fact("orphan-job", {
19
+ status: "superseded",
20
+ supersededBy: "missing-job",
21
+ });
22
+ const ON = { recallStateViews: true } as const;
23
+ const CHANGE = "when did the job title change";
24
+ const NON_CHANGE = "what is the current job title";
25
+
26
+ test("change-intent query labels both facts when successor is in the set", () => {
27
+ const labeled = widenRecallStateViews([CURRENT], CHANGE, ON, [HISTORICAL]);
28
+ assert.equal(labeled.length, 2);
29
+ assert.equal(labeled[0]?.id, "new-job");
30
+ assert.equal(labeled[0]?.stateLabel, "current");
31
+ assert.equal(labeled[1]?.id, "old-job");
32
+ assert.equal(labeled[1]?.stateLabel, "historical");
33
+ assert.deepEqual(
34
+ applyRecallStateViews([CURRENT, HISTORICAL], CHANGE, ON).map((row) => [
35
+ row.id,
36
+ row.stateLabel,
37
+ ]),
38
+ [
39
+ ["new-job", "current"],
40
+ ["old-job", "historical"],
41
+ ],
42
+ );
43
+ });
44
+
45
+ test("non-change query is identical (same array reference)", () => {
46
+ const input = [CURRENT, HISTORICAL];
47
+ assert.equal(widenRecallStateViews(input, NON_CHANGE, ON, [ORPHAN]), input);
48
+ assert.equal(applyRecallStateViews(input, NON_CHANGE, ON), input);
49
+ assert.equal(input[0]?.stateLabel, undefined);
50
+ });
51
+
52
+ test("recallStateViews false is identity (same array reference)", () => {
53
+ const input = [CURRENT];
54
+ assert.equal(widenRecallStateViews(input, CHANGE, {}, [HISTORICAL]), input);
55
+ assert.equal(widenRecallStateViews(input, CHANGE, { recallStateViews: false }, [HISTORICAL]), input);
56
+ assert.equal(applyRecallStateViews(input, CHANGE, { recallStateViews: false }), input);
57
+ assert.equal(input[0]?.stateLabel, undefined);
58
+ });
59
+
60
+ test("superseded without successor is dropped", () => {
61
+ assert.deepEqual(widenRecallStateViews([ORPHAN], CHANGE, ON), []);
62
+ assert.deepEqual(widenRecallStateViews([CURRENT], CHANGE, ON, [ORPHAN]), [
63
+ { ...CURRENT, stateLabel: "current" },
64
+ ]);
65
+ assert.deepEqual(applyRecallStateViews([ORPHAN], CHANGE, ON), []);
66
+ });
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Recall state-view widening (issue #1952).
3
+ *
4
+ * When recallStateViews is on and the query is change-oriented, admit a
5
+ * superseded memory only if its successor is already in the candidate set.
6
+ * Flag off / non-change queries are identity.
7
+ */
8
+ import {
9
+ annotateStateView,
10
+ isChangeOrientedQuery,
11
+ parseRecallStateViews,
12
+ resultStateViewId,
13
+ shouldWidenSuperseded,
14
+ type StateViewResult,
15
+ } from "./recall-state-view.js";
16
+
17
+ export function widenRecallStateViews<T extends StateViewResult>(
18
+ results: T[],
19
+ query: string,
20
+ config: unknown,
21
+ pool: readonly T[] = [],
22
+ ): T[] {
23
+ const raw =
24
+ typeof config === "object" && config !== null && "recallStateViews" in config
25
+ ? config.recallStateViews
26
+ : undefined;
27
+ const enabled = parseRecallStateViews(raw);
28
+ if (!enabled || !isChangeOrientedQuery(query)) return results;
29
+
30
+ const candidateIds = new Set<string>();
31
+ for (const result of results) {
32
+ const id = resultStateViewId(result);
33
+ if (id) candidateIds.add(id);
34
+ }
35
+
36
+ const seen = new Set(candidateIds);
37
+ const extra: T[] = [];
38
+ for (const item of pool) {
39
+ const id = resultStateViewId(item);
40
+ if (!id || seen.has(id)) continue;
41
+ if (!shouldWidenSuperseded(item.supersededBy, candidateIds)) continue;
42
+ extra.push(item);
43
+ seen.add(id);
44
+ }
45
+
46
+ return annotateStateView(extra.length > 0 ? results.concat(extra) : results, query, [], {
47
+ enabled: true,
48
+ });
49
+ }
@@ -1,28 +1,18 @@
1
1
  /**
2
2
  * Recall inject seam for state views (issue #1952).
3
3
  *
4
- * parseConfig cannot grow (fileSizeGrandfather). Operators set
5
- * `recallStateViews` on the live PluginConfig extra field. Default false
6
- * is identity. Use parseRecallStateViews — do not read a scattered
7
- * config flag property here.
4
+ * Widening lives in recall-state-view-widen.ts. parseConfig cannot grow.
5
+ * Operators set `recallStateViews` on the live PluginConfig extra field.
6
+ * Default false is identity.
8
7
  */
9
8
 
10
- import {
11
- annotateStateView,
12
- parseRecallStateViews,
13
- type StateViewResult,
14
- } from "./recall-state-view.js";
9
+ import { widenRecallStateViews } from "./recall-state-view-widen.js";
10
+ import type { StateViewResult } from "./recall-state-view.js";
15
11
 
16
12
  export function applyRecallStateViews<T extends StateViewResult>(
17
13
  results: T[],
18
14
  query: string,
19
15
  config: unknown,
20
16
  ): T[] {
21
- const raw =
22
- typeof config === "object" && config !== null && "recallStateViews" in config
23
- ? (config as { recallStateViews?: unknown }).recallStateViews
24
- : undefined;
25
- return annotateStateView(results, query, [], {
26
- enabled: parseRecallStateViews(raw),
27
- });
17
+ return widenRecallStateViews(results, query, config);
28
18
  }
@@ -0,0 +1,36 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+
4
+ import {
5
+ filterLiveEnvelopes,
6
+ markSupersededCirculation,
7
+ type SharedStalenessItem,
8
+ } from "./staleness.js";
9
+
10
+ test("filterLiveEnvelopes drops at the expiry instant (half-open)", () => {
11
+ const expiresAt = "2026-08-18T12:00:00.000Z";
12
+ const at = Date.parse(expiresAt);
13
+ const live: SharedStalenessItem = { id: "keep", expiresAt };
14
+ const forever: SharedStalenessItem = { id: "legacy" };
15
+ const items: SharedStalenessItem[] = [live, forever];
16
+
17
+ assert.deepEqual(filterLiveEnvelopes(items, at - 1), items);
18
+ assert.deepEqual(filterLiveEnvelopes(items, at), [forever]);
19
+ assert.deepEqual(filterLiveEnvelopes(items, at + 1), [forever]);
20
+ assert.equal(items.length, 2);
21
+ });
22
+
23
+ test("markSupersededCirculation flags targets that still circulate", () => {
24
+ const older: SharedStalenessItem = { id: "item-1", expiresAt: "2026-08-19T00:00:00.000Z" };
25
+ const newer: SharedStalenessItem = { id: "item-2", supersedes: "item-1" };
26
+ const other: SharedStalenessItem = { id: "item-3" };
27
+ const items: SharedStalenessItem[] = [older, newer, other];
28
+
29
+
30
+ const marked = markSupersededCirculation(items);
31
+ assert.equal(marked[0]?.circulating, true);
32
+ assert.equal(marked[1]?.circulating, undefined);
33
+ assert.equal(marked[2]?.circulating, undefined);
34
+ assert.equal(older.circulating, undefined);
35
+ assert.notEqual(marked[0], older);
36
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared-item staleness (issue #1957).
3
+ *
4
+ * Pure helpers. Expired items drop; superseded items that still circulate
5
+ * get a marker. Callers never `rm`.
6
+ */
7
+ import { isExpired } from "./governance.js";
8
+
9
+ export interface SharedStalenessItem {
10
+ id: string;
11
+ expiresAt?: string;
12
+ supersedes?: string;
13
+ circulating?: boolean;
14
+ }
15
+
16
+ /** Drop expired items. Half-open: `nowMs >= expiresAt` is expired. */
17
+ export function filterLiveEnvelopes<T extends { expiresAt?: string }>(
18
+ items: readonly T[],
19
+ nowMs: number,
20
+ ): T[] {
21
+ return items.filter((item) => !isExpired(item, nowMs));
22
+ }
23
+
24
+ /**
25
+ * Mark items whose id appears in another item's `supersedes`.
26
+ * Returns a new array. Does not mutate input and does not delete files.
27
+ */
28
+ export function markSupersededCirculation<T extends SharedStalenessItem>(
29
+ items: readonly T[],
30
+ ): T[] {
31
+ const supersededIds = new Set<string>();
32
+ for (const item of items) {
33
+ if (item.supersedes) supersededIds.add(item.supersedes);
34
+ }
35
+ return items.map((item) =>
36
+ supersededIds.has(item.id) ? { ...item, circulating: true } : item,
37
+ );
38
+ }