@graphrefly/graphrefly 0.47.2 → 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 (266) hide show
  1. package/dist/base/composition/index.cjs +4 -3
  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 +8 -8
  6. package/dist/base/index.cjs +152 -78
  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 +75 -70
  11. package/dist/base/io/index.cjs +31 -17
  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 +1 -1
  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 +5 -3
  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 +5 -3
  26. package/dist/base/sources/browser/index.js.map +1 -1
  27. package/dist/base/sources/event/index.cjs +28 -0
  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 +4 -1
  32. package/dist/base/sources/index.cjs +75 -37
  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 +5 -2
  37. package/dist/{chunk-R6ZCSXKX.js → chunk-23MAWVOJ.js} +3 -3
  38. package/dist/{chunk-MS3WPRJR.js → chunk-3REMCHSS.js} +6 -6
  39. package/dist/chunk-3REMCHSS.js.map +1 -0
  40. package/dist/{chunk-CEVNQ74M.js → chunk-3YGXPUHW.js} +2 -2
  41. package/dist/{chunk-CEVNQ74M.js.map → chunk-3YGXPUHW.js.map} +1 -1
  42. package/dist/{chunk-6ZLCPUXS.js → chunk-46X2EFQH.js} +15 -4
  43. package/dist/chunk-46X2EFQH.js.map +1 -0
  44. package/dist/{chunk-NY2PYHNC.js → chunk-5UY3PNFY.js} +12 -5
  45. package/dist/chunk-5UY3PNFY.js.map +1 -0
  46. package/dist/{chunk-FQSQONOU.js → chunk-65OM4XLQ.js} +49 -3
  47. package/dist/chunk-65OM4XLQ.js.map +1 -0
  48. package/dist/{chunk-3PSLNJDU.js → chunk-6DQYBIHW.js} +314 -49
  49. package/dist/chunk-6DQYBIHW.js.map +1 -0
  50. package/dist/{chunk-LDCSZ72P.js → chunk-6YBER5UP.js} +3 -3
  51. package/dist/{chunk-LDCSZ72P.js.map → chunk-6YBER5UP.js.map} +1 -1
  52. package/dist/{chunk-3O3NKZJW.js → chunk-7T7WLEPM.js} +24 -3
  53. package/dist/chunk-7T7WLEPM.js.map +1 -0
  54. package/dist/{chunk-PKPO3JTZ.js → chunk-AQAKDE7F.js} +29 -11
  55. package/dist/chunk-AQAKDE7F.js.map +1 -0
  56. package/dist/{chunk-6MRSX3YK.js → chunk-B5Y5GPD5.js} +2 -2
  57. package/dist/{chunk-BXGZFGZ4.js → chunk-C5QD5DQX.js} +22 -1
  58. package/dist/chunk-C5QD5DQX.js.map +1 -0
  59. package/dist/{chunk-4XCHZRUJ.js → chunk-D5YGR4TP.js} +58 -7
  60. package/dist/chunk-D5YGR4TP.js.map +1 -0
  61. package/dist/{chunk-NPRP3MCV.js → chunk-DHDCOOJU.js} +2 -2
  62. package/dist/chunk-DHDCOOJU.js.map +1 -0
  63. package/dist/{chunk-VP3TIUDF.js → chunk-DVTDF5OI.js} +2 -2
  64. package/dist/{chunk-OXD5LFQP.js → chunk-G7H6PN7P.js} +2 -2
  65. package/dist/{chunk-EL5VHUGK.js → chunk-GGKHHG5Y.js} +32 -18
  66. package/dist/chunk-GGKHHG5Y.js.map +1 -0
  67. package/dist/{chunk-446I4EGD.js → chunk-J5TBZFBD.js} +2 -2
  68. package/dist/{chunk-7AVQIGF6.js → chunk-K4ZYJ4EM.js} +554 -460
  69. package/dist/chunk-K4ZYJ4EM.js.map +1 -0
  70. package/dist/{chunk-QFE5BQH7.js → chunk-LTSI7ULC.js} +2 -2
  71. package/dist/{chunk-5GVURVIG.js → chunk-MMHGYX44.js} +12 -2
  72. package/dist/{chunk-5GVURVIG.js.map → chunk-MMHGYX44.js.map} +1 -1
  73. package/dist/{chunk-KRFGO5QH.js → chunk-MQMTRKY3.js} +118 -43
  74. package/dist/chunk-MQMTRKY3.js.map +1 -0
  75. package/dist/{chunk-42FQ27MQ.js → chunk-MTODGQBR.js} +44 -179
  76. package/dist/chunk-MTODGQBR.js.map +1 -0
  77. package/dist/{chunk-FVINAAKA.js → chunk-NBK6QQMG.js} +14 -13
  78. package/dist/{chunk-FVINAAKA.js.map → chunk-NBK6QQMG.js.map} +1 -1
  79. package/dist/{chunk-KNU73RZW.js → chunk-NSA5K5G2.js} +2 -2
  80. package/dist/{chunk-MLTPJMH6.js → chunk-QQYULEZL.js} +2 -2
  81. package/dist/chunk-QSW4DFKE.js +31 -0
  82. package/dist/chunk-QSW4DFKE.js.map +1 -0
  83. package/dist/{chunk-VAZXUK6G.js → chunk-SUNCHMML.js} +2 -2
  84. package/dist/{chunk-EP4WVQLX.js → chunk-T2U6N3FV.js} +6 -6
  85. package/dist/{chunk-T7SP3EYR.js → chunk-T5URUIIY.js} +33 -24
  86. package/dist/chunk-T5URUIIY.js.map +1 -0
  87. package/dist/{chunk-VNXAF2KE.js → chunk-TPTZZV25.js} +6 -6
  88. package/dist/chunk-TPTZZV25.js.map +1 -0
  89. package/dist/{chunk-IOJDYUA7.js → chunk-V46JWFGV.js} +6 -5
  90. package/dist/chunk-V46JWFGV.js.map +1 -0
  91. package/dist/{chunk-WGDEBIP4.js → chunk-X6ESZDR6.js} +5 -6
  92. package/dist/chunk-X6ESZDR6.js.map +1 -0
  93. package/dist/{chunk-N65E26UL.js → chunk-XEWV254I.js} +2 -2
  94. package/dist/{chunk-N65E26UL.js.map → chunk-XEWV254I.js.map} +1 -1
  95. package/dist/{chunk-PTWADEH3.js → chunk-YBJVKMTM.js} +34 -14
  96. package/dist/chunk-YBJVKMTM.js.map +1 -0
  97. package/dist/{chunk-DDTS7F5O.js → chunk-ZW32BPXV.js} +12 -3
  98. package/dist/chunk-ZW32BPXV.js.map +1 -0
  99. package/dist/compat/index.cjs +51 -4
  100. package/dist/compat/index.cjs.map +1 -1
  101. package/dist/compat/index.d.cts +1 -1
  102. package/dist/compat/index.d.ts +1 -1
  103. package/dist/compat/index.js +6 -6
  104. package/dist/compat/nestjs/index.cjs +51 -4
  105. package/dist/compat/nestjs/index.cjs.map +1 -1
  106. package/dist/compat/nestjs/index.d.cts +1 -1
  107. package/dist/compat/nestjs/index.d.ts +1 -1
  108. package/dist/compat/nestjs/index.js +3 -3
  109. package/dist/{fallback-Bx46zqky.d.cts → fallback-BROR6ZhO.d.cts} +1 -1
  110. package/dist/{fallback-pIWW8A2d.d.ts → fallback-DO80aM_3.d.ts} +1 -1
  111. package/dist/{index-B_p8tnvf.d.cts → index-D1z3XcF9.d.cts} +1 -0
  112. package/dist/{index-_HDSmPyp.d.ts → index-DZ6yua0Q.d.ts} +1 -0
  113. package/dist/index.cjs +2215 -1676
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.d.cts +10 -10
  116. package/dist/index.d.ts +10 -10
  117. package/dist/index.js +169 -146
  118. package/dist/index.js.map +1 -1
  119. package/dist/presets/ai/index.cjs +46 -0
  120. package/dist/presets/ai/index.cjs.map +1 -1
  121. package/dist/presets/ai/index.js +12 -12
  122. package/dist/presets/harness/index.cjs +130 -18
  123. package/dist/presets/harness/index.cjs.map +1 -1
  124. package/dist/presets/harness/index.d.cts +15 -5
  125. package/dist/presets/harness/index.d.ts +15 -5
  126. package/dist/presets/harness/index.js +22 -22
  127. package/dist/presets/index.cjs +222 -53
  128. package/dist/presets/index.cjs.map +1 -1
  129. package/dist/presets/index.d.cts +2 -2
  130. package/dist/presets/index.d.ts +2 -2
  131. package/dist/presets/index.js +45 -45
  132. package/dist/presets/inspect/index.cjs +63 -14
  133. package/dist/presets/inspect/index.cjs.map +1 -1
  134. package/dist/presets/inspect/index.d.cts +1 -1
  135. package/dist/presets/inspect/index.d.ts +1 -1
  136. package/dist/presets/inspect/index.js +6 -6
  137. package/dist/presets/resilience/index.cjs +29 -21
  138. package/dist/presets/resilience/index.cjs.map +1 -1
  139. package/dist/presets/resilience/index.d.cts +12 -8
  140. package/dist/presets/resilience/index.d.ts +12 -8
  141. package/dist/presets/resilience/index.js +3 -3
  142. package/dist/{rate-limiter-DpVbSYdH.d.cts → rate-limiter-DC26FM8J.d.cts} +10 -1
  143. package/dist/{rate-limiter-CEALq4N1.d.ts → rate-limiter-DyWpwpQP.d.ts} +10 -1
  144. package/dist/{reactive-layout-fswlBUvX.d.ts → reactive-layout-BBBWH0V_.d.cts} +85 -4
  145. package/dist/{reactive-layout-fswlBUvX.d.cts → reactive-layout-BBBWH0V_.d.ts} +85 -4
  146. package/dist/solutions/index.cjs +168 -47
  147. package/dist/solutions/index.cjs.map +1 -1
  148. package/dist/solutions/index.d.cts +2 -2
  149. package/dist/solutions/index.d.ts +2 -2
  150. package/dist/solutions/index.js +28 -28
  151. package/dist/{spawnable-5mDY501F.d.cts → spawnable-B2IlW60f.d.cts} +23 -2
  152. package/dist/{spawnable-D3lR0oQu.d.ts → spawnable-tttFz2Nh.d.ts} +23 -2
  153. package/dist/testing/index.cjs +94 -0
  154. package/dist/testing/index.cjs.map +1 -0
  155. package/dist/testing/index.d.cts +59 -0
  156. package/dist/testing/index.d.ts +59 -0
  157. package/dist/testing/index.js +73 -0
  158. package/dist/testing/index.js.map +1 -0
  159. package/dist/utils/ai/browser.cjs.map +1 -1
  160. package/dist/utils/ai/browser.d.cts +2 -2
  161. package/dist/utils/ai/browser.d.ts +2 -2
  162. package/dist/utils/ai/browser.js +6 -6
  163. package/dist/utils/ai/browser.js.map +1 -1
  164. package/dist/utils/ai/index.cjs +250 -166
  165. package/dist/utils/ai/index.cjs.map +1 -1
  166. package/dist/utils/ai/index.d.cts +108 -12
  167. package/dist/utils/ai/index.d.ts +108 -12
  168. package/dist/utils/ai/index.js +21 -19
  169. package/dist/utils/ai/node.cjs.map +1 -1
  170. package/dist/utils/ai/node.d.cts +5 -5
  171. package/dist/utils/ai/node.d.ts +5 -5
  172. package/dist/utils/ai/node.js +2 -2
  173. package/dist/utils/ai/node.js.map +1 -1
  174. package/dist/utils/cqrs/index.cjs +29 -3
  175. package/dist/utils/cqrs/index.cjs.map +1 -1
  176. package/dist/utils/cqrs/index.d.cts +12 -7
  177. package/dist/utils/cqrs/index.d.ts +12 -7
  178. package/dist/utils/cqrs/index.js +2 -2
  179. package/dist/utils/demo-shell/index.cjs +45 -19
  180. package/dist/utils/demo-shell/index.cjs.map +1 -1
  181. package/dist/utils/demo-shell/index.d.cts +1 -1
  182. package/dist/utils/demo-shell/index.d.ts +1 -1
  183. package/dist/utils/demo-shell/index.js +2 -2
  184. package/dist/utils/domain-templates/index.cjs.map +1 -1
  185. package/dist/utils/domain-templates/index.js +3 -3
  186. package/dist/utils/graphspec/index.cjs.map +1 -1
  187. package/dist/utils/graphspec/index.js +3 -3
  188. package/dist/utils/index.cjs +1642 -1225
  189. package/dist/utils/index.cjs.map +1 -1
  190. package/dist/utils/index.d.cts +7 -7
  191. package/dist/utils/index.d.ts +7 -7
  192. package/dist/utils/index.js +72 -54
  193. package/dist/utils/inspect/index.cjs +52 -4
  194. package/dist/utils/inspect/index.cjs.map +1 -1
  195. package/dist/utils/inspect/index.d.cts +32 -3
  196. package/dist/utils/inspect/index.d.ts +32 -3
  197. package/dist/utils/inspect/index.js +4 -4
  198. package/dist/utils/job-queue/index.cjs +46 -9
  199. package/dist/utils/job-queue/index.cjs.map +1 -1
  200. package/dist/utils/job-queue/index.d.cts +33 -3
  201. package/dist/utils/job-queue/index.d.ts +33 -3
  202. package/dist/utils/job-queue/index.js +2 -2
  203. package/dist/utils/memory/index.cjs +556 -462
  204. package/dist/utils/memory/index.cjs.map +1 -1
  205. package/dist/utils/memory/index.d.cts +203 -24
  206. package/dist/utils/memory/index.d.ts +203 -24
  207. package/dist/utils/memory/index.js +10 -2
  208. package/dist/utils/messaging/index.cjs.map +1 -1
  209. package/dist/utils/messaging/index.d.cts +4 -3
  210. package/dist/utils/messaging/index.d.ts +4 -3
  211. package/dist/utils/messaging/index.js +2 -2
  212. package/dist/utils/orchestration/index.cjs +9 -0
  213. package/dist/utils/orchestration/index.cjs.map +1 -1
  214. package/dist/utils/orchestration/index.js +3 -3
  215. package/dist/utils/process/index.cjs +32 -2
  216. package/dist/utils/process/index.cjs.map +1 -1
  217. package/dist/utils/process/index.d.cts +4 -3
  218. package/dist/utils/process/index.d.ts +4 -3
  219. package/dist/utils/process/index.js +2 -2
  220. package/dist/utils/reactive-layout/index.cjs +184 -55
  221. package/dist/utils/reactive-layout/index.cjs.map +1 -1
  222. package/dist/utils/reactive-layout/index.d.cts +128 -3
  223. package/dist/utils/reactive-layout/index.d.ts +128 -3
  224. package/dist/utils/reactive-layout/index.js +16 -8
  225. package/dist/utils/reduction/index.cjs.map +1 -1
  226. package/dist/utils/reduction/index.js +2 -2
  227. package/dist/utils/resilience/index.cjs +29 -20
  228. package/dist/utils/resilience/index.cjs.map +1 -1
  229. package/dist/utils/resilience/index.d.cts +1 -1
  230. package/dist/utils/resilience/index.d.ts +1 -1
  231. package/dist/utils/resilience/index.js +2 -2
  232. package/dist/utils/surface/index.cjs.map +1 -1
  233. package/dist/utils/surface/index.js +4 -4
  234. package/package.json +15 -3
  235. package/dist/chunk-3O3NKZJW.js.map +0 -1
  236. package/dist/chunk-3PSLNJDU.js.map +0 -1
  237. package/dist/chunk-42FQ27MQ.js.map +0 -1
  238. package/dist/chunk-4XCHZRUJ.js.map +0 -1
  239. package/dist/chunk-6ZLCPUXS.js.map +0 -1
  240. package/dist/chunk-7AVQIGF6.js.map +0 -1
  241. package/dist/chunk-BXGZFGZ4.js.map +0 -1
  242. package/dist/chunk-DDTS7F5O.js.map +0 -1
  243. package/dist/chunk-EL5VHUGK.js.map +0 -1
  244. package/dist/chunk-FQSQONOU.js.map +0 -1
  245. package/dist/chunk-IOJDYUA7.js.map +0 -1
  246. package/dist/chunk-KRFGO5QH.js.map +0 -1
  247. package/dist/chunk-MS3WPRJR.js.map +0 -1
  248. package/dist/chunk-NPRP3MCV.js.map +0 -1
  249. package/dist/chunk-NY2PYHNC.js.map +0 -1
  250. package/dist/chunk-PKPO3JTZ.js.map +0 -1
  251. package/dist/chunk-PTWADEH3.js.map +0 -1
  252. package/dist/chunk-T7SP3EYR.js.map +0 -1
  253. package/dist/chunk-VNXAF2KE.js.map +0 -1
  254. package/dist/chunk-W2BOPXTI.js +0 -1
  255. package/dist/chunk-W2BOPXTI.js.map +0 -1
  256. package/dist/chunk-WGDEBIP4.js.map +0 -1
  257. /package/dist/{chunk-R6ZCSXKX.js.map → chunk-23MAWVOJ.js.map} +0 -0
  258. /package/dist/{chunk-6MRSX3YK.js.map → chunk-B5Y5GPD5.js.map} +0 -0
  259. /package/dist/{chunk-VP3TIUDF.js.map → chunk-DVTDF5OI.js.map} +0 -0
  260. /package/dist/{chunk-OXD5LFQP.js.map → chunk-G7H6PN7P.js.map} +0 -0
  261. /package/dist/{chunk-446I4EGD.js.map → chunk-J5TBZFBD.js.map} +0 -0
  262. /package/dist/{chunk-QFE5BQH7.js.map → chunk-LTSI7ULC.js.map} +0 -0
  263. /package/dist/{chunk-KNU73RZW.js.map → chunk-NSA5K5G2.js.map} +0 -0
  264. /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
  265. /package/dist/{chunk-VAZXUK6G.js.map → chunk-SUNCHMML.js.map} +0 -0
  266. /package/dist/{chunk-EP4WVQLX.js.map → chunk-T2U6N3FV.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presets/harness/actor-pool.ts","../src/presets/harness/eval-verifier.ts","../src/presets/harness/refine-executor.ts","../src/presets/harness/ownership-controller.ts","../src/presets/harness/profile.ts","../src/presets/harness/trace.ts"],"sourcesContent":["/**\n * DS-14.6.A U-B — `actorPool()` (Phase 14.5).\n *\n * The dynamic-track complement to `spawnable()` (SESSION-DS-14.6-A L7/L8 +\n * 9Q walk). An actor is **identity + cursor + tool closure, NOT a subgraph**\n * (D-B1): no per-actor mount, so `describe()` shows only the pool / todo /\n * context-hub collections and the actor count drifts inside a single\n * reactive `active` map node. `depthCap` is enforced via the depth carried\n * on the attach request (D-B2); `release()` cascades teardown to the\n * actor's context view + todo cursor subscriptions (§3i — free).\n *\n * Contrast `spawnable()`: agent IS a subgraph, topology reflects the agent\n * set, `describe()`-visible — use it when agent identities are pre-known.\n * Use `actorPool()` for runtime recursive fan-out where agent count drifts.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype ContextEntry,\n\ttype ContextView,\n\ttype RenderedEntry,\n\trenderContextView,\n\ttype TaggedContextPoolBundle,\n\ttaggedContextPool,\n} from \"../ai/context/index.js\";\n\nexport type ActorId = string;\n\nexport interface Todo {\n\treadonly id: string;\n\treadonly assignee?: ActorId;\n\treadonly payload: unknown;\n}\n\nexport type ActorStatus = \"idle\" | \"running\" | \"blocked\" | \"done\";\n\nexport interface ActorState {\n\treadonly id: ActorId;\n\treadonly depth: number;\n\treadonly status: ActorStatus;\n}\n\nexport interface ActorSpec<T> {\n\treadonly id?: ActorId;\n\t/** Recursion depth — gated against `depthCap` (D-B2). Default 0 (root). */\n\treadonly depth?: number;\n\t/** Per-actor compression view over the shared context pool. */\n\treadonly view: Omit<ContextView<T>, \"pressure\"> & { readonly pressure: Node<number> };\n}\n\nexport interface ActorHandle<T> {\n\treadonly id: ActorId;\n\t/** This actor's compressed context slice. */\n\treadonly context: Node<readonly RenderedEntry<T>[]>;\n\t/** Todos currently assigned to this actor (or unassigned). */\n\treadonly todoCursor: Node<readonly Todo[]>;\n\t/** Write an entry into the shared pool, stamped with this actor's id tag. */\n\tpublish(entry: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string;\n\tenqueueTodo(t: Todo): void;\n\treadonly status: Node<ActorStatus>;\n\tsetStatus(s: ActorStatus): void;\n\t/** Idempotent. Tears the actor's subscriptions + removes it from `active`. */\n\trelease(): void;\n}\n\nexport interface ActorPoolOptions<T> {\n\treadonly name?: string;\n\t/**\n\t * Max recursion depth; `attachActor` with `depth > depthCap` throws.\n\t * Default: `8` (F-ACTOR, 2026-05-18 smell sweep — a finite default bounds\n\t * runaway recursive fan-out; previously silently `Infinity`). Pass an\n\t * explicit `Number.POSITIVE_INFINITY` to opt in to unbounded recursion.\n\t */\n\treadonly depthCap?: number;\n\t/** Forwarded to the backing context pool. */\n\treadonly contextTopic?: string;\n\treadonly llmCompress?: TaggedContextPoolBundle<T>[\"_opts\"][\"llmCompress\"];\n}\n\nexport interface ActorPoolBundle<T> {\n\tattachActor(spec: ActorSpec<T>): ActorHandle<T>;\n\treadonly contextPool: TaggedContextPoolBundle<T>;\n\treadonly todos: ReactiveLogBundle<Todo>;\n\t/** Single reactive map of live actors — `describe()`-coherent (D-B1). */\n\treadonly active: Node<ReadonlyMap<ActorId, ActorState>>;\n\treadonly graph: Graph;\n\tdispose(): void;\n}\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _actorPoolSeq = 0;\n\nexport function actorPool<T = unknown>(\n\tparent: Graph,\n\topts: ActorPoolOptions<T> = {},\n): ActorPoolBundle<T> {\n\t// QA P6: collision-safe default — recursive fan-out spins nested pools\n\t// under one parent; static \"actorPool\" would collide on `parent.mount`.\n\tconst name = opts.name ?? `actorPool-${++_actorPoolSeq}`;\n\tconst graph = new Graph(name);\n\tparent.mount(name, graph);\n\tconst depthCap = opts.depthCap ?? 8;\n\t// QA P5: per-pool actor counter (was module-global → test-pollution).\n\tlet autoActor = 0;\n\t// QA P7: track live handles so dispose() can release them all.\n\tconst liveHandles = new Set<ActorHandle<T>>();\n\n\tconst contextPool = taggedContextPool<T>(graph, {\n\t\ttopic: opts.contextTopic ?? \"context\",\n\t\tllmCompress: opts.llmCompress,\n\t\tname: `${name}.ctx`,\n\t});\n\tconst todos: ReactiveLogBundle<Todo> = reactiveLog<Todo>(undefined, { name: `${name}.todos` });\n\n\t// Single reactive `active` map node — actor count drifts inside it; no\n\t// per-actor subgraph mount (D-B1, describe-coherent).\n\tconst stateMap = new Map<ActorId, ActorState>();\n\tconst active = node<ReadonlyMap<ActorId, ActorState>>([], {\n\t\tname: `${name}.active`,\n\t\tinitial: new Map(),\n\t});\n\tfunction pushActive(): void {\n\t\tactive.emit(new Map(stateMap));\n\t}\n\n\tfunction attachActor(spec: ActorSpec<T>): ActorHandle<T> {\n\t\tconst depth = spec.depth ?? 0;\n\t\tif (depth > depthCap) {\n\t\t\tthrow new RangeError(`actorPool: depth ${depth} exceeds depthCap ${depthCap}`);\n\t\t}\n\t\tconst id = spec.id ?? `actor-${++autoActor}`;\n\n\t\tconst context = renderContextView(contextPool, spec.view as ContextView<T>);\n\t\t// Per-actor todo cursor — assigned-to-me or unassigned.\n\t\tconst todoCursor = node<readonly Todo[]>(\n\t\t\t[todos.entries as Node],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst all = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly Todo[]\n\t\t\t\t\t| undefined;\n\t\t\t\tactions.emit((all ?? []).filter((t) => t.assignee === id || t.assignee === undefined));\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tconst status = node<ActorStatus>([], { name: `${name}.${id}.status`, initial: \"idle\" });\n\n\t\tstateMap.set(id, { id, depth, status: \"idle\" });\n\t\tpushActive();\n\n\t\t// Keepalive subs so `.cache` stays warm; torn on release (cascade-cancel).\n\t\tconst subs = [\n\t\t\tcontext.subscribe(() => {}),\n\t\t\ttodoCursor.subscribe(() => {}),\n\t\t\tstatus.subscribe(() => {}),\n\t\t];\n\t\tlet released = false;\n\n\t\tconst handle: ActorHandle<T> = {\n\t\t\tid,\n\t\t\tcontext,\n\t\t\ttodoCursor,\n\t\t\tstatus,\n\t\t\tpublish(entry) {\n\t\t\t\tconst tags = [...(entry.tags ?? []), `actor:${id}`];\n\t\t\t\treturn contextPool.add({ ...entry, tags });\n\t\t\t},\n\t\t\tenqueueTodo(t) {\n\t\t\t\ttodos.append(t);\n\t\t\t},\n\t\t\tsetStatus(s) {\n\t\t\t\tstatus.emit(s);\n\t\t\t\tconst prev = stateMap.get(id);\n\t\t\t\tif (prev) {\n\t\t\t\t\tstateMap.set(id, { ...prev, status: s });\n\t\t\t\t\tpushActive();\n\t\t\t\t}\n\t\t\t},\n\t\t\trelease() {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\t// Cascade-cancel: tearing the keepalive subs deactivates the\n\t\t\t\t// per-actor derived nodes (lazy-deactivation — COMPOSITION-GUIDE\n\t\t\t\t// §1), detaching `context`/`todoCursor`/`status` from the shared\n\t\t\t\t// pool/todos logs once no other subscriber remains.\n\t\t\t\tfor (const u of subs) u();\n\t\t\t\tstateMap.delete(id);\n\t\t\t\tliveHandles.delete(handle);\n\t\t\t\tpushActive();\n\t\t\t},\n\t\t};\n\t\tliveHandles.add(handle);\n\t\treturn handle;\n\t}\n\n\treturn {\n\t\tattachActor,\n\t\tcontextPool,\n\t\ttodos,\n\t\tactive,\n\t\tgraph,\n\t\tdispose(): void {\n\t\t\t// QA P7: release outstanding actors first (tears their keepalive\n\t\t\t// subs / deactivates per-actor derived nodes) before disposing the\n\t\t\t// shared pool + todo log.\n\t\t\tfor (const h of [...liveHandles]) h.release();\n\t\t\tcontextPool.dispose();\n\t\t\ttodos.dispose();\n\t\t},\n\t};\n}\n","/**\n * evalVerifier — re-run the affected eval tasks against the execute-stage\n * artifact instead of asking an LLM to opine on the fix.\n *\n * Pairs naturally with {@link refineExecutor}: refineExecutor emits an\n * `ExecuteOutput<T>.artifact` holding the converged candidate; evalVerifier\n * pulls it out via `extractArtifact` and feeds a single-candidate batch\n * into the same `Evaluator<T>` shape that `refineLoop` used. Consistent\n * scoring between EXECUTE and VERIFY — no \"LLM said it looks fine\" gap.\n *\n * **C2 lifecycle (Tier 6.5).** The work fn is invoked once per claimed\n * verify-stage job. A fresh single-candidate eval subgraph is mounted\n * inside the work fn and tears down when the JobFlow pump ack/unsubs.\n *\n * @module\n */\n\nimport { batch, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { filter } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type {\n\tExecuteOutput,\n\tHarnessExecutor,\n\tHarnessJobPayload,\n\tHarnessVerifier,\n\tTriagedItem,\n\tVerifyOutput,\n} from \"../../utils/harness/types.js\";\nimport type { JobEnvelope } from \"../../utils/job-queue/index.js\";\nimport { refineExecutor } from \"./refine-executor.js\";\nimport type {\n\tDatasetItem,\n\tEvalResult,\n\tEvaluator,\n\tRefineLoopOptions,\n\tRefineStrategy,\n} from \"./refine-loop.js\";\n\n/** Summary of the re-eval wave passed to a custom `toOutput` mapper. */\nexport interface EvalVerifierSummary {\n\treadonly scores: readonly EvalResult[];\n\treadonly meanScore: number;\n\treadonly passCount: number;\n\treadonly total: number;\n\treadonly threshold: number;\n\t/**\n\t * True when the EXECUTE stage did not produce an artifact (i.e.\n\t * `extractArtifact` returned `null` / `undefined`). Downstream mappers\n\t * can distinguish this from \"evaluator ran but everything scored zero\".\n\t */\n\treadonly missingArtifact?: boolean;\n}\n\n/** Configuration for {@link evalVerifier}. */\nexport interface EvalVerifierConfig<T> {\n\t/**\n\t * Pull the artifact that should be re-evaluated out of the execute-stage\n\t * output. Default: `(exec) => exec.artifact as T` — works out-of-the-box\n\t * with `refineExecutor` (which populates `artifact` by default).\n\t */\n\textractArtifact?: (exec: ExecuteOutput<T>, item: TriagedItem) => T | null | undefined;\n\n\t/**\n\t * Reactive evaluator — same contract as `refineLoop`'s `Evaluator<T>`.\n\t */\n\tevaluator: Evaluator<T>;\n\n\t/**\n\t * Resolve which dataset rows to score this verification against.\n\t */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\n\t/** Mean score required to pass verification. Default `0.5`. */\n\tthreshold?: number;\n\n\t/** Optional output mapper — override the default findings / errorClass shape. */\n\ttoOutput?: (summary: EvalVerifierSummary) => VerifyOutput;\n\n\t/** Node name prefix for introspection. */\n\tname?: string;\n\n\t/**\n\t * Optional parent graph on which per-claim eval subgraphs mount at\n\t * `eval/${claimId}` (DS-13.5.D.4, locked 2026-05-01). When provided,\n\t * each claim creates a fresh `Graph(\\`eval_${claimId}\\`)` subgraph\n\t * carrying `candidates` / `dataset` / `output` and mounts it at\n\t * `eval/${claimId}` on this parent — `describe()` walks the parent\n\t * see the per-claim topology while the claim is in flight, and the\n\t * subgraph is removed via `parent.remove(\"eval/${claimId}\")` on the\n\t * output node's `deactivate` cleanup (fires when JobFlow's pump\n\t * unsubscribes after ack/nack).\n\t *\n\t * **claimId source.** `JobEnvelope.id` (assigned at enqueue time);\n\t * unique within a JobFlow lifetime — uniqueness within a single pump\n\t * cycle is the JobFlow's contract.\n\t *\n\t * When omitted, internal nodes float (pre-DS-13.5.D.4 behavior).\n\t */\n\tgraph?: Graph;\n}\n\nfunction meanScore(scores: readonly EvalResult[]): number {\n\tif (scores.length === 0) return Number.NEGATIVE_INFINITY;\n\tlet sum = 0;\n\tfor (const s of scores) sum += s.score;\n\treturn sum / scores.length;\n}\n\nfunction defaultToOutput(summary: EvalVerifierSummary): VerifyOutput {\n\tconst { passCount, total, meanScore: mean, threshold, missingArtifact } = summary;\n\tconst meanStr = Number.isFinite(mean) ? mean.toFixed(3) : String(mean);\n\tconst verified = !missingArtifact && total > 0 && mean >= threshold;\n\tconst findings = missingArtifact\n\t\t? [\"EXECUTE stage did not emit an artifact; cannot verify reactively\"]\n\t\t: verified\n\t\t\t? [`${passCount}/${total} eval tasks passed; mean score ${meanStr} ≥ ${threshold}`]\n\t\t\t: total === 0\n\t\t\t\t? [\"No eval tasks were selected for this item — cannot verify\"]\n\t\t\t\t: [\n\t\t\t\t\t\t`${passCount}/${total} eval tasks passed; mean score ${meanStr} < threshold ${threshold}`,\n\t\t\t\t\t];\n\treturn verified\n\t\t? { verified: true, findings }\n\t\t: { verified: false, findings, errorClass: \"structural\" };\n}\n\nfunction defaultExtractArtifact<T>(exec: ExecuteOutput<T>): T | null | undefined {\n\treturn exec.artifact ?? null;\n}\n\n/**\n * Build a {@link HarnessVerifier} that re-runs the eval suite against the\n * artifact produced by EXECUTE.\n *\n * Reads `job.payload.execution` (filled by the upstream execute work fn)\n * and runs the evaluator against `extractArtifact(execution, item)`.\n * Returns the same payload with `verify` filled in.\n *\n * @example Pair with refineExecutor for end-to-end eval consistency.\n * ```ts\n * const evaluator: Evaluator<CatalogEntry> = (cands, ds) => runEval(cands, ds);\n * const harness = harnessLoop(\"repair\", {\n * adapter,\n * executor: refineExecutor({ ..., evaluator, ...strategyConfig }),\n * verifier: evalVerifier({ evaluator, datasetFor, threshold: 0.8 }),\n * });\n * ```\n */\nexport function evalVerifier<T>(config: EvalVerifierConfig<T>): HarnessVerifier<T> {\n\tconst name = config.name ?? \"eval-verifier\";\n\tconst threshold = config.threshold ?? 0.5;\n\tconst toOutput = config.toOutput ?? defaultToOutput;\n\tconst extract = config.extractArtifact ?? defaultExtractArtifact<T>;\n\tconst parentGraph = config.graph;\n\t// DS-13.5.B QA A7 (2026-05-03): per-claimId collision counter.\n\t// Reingest paths preserve identity per DS-13.5.D.3 so the same\n\t// claimId can land on the verifier while a prior cycle is still\n\t// in-flight. Without disambiguation, `parentGraph.mount(\n\t// \"eval/${id}\", sub)` would either silently overwrite the prior\n\t// mount or throw \"mount already exists\". The counter is keyed by\n\t// claimId so DISTINCT ids start at seq=0 (`eval/${id}`) and only\n\t// REPEAT ids get a `_${seq}` suffix.\n\tconst mountSeqByClaimId = new Map<string, number>();\n\n\treturn (job: JobEnvelope<HarnessJobPayload<T>>) => {\n\t\tconst { item, execution } = job.payload;\n\t\t// Defensive: verify stage should always run AFTER execute stage with\n\t\t// `execution` populated. If it isn't, surface that as a structural\n\t\t// failure so the dispatch effect can route the item.\n\t\tif (execution == null) {\n\t\t\treturn {\n\t\t\t\t...job.payload,\n\t\t\t\tverify: {\n\t\t\t\t\tverified: false,\n\t\t\t\t\tfindings: [\"evalVerifier: prior execute stage produced no execution\"],\n\t\t\t\t\terrorClass: \"structural\" as const,\n\t\t\t\t},\n\t\t\t} satisfies HarnessJobPayload<T>;\n\t\t}\n\t\tconst artifact = extract(execution, item);\n\t\tif (artifact == null) {\n\t\t\treturn {\n\t\t\t\t...job.payload,\n\t\t\t\tverify: toOutput({\n\t\t\t\t\tscores: [],\n\t\t\t\t\tmeanScore: Number.NEGATIVE_INFINITY,\n\t\t\t\t\tpassCount: 0,\n\t\t\t\t\ttotal: 0,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tmissingArtifact: true,\n\t\t\t\t}),\n\t\t\t} satisfies HarnessJobPayload<T>;\n\t\t}\n\n\t\t// Per-claim eval subgraph. State seeds with the single candidate +\n\t\t// resolved dataset; the evaluator returns a Node<readonly EvalResult[]>.\n\t\t// The terminal payload emits when the evaluator settles; intermediate\n\t\t// nulls are filtered.\n\t\t//\n\t\t// **Batch-coalescing for synchronous-emit-during-subscribe evaluators\n\t\t// (COMPOSITION-GUIDE §9a).** This `batch()` wrap is load-bearing for a\n\t\t// SPECIFIC evaluator pattern: evaluators that, during the\n\t\t// `evaluator(candidates, dataset)` constructor call, synchronously\n\t\t// `subscribe()` to BOTH inputs and emit on each subscribe-callback\n\t\t// firing. Each subscribe pushes the cached value to its callback, the\n\t\t// callback runs `out.emit(...)`, and that emit becomes its own wave\n\t\t// when not inside a batch — leaving multiple DATA messages visible to\n\t\t// the downstream `derived` once it activates. The JobFlow pump's\n\t\t// \"first DATA wins\" capture would then fire on the FIRST intermediate\n\t\t// emit (e.g. empty scores from a pre-dataset recompute) instead of\n\t\t// the final settled value.\n\t\t//\n\t\t// Wrapping the constructor call in `batch()` coalesces those internal\n\t\t// emits into one multi-message delivery (§9a); sugar `derived`\n\t\t// auto-unwraps to the LAST value per its snapshot/combine semantics\n\t\t// (sugar.ts), so the downstream sees only the final settled scores.\n\t\t//\n\t\t// **Async evaluators are NOT covered by this fix.** Evaluators that\n\t\t// subscribe via microtask / Promise.then() / setTimeout don't see the\n\t\t// §9a hazard at all — their emits land in separate waves regardless\n\t\t// of whether the constructor call is batched. The fix is strictly\n\t\t// for the synchronous-emit-during-subscribe pattern (today's tests:\n\t\t// `presenceEvaluator` in actuator-executor.test.ts; `keywordEvaluator`\n\t\t// in refine-executor.test.ts uses `derived` and is naturally\n\t\t// single-emit). See `harness-default-bridges.test.ts` regression test\n\t\t// \"evalVerifier coalesces synchronous-emit-during-subscribe\n\t\t// evaluators\" for the locked contract.\n\t\t// DS-13.5.D.4 (locked 2026-05-01): when `parentGraph` is configured,\n\t\t// each claim creates its own subgraph `eval_${claimId}` and mounts\n\t\t// it at `eval/${claimId}` on the parent. Internal node names use\n\t\t// the simple shape (`candidates`, `dataset`, `output`) since each\n\t\t// subgraph is a fresh namespace. Cleanup attaches to `raw`'s\n\t\t// deactivate hook so the segment is removed when JobFlow\n\t\t// unsubscribes after ack/nack (canonical \"last unsubscribe\"\n\t\t// signal via the existing NodeFnCleanup.onDeactivation protocol).\n\t\tconst claimId = job.id;\n\t\t// QA A7: only append a `_${seq}` suffix when this claimId has\n\t\t// already been mounted (collision case). Distinct claimIds\n\t\t// resolve to `eval/${claimId}` as before.\n\t\tconst seq = mountSeqByClaimId.get(claimId) ?? 0;\n\t\tmountSeqByClaimId.set(claimId, seq + 1);\n\t\tconst segmentSuffix = seq === 0 ? \"\" : `_${seq}`;\n\t\tconst segmentPath = `eval/${claimId}${segmentSuffix}`;\n\t\tconst sub = parentGraph != null ? new Graph(`eval_${claimId}${segmentSuffix}`) : null;\n\t\tconst candidatesName = sub != null ? \"candidates\" : `${name}/candidates`;\n\t\tconst datasetName = sub != null ? \"dataset\" : `${name}/dataset`;\n\t\tconst outputName = sub != null ? \"output\" : `${name}/output`;\n\t\tconst gateName = sub != null ? \"gate-out\" : `${name}/gate-out`;\n\n\t\tconst candidates = node<readonly T[]>([], {\n\t\t\tinitial: [artifact as T],\n\t\t\tname: candidatesName,\n\t\t});\n\t\tconst dataset = node<readonly DatasetItem[]>([], {\n\t\t\tinitial: config.datasetFor(item),\n\t\t\tname: datasetName,\n\t\t});\n\t\tif (sub != null) {\n\t\t\tsub.add(candidates, { name: \"candidates\" });\n\t\t\tsub.add(dataset, { name: \"dataset\" });\n\t\t}\n\t\tlet scoresNode!: ReturnType<Evaluator<T>>;\n\t\tbatch(() => {\n\t\t\tscoresNode = config.evaluator(candidates, dataset);\n\t\t});\n\t\t// DS-13.5.B QA A1 (2026-05-03): the deactivate cleanup hook MUST\n\t\t// be returned on every fn run, including the early-return path\n\t\t// where `arr == null` (evaluator emits a placeholder before\n\t\t// settling). Cleanup capture happens at the END of fn execution\n\t\t// (NodeFnCleanup contract), so a fn that returned early without\n\t\t// the cleanup object would leak `eval/${claimId}` if its first\n\t\t// run produced null and the consumer unsubscribed before\n\t\t// scoresNode emits non-null.\n\t\tconst cleanup =\n\t\t\tparentGraph != null\n\t\t\t\t? () => ({\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\t// Auto-unmount on JobFlow's pump unsubscribe after\n\t\t\t\t\t\t\t// ack/nack (DS-13.5.D.4). Idempotent: try/catch\n\t\t\t\t\t\t\t// covers the case where the segment was already\n\t\t\t\t\t\t\t// removed (e.g. parent destroy cascade ran first).\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparentGraph.remove(segmentPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t/* best-effort cleanup */\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t: () => undefined;\n\t\tconst raw = node<HarnessJobPayload<T> | null>(\n\t\t\t[scoresNode as Node<unknown>],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly EvalResult[] | null | undefined;\n\t\t\t\tif (arr == null) {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn cleanup();\n\t\t\t\t}\n\t\t\t\tconst mean = meanScore(arr);\n\t\t\t\tconst passCount = arr.filter((s) => s.score >= threshold).length;\n\t\t\t\tactions.emit({\n\t\t\t\t\t...job.payload,\n\t\t\t\t\tverify: toOutput({\n\t\t\t\t\t\tscores: arr,\n\t\t\t\t\t\tmeanScore: mean,\n\t\t\t\t\t\tpassCount,\n\t\t\t\t\t\ttotal: arr.length,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn cleanup();\n\t\t\t},\n\t\t\t{ name: outputName, describeKind: \"derived\" },\n\t\t);\n\t\tconst gateOut = filter(raw, (v) => v != null, { name: gateName }) as ReturnType<\n\t\t\tHarnessVerifier<T>\n\t\t>;\n\t\tif (sub != null) {\n\t\t\tsub.add(raw, { name: \"output\" });\n\t\t\t// QA A6: register the gate-out filter on the per-claim\n\t\t\t// subgraph so describe() walks see the consumer-facing node\n\t\t\t// alongside candidates/dataset/output. Without this, the\n\t\t\t// returned filter floats and the subgraph's external surface\n\t\t\t// is incomplete in topology snapshots.\n\t\t\tsub.add(gateOut as Node<unknown>, { name: \"gate-out\" });\n\t\t\t(parentGraph as Graph).mount(segmentPath, sub);\n\t\t}\n\t\treturn gateOut;\n\t};\n}\n\n/**\n * Config for {@link harnessEvalPair} — the typed bundle that produces a\n * matched `refineExecutor<T>` + `evalVerifier<T>` pair sharing one\n * {@link Evaluator} and one `datasetFor` resolver.\n */\nexport interface HarnessEvalPairConfig<T> {\n\t/** Map a triaged item to the seed candidate. */\n\tseedFrom: (item: TriagedItem) => T;\n\t/** The reactive evaluator used by BOTH executor and verifier. */\n\tevaluator: Evaluator<T>;\n\t/** The refinement strategy (e.g. `errorCritique(teacher)`). */\n\tstrategy: RefineStrategy<T>;\n\t/** Resolve dataset rows per triaged item. */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\t/** Pass-threshold for the verifier. Default `0.5`. */\n\tthreshold?: number;\n\t/** Convergence / budget options forwarded to each inner `refineLoop`. */\n\trefine?: Omit<RefineLoopOptions, \"dataset\" | \"name\">;\n\t/**\n\t * Shared node-name prefix — the executor becomes `${name}-exec` and the\n\t * verifier `${name}-verify` for distinct but related describe() paths.\n\t * Default `\"harness-pair\"`.\n\t */\n\tname?: string;\n}\n\n/**\n * Typed factory that returns a matched `{ executor, verifier }` pair.\n *\n * Prevents the \"executor wrote `A`, verifier expected `B`\" class of runtime\n * cast errors — `T` is threaded through both sides, so mixing up the\n * configuration is a compile error instead of a silent `as T` in\n * `extractArtifact`. Shares the evaluator so EXECUTE and VERIFY score with\n * identical semantics (the whole point of `evalVerifier`).\n */\nexport function harnessEvalPair<T>(config: HarnessEvalPairConfig<T>): {\n\texecutor: HarnessExecutor<T>;\n\tverifier: HarnessVerifier<T>;\n} {\n\tconst baseName = config.name ?? \"harness-pair\";\n\tconst executor = refineExecutor<T>({\n\t\tname: `${baseName}-exec`,\n\t\tseedFrom: config.seedFrom,\n\t\tevaluator: config.evaluator,\n\t\tstrategy: config.strategy,\n\t\tdatasetFor: config.datasetFor,\n\t\trefine: config.refine,\n\t});\n\tconst verifier = evalVerifier<T>({\n\t\tname: `${baseName}-verify`,\n\t\tevaluator: config.evaluator,\n\t\tdatasetFor: config.datasetFor,\n\t\tthreshold: config.threshold,\n\t});\n\treturn { executor, verifier };\n}\n","/**\n * refineExecutor — bridge a `refineLoop` into the harness EXECUTE work fn.\n *\n * Each claimed job mounts a fresh `refineLoop`; when the loop reaches a\n * terminal status (`converged` / `budget` / `errored`), the work fn emits a\n * single {@link HarnessJobPayload} with `execution` filled in. The JobFlow\n * pump subscribes once, takes the first DATA, then unsubscribes — so the\n * inner loop tears down cleanly when the harness acks the job.\n *\n * **C2 lifecycle (Tier 6.5).** The work fn is invoked once per claim, so\n * no internal `switchMap` is needed (the prior pre-C2 shape used switchMap\n * to handle a stream of items). The pump owns the per-claim lifecycle:\n * activation when the work fn returns, teardown when the result Node is\n * unsubscribed.\n *\n * **Cross-item learning:** a fresh refineLoop per item means\n * `errorCritique`-style failure sampling does NOT accumulate across items\n * sharing a `rootCause`. A persistent-loop + re-seed surface is filed in\n * `docs/optimizations.md` as a long-term follow-up.\n *\n * @module\n */\n\nimport { node } from \"@graphrefly/pure-ts/core\";\nimport { filter } from \"@graphrefly/pure-ts/extra\";\nimport type {\n\tExecuteOutput,\n\tHarnessExecutor,\n\tHarnessJobPayload,\n\tTriagedItem,\n} from \"../../utils/harness/types.js\";\nimport type { JobEnvelope } from \"../../utils/job-queue/index.js\";\nimport {\n\ttype DatasetItem,\n\ttype Evaluator,\n\ttype RefineLoopOptions,\n\ttype RefineStatus,\n\ttype RefineStrategy,\n\trefineLoop,\n} from \"./refine-loop.js\";\n\n/** Terminal-run snapshot passed to a custom `toOutput` mapper. */\nexport interface RefineExecutorResult<T> {\n\t/**\n\t * Best candidate the inner loop converged on. `undefined` (SENTINEL) if the\n\t * inner loop never produced a best — e.g. it `errored` before any iteration\n\t * settled. (`loop.best` is a SENTINEL `Node<T>` post the 2026-05-18\n\t * anti-pattern sweep — no `null` placeholder.)\n\t */\n\treadonly best: T | undefined;\n\t/** Aggregate score at termination. `-Infinity` if the batch was empty. */\n\treadonly score: number;\n\t/** Reason the loop terminated. */\n\treadonly status: RefineStatus;\n}\n\n/** Configuration for {@link refineExecutor}. */\nexport interface RefineExecutorConfig<T> {\n\t/** Map a triaged item to the seed candidate (e.g. a catalog entry, prompt, patch). */\n\tseedFrom: (item: TriagedItem) => T;\n\n\t/** Reactive evaluator — same shape as passed to `refineLoop`. */\n\tevaluator: Evaluator<T>;\n\n\t/** Strategy (e.g. `errorCritique(teacher)`). Applied to every item's inner loop. */\n\tstrategy: RefineStrategy<T>;\n\n\t/** Map a triaged item to the dataset rows the evaluator should score against. */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\n\t/**\n\t * Optional mapper from the inner loop's terminal snapshot to an\n\t * `ExecuteOutput<T>`. Default: converged→success, budget→partial,\n\t * errored→failure.\n\t */\n\ttoOutput?: (result: RefineExecutorResult<T>) => ExecuteOutput<T>;\n\n\t/** Convergence / budget options forwarded to each inner `refineLoop`. */\n\trefine?: Omit<RefineLoopOptions, \"dataset\" | \"name\">;\n\n\t/** Node name prefix for introspection. Default `\"refine-executor\"`. */\n\tname?: string;\n}\n\nfunction defaultToOutput<T>(result: RefineExecutorResult<T>): ExecuteOutput<T> {\n\tconst { best, score, status } = result;\n\tconst scoreStr = Number.isFinite(score) ? score.toFixed(3) : String(score);\n\tconst artifact: T | undefined = best;\n\tif (status === \"converged\") {\n\t\treturn {\n\t\t\toutcome: \"success\",\n\t\t\tdetail: `refineLoop converged at score ${scoreStr}`,\n\t\t\tartifact,\n\t\t};\n\t}\n\tif (status === \"budget\") {\n\t\treturn {\n\t\t\toutcome: \"partial\",\n\t\t\tdetail: `refineLoop hit budget at score ${scoreStr}`,\n\t\t\tartifact,\n\t\t};\n\t}\n\treturn {\n\t\toutcome: \"failure\",\n\t\tdetail: `refineLoop errored (status=${status})`,\n\t\tartifact,\n\t};\n}\n\n/**\n * Build a {@link HarnessExecutor} backed by a `refineLoop` per claimed\n * job.\n *\n * @example Eval-driven repair loop in the harness EXECUTE slot.\n * ```ts\n * const harness = harnessLoop(\"repair\", {\n * adapter,\n * executor: refineExecutor({\n * seedFrom: (item) => initialCatalogEntry(item),\n * datasetFor: (item) => pickAffectedTasks(item, allTasks),\n * evaluator: (cands, tasks) => runEvalBatch(cands, tasks),\n * strategy: errorCritique({ teacher, width: 3 }),\n * refine: { maxIterations: 5, minScore: 0.9 },\n * }),\n * });\n * ```\n */\nexport function refineExecutor<T>(config: RefineExecutorConfig<T>): HarnessExecutor<T> {\n\tconst name = config.name ?? \"refine-executor\";\n\tconst toOutput = config.toOutput ?? defaultToOutput<T>;\n\n\treturn (job: JobEnvelope<HarnessJobPayload<T>>) => {\n\t\tconst item = job.payload.item;\n\t\tconst loop = refineLoop<T>(config.seedFrom(item), config.evaluator, config.strategy, {\n\t\t\t...config.refine,\n\t\t\tdataset: config.datasetFor(item),\n\t\t\tname: `${name}/inner`,\n\t\t});\n\t\t// Terminal-allowlist guard — emit non-null only on `converged` / `budget` /\n\t\t// `errored`; intermediate `running` waves emit `null` (deduped via the\n\t\t// node's default Object.is). The trailing `filter(v != null)` strips\n\t\t// the null DATA so the JobFlow pump's first-DATA capture sees the\n\t\t// terminal payload, not the intermediate null.\n\t\tconst raw = node<HarnessJobPayload<T> | null>(\n\t\t\t[loop.status, loop.best, loop._score],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst s = data[0] as RefineStatus;\n\t\t\t\tif (s !== \"converged\" && s !== \"budget\" && s !== \"errored\") {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst exec = toOutput({\n\t\t\t\t\tbest: data[1] as T | undefined,\n\t\t\t\t\tscore: data[2] as number,\n\t\t\t\t\tstatus: s,\n\t\t\t\t});\n\t\t\t\tactions.emit({\n\t\t\t\t\t...job.payload,\n\t\t\t\t\texecution: { item, ...exec },\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ name: `${name}/output`, describeKind: \"derived\" },\n\t\t);\n\t\treturn filter(raw, (v) => v != null, { name: `${name}/gate-out` }) as ReturnType<\n\t\t\tHarnessExecutor<T>\n\t\t>;\n\t};\n}\n","/**\n * `ownershipController()` — multi-agent subgraph ownership preset\n * (DS-14.5.A delta #8; L5/L6 + Q1–Q10).\n *\n * **Placement (documented choice).** Lives in `presets/harness/` alongside\n * the other multi-agent coordination presets (`spawnable()`, `actorPool()`).\n * Per the 4-layer rubric this is a ≥3-utils composition (messaging `topic` +\n * `derived` arbitration + Guard ABAC) wiring multi-agent coordination — the\n * same charter as `harness/`'s existing `spawnable`/`actorPool`. A separate\n * `presets/multi-agent/` directory was rejected to avoid fragmenting the\n * multi-agent presets across two folders for a single factory (L6: \"recipe +\n * preset, NO new primitive\").\n *\n * **What it is.** A `Graph` that owns a shared ownership `topic` (Q3 — one\n * topic carries claim / release / override; subscribers narrow by `kind`),\n * a reactive `current` derivation that folds the ownership log applying the\n * L0–L3 staircase, and a `guard` (`policyAllowing` — the Q7 reactive-options\n * Guard widening) the caller mounts on the owned subgraph. It **consumes the\n * existing DS-14 {@link OwnershipChange}** envelope — it does NOT redefine it.\n *\n * **Staircase (Q10 — `level` is a priority axis, NOT a mechanism enum):**\n * - **L1 TTL** — a `claim` carries a level; the controller's `ttl` (ms)\n * bounds the live window. L1 honors TTL strictly (Q4): a crash inside the\n * window does NOT early-release; recommend `ttl ≤ 60s`.\n * - **L2 heartbeat** — `heartbeat?: NodeInput<unknown>` (Q2). Any reactive\n * trigger Node; each emission resets the countdown (\"max tolerance since\n * last sign of life\", unified across L1/L2). No library timer is shipped\n * and no `claim.heartbeat()` method exists (`feedback_no_imperative` +\n * `feedback_no_imperative_wrap_as_primitive`).\n * - **L3 supervisor** — a `kind:\"override\"` change wins by `level` priority\n * regardless of expiry/heartbeat (priority axis independent of the expiry\n * axis). Supervisor publishes to the SAME topic (Q3).\n *\n * **No polling / no timer (spec §5.8/§5.9/§5.10).** Expiry is evaluated\n * reactively: `current` recomputes whenever the ownership topic OR the\n * heartbeat OR the optional `clock` trigger emits, folding the whole log\n * from scratch (idempotent — no carried mutable cursor). Auto-release on\n * wall-clock TTL requires the caller to wire a reactive `clock` tick\n * (`fromTimer({ ms })` or an activity-derived Node) — the library does not\n * own a timer (L6 / Q2). Without `clock`, expiry still resolves at the next\n * topic/heartbeat emission and on any read that recomputes the derivation.\n *\n * @module\n */\n\nimport { type Node, type NodeGuard, policyAllowing, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput, OwnershipChange, OwnershipChangePayload } from \"@graphrefly/pure-ts/extra\";\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { type TopicGraph, topic } from \"../../utils/messaging/index.js\";\n\n/** Ownership level — priority axis (Q10). Higher rank = higher priority. */\nconst LEVEL_RANK = { L0: 0, L1: 1, L2: 2, L3: 3 } as const;\ntype OwnershipLevel = keyof typeof LEVEL_RANK;\n\n/** Options for {@link ownershipController}. */\nexport type OwnershipControllerOptions = {\n\t/**\n\t * TTL (milliseconds) bounding the live window of a claim. Honored\n\t * strictly (Q4) — a crash inside the window does not early-release.\n\t * Recommend ≤ 60_000 for L1 holds; wire `heartbeat` (L2) for longer.\n\t */\n\treadonly ttl: number;\n\t/**\n\t * L2 heartbeat (Q2). Any reactive trigger Node — each emission resets the\n\t * TTL countdown. Simple: `fromTimer({ ms: ttl / 3 })`. Activity-based:\n\t * `derived([toolCalls.events], …)`. Omitted → pure L1 TTL semantics.\n\t */\n\treadonly heartbeat?: NodeInput<unknown>;\n\t/**\n\t * L3 supervisor id. A `kind:\"override\"` change whose `actor` equals this\n\t * id wins by `level` priority regardless of expiry/heartbeat. Override\n\t * delivery is the shared topic with the `kind:\"override\"` discriminant\n\t * (Q3) — not a separate priority topic.\n\t */\n\treadonly supervisor?: string;\n\t/**\n\t * Optional reactive clock trigger used ONLY to re-evaluate TTL expiry\n\t * (e.g. `fromTimer({ ms: 1_000 })`). The library ships no timer (L6/Q2);\n\t * wire this for wall-clock-driven auto-release without an intervening\n\t * claim/heartbeat. Without it, expiry resolves lazily on the next\n\t * topic/heartbeat emission.\n\t */\n\treadonly clock?: NodeInput<unknown>;\n\t/** Bounded retention for the ownership topic (default 256). */\n\treadonly retainedLimit?: number;\n};\n\n/**\n * Resolved ownership state emitted by {@link OwnershipControllerGraph.current}.\n * `owner` is `null` when unclaimed or the live claim has expired.\n */\nexport type OwnershipState = {\n\treadonly owner: string | null;\n\treadonly level: OwnershipLevel | null;\n\t/** Allow-set fed to the Guard. `[]` (deny-all) when `owner === null`. */\n\treadonly allowed: readonly string[];\n\t/**\n\t * Internal (F3/F4) — last sign-of-life (wall-clock ns) for the *current*\n\t * claim: `max(claim.sinceNs, last in-window heartbeat)`. Carried in the\n\t * derivation's OWN emitted state (read back via `ctx.prevData`) so the\n\t * fold is pure — same (folded log, beat-this-wave, now, prevState) →\n\t * same output. NEVER an instance field. `null` when unclaimed. Scoped to\n\t * the active claim: a value older than the active claim's `sinceNs` (a\n\t * prior owner's beat) is discarded so it cannot extend a new owner.\n\t */\n\treadonly signOfLifeNs: number | null;\n};\n\nconst EMPTY_STATE: OwnershipState = {\n\towner: null,\n\tlevel: null,\n\tallowed: [],\n\tsignOfLifeNs: null,\n};\n\ntype ActiveOwner = { owner: string; level: OwnershipLevel; sinceNs: number };\n\n/**\n * Multi-agent subgraph ownership controller. See module docs.\n *\n * Public surface:\n * - `topic` — the shared ownership `TopicGraph<OwnershipChange>` (Q3).\n * Agents publish claim/release/override here (use the `claim`/`release`/\n * `override` helpers — thin reactive wrappers over `topic.publish`, i.e.\n * message flow, NOT imperative triggers).\n * - `current` — `Node<OwnershipState>`: the reactively-resolved owner after\n * applying L1 TTL + L2 heartbeat + L3 supervisor arbitration.\n * - `allowed` — `Node<readonly string[]>`: the Guard allow-set (derived from\n * `current`); re-points on claim/release/override with no rewire.\n * - `guard` — `NodeGuard` from `policyAllowing(this.allowed)`. Mount on the\n * owned subgraph's nodes (`node({ guard })`) for the Q7 hard-block.\n */\nexport class OwnershipControllerGraph extends Graph {\n\treadonly topic: TopicGraph<OwnershipChange>;\n\treadonly current: Node<OwnershipState>;\n\treadonly allowed: Node<readonly string[]>;\n\treadonly guard: NodeGuard;\n\n\tprivate readonly _ttlNs: number;\n\tprivate readonly _supervisor: string | undefined;\n\t/**\n\t * Whether a heartbeat `NodeInput` was supplied at construction (F14 —\n\t * `claim()`'s `level` default is `\"L2\"` when wired, else `\"L1\"`). NOT a\n\t * mutable accumulator — set once in the constructor, read-only after.\n\t */\n\tprivate readonly _hasHeartbeat: boolean;\n\n\tconstructor(name: string, opts: OwnershipControllerOptions) {\n\t\tsuper(name);\n\t\tthis._ttlNs = Math.max(0, opts.ttl) * 1_000_000;\n\t\tthis._supervisor = opts.supervisor;\n\t\tthis._hasHeartbeat = opts.heartbeat != null;\n\n\t\tthis.topic = topic<OwnershipChange>(`${name}__ownership`, {\n\t\t\tretainedLimit: opts.retainedLimit ?? 256,\n\t\t});\n\t\t// The topic is its own TopicGraph; tear it down with this controller.\n\t\t// (Not mounted — `topic.events` already belongs to the TopicGraph; a\n\t\t// re-`add` would violate single-graph node ownership. Consumers\n\t\t// inspect ownership via `current` / `allowed`, not via a mount.)\n\t\tthis.addDisposer(() => {\n\t\t\tthis.topic.destroy();\n\t\t});\n\n\t\t// `current` recomputes whenever the ownership stream changes, the\n\t\t// heartbeat fires, or the optional clock ticks — the only sources\n\t\t// that can change the resolved owner. ALL deps wired BEFORE any claim\n\t\t// can be published (observers before emitters — §47 rule 2).\n\t\tconst deps: Node<unknown>[] = [this.topic.events as Node<unknown>];\n\t\tconst heartbeatIdx = opts.heartbeat != null ? deps.push(fromAny(opts.heartbeat)) - 1 : -1;\n\t\tif (opts.clock != null) deps.push(fromAny(opts.clock) as Node<unknown>);\n\n\t\tthis.current = this.derived<OwnershipState>(\n\t\t\t\"currentOwner\",\n\t\t\tdeps,\n\t\t\t(batchData, ctx) => {\n\t\t\t\t// Wall-clock (F2) — must match `makeChange`'s `t_ns` stamp so\n\t\t\t\t// `nowNs - active.sinceNs` compares like-for-like. Mixing\n\t\t\t\t// monotonic + wall clocks (the prior bug) made TTL math\n\t\t\t\t// nonsense once the two clocks diverged.\n\t\t\t\tconst nowNs = wallClockNs();\n\t\t\t\t// Did the heartbeat dep emit this wave? `batchData[i]` is the\n\t\t\t\t// array of values dep `i` emitted THIS wave; a non-empty\n\t\t\t\t// heartbeat batch is one or more beats.\n\t\t\t\tconst beatThisWave =\n\t\t\t\t\theartbeatIdx >= 0 &&\n\t\t\t\t\t(() => {\n\t\t\t\t\t\tconst hb = batchData[heartbeatIdx] as readonly unknown[] | null | undefined;\n\t\t\t\t\t\treturn hb != null && hb.length > 0;\n\t\t\t\t\t})();\n\n\t\t\t\t// Fold the WHOLE ownership log from scratch (idempotent — the\n\t\t\t\t// topic emits the full retained array, so a cursor would be a\n\t\t\t\t// bug surface; pure reduction is correct and simple, §47).\n\t\t\t\t// `batchData[0]` is `(readonly OwnershipChange[])[]` — the\n\t\t\t\t// snapshots emitted this wave; take the latest (mirrors\n\t\t\t\t// `topic.latest`'s `batch.at(-1)` pattern). On a SENTINEL\n\t\t\t\t// first-activation wave fall back to `ctx.prevData[0]`.\n\t\t\t\tconst topoBatch = batchData[0] as\n\t\t\t\t\t| readonly (readonly OwnershipChange[])[]\n\t\t\t\t\t| null\n\t\t\t\t\t| undefined;\n\t\t\t\tconst log = (\n\t\t\t\t\ttopoBatch != null && topoBatch.length > 0\n\t\t\t\t\t\t? topoBatch[topoBatch.length - 1]\n\t\t\t\t\t\t: (ctx.prevData[0] as readonly OwnershipChange[] | undefined)\n\t\t\t\t) as readonly OwnershipChange[] | undefined;\n\t\t\t\tlet active: ActiveOwner | null = null;\n\t\t\t\tif (log != null) {\n\t\t\t\t\tfor (const ch of log) {\n\t\t\t\t\t\tif (ch?.change == null) continue;\n\t\t\t\t\t\tactive = applyChange(active, ch, this._supervisor);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// F3/F4 — PURE sign-of-life. Read the prior `signOfLifeNs`\n\t\t\t\t// from THIS derivation's own previously-emitted state\n\t\t\t\t// (`ctx.prevData[0]` for the `current` node is unavailable —\n\t\t\t\t// `prevData[0]` is the topic dep — so we read `ctx.cache`,\n\t\t\t\t// the node's own last emit). No instance field anywhere.\n\t\t\t\tconst prevState = (ctx.cache ?? undefined) as OwnershipState | undefined;\n\n\t\t\t\tlet nextActive: ActiveOwner | null = active;\n\t\t\t\tlet signOfLifeNs: number | null = null;\n\n\t\t\t\tif (active != null && this._ttlNs > 0) {\n\t\t\t\t\t// Carry the prior sign-of-life ONLY if it belongs to THIS\n\t\t\t\t\t// claim (>= the active claim's `sinceNs`). A value from a\n\t\t\t\t\t// prior owner (older than `sinceNs`) is discarded so a\n\t\t\t\t\t// stale beat cannot extend a freshly-claimed window. A new\n\t\t\t\t\t// owner therefore starts from its own claim time.\n\t\t\t\t\tconst carried =\n\t\t\t\t\t\tprevState?.signOfLifeNs != null && prevState.signOfLifeNs >= active.sinceNs\n\t\t\t\t\t\t\t? prevState.signOfLifeNs\n\t\t\t\t\t\t\t: active.sinceNs;\n\t\t\t\t\t// Expire FIRST against the carried sign-of-life (Q4 strict —\n\t\t\t\t\t// a late beat must NOT resurrect an already-lapsed claim),\n\t\t\t\t\t// THEN accept a still-timely beat THIS wave. `signOfLifeNs`\n\t\t\t\t\t// only ever advances on an actual beat-this-wave, so a\n\t\t\t\t\t// recompute storm with no beat cannot renew a dead claim\n\t\t\t\t\t// (idempotent re-fold).\n\t\t\t\t\tconst lapsed = nowNs - carried >= this._ttlNs;\n\t\t\t\t\tif (lapsed) {\n\t\t\t\t\t\tnextActive = null;\n\t\t\t\t\t\tsignOfLifeNs = null;\n\t\t\t\t\t} else if (beatThisWave) {\n\t\t\t\t\t\tsignOfLifeNs = nowNs; // timely beat → renew\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsignOfLifeNs = carried; // unchanged — carry forward\n\t\t\t\t\t}\n\t\t\t\t} else if (active != null) {\n\t\t\t\t\t// No TTL configured — never expires; sign-of-life still\n\t\t\t\t\t// tracked (owner-scoped) for completeness/observability.\n\t\t\t\t\tconst carried =\n\t\t\t\t\t\tprevState?.signOfLifeNs != null && prevState.signOfLifeNs >= active.sinceNs\n\t\t\t\t\t\t\t? prevState.signOfLifeNs\n\t\t\t\t\t\t\t: active.sinceNs;\n\t\t\t\t\tsignOfLifeNs = beatThisWave ? nowNs : carried;\n\t\t\t\t}\n\n\t\t\t\treturn [\n\t\t\t\t\tnextActive == null\n\t\t\t\t\t\t? EMPTY_STATE\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\towner: nextActive.owner,\n\t\t\t\t\t\t\t\tlevel: nextActive.level,\n\t\t\t\t\t\t\t\tallowed: [nextActive.owner],\n\t\t\t\t\t\t\t\tsignOfLifeNs,\n\t\t\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t},\n\t\t\t{ keepAlive: true },\n\t\t);\n\n\t\tthis.allowed = this.derived<readonly string[]>(\n\t\t\t\"allowed\",\n\t\t\t[this.current],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst batch = batchData[0] as readonly OwnershipState[] | null | undefined;\n\t\t\t\tconst s = (batch != null && batch.length > 0 ? batch[batch.length - 1] : ctx.prevData[0]) as\n\t\t\t\t\t| OwnershipState\n\t\t\t\t\t| undefined;\n\t\t\t\treturn [s?.allowed ?? []];\n\t\t\t},\n\t\t\t{ keepAlive: true },\n\t\t);\n\t\t// F12 — `keepAlive: true` above already installs a self-pruning\n\t\t// keepalive subscription (same as `current`); a second\n\t\t// `keepalive(this.allowed)` disposer was redundant double-subscription.\n\n\t\t// Q7 — the reactive-options Guard. `policyAllowing` reads\n\t\t// `this.allowed.cache` synchronously at write-check time, so\n\t\t// claim/release/override re-point the allow-set with NO rewire.\n\t\tthis.guard = policyAllowing(this.allowed);\n\t}\n\n\t/**\n\t * Publish a `claim`. Thin reactive wrapper over `topic.publish` (message\n\t * flow per §29 — NOT an imperative trigger). `level` defaults to `\"L2\"`\n\t * when this controller has a heartbeat wired, else `\"L1\"`.\n\t */\n\tclaim(actor: string, level?: OwnershipLevel): void {\n\t\t// F14 — documented default (JSDoc + §47): L2 when a heartbeat\n\t\t// NodeInput was wired at construction, else L1.\n\t\tconst lvl = level ?? (this._hasHeartbeat ? \"L2\" : \"L1\");\n\t\tthis.topic.publish(makeChange({ kind: \"claim\", subgraphId: this.name, actor, level: lvl }));\n\t}\n\n\t/** Publish a `release`. Clears ownership iff `actor` is the current owner. */\n\trelease(actor: string): void {\n\t\tthis.topic.publish(makeChange({ kind: \"release\", subgraphId: this.name, actor }));\n\t}\n\n\t/**\n\t * Publish a supervisor `override` (L3). Wins by `level` priority\n\t * regardless of expiry (Q10). `actor` should be this controller's\n\t * `supervisor` id for the override to take precedence.\n\t */\n\toverride(actor: string, previousActor: string, reason: string): void {\n\t\tthis.topic.publish(\n\t\t\tmakeChange({ kind: \"override\", subgraphId: this.name, actor, previousActor, reason }),\n\t\t);\n\t}\n}\n\n/** Wrap an {@link OwnershipChangePayload} in the DS-14 {@link OwnershipChange} envelope. */\nfunction makeChange(payload: OwnershipChangePayload): OwnershipChange {\n\t// F2 — `BaseChange.t_ns` is contractually wall-clock (`wallClockNs()`,\n\t// see change.ts). The fold compares `nowNs (wallClockNs)` against\n\t// `ch.t_ns` for TTL/expiry, so stamp + compare MUST use the same clock.\n\tconst t = wallClockNs();\n\treturn { structure: \"ownership\", version: t, t_ns: t, lifecycle: \"ownership\", change: payload };\n}\n\n/**\n * Fold one ownership change into the resolved-owner state.\n *\n * - `claim` — sets the active owner (records claim time for L1 TTL). A\n * lower-priority claim cannot displace a higher-`level` live owner (Q10 —\n * override arbitration is pure level comparison).\n * - `release` — clears ownership iff the releasing actor is the owner.\n * - `override` — supervisor override: wins by `level` priority. Carries\n * `previousActor` + `reason` per DS-14 (Q3); modeled as an L3 hand-off to\n * `p.actor`.\n */\nfunction applyChange(\n\tactive: ActiveOwner | null,\n\tch: OwnershipChange,\n\tsupervisor: string | undefined,\n): ActiveOwner | null {\n\tconst p = ch.change;\n\t// Use the change's publish timestamp (`t_ns` — wall-clock, stamped in\n\t// `makeChange`) as the claim time — NOT the fold time. The log is re-folded\n\t// from scratch on every recompute (§47), so stamping a fresh clock read\n\t// here would re-baseline the TTL window every recompute and the claim would\n\t// never expire. The fold compares against `wallClockNs()` (F2 — same clock).\n\tif (p.kind === \"claim\") {\n\t\tif (active != null && LEVEL_RANK[active.level] > LEVEL_RANK[p.level]) return active;\n\t\treturn { owner: p.actor, level: p.level, sinceNs: ch.t_ns };\n\t}\n\tif (p.kind === \"release\") {\n\t\tif (active != null && active.owner === p.actor) return null;\n\t\treturn active;\n\t}\n\t// override (F5) — a `kind:\"override\"` only seizes ownership when the\n\t// publishing actor IS the configured supervisor. The prior disjunction\n\t// `|| LEVEL_RANK.L3 >= LEVEL_RANK[active.level]` was a tautology (L3 is the\n\t// max rank ⇒ always true), so ANY actor's override took over. If no\n\t// supervisor is configured, overrides are explicitly disabled (a non-null\n\t// `supervisor` is the gate, not an accidental fall-through).\n\tconst isSupervisor = supervisor != null && p.actor === supervisor;\n\tif (isSupervisor) {\n\t\treturn { owner: p.actor, level: \"L3\", sinceNs: ch.t_ns };\n\t}\n\treturn active;\n}\n\n/**\n * Create a multi-agent subgraph ownership controller (DS-14.5.A #8).\n *\n * @example\n * ```ts\n * const oc = ownershipController(\"payments\", { ttl: 30_000, supervisor: \"lead\" });\n * // Mount the Guard on the owned subgraph:\n * const n = node([], { initial: 0, guard: oc.guard });\n * oc.claim(\"agent-a\"); // agent-a now owns; non-owner writes throw\n * oc.override(\"lead\", \"agent-a\", \"rebalance\"); // supervisor takes over\n * ```\n */\nexport function ownershipController(\n\tname: string,\n\topts: OwnershipControllerOptions,\n): OwnershipControllerGraph {\n\treturn new OwnershipControllerGraph(name, opts);\n}\n","/**\n * Harness-specific graph profiling (roadmap §9.0).\n *\n * Extends {@link graphProfile} with harness domain counters:\n * queue depths, strategy entries, retry/reingestion tracker sizes.\n *\n * @module\n */\n\nimport {\n\ttype GraphProfileOptions,\n\ttype GraphProfileResult,\n\tgraphProfile,\n} from \"@graphrefly/pure-ts/graph\";\nimport { QUEUE_NAMES } from \"../../utils/harness/defaults.js\";\nimport type { QueueRoute, TriagedItem } from \"../../utils/harness/types.js\";\nimport type { HarnessGraph } from \"./harness-loop.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Harness-specific profile extending the base graph profile. */\nexport interface HarnessProfileResult extends GraphProfileResult {\n\t/** Per-queue retained item counts. */\n\tqueueDepths: Record<QueueRoute, number>;\n\t/** Number of rootCause→intervention entries in the strategy model. */\n\tstrategyEntries: number;\n\t/** Global retry count across all items. */\n\ttotalRetries: number;\n\t/** Global reingestion count across all items. */\n\ttotalReingestions: number;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Profile a harness graph with domain-specific counters.\n *\n * **Snapshot caveat (Unit 22 B).** Reads `.cache` values from the\n * strategy / retry / reingestion nodes + each queue topic's `.retained()`\n * view. These are point-in-time reads and are not transactional — if you\n * invoke this during an in-flight reactive wave the values may reflect\n * a partially-settled frame. For end-of-wave accuracy, call from outside\n * any batch boundary.\n *\n * @param harness - The HarnessGraph to profile.\n * @param opts - Optional base profile options.\n * @returns Harness profile with queue depths, strategy stats, and tracker sizes.\n */\nexport function harnessProfile(\n\tharness: HarnessGraph,\n\topts?: GraphProfileOptions,\n): HarnessProfileResult {\n\tconst base = graphProfile(harness, opts);\n\n\t// Unit 22 B: iterate the hub's topic registry instead of a raw Map so\n\t// queue topics added post-construction (dead-letter `__unrouted`, etc.)\n\t// don't get silently ignored.\n\tconst queueDepths: Record<string, number> = {};\n\tfor (const route of QUEUE_NAMES) {\n\t\tconst t = harness.queues.has(route) ? harness.queues.topic<TriagedItem>(route) : null;\n\t\tqueueDepths[route] = t?.retained().length ?? 0;\n\t}\n\n\treturn {\n\t\t...base,\n\t\tqueueDepths: queueDepths as Record<QueueRoute, number>,\n\t\tstrategyEntries: harness.strategy.entries.cache?.size ?? 0,\n\t\ttotalRetries: harness.totalRetries.cache ?? 0,\n\t\ttotalReingestions: harness.totalReingestions.cache ?? 0,\n\t};\n}\n","/**\n * Harness pipeline trace — thin sugar over `graph.observe({ format: \"stage-log\" })`.\n *\n * Since 2026-04-22 (D2), stage-labeled tracing is a first-class observe format\n * on {@link Graph}. `harnessTrace` wires that format over the 7 pipeline stages\n * (INTAKE → TRIAGE → QUEUE → GATE → EXECUTE → VERIFY → STRATEGY) with sensible\n * defaults so harness consumers don't need to restate the stage map.\n *\n * For non-harness graphs, call `graph.observe({ format: \"stage-log\", stageLabels })`\n * directly — the format is domain-agnostic.\n *\n * @module\n */\n\nimport { monotonicNs } from \"@graphrefly/pure-ts/core\";\nimport type { ObserveEvent, ObserveResult } from \"@graphrefly/pure-ts/graph\";\nimport type { HarnessGraph } from \"./harness-loop.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Event type captured by structured trace. */\nexport type TraceEventType = \"data\" | \"error\" | \"complete\";\n\n/** A single structured trace event. */\nexport interface TraceEvent {\n\t/** Elapsed seconds since trace was created. */\n\telapsed: number;\n\t/** Pipeline stage label (INTAKE, TRIAGE, QUEUE, GATE, EXECUTE, VERIFY, STRATEGY). */\n\tstage: string;\n\t/** Event type. */\n\ttype: TraceEventType;\n\t/** Data payload (present for \"data\" and \"error\" events). Omitted at \"summary\" detail. */\n\tdata?: unknown;\n\t/** Human-readable summary of the data. Present at \"standard\" and \"full\" detail. */\n\tsummary?: string;\n}\n\n/** Detail level for trace output. */\nexport type TraceDetail =\n\t/** Stage + elapsed only. No data preview. Lowest overhead. */\n\t| \"summary\"\n\t/** Stage + elapsed + truncated data preview. Default. */\n\t| \"standard\"\n\t/** Stage + elapsed + full raw data. Use for debugging, not production. */\n\t| \"full\";\n\n/** Handle returned by {@link harnessTrace}. Call `dispose()` to stop tracing. */\nexport interface HarnessTraceHandle {\n\t/** Stop tracing and detach all observers. Safe to call multiple times. */\n\tdispose(): void;\n\t/**\n\t * Structured trace events collected since creation. Plain array — no\n\t * subscription needed (COMPOSITION-GUIDE §1: avoid lazy-activation\n\t * friction for inspection tools). Populated reactively via observe().\n\t */\n\treadonly events: readonly TraceEvent[];\n}\n\n/** Options for {@link harnessTrace}. */\nexport interface HarnessTraceOptions {\n\t/** Sink for rendered trace lines. Default: `console.log`. Pass `null` for structured-only. */\n\tlogger?: ((line: string) => void) | null;\n\t/** Detail level for both string and structured output. Default: `\"summary\"`. */\n\tdetail?: TraceDetail;\n}\n\n// ---------------------------------------------------------------------------\n// Stage labels\n// ---------------------------------------------------------------------------\n\n/**\n * Observe paths → stage labels for the 7 harness stages. Path set is\n * sourced from {@link HarnessGraph.stageNodes} so inspection tools stay\n * decoupled from mount-structure changes (Unit 22 C).\n */\nfunction buildStageLabels(harness: HarnessGraph): Record<string, string> {\n\tconst labels: Record<string, string> = {};\n\tfor (const { label, paths } of harness.stageNodes()) {\n\t\tfor (const p of paths) labels[p] = label;\n\t}\n\treturn labels;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Attach a stage-log trace over the harness pipeline. Delegates to\n * `harness.observe({ format: \"stage-log\", ... })` for each stage path —\n * every event is captured in `handle.events` (structured) AND rendered via\n * the `logger` (string output).\n *\n * **Detail levels:**\n * - `\"summary\"` — stage + elapsed only. Minimal overhead.\n * - `\"standard\"` (default) — stage + elapsed + truncated data preview.\n * - `\"full\"` — stage + elapsed + full raw data object in events.\n *\n * Elapsed timestamps are relative to the `harnessTrace()` invocation time,\n * not the first event.\n */\nexport function harnessTrace(\n\tharness: HarnessGraph,\n\topts?: HarnessTraceOptions,\n): HarnessTraceHandle {\n\tconst logger: ((line: string) => void) | null =\n\t\topts?.logger === null ? null : (opts?.logger ?? console.log);\n\tconst detail: TraceDetail = opts?.detail ?? \"summary\";\n\tconst startNs = monotonicNs();\n\tconst observations: ObserveResult[] = [];\n\tconst events: TraceEvent[] = [];\n\tconst stageLabels = buildStageLabels(harness);\n\n\tfunction elapsedSecs(): number {\n\t\treturn (monotonicNs() - startNs) / 1e9;\n\t}\n\n\tfunction recordEvent(stage: string, type: TraceEventType, rawData: unknown): void {\n\t\tconst ev: TraceEvent = { elapsed: elapsedSecs(), stage, type };\n\t\tif (detail !== \"summary\") ev.summary = summarize(rawData);\n\t\tif (detail === \"full\") ev.data = rawData;\n\t\tevents.push(ev);\n\t}\n\n\t// One observe call per path — keeps per-stage elapsed offsets anchored to\n\t// this invocation (the shared stage-log format uses its own elapsed clock\n\t// per observation, which matches the legacy behavior). We also intercept\n\t// each event through `onEvent` so structured `events[]` stays populated\n\t// regardless of `logger`.\n\tfor (const [path, stage] of Object.entries(stageLabels)) {\n\t\ttry {\n\t\t\tconst obs = harness.observe(path, {\n\t\t\t\tformat: \"stage-log\",\n\t\t\t\tstageLabels,\n\t\t\t\tlogger: logger ? (line: string) => logger(line) : () => {},\n\t\t\t\tincludeTypes: [\"data\", \"error\", \"complete\"],\n\t\t\t});\n\t\t\tobs.onEvent((event: ObserveEvent) => {\n\t\t\t\tif (event.type === \"data\") recordEvent(stage, \"data\", (event as { data: unknown }).data);\n\t\t\t\telse if (event.type === \"error\")\n\t\t\t\t\trecordEvent(stage, \"error\", (event as { data: unknown }).data);\n\t\t\t\telse if (event.type === \"complete\") recordEvent(stage, \"complete\", undefined);\n\t\t\t});\n\t\t\tobservations.push(obs);\n\t\t} catch (err) {\n\t\t\t// Node may not exist yet (e.g., a gated-queue route that hasn't been\n\t\t\t// mounted on this harness). Record a synthetic error trace event so\n\t\t\t// consumers see WHICH stage dropped out and why — silent swallow\n\t\t\t// breaks dry-run equivalence (a regression in stage wiring would\n\t\t\t// not surface in the trace).\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\trecordEvent(stage, \"error\", `observe-unavailable: ${path} — ${msg}`);\n\t\t\tif (logger) {\n\t\t\t\tlogger(`[${elapsedSecs().toFixed(3)}s] ${stage.padEnd(9)} ✗ observe-unavailable: ${msg}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tget events(): readonly TraceEvent[] {\n\t\t\treturn events;\n\t\t},\n\t\tdispose() {\n\t\t\tfor (const obs of observations) obs.dispose();\n\t\t\tobservations.length = 0;\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — kept here because `observe({ format: \"stage-log\" })` emits short\n// one-line previews; the structured `events[]` is free to carry richer\n// summaries with different truncation bounds (120 for JSON, 80 for strings).\n// ---------------------------------------------------------------------------\n\nfunction summarize(value: unknown): string {\n\tif (value == null) return \"null\";\n\tif (typeof value === \"string\") return truncate(value, 80);\n\tif (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n\tif (typeof value === \"bigint\") return String(value);\n\ttry {\n\t\tconst json = JSON.stringify(value);\n\t\treturn truncate(json, 120);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length > max ? `${s.slice(0, max - 1)}…` : s;\n}\n"],"mappings":"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","names":["node","filter","Graph","node","node","batch","defaultToOutput","Graph","node","batch","filter","Graph","Graph","batch"]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-N6MNJNHB.js";
4
4
 
5
5
  // src/base/composition/single-from-any.ts
6
- import { COMPLETE, ERROR } from "@graphrefly/pure-ts/core";
6
+ import { COMPLETE, ERROR, TEARDOWN } from "@graphrefly/pure-ts/core";
7
7
  import { fromAny } from "@graphrefly/pure-ts/extra";
8
8
  function singleFromAny(factory, opts = {}) {
9
9
  const keyFn = opts.keyFn ?? ((k) => String(k));
@@ -70,11 +70,12 @@ function singleNodeFromAny(factory, opts = {}) {
70
70
  if (existing) return existing;
71
71
  const node = fromAny(factory(key));
72
72
  inFlight.set(k, node);
73
- const unsub = node.subscribe((msgs) => {
73
+ let unsub;
74
+ unsub = node.subscribe((msgs) => {
74
75
  for (const m of msgs) {
75
- if (m[0] === ERROR || m[0] === COMPLETE) {
76
+ if (m[0] === ERROR || m[0] === COMPLETE || m[0] === TEARDOWN) {
76
77
  if (inFlight.get(k) === node) inFlight.delete(k);
77
- unsub();
78
+ unsub?.();
78
79
  return;
79
80
  }
80
81
  }
@@ -87,4 +88,4 @@ export {
87
88
  singleFromAny,
88
89
  singleNodeFromAny
89
90
  };
90
- //# sourceMappingURL=chunk-IOJDYUA7.js.map
91
+ //# sourceMappingURL=chunk-V46JWFGV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/base/composition/single-from-any.ts"],"sourcesContent":["/**\n * `singleFromAny` — keyed promise/Node de-duplication (\"singleflight\").\n *\n * Given a `factory: (key) => NodeInput<T>`, returns a callable that dedupes\n * concurrent invocations sharing the same key — all callers with the same\n * key while a request is in-flight receive the same `Promise<T>`. Once the\n * underlying source settles (DATA, ERROR, or COMPLETE), the cache entry is\n * cleared so the next call re-invokes the factory.\n *\n * This is the classic \"singleflight\" pattern from Go, generalised over the\n * library's `NodeInput<T>` bridge so callers can pass Promise-returning\n * factories, Node-returning factories, or plain value factories with\n * identical semantics.\n *\n * Use cases:\n * - `withReplayCache` cache-miss thundering-herd dedup\n * - Shared HTTP fetches keyed by URL\n * - Expensive compute keyed by request fingerprint\n *\n * @example\n * ```ts\n * const fetchUser = singleFromAny<string, User>((id) => fetch(`/users/${id}`).then(r => r.json()));\n * // Two concurrent callers with id=\"42\" → one underlying fetch, two Promises resolving to the same User.\n * const [a, b] = await Promise.all([fetchUser(\"42\"), fetchUser(\"42\")]);\n * ```\n *\n * @category extra\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { COMPLETE, ERROR, TEARDOWN } from \"@graphrefly/pure-ts/core\";\n// Import directly from the source sub-files (rather than the `./sources.js`\n// barrel) so the `single-from-any` module is NOT part of any cycle that runs\n// through `extra/sources/index.ts` — eager re-exports through the barrel were\n// observed to leave `firstValueFrom` / `keepalive` unresolved during nested\n// import chains under vite-node.\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../sources/settled.js\";\n\nexport interface SingleFromAnyOptions<K> {\n\t/**\n\t * Convert a typed key into a cache-string. Defaults to `String(key)`, which\n\t * works for primitive keys; callers with object keys should provide a\n\t * stable serializer (e.g., canonical JSON).\n\t */\n\tkeyFn?: (key: K) => string;\n}\n\n/**\n * Dedupe concurrent `factory(key)` invocations. Returns a bound callable.\n *\n * @param factory - Produces a `NodeInput<T>` for each unique key.\n * @param opts - Optional key-stringification.\n * @returns A function `(key: K) => Promise<T>` whose inflight results are shared per key.\n */\nexport function singleFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Promise<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Promise<T>>();\n\n\treturn (key: K): Promise<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst input = factory(key);\n\n\t\t// Resolve the NodeInput to a Promise<T>. Different input shapes need\n\t\t// different bridges — Promise/Node/AsyncIterable/Iterable/plain value.\n\t\tlet rawPromise: Promise<T>;\n\t\tif (input != null && typeof (input as PromiseLike<T>).then === \"function\") {\n\t\t\trawPromise = Promise.resolve(input as PromiseLike<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\t\"subscribe\" in (input as object) &&\n\t\t\t\"cache\" in (input as object)\n\t\t) {\n\t\t\t// Node: bridge via firstValueFrom.\n\t\t\trawPromise = firstValueFrom(input as Node<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\tSymbol.asyncIterator in (input as object)\n\t\t) {\n\t\t\t// AsyncIterable — take the first value, then close the iterator so\n\t\t\t// any owned resources (HTTP body, subscription, timer) are released.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as AsyncIterable<T>)[Symbol.asyncIterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty async iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\tawait iter.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else if (input != null && typeof input === \"object\" && Symbol.iterator in (input as object)) {\n\t\t\t// Iterable — take the first value, close the iterator.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as Iterable<T>)[Symbol.iterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\titer.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else {\n\t\t\t// Plain value.\n\t\t\trawPromise = Promise.resolve(input as T);\n\t\t}\n\n\t\t// Install the cache entry BEFORE attaching `.finally`. Otherwise a\n\t\t// sync-resolved Promise's finally microtask could run before the\n\t\t// `inFlight.set` below, leaving a stale entry installed afterwards.\n\t\t// We wrap in a holder whose reference we capture *before* chaining.\n\t\tlet tracked!: Promise<T>;\n\t\tconst cleanup = (): void => {\n\t\t\tif (inFlight.get(k) === tracked) inFlight.delete(k);\n\t\t};\n\t\ttracked = rawPromise.then(\n\t\t\t(v) => {\n\t\t\t\tcleanup();\n\t\t\t\treturn v;\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tcleanup();\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\t\tinFlight.set(k, tracked);\n\t\treturn tracked;\n\t};\n}\n\n/**\n * Reactive variant: returns a bound callable that hands out `Node<T>` values.\n * All concurrent callers with the same key during an in-flight source share\n * the same Node. The cache entry is evicted (so the next call re-invokes\n * `factory`) when the underlying source either:\n *\n * - **terminally settles** — `ERROR` or `COMPLETE`; or\n * - **tears down** — `TEARDOWN` (M8 fix). A DATA-only source (e.g. a\n * long-lived `state(...)`) never emits `ERROR`/`COMPLETE`, so without\n * the TEARDOWN arm a destroyed shared Node — plus this watcher\n * subscription — would be pinned in the `inFlight` Map forever. Evicting\n * on TEARDOWN bounds the entry's lifetime to the Node's own lifetime.\n *\n * DATA is NOT an eviction trigger — callers subscribing after the first\n * DATA still receive the shared Node (and push-on-subscribe per the spec's\n * cached-DATA contract). The Node stays shared while alive (the dedup\n * contract); only its death (terminal or teardown) releases the entry.\n *\n * Use when downstream wants reactive subscription (not a one-shot Promise).\n *\n * @category extra\n */\nexport function singleNodeFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Node<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Node<T>>();\n\n\treturn (key: K): Node<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst node = fromAny(factory(key));\n\t\tinFlight.set(k, node);\n\n\t\t// Evict on Node death — terminal settle (ERROR / COMPLETE) OR\n\t\t// TEARDOWN (M8). DATA is a value emission, not a lifecycle\n\t\t// transition; multi-emitting Nodes continue to share across\n\t\t// subscribers after the first value. The TEARDOWN arm is what\n\t\t// releases DATA-only `state(...)` sources, which never terminate.\n\t\t// `unsub` is hoisted (mirrors `singleFromAny`'s `let tracked!`): the\n\t\t// sink closes over it, and a `fromAny` source that synchronously\n\t\t// replays a cached terminal/TEARDOWN on subscribe would otherwise hit\n\t\t// `unsub` in its TDZ. In that sync-terminal case `unsub` is still\n\t\t// `undefined` when the sink runs — `unsub?.()` no-ops, but the\n\t\t// load-bearing `inFlight.delete(k)` eviction still runs and an\n\t\t// already-terminal node won't re-emit (the dangling sub is inert).\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === ERROR || m[0] === COMPLETE || m[0] === TEARDOWN) {\n\t\t\t\t\tif (inFlight.get(k) === node) inFlight.delete(k);\n\t\t\t\t\tunsub?.();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn node;\n\t};\n}\n"],"mappings":";;;;;AA8BA,SAAS,UAAU,OAAO,gBAAgB;AAM1C,SAAS,eAA+B;AAmBjC,SAAS,cACf,SACA,OAAgC,CAAC,GACR;AACzB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAwB;AAE7C,SAAO,CAAC,QAAuB;AAC9B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,QAAQ,QAAQ,GAAG;AAIzB,QAAI;AACJ,QAAI,SAAS,QAAQ,OAAQ,MAAyB,SAAS,YAAY;AAC1E,mBAAa,QAAQ,QAAQ,KAAuB;AAAA,IACrD,WACC,SAAS,QACT,OAAO,UAAU,YACjB,eAAgB,SAChB,WAAY,OACX;AAED,mBAAa,eAAe,KAAgB;AAAA,IAC7C,WACC,SAAS,QACT,OAAO,UAAU,YACjB,OAAO,iBAAkB,OACxB;AAGD,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAA2B,OAAO,aAAa,EAAE;AAC/D,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,MAAM,KAAK,KAAK;AACxC,cAAI,KAAM,OAAM,IAAI,MAAM,sDAAsD;AAChF,iBAAO;AAAA,QACR,UAAE;AACD,gBAAM,KAAK,SAAS;AAAA,QACrB;AAAA,MACD,GAAG;AAAA,IACJ,WAAW,SAAS,QAAQ,OAAO,UAAU,YAAY,OAAO,YAAa,OAAkB;AAE9F,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAAsB,OAAO,QAAQ,EAAE;AACrD,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,KAAK,KAAK;AAClC,cAAI,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC1E,iBAAO;AAAA,QACR,UAAE;AACD,eAAK,SAAS;AAAA,QACf;AAAA,MACD,GAAG;AAAA,IACJ,OAAO;AAEN,mBAAa,QAAQ,QAAQ,KAAU;AAAA,IACxC;AAMA,QAAI;AACJ,UAAM,UAAU,MAAY;AAC3B,UAAI,SAAS,IAAI,CAAC,MAAM,QAAS,UAAS,OAAO,CAAC;AAAA,IACnD;AACA,cAAU,WAAW;AAAA,MACpB,CAAC,MAAM;AACN,gBAAQ;AACR,eAAO;AAAA,MACR;AAAA,MACA,CAAC,MAAM;AACN,gBAAQ;AACR,cAAM;AAAA,MACP;AAAA,IACD;AACA,aAAS,IAAI,GAAG,OAAO;AACvB,WAAO;AAAA,EACR;AACD;AAwBO,SAAS,kBACf,SACA,OAAgC,CAAC,GACX;AACtB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAqB;AAE1C,SAAO,CAAC,QAAoB;AAC3B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,OAAO,QAAQ,QAAQ,GAAG,CAAC;AACjC,aAAS,IAAI,GAAG,IAAI;AAcpB,QAAI;AACJ,YAAQ,KAAK,UAAU,CAAC,SAAS;AAChC,iBAAW,KAAK,MAAM;AACrB,YAAI,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,MAAM,YAAY,EAAE,CAAC,MAAM,UAAU;AAC7D,cAAI,SAAS,IAAI,CAAC,MAAM,KAAM,UAAS,OAAO,CAAC;AAC/C,kBAAQ;AACR;AAAA,QACD;AAAA,MACD;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AACD;","names":[]}
@@ -4,13 +4,10 @@ import {
4
4
  fallback,
5
5
  rateLimiter,
6
6
  withBreaker
7
- } from "./chunk-T7SP3EYR.js";
7
+ } from "./chunk-T5URUIIY.js";
8
8
  import {
9
9
  withTimeout
10
10
  } from "./chunk-GUNIRPEJ.js";
11
- import {
12
- domainMeta
13
- } from "./chunk-FMPF42Q4.js";
14
11
  import {
15
12
  withStatus
16
13
  } from "./chunk-JA67ZQG2.js";
@@ -20,6 +17,9 @@ import {
20
17
  import {
21
18
  NS_PER_MS
22
19
  } from "./chunk-P5LBT622.js";
20
+ import {
21
+ domainMeta
22
+ } from "./chunk-FMPF42Q4.js";
23
23
 
24
24
  // src/presets/resilience/resilient-pipeline.ts
25
25
  import { ERROR, node, placeholderArgs } from "@graphrefly/pure-ts/core";
@@ -105,7 +105,6 @@ var ResilientPipelineGraph = class extends Graph {
105
105
  } else {
106
106
  const rateOpts = {
107
107
  ...opts.rateLimit,
108
- maxBuffer: opts.rateLimit.maxBuffer ?? Infinity,
109
108
  meta: domainMeta("resilient", "rate-limit")
110
109
  };
111
110
  const bundle = rateLimiter(current, rateOpts);
@@ -253,4 +252,4 @@ export {
253
252
  ResilientPipelineGraph,
254
253
  resilientPipeline
255
254
  };
256
- //# sourceMappingURL=chunk-WGDEBIP4.js.map
255
+ //# sourceMappingURL=chunk-X6ESZDR6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presets/resilience/resilient-pipeline.ts"],"sourcesContent":["/**\n * Resilience composition with correct nesting order (roadmap §9.0b — Tier 5.2 Wave-B rebuild).\n *\n * {@link resilientPipeline} composes the resilience primitives from\n * `extra/resilience/` in the canonical nesting order:\n *\n * ```text\n * rateLimit → budget → breaker → timeout → retry → fallback → status\n * ```\n *\n * Returns a {@link ResilientPipelineGraph} (Graph subclass) with mounted\n * intermediate nodes and per-layer status companions, replacing the prior\n * bundle return. Each intermediate is mounted under a stable name so\n * `pipeline.describe()` shows the resilience chain in topology snapshots,\n * mermaid renders, and `lens.health` aggregations.\n *\n * **Per-attempt timeout vs. retry ordering.** `timeout` is applied BEFORE\n * `retry` so each retry attempt resubscribes to a fresh deadline (per-attempt\n * semantics). If `timeout` wrapped `retry`, a single deadline would apply to\n * the entire retry chain — not what callers expect.\n *\n * **`breakerOnOpen` + `retry` interaction.** With `breakerOnOpen: \"error\"` AND\n * `retry`, retry sees `CircuitOpenError` and resubscribes; the next attempt\n * very likely also breaker-open → another error → retry burns its budget\n * against an open circuit. Either set retry's `backoff` long enough for the\n * breaker reset window OR keep the default `breakerOnOpen: \"skip\"` (emits\n * RESOLVED when open; downstream drops the beat without retry firing).\n *\n * **Reactive options (switchMap rebuild).** Every primitive option accepts a\n * `T | Node<T>` (precedent-aligned with `FallbackInput<T>`). When the caller\n * supplies a static value, the layer is built once at construction. When the\n * caller supplies a `Node<T>`, the pipeline subscribes via `switchMap` and\n * **rebuilds the layer on every option emission** — the chain stalls until\n * the option Node emits its first DATA. Each rebuild creates a fresh\n * primitive instance, so internal state is lost (rate-limiter pending buffer,\n * breaker failure count, retry attempt count, in-flight timeout). Per-layer\n * **companion Nodes** (`droppedCount`, `rateLimitState`, `breakerState`) are\n * therefore exposed ONLY for the static-options path. Primitive-side widening\n * (filed in `docs/optimizations.md` under \"Tier 5.2 follow-up — primitive-side\n * reactive-options widening\") will preserve internal state once it lands and\n * the pipeline will trivially forward Node-form options to the primitive.\n *\n * @module\n */\nimport { ERROR, type Node, node, placeholderArgs } from \"@graphrefly/pure-ts/core\";\nimport { switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { NS_PER_MS } from \"../../base/resilience/backoff.js\";\nimport {\n\ttype BreakerState,\n\ttype BudgetConstraint,\n\tbudgetGate,\n\ttype CircuitBreakerOptions,\n\tcircuitBreaker,\n\ttype FallbackInput,\n\tfallback,\n\ttype NodeOrValue,\n\ttype RateLimiterOptions,\n\ttype RateLimiterState,\n\ttype RetryOptions,\n\ttype RetryState,\n\trateLimiter,\n\tretry,\n\ttype StatusValue,\n\ttype TimeoutOptions,\n\ttype TimeoutState,\n\twithBreaker,\n\twithStatus,\n\twithTimeout,\n} from \"../../utils/resilience/index.js\";\n\n// ---------------------------------------------------------------------------\n// Reactive-option helpers\n// ---------------------------------------------------------------------------\n\n/**\n * `T | Node<T>` for primitive options — precedent-aligned with\n * {@link FallbackInput} and `policyGate.policies`. When the caller supplies a\n * static value, the layer is built once at construction. When the caller\n * supplies a `Node<T>`, the pipeline subscribes via {@link switchMap}: the\n * layer is rebuilt on every option emission. **State-loss caveat:** each\n * rebuild creates a fresh primitive instance — `rateLimiter` loses its pending\n * buffer, `circuitBreaker` resets failure count, `retry` resets attempt\n * count, `timeout` cancels in-flight deadline. This is the documented\n * switchMap-pattern semantics; primitive-side widening (filed in\n * `docs/optimizations.md`) will preserve internal state once it lands and the\n * pipeline can forward Node-form options directly.\n *\n * Per-layer **companion Nodes** (`droppedCount`, `rateLimitState`,\n * `breakerState`) are exposed only for the static-options path — Node-form\n * leaves them as `undefined` because each rebuild creates new companion\n * instances and a switchMap-mirrored companion would track only the latest\n * bundle. Callers needing both reactive options AND companions wait for\n * primitive-side widening.\n */\n// NodeOrValue re-imported from utils/resilience (same type, avoid barrel duplicate).\n\nfunction isNode<T>(x: unknown): x is Node<T> {\n\treturn (\n\t\ttypeof x === \"object\" && x !== null && \"subscribe\" in (x as object) && \"down\" in (x as object)\n\t);\n}\n\n/**\n * Validation shared by the static and reactive timeout paths. The reactive\n * path runs this inside the `switchMap` projection so an emitted bad value\n * surfaces as a thrown error at projection time (the consuming subscribe\n * routes it through the reactive ERROR channel rather than crashing\n * construction).\n */\nfunction assertTimeoutMsValid(ms: number): void {\n\tif (ms <= 0) throw new RangeError(\"timeoutMs must be > 0\");\n\t// Guard against `timeoutMs * NS_PER_MS` overflowing\n\t// `Number.MAX_SAFE_INTEGER` (~9.007e15). 9_000_000 ms ≈ 2.5 hours is a\n\t// sane upper bound; callers needing longer deadlines should express them\n\t// at the primitive level.\n\tif (ms > 9_000_000) {\n\t\tthrow new RangeError(\n\t\t\t\"timeoutMs must be <= 9_000_000 (≈2.5h) to stay within safe ns arithmetic\",\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link resilientPipeline}. Every layer is optional — omit a\n * field and that layer is skipped.\n *\n * Reactive (`Node<T>`) forms are accepted everywhere a primitive value would\n * fit; the pipeline subscribes via `switchMap` and rebuilds the layer on each\n * emission. See module JSDoc for the rebuild semantics + state-loss caveat.\n */\nexport interface ResilientPipelineOptions<T> {\n\t/**\n\t * Admission control — at most `maxEvents` `DATA` per `windowNs`. See\n\t * {@link rateLimiter}.\n\t *\n\t * **`maxBuffer` is required in BOTH the value form and the Node form** —\n\t * forwarded directly to {@link rateLimiter}, which is fail-loud (D4): an\n\t * un-seeded opts Node, or a value/cached value omitting `maxBuffer`, throws\n\t * `RangeError` at construction. Pass a finite positive integer for a bounded\n\t * queue, or the literal `Infinity` to explicitly opt in to unbounded (the\n\t * silent bounded/unbounded lock is the most common rateLimiter\n\t * mis-configuration). There is **no value-vs-Node asymmetry and no legacy\n\t * `?? Infinity` convenience injection** — both forms match the primitive's\n\t * fail-loud contract (F-B-root, 2026-05-18 smell sweep).\n\t */\n\trateLimit?: NodeOrValue<RateLimiterOptions>;\n\t/** Cost/constraint gate. See {@link budgetGate}. */\n\tbudget?: NodeOrValue<ReadonlyArray<BudgetConstraint>>;\n\t/** Circuit breaker — fail-fast when the downstream resource is unhealthy. See {@link circuitBreaker}. */\n\tbreaker?: NodeOrValue<CircuitBreakerOptions>;\n\t/**\n\t * Behavior when the breaker is open:\n\t * - `\"skip\"` (default) — emit `RESOLVED` (lets downstream drop the beat).\n\t * - `\"error\"` — emit a `CircuitOpenError` so `retry` / `fallback` can react.\n\t * See module JSDoc for the retry-budget burn caveat.\n\t *\n\t * Static (configuration-only — no reactive form).\n\t */\n\tbreakerOnOpen?: \"skip\" | \"error\";\n\t/** Retry policy on terminal `ERROR`. See {@link retry}. */\n\tretry?: NodeOrValue<RetryOptions>;\n\t/**\n\t * Per-attempt deadline in milliseconds. Converted to ns internally. Omit\n\t * to skip the timeout wrap.\n\t *\n\t * Specified in ms (not ns) because callers consistently think in\n\t * millisecond deadlines; the underlying {@link timeout} primitive takes ns\n\t * internally.\n\t */\n\ttimeoutMs?: NodeOrValue<number>;\n\t/** Final fallback value emitted on terminal `ERROR` after retry exhausts. See {@link fallback}. */\n\tfallback?: FallbackInput<T>;\n\t/**\n\t * Initial status reported by the status node. Default `\"pending\"`. Static.\n\t */\n\tinitialStatus?: StatusValue;\n\t/** Wrapper graph name. Default `\"resilient_pipeline\"`. */\n\tname?: string;\n\t/** Wrapper graph options. */\n\tgraph?: GraphOptions;\n}\n\n// ---------------------------------------------------------------------------\n// ResilientPipelineGraph\n// ---------------------------------------------------------------------------\n\n/**\n * Graph subclass returned by {@link resilientPipeline}. Mounts each\n * configured intermediate under a stable name and exposes per-layer status\n * companions.\n *\n * @category patterns\n */\nexport class ResilientPipelineGraph<T> extends Graph {\n\t/**\n\t * Final resilient node — subscribe to this for `DATA` emissions.\n\t *\n\t * Named `output` (not `node`) because `Graph.node(name)` already names the\n\t * path-resolution method on the base class; a `readonly node` field would\n\t * shadow it.\n\t */\n\treadonly output: Node<T>;\n\t/** Live status: `\"pending\" | \"running\" | \"completed\" | \"errored\"`. */\n\treadonly status: Node<StatusValue>;\n\t/**\n\t * Last error payload, or `null` when not errored.\n\t *\n\t * Named `lastError` (not `error`) because `Graph.error(name, err)` already\n\t * names a method on the base class.\n\t */\n\treadonly lastError: Node<unknown | null>;\n\t/** Breaker state when `opts.breaker` is provided; `undefined` otherwise. */\n\treadonly breakerState: Node<BreakerState> | undefined;\n\t/**\n\t * Timeout state companion when `opts.timeoutMs` is supplied as a\n\t * `Node<Partial<TimeoutOptions>>`-like form; `undefined` otherwise\n\t * (DS-13.5.B forwarding contract — Node-form opts skip the switchMap\n\t * rebuild and lift the primitive's lifecycle companion onto the\n\t * pipeline bundle).\n\t */\n\treadonly timeoutState: Node<TimeoutState> | undefined;\n\t/**\n\t * Retry state companion when `opts.retry` is supplied as a\n\t * `Node<RetryOptions>`-like form; `undefined` otherwise\n\t * (DS-13.5.B forwarding contract).\n\t */\n\treadonly retryState: Node<RetryState> | undefined;\n\t/**\n\t * Drop-counter when `opts.rateLimit` is provided; `undefined` otherwise.\n\t *\n\t * **Lifetime note:** `droppedCount` retains its final value through\n\t * terminal (`COMPLETE` / `ERROR` / `TEARDOWN`); the underlying counter\n\t * resets to `0` only at the next subscription cycle.\n\t */\n\treadonly droppedCount: Node<number> | undefined;\n\t/**\n\t * Combined rate-limit state when `opts.rateLimit` is provided; `undefined`\n\t * otherwise. Same lifecycle as {@link droppedCount} but exposes\n\t * `pendingCount` and `paused` alongside the drop counter for richer\n\t * backpressure observability (Tier 5.2 D7).\n\t */\n\treadonly rateLimitState: Node<RateLimiterState> | undefined;\n\n\tconstructor(source: Node<T>, opts: ResilientPipelineOptions<T> = {}) {\n\t\tsuper(opts.name ?? \"resilient_pipeline\", opts.graph);\n\n\t\tlet current: Node<T> = source;\n\t\tlet droppedCount: Node<number> | undefined;\n\t\tlet rateLimitState: Node<RateLimiterState> | undefined;\n\t\tlet breakerState: Node<BreakerState> | undefined;\n\t\tlet timeoutState: Node<TimeoutState> | undefined;\n\t\tlet retryState: Node<RetryState> | undefined;\n\n\t\t// 1. Admission control — cheapest to drop / queue before any other work.\n\t\tif (opts.rateLimit != null) {\n\t\t\tif (isNode<RateLimiterOptions>(opts.rateLimit)) {\n\t\t\t\t// DS-13.5.B forwarding: rateLimiter primitive is widened to\n\t\t\t\t// accept `NodeOrValue<RateLimiterOptions>` directly. Forward\n\t\t\t\t// the Node form to preserve internal state (pending buffer,\n\t\t\t\t// dropped counter) across opts swaps. Companion nodes\n\t\t\t\t// (droppedCount / rateLimitState) lift onto the pipeline\n\t\t\t\t// bundle. The pre-DS-13.5.B switchMap-rebuild path is gone.\n\t\t\t\tconst bundle = rateLimiter(current, opts.rateLimit);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tdroppedCount = bundle.droppedCount;\n\t\t\t\trateLimitState = bundle.rateLimitState;\n\t\t\t\tthis.add(current, { name: \"rateLimited\" });\n\t\t\t\tthis.add(droppedCount, { name: \"droppedCount\" });\n\t\t\t\tthis.add(rateLimitState, { name: \"rateLimitState\" });\n\t\t\t} else {\n\t\t\t\t// F-B-root (2026-05-18 smell sweep): no `?? Infinity` injection.\n\t\t\t\t// `maxBuffer` is required by the type and validated fail-loud by\n\t\t\t\t// `rateLimiter` (D4) — `Infinity` is an explicit unbounded opt-in.\n\t\t\t\tconst rateOpts: RateLimiterOptions = {\n\t\t\t\t\t...opts.rateLimit,\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"rate-limit\"),\n\t\t\t\t};\n\t\t\t\tconst bundle = rateLimiter(current, rateOpts);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tdroppedCount = bundle.droppedCount;\n\t\t\t\trateLimitState = bundle.rateLimitState;\n\t\t\t\tthis.add(current, { name: \"rateLimited\" });\n\t\t\t\tthis.add(droppedCount, { name: \"droppedCount\" });\n\t\t\t\tthis.add(rateLimitState, { name: \"rateLimitState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 2. Budget — block when constraints are exhausted. Also cheap (no I/O).\n\t\tif (opts.budget != null) {\n\t\t\tif (isNode<ReadonlyArray<BudgetConstraint>>(opts.budget)) {\n\t\t\t\tconst inputForLayer = current;\n\t\t\t\tconst reactiveBudget = opts.budget;\n\t\t\t\tcurrent = switchMap(reactiveBudget, (constraints) =>\n\t\t\t\t\tconstraints.length > 0\n\t\t\t\t\t\t? budgetGate(inputForLayer, constraints, {\n\t\t\t\t\t\t\t\tmeta: domainMeta(\"resilient\", \"budget\"),\n\t\t\t\t\t\t\t}).node\n\t\t\t\t\t\t: inputForLayer,\n\t\t\t\t);\n\t\t\t\tthis.add(current, { name: \"budgetGated\" });\n\t\t\t} else if (opts.budget.length > 0) {\n\t\t\t\tcurrent = budgetGate(current, opts.budget, {\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"budget\"),\n\t\t\t\t}).node;\n\t\t\t\tthis.add(current, { name: \"budgetGated\" });\n\t\t\t}\n\t\t}\n\n\t\t// 3. Breaker — skip the resource when unhealthy (fail-fast before retry wastes time).\n\t\tif (opts.breaker != null) {\n\t\t\t// DS-13.5.B forwarding: circuitBreaker primitive accepts\n\t\t\t// `NodeOrValue<CircuitBreakerOptions>` directly. Pass the Node\n\t\t\t// form straight through so internal state (`_state`,\n\t\t\t// `_failureCount`, `_openCycle`, …) is preserved across opts\n\t\t\t// swaps. Companion `breakerState` lifts onto the pipeline\n\t\t\t// bundle in both static and Node-form paths.\n\t\t\tconst breaker = circuitBreaker(opts.breaker as NodeOrValue<CircuitBreakerOptions>);\n\t\t\tconst onOpen = opts.breakerOnOpen ?? \"skip\";\n\t\t\tconst wrapped = withBreaker<T>(breaker, {\n\t\t\t\tonOpen,\n\t\t\t\tmeta: domainMeta(\"resilient\", \"breaker\"),\n\t\t\t})(current);\n\t\t\tcurrent = wrapped.node;\n\t\t\tbreakerState = wrapped.breakerState;\n\t\t\tthis.add(current, { name: \"breakerWrapped\" });\n\t\t\tthis.add(breakerState, { name: \"breakerState\" });\n\t\t}\n\n\t\t// 4. Timeout — per-attempt deadline. Applied BEFORE retry so each retry\n\t\t// resubscribes to a fresh timeout. Swapping the order (timeout\n\t\t// OUTSIDE retry) would apply one global deadline to the entire\n\t\t// retry chain — not what callers expect for \"per-attempt timeout.\"\n\t\tif (opts.timeoutMs != null) {\n\t\t\tif (isNode<number>(opts.timeoutMs)) {\n\t\t\t\t// DS-13.5.B forwarding: build a derived `Node<{ns}>` from\n\t\t\t\t// the caller's `Node<number>` (ms) and pass directly to the\n\t\t\t\t// widened timeout primitive. State preservation (in-flight\n\t\t\t\t// deadline) is handled inside timeout's reactive opts path.\n\t\t\t\t// Companion `timeoutState` lifts onto the pipeline bundle.\n\t\t\t\tconst reactiveTimeoutMs = opts.timeoutMs;\n\t\t\t\tconst initialMs = reactiveTimeoutMs.cache as number | undefined;\n\t\t\t\t// QA A5 (2026-05-03): assert validity of the cached initial\n\t\t\t\t// value at construction so a bad cache fails loud at wire\n\t\t\t\t// time, not silently at first emit. Reactive emits with\n\t\t\t\t// invalid values flow through the producer body's ERROR\n\t\t\t\t// channel rather than throwing into the host scheduler.\n\t\t\t\tif (initialMs !== undefined) assertTimeoutMsValid(initialMs);\n\t\t\t\tconst optsBridge = node<Partial<TimeoutOptions>>(\n\t\t\t\t\t[reactiveTimeoutMs as Node<unknown>],\n\t\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst ms = data[0] as number | undefined;\n\t\t\t\t\t\tif (ms === undefined) return;\n\t\t\t\t\t\t// QA A5: route validation failures through the\n\t\t\t\t\t\t// reactive ERROR channel — sync `throw` inside a\n\t\t\t\t\t\t// producer body corrupts the host scheduler's\n\t\t\t\t\t\t// wave dispatch (mirrors timeout primitive's\n\t\t\t\t\t\t// \"sync throw would corrupt the host scheduler\"\n\t\t\t\t\t\t// rationale).\n\t\t\t\t\t\tif (typeof ms !== \"number\" || !Number.isFinite(ms) || ms <= 0 || ms > 9_000_000) {\n\t\t\t\t\t\t\tactions.down([\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\tERROR,\n\t\t\t\t\t\t\t\t\tnew RangeError(\n\t\t\t\t\t\t\t\t\t\t`resilientPipeline: timeoutMs reactive emit invalid (${ms}); must be > 0 and <= 9_000_000.`,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactions.emit({ ns: ms * NS_PER_MS });\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\t\tname: \"timeoutOptsBridge\",\n\t\t\t\t\t\t...(initialMs !== undefined\n\t\t\t\t\t\t\t? { initial: { ns: initialMs * NS_PER_MS } as Partial<TimeoutOptions> }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\t// QA A5: register the bridge on the pipeline graph so\n\t\t\t\t// describe() walks see the full topology (dry-run /\n\t\t\t\t// real-run equivalence per CLAUDE.md).\n\t\t\t\tthis.add(optsBridge, { name: \"timeoutOptsBridge\" });\n\t\t\t\tconst bundle = withTimeout(current, optsBridge, {\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"timeout\"),\n\t\t\t\t});\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\ttimeoutState = bundle.timeoutState;\n\t\t\t\tthis.add(current, { name: \"timeoutWrapped\" });\n\t\t\t\tthis.add(timeoutState, { name: \"timeoutState\" });\n\t\t\t} else {\n\t\t\t\tassertTimeoutMsValid(opts.timeoutMs);\n\t\t\t\tconst bundle = withTimeout(\n\t\t\t\t\tcurrent,\n\t\t\t\t\t{ ns: opts.timeoutMs * NS_PER_MS },\n\t\t\t\t\t{\n\t\t\t\t\t\tmeta: domainMeta(\"resilient\", \"timeout\"),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\ttimeoutState = bundle.timeoutState;\n\t\t\t\tthis.add(current, { name: \"timeoutWrapped\" });\n\t\t\t\tthis.add(timeoutState, { name: \"timeoutState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 5. Retry — resubscribe on `ERROR` up to `count` times. Wraps timeout\n\t\t// so each retry gets its own fresh deadline.\n\t\tif (opts.retry != null) {\n\t\t\t// DS-13.5.B forwarding: retry primitive accepts\n\t\t\t// `NodeOrValue<RetryOptions>` directly. Forward Node form so\n\t\t\t// `attempt` / `prevDelay` / in-flight timer survive opts swaps.\n\t\t\t// Companion `retryState` lifts onto the pipeline bundle.\n\t\t\tif (isNode<RetryOptions>(opts.retry)) {\n\t\t\t\tconst bundle = retry(current, opts.retry as NodeOrValue<RetryOptions>);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tretryState = bundle.retryState;\n\t\t\t\tthis.add(current, { name: \"retryWrapped\" });\n\t\t\t\tthis.add(retryState, { name: \"retryState\" });\n\t\t\t} else {\n\t\t\t\tconst bundle = retry(current, {\n\t\t\t\t\t...opts.retry,\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"retry\"),\n\t\t\t\t});\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tretryState = bundle.retryState;\n\t\t\t\tthis.add(current, { name: \"retryWrapped\" });\n\t\t\t\tthis.add(retryState, { name: \"retryState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 6. Fallback — last resort after retry+timeout exhaust. Guard\n\t\t// `opts.fallback !== undefined` so `null` is a valid fallback.\n\t\tif (opts.fallback !== undefined) {\n\t\t\tcurrent = fallback(current, opts.fallback, {\n\t\t\t\tmeta: domainMeta(\"resilient\", \"fallback\"),\n\t\t\t});\n\t\t\tthis.add(current, { name: \"fallbackWrapped\" });\n\t\t}\n\n\t\t// 7. Status wrapping — observability. Always last so it sees the final shape.\n\t\tconst statusBundle = withStatus(current, {\n\t\t\tinitialStatus: opts.initialStatus ?? \"pending\",\n\t\t\tmeta: domainMeta(\"resilient\", \"status\"),\n\t\t});\n\n\t\tthis.output = statusBundle.node;\n\t\tthis.status = statusBundle.status;\n\t\tthis.lastError = statusBundle.error;\n\t\tthis.breakerState = breakerState;\n\t\tthis.droppedCount = droppedCount;\n\t\tthis.rateLimitState = rateLimitState;\n\t\tthis.timeoutState = timeoutState;\n\t\tthis.retryState = retryState;\n\n\t\t// Mount the externally-visible top-level entries by name. Each carries\n\t\t// its own factoryTag meta from the underlying primitive (`withStatus`\n\t\t// for `output`/`status`/`lastError`); domain-level provenance lives on\n\t\t// the Graph itself via the `tagFactory(\"resilientPipeline\", ...)` call\n\t\t// in the public factory below. The mount names use `output` /\n\t\t// `lastError` to match the property names — the previous `node` /\n\t\t// `error` clashed with `Graph.node(name)` / `Graph.error(name, err)`.\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.add(this.status, { name: \"status\" });\n\t\tthis.add(this.lastError, { name: \"lastError\" });\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Compose a resilient pipeline around `source` in the canonical nesting\n * order — `rateLimit → budget → breaker → timeout → retry → fallback → status`.\n * Omit any option to skip that layer.\n *\n * Returns a {@link ResilientPipelineGraph} (Graph subclass) —\n * `pipeline.output` is the externally visible final node; `pipeline.status`\n * / `pipeline.lastError` / `pipeline.breakerState` / `pipeline.droppedCount`\n * are the per-layer companions. Call `pipeline.describe()` to see the\n * mounted intermediates; compose with {@link graphLens}'s `health` for\n * aggregate status.\n *\n * **Naming note:** `output` and `lastError` (not `node` / `error`) avoid\n * clashes with `Graph.node(name)` and `Graph.error(name, err)` on the base\n * class.\n *\n * @param source - Upstream node to wrap.\n * @param opts - See {@link ResilientPipelineOptions}. All fields optional.\n *\n * @example\n * ```ts\n * const safeFetch = resilientPipeline(fetchNode, {\n * rateLimit: { maxEvents: 10, windowNs: NS_PER_SEC, maxBuffer: 100 },\n * breaker: { failureThreshold: 5 },\n * retry: { count: 3, backoff: \"exponential\" },\n * timeoutMs: 10_000,\n * fallback: null,\n * });\n * safeFetch.output.subscribe(msgs => console.log(msgs));\n * safeFetch.status.subscribe(msgs => console.log(msgs));\n * graphSpecToAscii(safeFetch.describe()); // visualize the chain\n * ```\n *\n * @category patterns\n */\nexport function resilientPipeline<T>(\n\tsource: Node<T>,\n\topts: ResilientPipelineOptions<T> = {},\n): ResilientPipelineGraph<T> {\n\tconst g = new ResilientPipelineGraph<T>(source, opts);\n\t// Self-tag for `graph.describe()` factory provenance (Phase 2.5 DG1=B).\n\t// `placeholderArgs` substitutes Node-typed and function-typed fields with\n\t// `\"<Node>\"` / `\"<function>\"` so `factoryArgs` stays JSON-serializable.\n\tg.tagFactory(\"resilientPipeline\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\treturn g;\n}\n\n// Tag the underlying status / error / breaker / dropped companions with a\n// best-effort factoryTag too via the wrapper class's meta — already covered\n// by `domainMeta(\"resilient\", kind)` on the mounted nodes.\n\n// Tier 9.1 γ-form: this module now lives inside `extra/resilience/`, so the\n// underlying primitive option types are already exported from the same barrel\n// (`./index.js`). The previous re-exports of `factoryTag` / `placeholderArgs` /\n// `NS_PER_MS` / `NS_PER_SEC` / option types were a workaround for the prior\n// `patterns/resilient-pipeline/` folder location and are now redundant.\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAS,OAAkB,MAAM,uBAAuB;AACxD,SAAS,iBAAiB;AAC1B,SAAS,aAAgC;AAoDzC,SAAS,OAAU,GAA0B;AAC5C,SACC,OAAO,MAAM,YAAY,MAAM,QAAQ,eAAgB,KAAgB,UAAW;AAEpF;AASA,SAAS,qBAAqB,IAAkB;AAC/C,MAAI,MAAM,EAAG,OAAM,IAAI,WAAW,uBAAuB;AAKzD,MAAI,KAAK,KAAW;AACnB,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACD;AA6EO,IAAM,yBAAN,cAAwC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3C;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,EAET,YAAY,QAAiB,OAAoC,CAAC,GAAG;AACpE,UAAM,KAAK,QAAQ,sBAAsB,KAAK,KAAK;AAEnD,QAAI,UAAmB;AACvB,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI;AAGJ,QAAI,KAAK,aAAa,MAAM;AAC3B,UAAI,OAA2B,KAAK,SAAS,GAAG;AAO/C,cAAM,SAAS,YAAY,SAAS,KAAK,SAAS;AAClD,kBAAU,OAAO;AACjB,uBAAe,OAAO;AACtB,yBAAiB,OAAO;AACxB,aAAK,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,aAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,aAAK,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAAA,MACpD,OAAO;AAIN,cAAM,WAA+B;AAAA,UACpC,GAAG,KAAK;AAAA,UACR,MAAM,WAAW,aAAa,YAAY;AAAA,QAC3C;AACA,cAAM,SAAS,YAAY,SAAS,QAAQ;AAC5C,kBAAU,OAAO;AACjB,uBAAe,OAAO;AACtB,yBAAiB,OAAO;AACxB,aAAK,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,aAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,aAAK,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAAA,MACpD;AAAA,IACD;AAGA,QAAI,KAAK,UAAU,MAAM;AACxB,UAAI,OAAwC,KAAK,MAAM,GAAG;AACzD,cAAM,gBAAgB;AACtB,cAAM,iBAAiB,KAAK;AAC5B,kBAAU;AAAA,UAAU;AAAA,UAAgB,CAAC,gBACpC,YAAY,SAAS,IAClB,WAAW,eAAe,aAAa;AAAA,YACvC,MAAM,WAAW,aAAa,QAAQ;AAAA,UACvC,CAAC,EAAE,OACF;AAAA,QACJ;AACA,aAAK,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AAAA,MAC1C,WAAW,KAAK,OAAO,SAAS,GAAG;AAClC,kBAAU,WAAW,SAAS,KAAK,QAAQ;AAAA,UAC1C,MAAM,WAAW,aAAa,QAAQ;AAAA,QACvC,CAAC,EAAE;AACH,aAAK,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC;AAAA,MAC1C;AAAA,IACD;AAGA,QAAI,KAAK,WAAW,MAAM;AAOzB,YAAM,UAAU,eAAe,KAAK,OAA6C;AACjF,YAAM,SAAS,KAAK,iBAAiB;AACrC,YAAM,UAAU,YAAe,SAAS;AAAA,QACvC;AAAA,QACA,MAAM,WAAW,aAAa,SAAS;AAAA,MACxC,CAAC,EAAE,OAAO;AACV,gBAAU,QAAQ;AAClB,qBAAe,QAAQ;AACvB,WAAK,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,WAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAAA,IAChD;AAMA,QAAI,KAAK,aAAa,MAAM;AAC3B,UAAI,OAAe,KAAK,SAAS,GAAG;AAMnC,cAAM,oBAAoB,KAAK;AAC/B,cAAM,YAAY,kBAAkB;AAMpC,YAAI,cAAc,OAAW,sBAAqB,SAAS;AAC3D,cAAM,aAAa;AAAA,UAClB,CAAC,iBAAkC;AAAA,UACnC,CAAC,WAAW,SAAS,QAAQ;AAC5B,kBAAM,OAAO,UAAU;AAAA,cAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,YACtD;AACA,kBAAM,KAAK,KAAK,CAAC;AACjB,gBAAI,OAAO,OAAW;AAOtB,gBAAI,OAAO,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,KAAK,MAAM,KAAK,KAAK,KAAW;AAChF,sBAAQ,KAAK;AAAA,gBACZ;AAAA,kBACC;AAAA,kBACA,IAAI;AAAA,oBACH,uDAAuD,EAAE;AAAA,kBAC1D;AAAA,gBACD;AAAA,cACD,CAAC;AACD;AAAA,YACD;AACA,oBAAQ,KAAK,EAAE,IAAI,KAAK,UAAU,CAAC;AAAA,UACpC;AAAA,UACA;AAAA,YACC,cAAc;AAAA,YACd,MAAM;AAAA,YACN,GAAI,cAAc,SACf,EAAE,SAAS,EAAE,IAAI,YAAY,UAAU,EAA6B,IACpE,CAAC;AAAA,UACL;AAAA,QACD;AAIA,aAAK,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,cAAM,SAAS,YAAY,SAAS,YAAY;AAAA,UAC/C,MAAM,WAAW,aAAa,SAAS;AAAA,QACxC,CAAC;AACD,kBAAU,OAAO;AACjB,uBAAe,OAAO;AACtB,aAAK,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,aAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAAA,MAChD,OAAO;AACN,6BAAqB,KAAK,SAAS;AACnC,cAAM,SAAS;AAAA,UACd;AAAA,UACA,EAAE,IAAI,KAAK,YAAY,UAAU;AAAA,UACjC;AAAA,YACC,MAAM,WAAW,aAAa,SAAS;AAAA,UACxC;AAAA,QACD;AACA,kBAAU,OAAO;AACjB,uBAAe,OAAO;AACtB,aAAK,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,aAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAAA,MAChD;AAAA,IACD;AAIA,QAAI,KAAK,SAAS,MAAM;AAKvB,UAAI,OAAqB,KAAK,KAAK,GAAG;AACrC,cAAM,SAAS,MAAM,SAAS,KAAK,KAAkC;AACrE,kBAAU,OAAO;AACjB,qBAAa,OAAO;AACpB,aAAK,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,aAAK,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAAA,MAC5C,OAAO;AACN,cAAM,SAAS,MAAM,SAAS;AAAA,UAC7B,GAAG,KAAK;AAAA,UACR,MAAM,WAAW,aAAa,OAAO;AAAA,QACtC,CAAC;AACD,kBAAU,OAAO;AACjB,qBAAa,OAAO;AACpB,aAAK,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,aAAK,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAAA,MAC5C;AAAA,IACD;AAIA,QAAI,KAAK,aAAa,QAAW;AAChC,gBAAU,SAAS,SAAS,KAAK,UAAU;AAAA,QAC1C,MAAM,WAAW,aAAa,UAAU;AAAA,MACzC,CAAC;AACD,WAAK,IAAI,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAAA,IAC9C;AAGA,UAAM,eAAe,WAAW,SAAS;AAAA,MACxC,eAAe,KAAK,iBAAiB;AAAA,MACrC,MAAM,WAAW,aAAa,QAAQ;AAAA,IACvC,CAAC;AAED,SAAK,SAAS,aAAa;AAC3B,SAAK,SAAS,aAAa;AAC3B,SAAK,YAAY,aAAa;AAC9B,SAAK,eAAe;AACpB,SAAK,eAAe;AACpB,SAAK,iBAAiB;AACtB,SAAK,eAAe;AACpB,SAAK,aAAa;AASlB,SAAK,IAAI,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,SAAK,IAAI,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,SAAK,IAAI,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAAA,EAC/C;AACD;AAyCO,SAAS,kBACf,QACA,OAAoC,CAAC,GACT;AAC5B,QAAM,IAAI,IAAI,uBAA0B,QAAQ,IAAI;AAIpD,IAAE,WAAW,qBAAqB,gBAAgB,IAA0C,CAAC;AAC7F,SAAO;AACR;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  singleFromAny
3
- } from "./chunk-IOJDYUA7.js";
3
+ } from "./chunk-V46JWFGV.js";
4
4
  import {
5
5
  firstValueFrom
6
6
  } from "./chunk-N6MNJNHB.js";
@@ -527,4 +527,4 @@ export {
527
527
  FallbackMissError,
528
528
  fallbackAdapter
529
529
  };
530
- //# sourceMappingURL=chunk-N65E26UL.js.map
530
+ //# sourceMappingURL=chunk-XEWV254I.js.map