@graphrefly/graphrefly 0.47.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/dist/base/composition/index.cjs +28 -19
  2. package/dist/base/composition/index.cjs.map +1 -1
  3. package/dist/base/composition/index.d.cts +14 -5
  4. package/dist/base/composition/index.d.ts +14 -5
  5. package/dist/base/composition/index.js +9 -9
  6. package/dist/base/index.cjs +294 -164
  7. package/dist/base/index.cjs.map +1 -1
  8. package/dist/base/index.d.cts +2 -2
  9. package/dist/base/index.d.ts +2 -2
  10. package/dist/base/index.js +77 -72
  11. package/dist/base/io/index.cjs +145 -85
  12. package/dist/base/io/index.cjs.map +1 -1
  13. package/dist/base/io/index.d.cts +32 -5
  14. package/dist/base/io/index.d.ts +32 -5
  15. package/dist/base/io/index.js +5 -5
  16. package/dist/base/mutation/index.cjs +21 -0
  17. package/dist/base/mutation/index.cjs.map +1 -1
  18. package/dist/base/mutation/index.d.cts +23 -1
  19. package/dist/base/mutation/index.d.ts +23 -1
  20. package/dist/base/mutation/index.js +3 -1
  21. package/dist/base/sources/browser/index.cjs +18 -12
  22. package/dist/base/sources/browser/index.cjs.map +1 -1
  23. package/dist/base/sources/browser/index.d.cts +20 -2
  24. package/dist/base/sources/browser/index.d.ts +20 -2
  25. package/dist/base/sources/browser/index.js +18 -12
  26. package/dist/base/sources/browser/index.js.map +1 -1
  27. package/dist/base/sources/event/index.cjs +29 -1
  28. package/dist/base/sources/event/index.cjs.map +1 -1
  29. package/dist/base/sources/event/index.d.cts +67 -3
  30. package/dist/base/sources/event/index.d.ts +67 -3
  31. package/dist/base/sources/event/index.js +5 -2
  32. package/dist/base/sources/index.cjs +96 -50
  33. package/dist/base/sources/index.cjs.map +1 -1
  34. package/dist/base/sources/index.d.cts +1 -1
  35. package/dist/base/sources/index.d.ts +1 -1
  36. package/dist/base/sources/index.js +7 -4
  37. package/dist/base/sources/node/index.cjs +43 -37
  38. package/dist/base/sources/node/index.cjs.map +1 -1
  39. package/dist/base/sources/node/index.js +43 -37
  40. package/dist/base/sources/node/index.js.map +1 -1
  41. package/dist/{chunk-J5WFUEO4.js → chunk-23MAWVOJ.js} +3 -3
  42. package/dist/{chunk-YXCPV26R.js → chunk-3REMCHSS.js} +39 -27
  43. package/dist/chunk-3REMCHSS.js.map +1 -0
  44. package/dist/{chunk-CEVNQ74M.js → chunk-3YGXPUHW.js} +2 -2
  45. package/dist/{chunk-CEVNQ74M.js.map → chunk-3YGXPUHW.js.map} +1 -1
  46. package/dist/{chunk-EVYY4X5A.js → chunk-46X2EFQH.js} +16 -5
  47. package/dist/chunk-46X2EFQH.js.map +1 -0
  48. package/dist/{chunk-NY2PYHNC.js → chunk-5UY3PNFY.js} +12 -5
  49. package/dist/chunk-5UY3PNFY.js.map +1 -0
  50. package/dist/{chunk-RGMTUZCL.js → chunk-65OM4XLQ.js} +50 -4
  51. package/dist/chunk-65OM4XLQ.js.map +1 -0
  52. package/dist/{chunk-3PSLNJDU.js → chunk-6DQYBIHW.js} +314 -49
  53. package/dist/chunk-6DQYBIHW.js.map +1 -0
  54. package/dist/{chunk-LDCSZ72P.js → chunk-6YBER5UP.js} +3 -3
  55. package/dist/{chunk-LDCSZ72P.js.map → chunk-6YBER5UP.js.map} +1 -1
  56. package/dist/{chunk-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
  57. package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
  58. package/dist/{chunk-VLAGJZSL.js → chunk-7T7WLEPM.js} +25 -4
  59. package/dist/chunk-7T7WLEPM.js.map +1 -0
  60. package/dist/{chunk-PKPO3JTZ.js → chunk-AQAKDE7F.js} +29 -11
  61. package/dist/chunk-AQAKDE7F.js.map +1 -0
  62. package/dist/{chunk-2OB3CEJS.js → chunk-B5Y5GPD5.js} +2 -2
  63. package/dist/{chunk-BXGZFGZ4.js → chunk-C5QD5DQX.js} +22 -1
  64. package/dist/chunk-C5QD5DQX.js.map +1 -0
  65. package/dist/{chunk-4XCHZRUJ.js → chunk-D5YGR4TP.js} +58 -7
  66. package/dist/chunk-D5YGR4TP.js.map +1 -0
  67. package/dist/{chunk-NPRP3MCV.js → chunk-DHDCOOJU.js} +2 -2
  68. package/dist/chunk-DHDCOOJU.js.map +1 -0
  69. package/dist/{chunk-MTTRCEJT.js → chunk-DVTDF5OI.js} +2 -2
  70. package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
  71. package/dist/chunk-F7EKHR32.js.map +1 -0
  72. package/dist/{chunk-A7KV5UK4.js → chunk-G7H6PN7P.js} +2 -2
  73. package/dist/{chunk-OCUDSN63.js → chunk-GGKHHG5Y.js} +110 -64
  74. package/dist/chunk-GGKHHG5Y.js.map +1 -0
  75. package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
  76. package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
  77. package/dist/{chunk-YJ4U2D2C.js → chunk-J5TBZFBD.js} +9 -7
  78. package/dist/chunk-J5TBZFBD.js.map +1 -0
  79. package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
  80. package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
  81. package/dist/{chunk-U225SKB4.js → chunk-K4ZYJ4EM.js} +569 -424
  82. package/dist/chunk-K4ZYJ4EM.js.map +1 -0
  83. package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
  84. package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
  85. package/dist/{chunk-IHTWQEDR.js → chunk-LTSI7ULC.js} +3 -3
  86. package/dist/{chunk-IHTWQEDR.js.map → chunk-LTSI7ULC.js.map} +1 -1
  87. package/dist/{chunk-DKNHAICT.js → chunk-MMHGYX44.js} +25 -9
  88. package/dist/chunk-MMHGYX44.js.map +1 -0
  89. package/dist/{chunk-K7PDZYQE.js → chunk-MQMTRKY3.js} +129 -50
  90. package/dist/chunk-MQMTRKY3.js.map +1 -0
  91. package/dist/{chunk-42FQ27MQ.js → chunk-MTODGQBR.js} +44 -179
  92. package/dist/chunk-MTODGQBR.js.map +1 -0
  93. package/dist/{chunk-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
  94. package/dist/{chunk-FVINAAKA.js → chunk-NBK6QQMG.js} +14 -13
  95. package/dist/{chunk-FVINAAKA.js.map → chunk-NBK6QQMG.js.map} +1 -1
  96. package/dist/{chunk-DM4OMPWK.js → chunk-NSA5K5G2.js} +2 -2
  97. package/dist/{chunk-MLTPJMH6.js → chunk-QQYULEZL.js} +2 -2
  98. package/dist/chunk-QSW4DFKE.js +31 -0
  99. package/dist/chunk-QSW4DFKE.js.map +1 -0
  100. package/dist/{chunk-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
  101. package/dist/chunk-S7HN5FHL.js.map +1 -0
  102. package/dist/{chunk-4S53H2KR.js → chunk-SUNCHMML.js} +2 -2
  103. package/dist/{chunk-4GYMCUDZ.js → chunk-T2U6N3FV.js} +7 -7
  104. package/dist/{chunk-RJOG4IJU.js → chunk-T5URUIIY.js} +50 -35
  105. package/dist/chunk-T5URUIIY.js.map +1 -0
  106. package/dist/{chunk-B4AKFXGE.js → chunk-TPTZZV25.js} +6 -6
  107. package/dist/chunk-TPTZZV25.js.map +1 -0
  108. package/dist/{chunk-BU3SEFA5.js → chunk-V46JWFGV.js} +7 -6
  109. package/dist/chunk-V46JWFGV.js.map +1 -0
  110. package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
  111. package/dist/chunk-VLDRAMP7.js.map +1 -0
  112. package/dist/{chunk-6XZYT4SW.js → chunk-X6ESZDR6.js} +8 -9
  113. package/dist/chunk-X6ESZDR6.js.map +1 -0
  114. package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
  115. package/dist/chunk-X7BA5PWG.js.map +1 -0
  116. package/dist/{chunk-CXANAIZU.js → chunk-XEWV254I.js} +3 -3
  117. package/dist/{chunk-CXANAIZU.js.map → chunk-XEWV254I.js.map} +1 -1
  118. package/dist/{chunk-V4Y3TM7U.js → chunk-YBJVKMTM.js} +38 -16
  119. package/dist/chunk-YBJVKMTM.js.map +1 -0
  120. package/dist/{chunk-7ADWWI2T.js → chunk-ZW32BPXV.js} +17 -6
  121. package/dist/chunk-ZW32BPXV.js.map +1 -0
  122. package/dist/compat/index.cjs +52 -5
  123. package/dist/compat/index.cjs.map +1 -1
  124. package/dist/compat/index.d.cts +1 -1
  125. package/dist/compat/index.d.ts +1 -1
  126. package/dist/compat/index.js +7 -7
  127. package/dist/compat/nestjs/index.cjs +52 -5
  128. package/dist/compat/nestjs/index.cjs.map +1 -1
  129. package/dist/compat/nestjs/index.d.cts +1 -1
  130. package/dist/compat/nestjs/index.d.ts +1 -1
  131. package/dist/compat/nestjs/index.js +4 -4
  132. package/dist/{fallback-Bx46zqky.d.cts → fallback-BROR6ZhO.d.cts} +1 -1
  133. package/dist/{fallback-pIWW8A2d.d.ts → fallback-DO80aM_3.d.ts} +1 -1
  134. package/dist/{index-B_p8tnvf.d.cts → index-D1z3XcF9.d.cts} +1 -0
  135. package/dist/{index-_HDSmPyp.d.ts → index-DZ6yua0Q.d.ts} +1 -0
  136. package/dist/index.cjs +2387 -1707
  137. package/dist/index.cjs.map +1 -1
  138. package/dist/index.d.cts +10 -10
  139. package/dist/index.d.ts +10 -10
  140. package/dist/index.js +173 -150
  141. package/dist/index.js.map +1 -1
  142. package/dist/presets/ai/index.cjs +88 -26
  143. package/dist/presets/ai/index.cjs.map +1 -1
  144. package/dist/presets/ai/index.js +14 -14
  145. package/dist/presets/harness/index.cjs +183 -51
  146. package/dist/presets/harness/index.cjs.map +1 -1
  147. package/dist/presets/harness/index.d.cts +15 -5
  148. package/dist/presets/harness/index.d.ts +15 -5
  149. package/dist/presets/harness/index.js +26 -26
  150. package/dist/presets/index.cjs +298 -101
  151. package/dist/presets/index.cjs.map +1 -1
  152. package/dist/presets/index.d.cts +2 -2
  153. package/dist/presets/index.d.ts +2 -2
  154. package/dist/presets/index.js +49 -49
  155. package/dist/presets/inspect/index.cjs +63 -14
  156. package/dist/presets/inspect/index.cjs.map +1 -1
  157. package/dist/presets/inspect/index.d.cts +1 -1
  158. package/dist/presets/inspect/index.d.ts +1 -1
  159. package/dist/presets/inspect/index.js +6 -6
  160. package/dist/presets/resilience/index.cjs +64 -44
  161. package/dist/presets/resilience/index.cjs.map +1 -1
  162. package/dist/presets/resilience/index.d.cts +12 -8
  163. package/dist/presets/resilience/index.d.ts +12 -8
  164. package/dist/presets/resilience/index.js +6 -6
  165. package/dist/{rate-limiter-DpVbSYdH.d.cts → rate-limiter-DC26FM8J.d.cts} +10 -1
  166. package/dist/{rate-limiter-CEALq4N1.d.ts → rate-limiter-DyWpwpQP.d.ts} +10 -1
  167. package/dist/{reactive-layout-fswlBUvX.d.ts → reactive-layout-BBBWH0V_.d.cts} +85 -4
  168. package/dist/{reactive-layout-fswlBUvX.d.cts → reactive-layout-BBBWH0V_.d.ts} +85 -4
  169. package/dist/solutions/index.cjs +239 -92
  170. package/dist/solutions/index.cjs.map +1 -1
  171. package/dist/solutions/index.d.cts +2 -2
  172. package/dist/solutions/index.d.ts +2 -2
  173. package/dist/solutions/index.js +32 -32
  174. package/dist/{spawnable-5mDY501F.d.cts → spawnable-B2IlW60f.d.cts} +23 -2
  175. package/dist/{spawnable-D3lR0oQu.d.ts → spawnable-tttFz2Nh.d.ts} +23 -2
  176. package/dist/testing/index.cjs +94 -0
  177. package/dist/testing/index.cjs.map +1 -0
  178. package/dist/testing/index.d.cts +59 -0
  179. package/dist/testing/index.d.ts +59 -0
  180. package/dist/testing/index.js +73 -0
  181. package/dist/testing/index.js.map +1 -0
  182. package/dist/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
  183. package/dist/utils/ai/browser.cjs.map +1 -1
  184. package/dist/utils/ai/browser.d.cts +2 -2
  185. package/dist/utils/ai/browser.d.ts +2 -2
  186. package/dist/utils/ai/browser.js +10 -10
  187. package/dist/utils/ai/browser.js.map +1 -1
  188. package/dist/utils/ai/index.cjs +291 -191
  189. package/dist/utils/ai/index.cjs.map +1 -1
  190. package/dist/utils/ai/index.d.cts +108 -12
  191. package/dist/utils/ai/index.d.ts +108 -12
  192. package/dist/utils/ai/index.js +23 -21
  193. package/dist/utils/ai/node.cjs.map +1 -1
  194. package/dist/utils/ai/node.d.cts +5 -5
  195. package/dist/utils/ai/node.d.ts +5 -5
  196. package/dist/utils/ai/node.js +3 -3
  197. package/dist/utils/ai/node.js.map +1 -1
  198. package/dist/utils/cqrs/index.cjs +29 -3
  199. package/dist/utils/cqrs/index.cjs.map +1 -1
  200. package/dist/utils/cqrs/index.d.cts +12 -7
  201. package/dist/utils/cqrs/index.d.ts +12 -7
  202. package/dist/utils/cqrs/index.js +2 -2
  203. package/dist/utils/demo-shell/index.cjs +45 -19
  204. package/dist/utils/demo-shell/index.cjs.map +1 -1
  205. package/dist/utils/demo-shell/index.d.cts +1 -1
  206. package/dist/utils/demo-shell/index.d.ts +1 -1
  207. package/dist/utils/demo-shell/index.js +2 -2
  208. package/dist/utils/domain-templates/index.cjs +1 -1
  209. package/dist/utils/domain-templates/index.cjs.map +1 -1
  210. package/dist/utils/domain-templates/index.js +3 -3
  211. package/dist/utils/graphspec/index.cjs +1 -1
  212. package/dist/utils/graphspec/index.cjs.map +1 -1
  213. package/dist/utils/graphspec/index.js +3 -3
  214. package/dist/utils/harness/index.cjs +16 -10
  215. package/dist/utils/harness/index.cjs.map +1 -1
  216. package/dist/utils/harness/index.js +1 -1
  217. package/dist/utils/index.cjs +1692 -1192
  218. package/dist/utils/index.cjs.map +1 -1
  219. package/dist/utils/index.d.cts +7 -7
  220. package/dist/utils/index.d.ts +7 -7
  221. package/dist/utils/index.js +77 -59
  222. package/dist/utils/inspect/index.cjs +52 -4
  223. package/dist/utils/inspect/index.cjs.map +1 -1
  224. package/dist/utils/inspect/index.d.cts +32 -3
  225. package/dist/utils/inspect/index.d.ts +32 -3
  226. package/dist/utils/inspect/index.js +4 -4
  227. package/dist/utils/job-queue/index.cjs +46 -9
  228. package/dist/utils/job-queue/index.cjs.map +1 -1
  229. package/dist/utils/job-queue/index.d.cts +33 -3
  230. package/dist/utils/job-queue/index.d.ts +33 -3
  231. package/dist/utils/job-queue/index.js +2 -2
  232. package/dist/utils/memory/index.cjs +570 -425
  233. package/dist/utils/memory/index.cjs.map +1 -1
  234. package/dist/utils/memory/index.d.cts +261 -33
  235. package/dist/utils/memory/index.d.ts +261 -33
  236. package/dist/utils/memory/index.js +10 -2
  237. package/dist/utils/messaging/index.cjs.map +1 -1
  238. package/dist/utils/messaging/index.d.cts +4 -3
  239. package/dist/utils/messaging/index.d.ts +4 -3
  240. package/dist/utils/messaging/index.js +2 -2
  241. package/dist/utils/orchestration/index.cjs +14 -3
  242. package/dist/utils/orchestration/index.cjs.map +1 -1
  243. package/dist/utils/orchestration/index.js +3 -3
  244. package/dist/utils/process/index.cjs +32 -2
  245. package/dist/utils/process/index.cjs.map +1 -1
  246. package/dist/utils/process/index.d.cts +4 -3
  247. package/dist/utils/process/index.d.ts +4 -3
  248. package/dist/utils/process/index.js +3 -3
  249. package/dist/utils/reactive-layout/index.cjs +184 -55
  250. package/dist/utils/reactive-layout/index.cjs.map +1 -1
  251. package/dist/utils/reactive-layout/index.d.cts +128 -3
  252. package/dist/utils/reactive-layout/index.d.ts +128 -3
  253. package/dist/utils/reactive-layout/index.js +16 -8
  254. package/dist/utils/reduction/index.cjs +1 -1
  255. package/dist/utils/reduction/index.cjs.map +1 -1
  256. package/dist/utils/reduction/index.js +2 -2
  257. package/dist/utils/resilience/index.cjs +64 -43
  258. package/dist/utils/resilience/index.cjs.map +1 -1
  259. package/dist/utils/resilience/index.d.cts +1 -1
  260. package/dist/utils/resilience/index.d.ts +1 -1
  261. package/dist/utils/resilience/index.js +5 -5
  262. package/dist/utils/surface/index.cjs +1 -1
  263. package/dist/utils/surface/index.cjs.map +1 -1
  264. package/dist/utils/surface/index.js +4 -4
  265. package/package.json +15 -3
  266. package/dist/chunk-3PSLNJDU.js.map +0 -1
  267. package/dist/chunk-42FQ27MQ.js.map +0 -1
  268. package/dist/chunk-4XCHZRUJ.js.map +0 -1
  269. package/dist/chunk-6XZYT4SW.js.map +0 -1
  270. package/dist/chunk-7ADWWI2T.js.map +0 -1
  271. package/dist/chunk-B4AKFXGE.js.map +0 -1
  272. package/dist/chunk-BU3SEFA5.js.map +0 -1
  273. package/dist/chunk-BXGZFGZ4.js.map +0 -1
  274. package/dist/chunk-DKNHAICT.js.map +0 -1
  275. package/dist/chunk-E5OZPDIW.js.map +0 -1
  276. package/dist/chunk-EVYY4X5A.js.map +0 -1
  277. package/dist/chunk-IJRR6YAI.js.map +0 -1
  278. package/dist/chunk-K7PDZYQE.js.map +0 -1
  279. package/dist/chunk-NPRP3MCV.js.map +0 -1
  280. package/dist/chunk-NY2PYHNC.js.map +0 -1
  281. package/dist/chunk-OCUDSN63.js.map +0 -1
  282. package/dist/chunk-PKPO3JTZ.js.map +0 -1
  283. package/dist/chunk-PZWISPIQ.js.map +0 -1
  284. package/dist/chunk-RGMTUZCL.js.map +0 -1
  285. package/dist/chunk-RJOG4IJU.js.map +0 -1
  286. package/dist/chunk-SOOKUYVM.js.map +0 -1
  287. package/dist/chunk-U225SKB4.js.map +0 -1
  288. package/dist/chunk-V4Y3TM7U.js.map +0 -1
  289. package/dist/chunk-VLAGJZSL.js.map +0 -1
  290. package/dist/chunk-W2BOPXTI.js +0 -1
  291. package/dist/chunk-YJ4U2D2C.js.map +0 -1
  292. package/dist/chunk-YXCPV26R.js.map +0 -1
  293. package/dist/timeout-U5O4ESK3.js.map +0 -1
  294. /package/dist/{chunk-J5WFUEO4.js.map → chunk-23MAWVOJ.js.map} +0 -0
  295. /package/dist/{chunk-2OB3CEJS.js.map → chunk-B5Y5GPD5.js.map} +0 -0
  296. /package/dist/{chunk-MTTRCEJT.js.map → chunk-DVTDF5OI.js.map} +0 -0
  297. /package/dist/{chunk-A7KV5UK4.js.map → chunk-G7H6PN7P.js.map} +0 -0
  298. /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
  299. /package/dist/{chunk-DM4OMPWK.js.map → chunk-NSA5K5G2.js.map} +0 -0
  300. /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
  301. /package/dist/{chunk-4S53H2KR.js.map → chunk-SUNCHMML.js.map} +0 -0
  302. /package/dist/{chunk-4GYMCUDZ.js.map → chunk-T2U6N3FV.js.map} +0 -0
  303. /package/dist/{chunk-W2BOPXTI.js.map → timeout-BEABACRP.js.map} +0 -0
@@ -9,15 +9,15 @@ import {
9
9
  createAuditLog,
10
10
  mutate,
11
11
  registerCursor
12
- } from "./chunk-BXGZFGZ4.js";
12
+ } from "./chunk-C5QD5DQX.js";
13
13
 
14
14
  // src/utils/memory/index.ts
15
- import { monotonicNs, NodeImpl, node as node9, wallClockNs as wallClockNs3 } from "@graphrefly/pure-ts/core";
15
+ import { monotonicNs as monotonicNs3, NodeImpl, node as node10, wallClockNs as wallClockNs3 } from "@graphrefly/pure-ts/core";
16
16
  import { fromTimer as fromTimer3, keepalive as keepalive6, reactiveMap } from "@graphrefly/pure-ts/extra";
17
17
  import { Graph as Graph2 } from "@graphrefly/pure-ts/graph";
18
18
 
19
19
  // src/utils/memory/fact-store.ts
20
- import { node, wallClockNs } from "@graphrefly/pure-ts/core";
20
+ import { monotonicNs, node, wallClockNs } from "@graphrefly/pure-ts/core";
21
21
  import { keepalive, reactiveLog } from "@graphrefly/pure-ts/extra";
22
22
  import { Graph } from "@graphrefly/pure-ts/graph";
23
23
  var OVERFLOW_SAMPLE_SIZE = 8;
@@ -51,428 +51,534 @@ function currentlyValid(f, asOf) {
51
51
  function lastOf(batch, prev) {
52
52
  return batch != null && batch.length > 0 ? batch.at(-1) : prev;
53
53
  }
54
- function reactiveFactStore(config) {
55
- const shardCount = Math.max(1, config.shardCount ?? 4);
56
- const maxIterations = Math.max(1, config.cascadeMaxIterations ?? 8);
57
- const reviewThreshold = config.reviewThreshold ?? 0.3;
58
- const shardBy = config.shardBy ?? ((f) => fnv1a(String(f.id)) % shardCount);
59
- let cascadeIteration = 0;
60
- const processedRoots = /* @__PURE__ */ new Set();
61
- const graph = new Graph("reactive_fact_store");
62
- const events = createAuditLog({
63
- name: "events",
64
- retainedLimit: 1024,
65
- graph
66
- });
67
- const seqCursor = registerCursor(graph, "seq", 0);
68
- const ingestLog = config.recordIngest ? reactiveLog([], { name: "ingest_log" }) : void 0;
69
- if (ingestLog) graph.addDisposer(() => ingestLog.dispose());
70
- const emptyStore = () => ({ byId: /* @__PURE__ */ new Map() });
71
- const shards = [];
72
- for (let s = 0; s < shardCount; s += 1) {
73
- const shard = node([], {
74
- initial: emptyStore(),
75
- name: `shard_${s}`,
76
- describeKind: "state",
77
- meta: factMeta("factstore", { shard: s })
54
+ var ReactiveFactStoreGraph = class extends Graph {
55
+ // Topic outputs (caller subscribes for custom processing).
56
+ /** Per-shard `state<FactStore<T>>` nodes (length = shard count). */
57
+ shards;
58
+ /** Unified read view across all shards (derived). */
59
+ factStore;
60
+ dependentsIndex;
61
+ answer;
62
+ cascade;
63
+ cascadeOverflow;
64
+ review;
65
+ consolidated;
66
+ events;
67
+ /**
68
+ * Payload-carrying, replayable log of every committed fragment. Present iff
69
+ * {@link ReactiveFactStoreConfig.recordIngest} is `true`. Unlike
70
+ * {@link ReactiveFactStoreGraph.events} (action-only audit), each entry is
71
+ * the full {@link MemoryFragment} — `attachStorage` it for a durable,
72
+ * replayable projection source (see `recordIngest` docs for the recipe).
73
+ */
74
+ ingestLog;
75
+ constructor(config) {
76
+ const shardCount = Math.max(1, config.shardCount ?? 4);
77
+ const maxIterations = Math.max(1, config.cascadeMaxIterations ?? 8);
78
+ const reviewThreshold = config.reviewThreshold ?? 0.3;
79
+ const shardBy = config.shardBy ?? ((f) => fnv1a(String(f.id)) % shardCount);
80
+ let cascadeIteration = 0;
81
+ const processedRoots = /* @__PURE__ */ new Set();
82
+ super("reactive_fact_store");
83
+ const events = createAuditLog({
84
+ name: "events",
85
+ retainedLimit: 1024,
86
+ graph: this
78
87
  });
79
- graph.add(shard, { name: `shard_${s}` });
80
- graph.addDisposer(keepalive(shard));
81
- shards.push(shard);
82
- }
83
- const shardIndexFor = (f) => {
84
- const key = shardBy(f);
85
- const n = typeof key === "number" ? key : fnv1a(String(key));
86
- const idx = (n % shardCount + shardCount) % shardCount;
87
- return idx;
88
- };
89
- const findShardOf = (id) => {
88
+ const seqCursor = registerCursor(this, "seq", 0);
89
+ const ingestLog = config.recordIngest ? reactiveLog([], { name: "ingest_log" }) : void 0;
90
+ if (ingestLog) this.addDisposer(() => ingestLog.dispose());
91
+ const emptyStore = () => ({ byId: /* @__PURE__ */ new Map() });
92
+ const shards = [];
90
93
  for (let s = 0; s < shardCount; s += 1) {
91
- const fs = shards[s].cache;
92
- if (fs?.byId.has(id)) return s;
93
- }
94
- return -1;
95
- };
96
- const allFacts = () => {
97
- const out2 = /* @__PURE__ */ new Map();
98
- for (const sh of shards) {
99
- const fs = sh.cache;
100
- if (!fs) continue;
101
- for (const [k, v] of fs.byId) out2.set(k, v);
102
- }
103
- return out2;
104
- };
105
- const commitFragment = (f) => {
106
- const idx = shardIndexFor(f);
107
- const cur = shards[idx].cache ?? emptyStore();
108
- const next = new Map(cur.byId);
109
- next.set(f.id, f);
110
- shards[idx].emit({ byId: next });
111
- };
112
- const replaceFragment = (id, mut) => {
113
- const idx = findShardOf(id);
114
- if (idx < 0) return false;
115
- const cur = shards[idx].cache;
116
- const prev = cur.byId.get(id);
117
- if (!prev) return false;
118
- const next = new Map(cur.byId);
119
- next.set(id, mut(prev));
120
- shards[idx].emit({ byId: next });
121
- return true;
122
- };
123
- const dependentsIndex = node([], {
124
- initial: /* @__PURE__ */ new Map(),
125
- name: "dependents_index",
126
- describeKind: "state",
127
- meta: factMeta("factstore", { role: "dependents_index" })
128
- });
129
- graph.add(dependentsIndex, { name: "dependents_index" });
130
- graph.addDisposer(keepalive(dependentsIndex));
131
- const indexFragment = (f, deps) => {
132
- const cur = dependentsIndex.cache;
133
- const next = /* @__PURE__ */ new Map();
134
- for (const [k, v] of cur) next.set(k, [...v]);
135
- for (const src of deps) {
136
- const bucket = next.get(src) ?? [];
137
- if (!bucket.includes(f.id)) bucket.push(f.id);
138
- next.set(src, bucket);
94
+ const shard = node([], {
95
+ initial: emptyStore(),
96
+ name: `shard_${s}`,
97
+ describeKind: "state",
98
+ meta: factMeta("factstore", { shard: s })
99
+ });
100
+ this.add(shard, { name: `shard_${s}` });
101
+ this.addDisposer(keepalive(shard));
102
+ shards.push(shard);
139
103
  }
140
- dependentsIndex.emit(next);
141
- };
142
- const factStore = node(
143
- shards,
144
- (batchData, actions, ctx) => {
145
- void batchData;
146
- void ctx;
147
- actions.emit({ byId: allFacts() });
148
- },
149
- {
150
- name: "fact_store",
151
- describeKind: "derived",
152
- initial: emptyStore(),
153
- meta: factMeta("factstore", { role: "read_view" }),
154
- // F10a: `allFacts()` builds a fresh Map every detector retrigger.
155
- // Fragments are immutable (replaced wholesale on mutation), so a
156
- // same-size + per-key-identity check is a sound structural equality
157
- // that stops `factStore` (and its `review` dependent) from re-firing
158
- // every cascade wave when nothing actually changed.
159
- equals: (a, b) => {
160
- if (a === b) return true;
161
- if (a.byId.size !== b.byId.size) return false;
162
- for (const [k, v] of a.byId) {
163
- if (b.byId.get(k) !== v) return false;
164
- }
165
- return true;
104
+ const shardIndexFor = (f) => {
105
+ const key = shardBy(f);
106
+ const n = typeof key === "number" ? key : fnv1a(String(key));
107
+ const idx = (n % shardCount + shardCount) % shardCount;
108
+ return idx;
109
+ };
110
+ const findShardOf = (id) => {
111
+ for (let s = 0; s < shardCount; s += 1) {
112
+ const fs = shards[s].cache;
113
+ if (fs?.byId.has(id)) return s;
166
114
  }
167
- }
168
- );
169
- graph.add(factStore, { name: "fact_store" });
170
- graph.addDisposer(keepalive(factStore));
171
- const extractOp = node(
172
- config.admissionFilter ? [config.ingest, config.admissionFilter] : [config.ingest],
173
- (batchData, actions, ctx) => {
174
- const f = lastOf(batchData[0], ctx.prevData[0]);
175
- if (f == null) {
176
- actions.emit(null);
177
- return;
115
+ return -1;
116
+ };
117
+ const allFacts = () => {
118
+ const out = /* @__PURE__ */ new Map();
119
+ for (const sh of shards) {
120
+ const fs = sh.cache;
121
+ if (!fs) continue;
122
+ for (const [k, v] of fs.byId) out.set(k, v);
178
123
  }
179
- if (config.admissionFilter) {
180
- const filter = lastOf(batchData[1], ctx.prevData[1]);
181
- if (filter && !filter(f)) {
124
+ return out;
125
+ };
126
+ const commitFragment = (f) => {
127
+ const idx = shardIndexFor(f);
128
+ const cur = shards[idx].cache ?? emptyStore();
129
+ const next = new Map(cur.byId);
130
+ next.set(f.id, f);
131
+ shards[idx].emit({ byId: next });
132
+ };
133
+ const replaceFragment = (id, mut) => {
134
+ const idx = findShardOf(id);
135
+ if (idx < 0) return false;
136
+ const cur = shards[idx].cache;
137
+ const prev = cur.byId.get(id);
138
+ if (!prev) return false;
139
+ const next = new Map(cur.byId);
140
+ next.set(id, mut(prev));
141
+ shards[idx].emit({ byId: next });
142
+ return true;
143
+ };
144
+ const dependentsIndex = node([], {
145
+ initial: /* @__PURE__ */ new Map(),
146
+ name: "dependents_index",
147
+ describeKind: "state",
148
+ meta: factMeta("factstore", { role: "dependents_index" })
149
+ });
150
+ this.add(dependentsIndex, { name: "dependents_index" });
151
+ this.addDisposer(keepalive(dependentsIndex));
152
+ const indexFragment = (f, deps) => {
153
+ const cur = dependentsIndex.cache;
154
+ const next = /* @__PURE__ */ new Map();
155
+ for (const [k, v] of cur) next.set(k, [...v]);
156
+ for (const src of deps) {
157
+ const bucket = next.get(src) ?? [];
158
+ if (!bucket.includes(f.id)) bucket.push(f.id);
159
+ next.set(src, bucket);
160
+ }
161
+ dependentsIndex.emit(next);
162
+ };
163
+ const factStore = node(
164
+ shards,
165
+ (batchData, actions, ctx) => {
166
+ void batchData;
167
+ void ctx;
168
+ actions.emit({ byId: allFacts() });
169
+ },
170
+ {
171
+ name: "fact_store",
172
+ describeKind: "derived",
173
+ initial: emptyStore(),
174
+ meta: factMeta("factstore", { role: "read_view" }),
175
+ // F10a: `allFacts()` builds a fresh Map every detector retrigger.
176
+ // Fragments are immutable (replaced wholesale on mutation), so a
177
+ // same-size + per-key-identity check is a sound structural equality
178
+ // that stops `factStore` (and its `review` dependent) from re-firing
179
+ // every cascade wave when nothing actually changed.
180
+ equals: (a, b) => {
181
+ if (a === b) return true;
182
+ if (a.byId.size !== b.byId.size) return false;
183
+ for (const [k, v] of a.byId) {
184
+ if (b.byId.get(k) !== v) return false;
185
+ }
186
+ return true;
187
+ }
188
+ }
189
+ );
190
+ this.add(factStore, { name: "fact_store" });
191
+ this.addDisposer(keepalive(factStore));
192
+ const extractOp = node(
193
+ config.admissionFilter ? [config.ingest, config.admissionFilter] : [config.ingest],
194
+ (batchData, actions, ctx) => {
195
+ const f = lastOf(batchData[0], ctx.prevData[0]);
196
+ if (f == null) {
182
197
  actions.emit(null);
183
198
  return;
184
199
  }
185
- }
186
- const deps = config.extractDependencies(f);
187
- cascadeIteration = 0;
188
- processedRoots.delete(f.id);
189
- commitFragment(f);
190
- indexFragment(f, deps);
191
- actions.emit(f);
192
- },
193
- {
194
- name: "extract_op",
195
- describeKind: "derived",
196
- meta: factMeta("extract")
197
- }
198
- );
199
- graph.add(extractOp, { name: "extract_op" });
200
- graph.addDisposer(keepalive(extractOp));
201
- const invalidationDetector = node(
202
- [...shards],
203
- (batchData, actions, ctx) => {
204
- void batchData;
205
- void ctx;
206
- const facts = allFacts();
207
- const index = dependentsIndex.cache;
208
- const out2 = [];
209
- const seen = /* @__PURE__ */ new Set();
210
- for (const f of facts.values()) {
211
- const obsolete = f.validTo !== void 0;
212
- if (!obsolete) continue;
213
- if (processedRoots.has(f.id)) continue;
214
- const dependents = index.get(f.id) ?? [];
215
- for (const dep of dependents) {
216
- const depFact = facts.get(dep);
217
- if (!depFact || depFact.validTo !== void 0) continue;
218
- const k = `${f.id}->${dep}`;
219
- if (seen.has(k)) continue;
220
- seen.add(k);
221
- out2.push({
222
- factId: dep,
223
- rootFactId: f.id,
224
- reason: "obsolete",
225
- // `obsolete` guard above guarantees `f.validTo` is set.
226
- rootValidTo: f.validTo,
227
- iteration: cascadeIteration + 1,
228
- causalReason: `dependentsIndex[${f.id}] \u2192 ${dep} (obsolete: validTo set)`
229
- });
200
+ if (config.admissionFilter) {
201
+ const filter = lastOf(batchData[1], ctx.prevData[1]);
202
+ if (filter && !filter(f)) {
203
+ actions.emit(null);
204
+ return;
205
+ }
230
206
  }
231
- processedRoots.add(f.id);
232
- }
233
- if (out2.length === 0) {
207
+ const deps = config.extractDependencies(f);
234
208
  cascadeIteration = 0;
209
+ processedRoots.delete(f.id);
210
+ commitFragment(f);
211
+ indexFragment(f, deps);
212
+ actions.emit(f);
213
+ },
214
+ {
215
+ name: "extract_op",
216
+ describeKind: "derived",
217
+ meta: factMeta("extract")
235
218
  }
236
- actions.emit(out2);
237
- },
238
- {
239
- name: "invalidation_detector",
240
- describeKind: "derived",
241
- initial: [],
242
- meta: factMeta("invalidation", { cycle: "cascade" })
243
- }
244
- );
245
- graph.add(invalidationDetector, { name: "invalidation_detector" });
246
- graph.addDisposer(keepalive(invalidationDetector));
247
- const cascade = node(
248
- [invalidationDetector],
249
- (batchData, actions, ctx) => {
250
- const evts = lastOf(batchData[0], ctx.prevData[0]) ?? [];
251
- actions.emit(evts);
252
- },
253
- {
254
- name: "cascade",
255
- describeKind: "derived",
256
- initial: [],
257
- meta: factMeta("cascade_topic", { cycle: "cascade" })
258
- }
259
- );
260
- graph.add(cascade, { name: "cascade" });
261
- graph.addDisposer(keepalive(cascade));
262
- const cascadeOverflow = node([], {
263
- initial: null,
264
- name: "cascade_overflow",
265
- describeKind: "state",
266
- meta: factMeta("cascade_overflow")
267
- });
268
- graph.add(cascadeOverflow, { name: "cascade_overflow" });
269
- graph.addDisposer(keepalive(cascadeOverflow));
270
- const cascadeProcessor = node(
271
- [cascade],
272
- (batchData, actions, ctx) => {
273
- const evts = lastOf(batchData[0], ctx.prevData[0]) ?? [];
274
- if (evts.length === 0) {
275
- actions.emit([]);
276
- return;
219
+ );
220
+ this.add(extractOp, { name: "extract_op" });
221
+ this.addDisposer(keepalive(extractOp));
222
+ const invalidationDetector = node(
223
+ [...shards],
224
+ (batchData, actions, ctx) => {
225
+ void batchData;
226
+ void ctx;
227
+ const facts = allFacts();
228
+ const index = dependentsIndex.cache;
229
+ const out = [];
230
+ const seen = /* @__PURE__ */ new Set();
231
+ for (const f of facts.values()) {
232
+ const obsolete = f.validTo !== void 0;
233
+ if (!obsolete) continue;
234
+ if (processedRoots.has(f.id)) continue;
235
+ const dependents = index.get(f.id) ?? [];
236
+ for (const dep of dependents) {
237
+ const depFact = facts.get(dep);
238
+ if (!depFact || depFact.validTo !== void 0) continue;
239
+ const k = `${f.id}->${dep}`;
240
+ if (seen.has(k)) continue;
241
+ seen.add(k);
242
+ out.push({
243
+ factId: dep,
244
+ rootFactId: f.id,
245
+ reason: "obsolete",
246
+ // `obsolete` guard above guarantees `f.validTo` is set.
247
+ rootValidTo: f.validTo,
248
+ iteration: cascadeIteration + 1,
249
+ causalReason: `dependentsIndex[${f.id}] \u2192 ${dep} (obsolete: validTo set)`
250
+ });
251
+ }
252
+ processedRoots.add(f.id);
253
+ }
254
+ if (out.length === 0) {
255
+ cascadeIteration = 0;
256
+ }
257
+ actions.emit(out);
258
+ },
259
+ {
260
+ name: "invalidation_detector",
261
+ describeKind: "derived",
262
+ initial: [],
263
+ meta: factMeta("invalidation", { cycle: "cascade" })
277
264
  }
278
- const byId = /* @__PURE__ */ new Map();
279
- for (const e of evts) if (!byId.has(e.factId)) byId.set(e.factId, e);
280
- cascadeIteration += 1;
281
- if (cascadeIteration > maxIterations) {
282
- const sample = [...byId.keys()].slice(0, OVERFLOW_SAMPLE_SIZE);
283
- const rootFactId = evts[0]?.rootFactId ?? "";
284
- cascadeOverflow.emit({
285
- droppedCount: byId.size,
286
- sample,
287
- rootFactId
288
- });
289
- events.append({
290
- action: "overflow",
291
- reason: "cascade",
292
- id: rootFactId,
293
- t_ns: wallClockNs(),
294
- seq: bumpCursor(seqCursor)
295
- });
296
- actions.emit([]);
297
- return;
265
+ );
266
+ this.add(invalidationDetector, { name: "invalidation_detector" });
267
+ this.addDisposer(keepalive(invalidationDetector));
268
+ const cascade = node(
269
+ [invalidationDetector],
270
+ (batchData, actions, ctx) => {
271
+ const evts = lastOf(batchData[0], ctx.prevData[0]) ?? [];
272
+ actions.emit(evts);
273
+ },
274
+ {
275
+ name: "cascade",
276
+ describeKind: "derived",
277
+ initial: [],
278
+ meta: factMeta("cascade_topic", { cycle: "cascade" })
298
279
  }
299
- for (const [id, e] of byId) {
300
- replaceFragment(
301
- id,
302
- (prev) => prev.validTo !== void 0 ? prev : { ...prev, validTo: e.rootValidTo }
303
- );
280
+ );
281
+ this.add(cascade, { name: "cascade" });
282
+ this.addDisposer(keepalive(cascade));
283
+ const cascadeOverflow = node([], {
284
+ initial: null,
285
+ name: "cascade_overflow",
286
+ describeKind: "state",
287
+ meta: factMeta("cascade_overflow")
288
+ });
289
+ this.add(cascadeOverflow, { name: "cascade_overflow" });
290
+ this.addDisposer(keepalive(cascadeOverflow));
291
+ const cascadeProcessor = node(
292
+ [cascade],
293
+ (batchData, actions, ctx) => {
294
+ const evts = lastOf(batchData[0], ctx.prevData[0]) ?? [];
295
+ if (evts.length === 0) {
296
+ actions.emit([]);
297
+ return;
298
+ }
299
+ const byId = /* @__PURE__ */ new Map();
300
+ for (const e of evts) if (!byId.has(e.factId)) byId.set(e.factId, e);
301
+ cascadeIteration += 1;
302
+ if (cascadeIteration > maxIterations) {
303
+ const sample = [...byId.keys()].slice(0, OVERFLOW_SAMPLE_SIZE);
304
+ const rootFactId = evts[0]?.rootFactId ?? "";
305
+ cascadeOverflow.emit({
306
+ droppedCount: byId.size,
307
+ sample,
308
+ rootFactId
309
+ });
310
+ events.append({
311
+ action: "overflow",
312
+ reason: "cascade",
313
+ id: rootFactId,
314
+ t_ns: wallClockNs(),
315
+ seq: bumpCursor(seqCursor)
316
+ });
317
+ actions.emit([]);
318
+ return;
319
+ }
320
+ for (const [id, e] of byId) {
321
+ replaceFragment(
322
+ id,
323
+ (prev) => prev.validTo !== void 0 ? prev : { ...prev, validTo: e.rootValidTo }
324
+ );
325
+ }
326
+ actions.emit([...byId.values()]);
327
+ },
328
+ {
329
+ name: "cascade_processor",
330
+ describeKind: "derived",
331
+ initial: [],
332
+ meta: factMeta("cascade_processor", { cycle: "cascade" })
304
333
  }
305
- actions.emit([...byId.values()]);
306
- },
307
- {
308
- name: "cascade_processor",
309
- describeKind: "derived",
310
- initial: [],
311
- meta: factMeta("cascade_processor", { cycle: "cascade" })
312
- }
313
- );
314
- graph.add(cascadeProcessor, { name: "cascade_processor" });
315
- graph.addDisposer(keepalive(cascadeProcessor));
316
- const review = node(
317
- [factStore],
318
- (batchData, actions, ctx) => {
319
- const fs = lastOf(batchData[0], ctx.prevData[0]);
320
- if (fs == null) {
334
+ );
335
+ this.add(cascadeProcessor, { name: "cascade_processor" });
336
+ this.addDisposer(keepalive(cascadeProcessor));
337
+ const review = node(
338
+ [factStore],
339
+ (batchData, actions, ctx) => {
340
+ const fs = lastOf(batchData[0], ctx.prevData[0]);
341
+ if (fs == null) {
342
+ actions.emit(null);
343
+ return;
344
+ }
345
+ for (const f of fs.byId.values()) {
346
+ if (f.confidence < reviewThreshold && f.validTo === void 0) {
347
+ actions.emit({
348
+ factId: f.id,
349
+ confidence: f.confidence,
350
+ threshold: reviewThreshold
351
+ });
352
+ return;
353
+ }
354
+ }
321
355
  actions.emit(null);
322
- return;
356
+ },
357
+ {
358
+ name: "review",
359
+ describeKind: "derived",
360
+ initial: null,
361
+ meta: factMeta("review"),
362
+ // F10a: dedupe on the requested factId (null === no request) so a
363
+ // stable low-confidence fact does not re-emit a review every wave.
364
+ equals: (a, b) => (a?.factId ?? null) === (b?.factId ?? null)
323
365
  }
324
- for (const f of fs.byId.values()) {
325
- if (f.confidence < reviewThreshold && f.validTo === void 0) {
326
- actions.emit({
327
- factId: f.id,
328
- confidence: f.confidence,
329
- threshold: reviewThreshold
366
+ );
367
+ this.add(review, { name: "review" });
368
+ this.addDisposer(keepalive(review));
369
+ if (config.outcome) {
370
+ const outcomeProcessor = node(
371
+ config.scoring ? [config.outcome, config.scoring] : [config.outcome],
372
+ (batchData, actions, ctx) => {
373
+ const sig = lastOf(batchData[0], ctx.prevData[0]);
374
+ if (sig == null) {
375
+ actions.emit(null);
376
+ return;
377
+ }
378
+ replaceFragment(sig.factId, (prev) => {
379
+ let nextConf = prev.confidence;
380
+ if (config.scoring) {
381
+ const policy = lastOf(batchData[1], ctx.prevData[1]);
382
+ if (policy) {
383
+ nextConf = policy(prev, makeReadHandle(allFacts()));
384
+ }
385
+ } else {
386
+ nextConf = Math.max(0, Math.min(1, prev.confidence + sig.reward));
387
+ }
388
+ return { ...prev, confidence: nextConf };
330
389
  });
331
- return;
390
+ actions.emit(sig);
391
+ },
392
+ {
393
+ name: "outcome_processor",
394
+ describeKind: "derived",
395
+ initial: null,
396
+ meta: factMeta("outcome")
332
397
  }
333
- }
334
- actions.emit(null);
335
- },
336
- {
337
- name: "review",
338
- describeKind: "derived",
339
- initial: null,
340
- meta: factMeta("review"),
341
- // F10a: dedupe on the requested factId (null === no request) so a
342
- // stable low-confidence fact does not re-emit a review every wave.
343
- equals: (a, b) => (a?.factId ?? null) === (b?.factId ?? null)
398
+ );
399
+ this.add(outcomeProcessor, { name: "outcome_processor" });
400
+ this.addDisposer(keepalive(outcomeProcessor));
344
401
  }
345
- );
346
- graph.add(review, { name: "review" });
347
- graph.addDisposer(keepalive(review));
348
- if (config.outcome) {
349
- const outcomeProcessor = node(
350
- config.scoring ? [config.outcome, config.scoring] : [config.outcome],
402
+ const answer = node(
403
+ config.query ? [config.query, factStore] : [factStore],
351
404
  (batchData, actions, ctx) => {
352
- const sig = lastOf(batchData[0], ctx.prevData[0]);
353
- if (sig == null) {
405
+ if (!config.query) {
354
406
  actions.emit(null);
355
407
  return;
356
408
  }
357
- replaceFragment(sig.factId, (prev) => {
358
- let nextConf = prev.confidence;
359
- if (config.scoring) {
360
- const policy = lastOf(batchData[1], ctx.prevData[1]);
361
- if (policy) {
362
- nextConf = policy(prev, makeReadHandle(allFacts()));
363
- }
364
- } else {
365
- nextConf = Math.max(0, Math.min(1, prev.confidence + sig.reward));
409
+ const q = lastOf(batchData[0], ctx.prevData[0]);
410
+ const fs = lastOf(batchData[1], ctx.prevData[1]);
411
+ if (q == null) {
412
+ actions.emit(null);
413
+ return;
414
+ }
415
+ const store = fs ?? emptyStore();
416
+ let results = [...store.byId.values()].filter((f) => {
417
+ if (q.tags && q.tags.length > 0 && !q.tags.some((t) => f.tags.includes(t))) {
418
+ return false;
366
419
  }
367
- return { ...prev, confidence: nextConf };
420
+ if (q.minConfidence !== void 0 && f.confidence < q.minConfidence) return false;
421
+ if (!currentlyValid(f, q.asOf)) return false;
422
+ return true;
368
423
  });
369
- actions.emit(sig);
424
+ results.sort((a, b) => b.confidence - a.confidence || Number(b.t_ns - a.t_ns));
425
+ if (q.limit !== void 0) results = results.slice(0, Math.max(0, q.limit));
426
+ actions.emit({ query: q, results });
370
427
  },
371
428
  {
372
- name: "outcome_processor",
429
+ name: "answer",
373
430
  describeKind: "derived",
374
431
  initial: null,
375
- meta: factMeta("outcome")
432
+ meta: factMeta("query", { role: "output" })
376
433
  }
377
434
  );
378
- graph.add(outcomeProcessor, { name: "outcome_processor" });
379
- graph.addDisposer(keepalive(outcomeProcessor));
380
- }
381
- const answer = node(
382
- config.query ? [config.query, factStore] : [factStore],
383
- (batchData, actions, ctx) => {
384
- if (!config.query) {
385
- actions.emit(null);
386
- return;
387
- }
388
- const q = lastOf(batchData[0], ctx.prevData[0]);
389
- const fs = lastOf(batchData[1], ctx.prevData[1]);
390
- if (q == null) {
391
- actions.emit(null);
392
- return;
393
- }
394
- const store = fs ?? emptyStore();
395
- let results = [...store.byId.values()].filter((f) => {
396
- if (q.tags && q.tags.length > 0 && !q.tags.some((t) => f.tags.includes(t))) {
397
- return false;
435
+ this.add(answer, { name: "answer" });
436
+ this.addDisposer(keepalive(answer));
437
+ const consolidated = node(
438
+ config.consolidateTrigger ? [config.consolidateTrigger] : [],
439
+ (batchData, actions, ctx) => {
440
+ void batchData;
441
+ void ctx;
442
+ if (!config.consolidateTrigger || !config.consolidate) {
443
+ actions.emit([]);
444
+ return;
398
445
  }
399
- if (q.minConfidence !== void 0 && f.confidence < q.minConfidence) return false;
400
- if (!currentlyValid(f, q.asOf)) return false;
401
- return true;
402
- });
403
- results.sort((a, b) => b.confidence - a.confidence || Number(b.t_ns - a.t_ns));
404
- if (q.limit !== void 0) results = results.slice(0, Math.max(0, q.limit));
405
- actions.emit({ query: q, results });
406
- },
407
- {
408
- name: "answer",
409
- describeKind: "derived",
410
- initial: null,
411
- meta: factMeta("query", { role: "output" })
412
- }
413
- );
414
- graph.add(answer, { name: "answer" });
415
- graph.addDisposer(keepalive(answer));
416
- const consolidated = node(
417
- config.consolidateTrigger ? [config.consolidateTrigger] : [],
418
- (batchData, actions, ctx) => {
419
- void batchData;
420
- void ctx;
421
- if (!config.consolidateTrigger || !config.consolidate) {
422
- actions.emit([]);
423
- return;
424
- }
425
- const fragments = config.consolidate(makeReadHandle(allFacts()));
426
- for (const f of fragments) {
427
- const deps = config.extractDependencies(f);
428
- processedRoots.delete(f.id);
429
- commitFragment(f);
430
- indexFragment(f, deps);
431
- events.append({
432
- action: "consolidate",
433
- id: f.id,
434
- t_ns: wallClockNs(),
435
- seq: bumpCursor(seqCursor)
436
- });
446
+ const fragments = config.consolidate(makeReadHandle(allFacts()));
447
+ for (const f of fragments) {
448
+ const deps = config.extractDependencies(f);
449
+ processedRoots.delete(f.id);
450
+ commitFragment(f);
451
+ indexFragment(f, deps);
452
+ events.append({
453
+ action: "consolidate",
454
+ id: f.id,
455
+ t_ns: wallClockNs(),
456
+ seq: bumpCursor(seqCursor)
457
+ });
458
+ }
459
+ actions.emit(fragments);
460
+ },
461
+ {
462
+ name: "consolidated",
463
+ describeKind: "derived",
464
+ initial: [],
465
+ // Inspection completeness (COMPOSITION-GUIDE §24 "make the
466
+ // invisible edge visible"): `consolidated` write-backs feed the
467
+ // bounded cascade store (commit → shard emit →
468
+ // `invalidationDetector`) exactly like `cascadeProcessor`, but
469
+ // is NOT a cascade-cycle node. `feeds:"cascade"` surfaces it as
470
+ // a cascade-store mutator in `describe()`/`explain()`;
471
+ // `drivesRoot:false` — by the consolidator contract successors
472
+ // are fresh live facts (no `validTo`), so on the contract path
473
+ // they do not root the cascade. (An out-of-contract `consolidate`
474
+ // that emits a `validTo`-set fragment WOULD root it via the
475
+ // detector — the tag reflects the documented contract, not a
476
+ // structural impossibility. Contrast `decay_processor` below,
477
+ // whose `drivesRoot:false` IS structurally provable.)
478
+ meta: factMeta("consolidator", { feeds: "cascade", drivesRoot: false })
437
479
  }
438
- actions.emit(fragments);
439
- },
440
- {
441
- name: "consolidated",
442
- describeKind: "derived",
443
- initial: [],
444
- meta: factMeta("consolidator")
480
+ );
481
+ this.add(consolidated, { name: "consolidated" });
482
+ this.addDisposer(keepalive(consolidated));
483
+ if (config.decayTrigger) {
484
+ const decayProcessor = node(
485
+ config.decay ? [config.decayTrigger, config.decay] : [config.decayTrigger],
486
+ (batchData, actions, ctx) => {
487
+ const policy = config.decay ? lastOf(batchData[1], ctx.prevData[1]) : void 0;
488
+ if (!policy) {
489
+ actions.emit([]);
490
+ return;
491
+ }
492
+ const now = BigInt(monotonicNs());
493
+ const changes = [];
494
+ for (const f of allFacts().values()) {
495
+ if (f.validTo !== void 0) continue;
496
+ const ageNs = now - f.t_ns;
497
+ const raw = policy(f.confidence, ageNs);
498
+ if (!Number.isFinite(raw)) continue;
499
+ const next = raw < 0 ? 0 : raw > 1 ? 1 : raw;
500
+ if (next === f.confidence) continue;
501
+ changes.push({ id: f.id, next });
502
+ }
503
+ const decayed = [];
504
+ for (const { id, next } of changes) {
505
+ const idx = findShardOf(id);
506
+ const fs = idx < 0 ? void 0 : shards[idx].cache;
507
+ const live = fs?.byId.get(id);
508
+ if (!live || live.validTo !== void 0) continue;
509
+ replaceFragment(
510
+ id,
511
+ (prev) => prev.validTo !== void 0 ? prev : { ...prev, confidence: next }
512
+ );
513
+ decayed.push({ ...live, confidence: next });
514
+ }
515
+ if (decayed.length > 0) {
516
+ events.append({
517
+ action: "decay",
518
+ t_ns: wallClockNs(),
519
+ seq: bumpCursor(seqCursor),
520
+ count: decayed.length
521
+ });
522
+ }
523
+ actions.emit(decayed);
524
+ },
525
+ {
526
+ name: "decay_processor",
527
+ describeKind: "derived",
528
+ initial: [],
529
+ // Inspection completeness (same convention as `consolidated`
530
+ // above — kept uniform): `decay_processor` write-backs feed
531
+ // the cascade store via `replaceFragment` → shard emit →
532
+ // `invalidationDetector`. `feeds:"cascade"` surfaces it as a
533
+ // cascade-store mutator; `drivesRoot:false` — decay only
534
+ // mutates `confidence`, never `validTo`, and the detector
535
+ // roots on `validTo` only, so it provably cannot root.
536
+ meta: factMeta("decay", { feeds: "cascade", drivesRoot: false })
537
+ }
538
+ );
539
+ this.add(decayProcessor, { name: "decay_processor" });
540
+ this.addDisposer(keepalive(decayProcessor));
445
541
  }
446
- );
447
- graph.add(consolidated, { name: "consolidated" });
448
- graph.addDisposer(keepalive(consolidated));
449
- const ingestAudit = node(
450
- [extractOp],
451
- (batchData, actions, ctx) => {
452
- const f = lastOf(batchData[0], ctx.prevData[0]);
453
- if (f != null) {
454
- events.append({
455
- action: "ingest",
456
- id: f.id,
457
- t_ns: wallClockNs(),
458
- seq: bumpCursor(seqCursor)
459
- });
460
- ingestLog?.append(f);
542
+ const ingestAudit = node(
543
+ [extractOp],
544
+ (batchData, actions, ctx) => {
545
+ const f = lastOf(batchData[0], ctx.prevData[0]);
546
+ if (f != null) {
547
+ events.append({
548
+ action: "ingest",
549
+ id: f.id,
550
+ t_ns: wallClockNs(),
551
+ seq: bumpCursor(seqCursor)
552
+ });
553
+ ingestLog?.append(f);
554
+ }
555
+ actions.emit(f ?? null);
556
+ },
557
+ {
558
+ name: "_ingest_audit",
559
+ describeKind: "derived",
560
+ initial: null,
561
+ meta: factMeta("audit")
461
562
  }
462
- actions.emit(f ?? null);
463
- },
464
- {
465
- name: "_ingest_audit",
466
- describeKind: "derived",
467
- initial: null,
468
- meta: factMeta("audit")
469
- }
470
- );
471
- graph.add(ingestAudit, { name: "_ingest_audit" });
472
- graph.addDisposer(keepalive(ingestAudit));
473
- function itemNode(id) {
563
+ );
564
+ this.add(ingestAudit, { name: "_ingest_audit" });
565
+ this.addDisposer(keepalive(ingestAudit));
566
+ this.shards = shards;
567
+ this.factStore = factStore;
568
+ this.dependentsIndex = dependentsIndex;
569
+ this.answer = answer;
570
+ this.cascade = cascade;
571
+ this.cascadeOverflow = cascadeOverflow;
572
+ this.review = review;
573
+ this.consolidated = consolidated;
574
+ this.events = events;
575
+ if (ingestLog) this.ingestLog = ingestLog;
576
+ }
577
+ // ── itemNode reactive read ───────────────────────────────────────────
578
+ /** Reactive read: a single fact by id (SENTINEL until the fact exists). */
579
+ itemNode(id) {
474
580
  return node(
475
- [factStore],
581
+ [this.factStore],
476
582
  (batchData, actions, ctx) => {
477
583
  const fs = lastOf(batchData[0], ctx.prevData[0]);
478
584
  actions.emit(fs?.byId.get(id));
@@ -484,20 +590,9 @@ function reactiveFactStore(config) {
484
590
  }
485
591
  );
486
592
  }
487
- const out = Object.assign(graph, {
488
- shards,
489
- factStore,
490
- dependentsIndex,
491
- answer,
492
- cascade,
493
- cascadeOverflow,
494
- review,
495
- consolidated,
496
- events,
497
- ...ingestLog ? { ingestLog } : {},
498
- itemNode
499
- });
500
- return out;
593
+ };
594
+ function reactiveFactStore(config) {
595
+ return new ReactiveFactStoreGraph(config);
501
596
  }
502
597
 
503
598
  // src/utils/memory/persistent-fact-store.ts
@@ -921,6 +1016,52 @@ function shardByTenant(tenantOf, opts = {}) {
921
1016
  return { shardBy: (f) => tenantOf(f), shardCount };
922
1017
  }
923
1018
 
1019
+ // src/utils/memory/simple-fact-store.ts
1020
+ import { monotonicNs as monotonicNs2, node as node9 } from "@graphrefly/pure-ts/core";
1021
+ var DEFAULT_DECAY_HALF_LIFE_NS = 604800000000000n;
1022
+ var DEFAULT_DECAY_PERIOD_MS = 36e5;
1023
+ function simpleFactStore(opts = {}) {
1024
+ const ingest = node9([], { initial: void 0 });
1025
+ const extractDependencies = opts.extractDependencies ?? (() => []);
1026
+ const consolidationCfg = opts.consolidate ? consolidationRem(opts.consolidate) : void 0;
1027
+ const baseCfg = {
1028
+ ingest,
1029
+ extractDependencies,
1030
+ ...consolidationCfg ?? {}
1031
+ };
1032
+ const mem = opts.storage ? persistentReactiveFactStore({
1033
+ ...baseCfg,
1034
+ storage: opts.storage,
1035
+ ...opts.persistName !== void 0 ? { persistName: opts.persistName } : {},
1036
+ ...opts.codec !== void 0 ? { codec: opts.codec } : {}
1037
+ }) : reactiveFactStore(baseCfg);
1038
+ if (opts.decay !== false) {
1039
+ const d = opts.decay ?? {};
1040
+ decayExponential(mem, ingest, {
1041
+ ...d,
1042
+ halfLifeNs: d.halfLifeNs ?? DEFAULT_DECAY_HALF_LIFE_NS,
1043
+ periodMs: d.periodMs ?? DEFAULT_DECAY_PERIOD_MS
1044
+ });
1045
+ }
1046
+ const remember = (id, payload, ro) => {
1047
+ const fragment = {
1048
+ id,
1049
+ payload,
1050
+ t_ns: BigInt(monotonicNs2()),
1051
+ confidence: ro?.confidence ?? 1,
1052
+ tags: ro?.tags ?? [],
1053
+ sources: ro?.sources ?? [],
1054
+ ...ro?.validTo !== void 0 ? { validTo: ro.validTo } : {},
1055
+ ...ro?.validFrom !== void 0 ? { validFrom: ro.validFrom } : {},
1056
+ ...ro?.provenance !== void 0 ? { provenance: ro.provenance } : {}
1057
+ };
1058
+ ingest.emit(fragment);
1059
+ };
1060
+ const out = mem;
1061
+ out.remember = remember;
1062
+ return out;
1063
+ }
1064
+
924
1065
  // src/utils/memory/index.ts
925
1066
  var NS_PER_SEC = 1e9;
926
1067
  function memoryMeta(kind, extra) {
@@ -928,7 +1069,7 @@ function memoryMeta(kind, extra) {
928
1069
  }
929
1070
  function toNode(v, name) {
930
1071
  if (v instanceof NodeImpl) return v;
931
- return node9([], { initial: v, ...name ? { name } : void 0 });
1072
+ return node10([], { initial: v, ...name ? { name } : void 0 });
932
1073
  }
933
1074
  function ageSeconds(now, lastNs) {
934
1075
  return (now - lastNs) / NS_PER_SEC;
@@ -988,7 +1129,7 @@ function collection(name, opts = {}) {
988
1129
  return scoreInput;
989
1130
  };
990
1131
  const graph = new Graph2(name);
991
- const retentionScore = (_k, v) => ranked ? decay(v.baseScore, ageSeconds(monotonicNs(), v.lastAccessNs), decayRate, minScore) : v.lastAccessNs;
1132
+ const retentionScore = (_k, v) => ranked ? decay(v.baseScore, ageSeconds(monotonicNs3(), v.lastAccessNs), decayRate, minScore) : v.lastAccessNs;
992
1133
  const items = reactiveMap({
993
1134
  name: "items",
994
1135
  ...maxSize !== void 0 ? { retention: { score: retentionScore, maxSize } } : {}
@@ -998,15 +1139,15 @@ function collection(name, opts = {}) {
998
1139
  if (ranked && decayRate > 0) {
999
1140
  const intervalMs = opts.refreshIntervalMs ?? Math.max(1, 1e3 * Math.LN2 / (10 * decayRate));
1000
1141
  const tickCounter = fromTimer3(intervalMs, { period: intervalMs });
1001
- refreshTick = node9(
1142
+ refreshTick = node10(
1002
1143
  [tickCounter],
1003
1144
  (_batchData, actions) => {
1004
- actions.emit(monotonicNs());
1145
+ actions.emit(monotonicNs3());
1005
1146
  },
1006
1147
  {
1007
1148
  name: "refresh_tick_ns",
1008
1149
  describeKind: "derived",
1009
- initial: monotonicNs(),
1150
+ initial: monotonicNs3(),
1010
1151
  meta: memoryMeta("clock")
1011
1152
  }
1012
1153
  );
@@ -1017,7 +1158,7 @@ function collection(name, opts = {}) {
1017
1158
  const rankedDeps = [items.entries];
1018
1159
  if (refreshTick) rankedDeps.push(refreshTick);
1019
1160
  if (scoreNode) rankedDeps.push(scoreNode);
1020
- rankedNode = node9(
1161
+ rankedNode = node10(
1021
1162
  rankedDeps,
1022
1163
  (batchData, actions, ctx) => {
1023
1164
  const values = batchData.map(
@@ -1027,9 +1168,9 @@ function collection(name, opts = {}) {
1027
1168
  let now;
1028
1169
  if (refreshTick) {
1029
1170
  const tickValue = values[1];
1030
- now = typeof tickValue === "number" ? tickValue : monotonicNs();
1171
+ now = typeof tickValue === "number" ? tickValue : monotonicNs3();
1031
1172
  } else {
1032
- now = monotonicNs();
1173
+ now = monotonicNs3();
1033
1174
  }
1034
1175
  if (!snapshot || snapshot.size === 0) {
1035
1176
  actions.emit([]);
@@ -1054,7 +1195,7 @@ function collection(name, opts = {}) {
1054
1195
  );
1055
1196
  graph.add(rankedNode, { name: "ranked" });
1056
1197
  } else {
1057
- rankedNode = node9([], {
1198
+ rankedNode = node10([], {
1058
1199
  initial: [],
1059
1200
  name: "ranked",
1060
1201
  describeKind: "state",
@@ -1062,7 +1203,7 @@ function collection(name, opts = {}) {
1062
1203
  });
1063
1204
  graph.add(rankedNode, { name: "ranked" });
1064
1205
  }
1065
- const size = node9(
1206
+ const size = node10(
1066
1207
  [items.entries],
1067
1208
  (batchData, actions, ctx) => {
1068
1209
  const data = batchData.map(
@@ -1087,7 +1228,7 @@ function collection(name, opts = {}) {
1087
1228
  });
1088
1229
  const seqCursor = registerCursor(graph, "seq", 0);
1089
1230
  const upsertImpl = (id, value, _opts) => {
1090
- const now = monotonicNs();
1231
+ const now = monotonicNs3();
1091
1232
  const prev = items.get(id);
1092
1233
  const baseScore = _opts?.score ?? readScoreFn()(value);
1093
1234
  items.set(id, {
@@ -1143,7 +1284,7 @@ function collection(name, opts = {}) {
1143
1284
  });
1144
1285
  function itemNode(id) {
1145
1286
  const idN = toNode(id, "id");
1146
- return node9(
1287
+ return node10(
1147
1288
  [items.entries, idN],
1148
1289
  (batchData, actions, ctx) => {
1149
1290
  const data = batchData.map(
@@ -1161,7 +1302,7 @@ function collection(name, opts = {}) {
1161
1302
  }
1162
1303
  function hasNode(id) {
1163
1304
  const idN = toNode(id, "id");
1164
- return node9(
1305
+ return node10(
1165
1306
  [items.entries, idN],
1166
1307
  (batchData, actions, ctx) => {
1167
1308
  const data = batchData.map(
@@ -1273,7 +1414,7 @@ function vectorIndex(opts = {}) {
1273
1414
  id,
1274
1415
  vector: [...vector],
1275
1416
  ...copiedMeta !== void 0 ? { meta: copiedMeta } : {},
1276
- upsertedAtNs: monotonicNs()
1417
+ upsertedAtNs: monotonicNs3()
1277
1418
  };
1278
1419
  entries.set(id, record);
1279
1420
  };
@@ -1329,7 +1470,7 @@ function vectorIndex(opts = {}) {
1329
1470
  });
1330
1471
  function searchNode(query, k = 5) {
1331
1472
  const kN = toNode(k, "k");
1332
- return node9(
1473
+ return node10(
1333
1474
  [entries.entries, query, kN],
1334
1475
  (batchData, actions, ctx) => {
1335
1476
  const values = batchData.map(
@@ -1445,7 +1586,7 @@ function knowledgeGraph(name, opts = {}) {
1445
1586
  });
1446
1587
  graph.add(entitiesMap.entries, { name: "entities" });
1447
1588
  graph.add(edgesMap.entries, { name: "edges" });
1448
- const adjacencyOut = node9(
1589
+ const adjacencyOut = node10(
1449
1590
  [edgesMap.entries],
1450
1591
  (batchData, actions, ctx) => {
1451
1592
  const data = batchData.map(
@@ -1462,7 +1603,7 @@ function knowledgeGraph(name, opts = {}) {
1462
1603
  meta: memoryMeta("adjacency_out")
1463
1604
  }
1464
1605
  );
1465
- const adjacencyIn = node9(
1606
+ const adjacencyIn = node10(
1466
1607
  [edgesMap.entries],
1467
1608
  (batchData, actions, ctx) => {
1468
1609
  const data = batchData.map(
@@ -1483,7 +1624,7 @@ function knowledgeGraph(name, opts = {}) {
1483
1624
  graph.add(adjacencyIn, { name: "adjacencyIn" });
1484
1625
  graph.addDisposer(keepalive6(adjacencyOut));
1485
1626
  graph.addDisposer(keepalive6(adjacencyIn));
1486
- const entityCount = node9(
1627
+ const entityCount = node10(
1487
1628
  [entitiesMap.entries],
1488
1629
  (batchData, actions, ctx) => {
1489
1630
  const data = batchData.map(
@@ -1494,7 +1635,7 @@ function knowledgeGraph(name, opts = {}) {
1494
1635
  },
1495
1636
  { name: "entityCount", describeKind: "derived", initial: 0, meta: memoryMeta("entity_count") }
1496
1637
  );
1497
- const edgeCount = node9(
1638
+ const edgeCount = node10(
1498
1639
  [edgesMap.entries],
1499
1640
  (batchData, actions, ctx) => {
1500
1641
  const data = batchData.map(
@@ -1626,7 +1767,7 @@ function knowledgeGraph(name, opts = {}) {
1626
1767
  const idN = toNode(id, "id");
1627
1768
  const relN = relation !== void 0 ? toNode(relation, "relation") : void 0;
1628
1769
  const deps = relN ? [adjacencyOut, adjacencyIn, idN, relN] : [adjacencyOut, adjacencyIn, idN];
1629
- return node9(
1770
+ return node10(
1630
1771
  deps,
1631
1772
  (batchData, actions, ctx) => {
1632
1773
  const values = batchData.map(
@@ -1694,6 +1835,7 @@ function knowledgeGraph(name, opts = {}) {
1694
1835
  }
1695
1836
 
1696
1837
  export {
1838
+ ReactiveFactStoreGraph,
1697
1839
  reactiveFactStore,
1698
1840
  persistentReactiveFactStore,
1699
1841
  admissionLlmJudge,
@@ -1704,9 +1846,12 @@ export {
1704
1846
  invalidationTracer,
1705
1847
  scoringByOutcome,
1706
1848
  shardByTenant,
1849
+ DEFAULT_DECAY_HALF_LIFE_NS,
1850
+ DEFAULT_DECAY_PERIOD_MS,
1851
+ simpleFactStore,
1707
1852
  cosineSimilarity,
1708
1853
  collection,
1709
1854
  vectorIndex,
1710
1855
  knowledgeGraph
1711
1856
  };
1712
- //# sourceMappingURL=chunk-U225SKB4.js.map
1857
+ //# sourceMappingURL=chunk-K4ZYJ4EM.js.map