@graphrefly/ts 0.0.0 → 0.0.1

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 (307) hide show
  1. package/README.md +135 -0
  2. package/dist/adapters/index.cjs +105 -66
  3. package/dist/adapters/index.cjs.map +1 -1
  4. package/dist/adapters/index.d.cts +11 -136
  5. package/dist/adapters/index.d.ts +11 -136
  6. package/dist/adapters/index.js +27 -225
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/adapters/observe-storage.d.cts +4 -4
  9. package/dist/adapters/observe-storage.d.ts +4 -4
  10. package/dist/adapters/observe-storage.js +1 -0
  11. package/dist/adapters/observe-storage.js.map +1 -1
  12. package/dist/adapters/react.cjs +166 -0
  13. package/dist/adapters/react.cjs.map +1 -0
  14. package/dist/adapters/react.d.cts +31 -0
  15. package/dist/adapters/react.d.ts +31 -0
  16. package/dist/adapters/react.js +51 -0
  17. package/dist/adapters/react.js.map +1 -0
  18. package/dist/adapters/solid.cjs +157 -0
  19. package/dist/adapters/solid.cjs.map +1 -0
  20. package/dist/adapters/solid.d.cts +26 -0
  21. package/dist/adapters/solid.d.ts +26 -0
  22. package/dist/adapters/solid.js +48 -0
  23. package/dist/adapters/solid.js.map +1 -0
  24. package/dist/adapters/svelte.cjs +148 -0
  25. package/dist/adapters/svelte.cjs.map +1 -0
  26. package/dist/adapters/svelte.d.cts +31 -0
  27. package/dist/adapters/svelte.d.ts +31 -0
  28. package/dist/adapters/svelte.js +46 -0
  29. package/dist/adapters/svelte.js.map +1 -0
  30. package/dist/adapters/vue.cjs +155 -0
  31. package/dist/adapters/vue.cjs.map +1 -0
  32. package/dist/adapters/vue.d.cts +26 -0
  33. package/dist/adapters/vue.d.ts +26 -0
  34. package/dist/adapters/vue.js +46 -0
  35. package/dist/adapters/vue.js.map +1 -0
  36. package/dist/agent-runtime-BesGDZcB.d.ts +555 -0
  37. package/dist/agent-runtime-DZTJ3C-p.d.cts +555 -0
  38. package/dist/agentic-memory-BmRCvh0d.d.ts +517 -0
  39. package/dist/agentic-memory-DfuVZ-lY.d.cts +517 -0
  40. package/dist/capability-admission-B0BzqAm5.d.cts +102 -0
  41. package/dist/capability-admission-g0mn9hpq.d.ts +102 -0
  42. package/dist/{chunk-JR4IKCR2.js → chunk-2747WN4Y.js} +5 -5
  43. package/dist/{chunk-2ILL7HQI.js → chunk-3JR3EDB2.js} +17 -17
  44. package/dist/{chunk-2ILL7HQI.js.map → chunk-3JR3EDB2.js.map} +1 -1
  45. package/dist/{chunk-GDL26N2T.js → chunk-3KN7NJDR.js} +2 -2
  46. package/dist/{chunk-DJC4CHLQ.js → chunk-43BKLFZU.js} +9 -9
  47. package/dist/chunk-6XAIOL3X.js +2407 -0
  48. package/dist/chunk-6XAIOL3X.js.map +1 -0
  49. package/dist/{chunk-SCRFRCGR.js → chunk-BSQGE5PS.js} +1 -1
  50. package/dist/{chunk-Y3ZLRGHC.js → chunk-CZNV3VXM.js} +16 -16
  51. package/dist/chunk-DGUM43GV.js +11 -0
  52. package/dist/chunk-DGUM43GV.js.map +1 -0
  53. package/dist/{chunk-JIMUDQN3.js → chunk-FBUU43PM.js} +2 -2
  54. package/dist/chunk-H75VXTGT.js +219 -0
  55. package/dist/chunk-H75VXTGT.js.map +1 -0
  56. package/dist/{chunk-RIIOUTGM.js → chunk-HKK2JD7Z.js} +12 -9
  57. package/dist/chunk-HKK2JD7Z.js.map +1 -0
  58. package/dist/{chunk-D6BG7U6A.js → chunk-IXZBUWSP.js} +3 -3
  59. package/dist/chunk-PC3BTTBE.js +3217 -0
  60. package/dist/chunk-PC3BTTBE.js.map +1 -0
  61. package/dist/chunk-QFY4AFY4.js +879 -0
  62. package/dist/chunk-QFY4AFY4.js.map +1 -0
  63. package/dist/{chunk-DK554R7P.js → chunk-S6HXABGL.js} +2 -1
  64. package/dist/chunk-S6HXABGL.js.map +1 -0
  65. package/dist/{chunk-PKVBHGBM.js → chunk-SS2A464I.js} +7 -7
  66. package/dist/chunk-UT3MHJCW.js +49 -0
  67. package/dist/chunk-UT3MHJCW.js.map +1 -0
  68. package/dist/{chunk-G4M3NHRJ.js → chunk-V7CIJE4B.js} +3 -3
  69. package/dist/{chunk-TEW47IVR.js → chunk-VPEFSDME.js} +2 -2
  70. package/dist/chunk-VTHLCFN4.js +368 -0
  71. package/dist/chunk-VTHLCFN4.js.map +1 -0
  72. package/dist/{chunk-SWTLEQL6.js → chunk-WQIA3GFB.js} +2 -2
  73. package/dist/chunk-WQIA3GFB.js.map +1 -0
  74. package/dist/{chunk-I3IHOHCJ.js → chunk-XKXWK2KP.js} +108 -64
  75. package/dist/chunk-XKXWK2KP.js.map +1 -0
  76. package/dist/{chunk-COHO25CZ.js → chunk-YDSIVHRR.js} +553 -7
  77. package/dist/chunk-YDSIVHRR.js.map +1 -0
  78. package/dist/chunk-YXMZ2N6J.js +1884 -0
  79. package/dist/chunk-YXMZ2N6J.js.map +1 -0
  80. package/dist/composition/index.cjs +102 -57
  81. package/dist/composition/index.cjs.map +1 -1
  82. package/dist/composition/index.d.cts +4 -4
  83. package/dist/composition/index.d.ts +4 -4
  84. package/dist/composition/index.js +6 -5
  85. package/dist/core/index.cjs +102 -57
  86. package/dist/core/index.cjs.map +1 -1
  87. package/dist/core/index.d.cts +2 -2
  88. package/dist/core/index.d.ts +2 -2
  89. package/dist/core/index.js +5 -4
  90. package/dist/cqrs/index.cjs.map +1 -1
  91. package/dist/cqrs/index.d.cts +4 -4
  92. package/dist/cqrs/index.d.ts +4 -4
  93. package/dist/cqrs/index.js +3 -2
  94. package/dist/cqrs/index.js.map +1 -1
  95. package/dist/cqrs/messaging.cjs +312 -0
  96. package/dist/cqrs/messaging.cjs.map +1 -0
  97. package/dist/cqrs/messaging.d.cts +57 -0
  98. package/dist/cqrs/messaging.d.ts +57 -0
  99. package/dist/cqrs/messaging.js +274 -0
  100. package/dist/cqrs/messaging.js.map +1 -0
  101. package/dist/cqrs/work-queue.cjs +329 -0
  102. package/dist/cqrs/work-queue.cjs.map +1 -0
  103. package/dist/cqrs/work-queue.d.cts +90 -0
  104. package/dist/cqrs/work-queue.d.ts +90 -0
  105. package/dist/cqrs/work-queue.js +292 -0
  106. package/dist/cqrs/work-queue.js.map +1 -0
  107. package/dist/data/index.cjs +19 -0
  108. package/dist/data/index.cjs.map +1 -0
  109. package/dist/data/index.d.cts +36 -0
  110. package/dist/data/index.d.ts +36 -0
  111. package/dist/data/index.js +1 -0
  112. package/dist/data/index.js.map +1 -0
  113. package/dist/data-structures/index.cjs +105 -57
  114. package/dist/data-structures/index.cjs.map +1 -1
  115. package/dist/data-structures/index.d.cts +8 -8
  116. package/dist/data-structures/index.d.ts +8 -8
  117. package/dist/data-structures/index.js +7 -6
  118. package/dist/{describe-BZb7AS2y.d.ts → describe-BpyJuWkw.d.ts} +1 -1
  119. package/dist/{describe-Ciu8SUnN.d.cts → describe-DYMw_l1C.d.cts} +1 -1
  120. package/dist/executors/work-queue.cjs +342 -0
  121. package/dist/executors/work-queue.cjs.map +1 -0
  122. package/dist/executors/work-queue.d.cts +90 -0
  123. package/dist/executors/work-queue.d.ts +90 -0
  124. package/dist/executors/work-queue.js +306 -0
  125. package/dist/executors/work-queue.js.map +1 -0
  126. package/dist/graph/index.cjs +112 -58
  127. package/dist/graph/index.cjs.map +1 -1
  128. package/dist/graph/index.d.cts +9 -9
  129. package/dist/graph/index.d.ts +9 -9
  130. package/dist/graph/index.js +18 -17
  131. package/dist/{graph-DfdF9zy4.d.ts → graph-D-1-SQeC.d.ts} +3 -3
  132. package/dist/{graph-s23RbbFO.d.cts → graph-DCEWh4T2.d.cts} +3 -3
  133. package/dist/{index-CAEmLCYF.d.cts → index-72VZC0-E.d.cts} +2 -2
  134. package/dist/{index-SnzZu3x7.d.ts → index-Bmxeu0nK.d.ts} +2 -2
  135. package/dist/index.cjs +112 -58
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.d.cts +11 -10
  138. package/dist/index.d.ts +11 -10
  139. package/dist/index.js +118 -113
  140. package/dist/inspection/boundary.cjs +98 -0
  141. package/dist/inspection/boundary.cjs.map +1 -0
  142. package/dist/inspection/boundary.d.cts +61 -0
  143. package/dist/inspection/boundary.d.ts +61 -0
  144. package/dist/inspection/boundary.js +75 -0
  145. package/dist/inspection/boundary.js.map +1 -0
  146. package/dist/{messages-BZqrGGm1.d.ts → messages-CAzUPPJM.d.cts} +10 -5
  147. package/dist/{messages-BZqrGGm1.d.cts → messages-CAzUPPJM.d.ts} +10 -5
  148. package/dist/messaging/index.cjs +744 -613
  149. package/dist/messaging/index.cjs.map +1 -1
  150. package/dist/messaging/index.d.cts +216 -160
  151. package/dist/messaging/index.d.ts +216 -160
  152. package/dist/messaging/index.js +19 -749
  153. package/dist/messaging/index.js.map +1 -1
  154. package/dist/operators/index.cjs +102 -57
  155. package/dist/operators/index.cjs.map +1 -1
  156. package/dist/operators/index.d.cts +6 -6
  157. package/dist/operators/index.d.ts +6 -6
  158. package/dist/operators/index.js +8 -7
  159. package/dist/orchestration/index.cjs +3333 -59
  160. package/dist/orchestration/index.cjs.map +1 -1
  161. package/dist/orchestration/index.d.cts +7 -4
  162. package/dist/orchestration/index.d.ts +7 -4
  163. package/dist/orchestration/index.js +49 -8
  164. package/dist/orchestration/index.js.map +1 -1
  165. package/dist/orchestration/messaging.cjs +314 -0
  166. package/dist/orchestration/messaging.cjs.map +1 -0
  167. package/dist/orchestration/messaging.d.cts +59 -0
  168. package/dist/orchestration/messaging.d.ts +59 -0
  169. package/dist/orchestration/messaging.js +276 -0
  170. package/dist/orchestration/messaging.js.map +1 -0
  171. package/dist/orchestration/work-queue.cjs +262 -0
  172. package/dist/orchestration/work-queue.cjs.map +1 -0
  173. package/dist/orchestration/work-queue.d.cts +85 -0
  174. package/dist/orchestration/work-queue.d.ts +85 -0
  175. package/dist/orchestration/work-queue.js +226 -0
  176. package/dist/orchestration/work-queue.js.map +1 -0
  177. package/dist/patterns/event-flow.cjs +447 -0
  178. package/dist/patterns/event-flow.cjs.map +1 -0
  179. package/dist/patterns/event-flow.d.cts +115 -0
  180. package/dist/patterns/event-flow.d.ts +115 -0
  181. package/dist/patterns/event-flow.js +14 -0
  182. package/dist/patterns/event-flow.js.map +1 -0
  183. package/dist/patterns/index.cjs +423 -18
  184. package/dist/patterns/index.cjs.map +1 -1
  185. package/dist/patterns/index.d.cts +8 -5
  186. package/dist/patterns/index.d.ts +8 -5
  187. package/dist/patterns/index.js +13 -4
  188. package/dist/{reactive-collection-Cb1II1Fi.d.ts → reactive-collection-BAmfrGjd.d.ts} +9 -9
  189. package/dist/{reactive-collection-BxBqtIOE.d.cts → reactive-collection-DNV0-gFi.d.cts} +9 -9
  190. package/dist/{reactive-collection-storage-D-KmjE0J.d.cts → reactive-collection-storage-BNEldDyi.d.cts} +5 -5
  191. package/dist/{reactive-collection-storage-BNiEc-Gd.d.ts → reactive-collection-storage-YZsAQsWK.d.ts} +5 -5
  192. package/dist/{reactive-map-D-g3dv8I.d.cts → reactive-map-DRD1LJ2H.d.cts} +6 -6
  193. package/dist/{reactive-map-BcB4KsQR.d.ts → reactive-map-EsDiCmJk.d.ts} +6 -6
  194. package/dist/render/index.d.cts +3 -3
  195. package/dist/render/index.d.ts +3 -3
  196. package/dist/render/index.js +1 -0
  197. package/dist/{semantic-memory-graph-BYoIlP35.d.cts → semantic-memory-graph-DKuNzuWw.d.cts} +2 -2
  198. package/dist/{semantic-memory-graph-CxyXLms3.d.ts → semantic-memory-graph-uwbwJdhe.d.ts} +2 -2
  199. package/dist/solutions/index.cjs +4478 -2
  200. package/dist/solutions/index.cjs.map +1 -1
  201. package/dist/solutions/index.d.cts +13 -519
  202. package/dist/solutions/index.d.ts +13 -519
  203. package/dist/solutions/index.js +90 -6
  204. package/dist/solutions/reactive-layout/browser/index.cjs +449 -0
  205. package/dist/solutions/reactive-layout/browser/index.cjs.map +1 -0
  206. package/dist/solutions/reactive-layout/browser/index.d.cts +44 -0
  207. package/dist/solutions/reactive-layout/browser/index.d.ts +44 -0
  208. package/dist/solutions/reactive-layout/browser/index.js +69 -0
  209. package/dist/solutions/reactive-layout/browser/index.js.map +1 -0
  210. package/dist/solutions/reactive-layout/index.cjs +4266 -0
  211. package/dist/solutions/reactive-layout/index.cjs.map +1 -0
  212. package/dist/solutions/reactive-layout/index.d.cts +581 -0
  213. package/dist/solutions/reactive-layout/index.d.ts +581 -0
  214. package/dist/solutions/reactive-layout/index.js +86 -0
  215. package/dist/solutions/reactive-layout/index.js.map +1 -0
  216. package/dist/solutions/reactive-layout/node-canvas/index.cjs +545 -0
  217. package/dist/solutions/reactive-layout/node-canvas/index.cjs.map +1 -0
  218. package/dist/solutions/reactive-layout/node-canvas/index.d.cts +54 -0
  219. package/dist/solutions/reactive-layout/node-canvas/index.d.ts +54 -0
  220. package/dist/solutions/reactive-layout/node-canvas/index.js +131 -0
  221. package/dist/solutions/reactive-layout/node-canvas/index.js.map +1 -0
  222. package/dist/solutions/reactive-layout/react-native/index.cjs +494 -0
  223. package/dist/solutions/reactive-layout/react-native/index.cjs.map +1 -0
  224. package/dist/solutions/reactive-layout/react-native/index.d.cts +51 -0
  225. package/dist/solutions/reactive-layout/react-native/index.d.ts +51 -0
  226. package/dist/solutions/reactive-layout/react-native/index.js +77 -0
  227. package/dist/solutions/reactive-layout/react-native/index.js.map +1 -0
  228. package/dist/solutions/reactive-layout/skia/index.cjs +547 -0
  229. package/dist/solutions/reactive-layout/skia/index.cjs.map +1 -0
  230. package/dist/solutions/reactive-layout/skia/index.d.cts +64 -0
  231. package/dist/solutions/reactive-layout/skia/index.d.ts +64 -0
  232. package/dist/solutions/reactive-layout/skia/index.js +70 -0
  233. package/dist/solutions/reactive-layout/skia/index.js.map +1 -0
  234. package/dist/solutions/work-item/actions.cjs +2164 -0
  235. package/dist/solutions/work-item/actions.cjs.map +1 -0
  236. package/dist/solutions/work-item/actions.d.cts +201 -0
  237. package/dist/solutions/work-item/actions.d.ts +201 -0
  238. package/dist/solutions/work-item/actions.js +1454 -0
  239. package/dist/solutions/work-item/actions.js.map +1 -0
  240. package/dist/solutions/work-item/scheduling.cjs +2454 -0
  241. package/dist/solutions/work-item/scheduling.cjs.map +1 -0
  242. package/dist/solutions/work-item/scheduling.d.cts +433 -0
  243. package/dist/solutions/work-item/scheduling.d.ts +433 -0
  244. package/dist/solutions/work-item/scheduling.js +32 -0
  245. package/dist/solutions/work-item/scheduling.js.map +1 -0
  246. package/dist/solutions/work-item/work-queue.cjs +306 -0
  247. package/dist/solutions/work-item/work-queue.cjs.map +1 -0
  248. package/dist/solutions/work-item/work-queue.d.cts +71 -0
  249. package/dist/solutions/work-item/work-queue.d.ts +71 -0
  250. package/dist/solutions/work-item/work-queue.js +270 -0
  251. package/dist/solutions/work-item/work-queue.js.map +1 -0
  252. package/dist/sources/browser.cjs +169 -57
  253. package/dist/sources/browser.cjs.map +1 -1
  254. package/dist/sources/browser.d.cts +33 -6
  255. package/dist/sources/browser.d.ts +33 -6
  256. package/dist/sources/browser.js +73 -6
  257. package/dist/sources/browser.js.map +1 -1
  258. package/dist/sources/index.cjs +102 -57
  259. package/dist/sources/index.cjs.map +1 -1
  260. package/dist/sources/index.d.cts +5 -5
  261. package/dist/sources/index.d.ts +5 -5
  262. package/dist/sources/index.js +6 -5
  263. package/dist/sources/node.cjs.map +1 -1
  264. package/dist/sources/node.d.cts +4 -4
  265. package/dist/sources/node.d.ts +4 -4
  266. package/dist/sources/node.js +2 -1
  267. package/dist/sources/node.js.map +1 -1
  268. package/dist/storage/browser.js +1 -0
  269. package/dist/storage/browser.js.map +1 -1
  270. package/dist/storage/index.d.cts +5 -5
  271. package/dist/storage/index.d.ts +5 -5
  272. package/dist/storage/index.js +5 -4
  273. package/dist/storage/node.js +1 -0
  274. package/dist/storage/node.js.map +1 -1
  275. package/dist/store-C-joM4gh.d.ts +123 -0
  276. package/dist/store-CNJwmT-h.d.cts +123 -0
  277. package/dist/testing/index.cjs +1 -0
  278. package/dist/testing/index.cjs.map +1 -1
  279. package/dist/testing/index.d.cts +1 -1
  280. package/dist/testing/index.d.ts +1 -1
  281. package/dist/testing/index.js +3 -2
  282. package/dist/{types-h12mNYbq.d.ts → types-BsJvElYZ.d.ts} +31 -31
  283. package/dist/{types-bNMSWKqF.d.cts → types-CcPIn7sy.d.cts} +31 -31
  284. package/dist/work-item-runtime-C3M79vE9.d.ts +228 -0
  285. package/dist/work-item-runtime-qaVgsL0T.d.cts +228 -0
  286. package/dist/work-queue/index.cjs +1132 -0
  287. package/dist/work-queue/index.cjs.map +1 -0
  288. package/dist/work-queue/index.d.cts +369 -0
  289. package/dist/work-queue/index.d.ts +369 -0
  290. package/dist/work-queue/index.js +1078 -0
  291. package/dist/work-queue/index.js.map +1 -0
  292. package/package.json +266 -2
  293. package/dist/chunk-COHO25CZ.js.map +0 -1
  294. package/dist/chunk-DK554R7P.js.map +0 -1
  295. package/dist/chunk-I3IHOHCJ.js.map +0 -1
  296. package/dist/chunk-RIIOUTGM.js.map +0 -1
  297. package/dist/chunk-SWTLEQL6.js.map +0 -1
  298. /package/dist/{chunk-JR4IKCR2.js.map → chunk-2747WN4Y.js.map} +0 -0
  299. /package/dist/{chunk-GDL26N2T.js.map → chunk-3KN7NJDR.js.map} +0 -0
  300. /package/dist/{chunk-DJC4CHLQ.js.map → chunk-43BKLFZU.js.map} +0 -0
  301. /package/dist/{chunk-SCRFRCGR.js.map → chunk-BSQGE5PS.js.map} +0 -0
  302. /package/dist/{chunk-Y3ZLRGHC.js.map → chunk-CZNV3VXM.js.map} +0 -0
  303. /package/dist/{chunk-JIMUDQN3.js.map → chunk-FBUU43PM.js.map} +0 -0
  304. /package/dist/{chunk-D6BG7U6A.js.map → chunk-IXZBUWSP.js.map} +0 -0
  305. /package/dist/{chunk-PKVBHGBM.js.map → chunk-SS2A464I.js.map} +0 -0
  306. /package/dist/{chunk-G4M3NHRJ.js.map → chunk-V7CIJE4B.js.map} +0 -0
  307. /package/dist/{chunk-TEW47IVR.js.map → chunk-VPEFSDME.js.map} +0 -0
@@ -0,0 +1,2407 @@
1
+ import {
2
+ depBatch
3
+ } from "./chunk-WQIA3GFB.js";
4
+
5
+ // src/solutions/work-item/scheduling.ts
6
+ var executionRelevantDefaults = /* @__PURE__ */ new Set([
7
+ "detail",
8
+ "detailRefs",
9
+ "acceptanceCriteria",
10
+ "verificationPlan",
11
+ "verificationSteps",
12
+ "dependencies"
13
+ ]);
14
+ var draftPatchKeys = /* @__PURE__ */ new Set([
15
+ "summary",
16
+ "detail",
17
+ "detailRefs",
18
+ "acceptanceCriteria",
19
+ "verificationPlan",
20
+ "verificationSteps",
21
+ "kind",
22
+ "priority",
23
+ "tags",
24
+ "owner",
25
+ "assignee",
26
+ "deadlineMs",
27
+ "customFields",
28
+ "sourceRefs",
29
+ "metadata"
30
+ ]);
31
+ function workItemCreatedFromDraft(workItemId, draft, opts = {}) {
32
+ return {
33
+ kind: "work-item-created",
34
+ eventId: opts.eventId ?? `${workItemId}:created`,
35
+ workItemId,
36
+ draft,
37
+ authorId: opts.authorId,
38
+ createdAtMs: opts.createdAtMs,
39
+ sourceRefs: opts.sourceRefs,
40
+ metadata: opts.metadata
41
+ };
42
+ }
43
+ function workItemSpawnProposed(proposalId, draft, opts = {}) {
44
+ return {
45
+ kind: "work-item-spawn-proposed",
46
+ proposalId,
47
+ draft,
48
+ parentWorkItemId: opts.parentWorkItemId,
49
+ proposedBy: opts.proposedBy,
50
+ sourceRefs: opts.sourceRefs,
51
+ metadata: opts.metadata
52
+ };
53
+ }
54
+ function acceptanceCriteriaChanged(workItemId, acceptanceCriteria, opts) {
55
+ return {
56
+ kind: "acceptance-criteria-changed",
57
+ eventId: opts.eventId,
58
+ workItemId,
59
+ acceptanceCriteria,
60
+ authorId: opts.authorId,
61
+ changedAtMs: opts.changedAtMs,
62
+ sourceRefs: opts.sourceRefs,
63
+ metadata: opts.metadata
64
+ };
65
+ }
66
+ function verificationPlanChanged(workItemId, verificationPlan, opts) {
67
+ return {
68
+ kind: "verification-plan-changed",
69
+ eventId: opts.eventId,
70
+ workItemId,
71
+ verificationPlan,
72
+ authorId: opts.authorId,
73
+ changedAtMs: opts.changedAtMs,
74
+ sourceRefs: opts.sourceRefs,
75
+ metadata: opts.metadata
76
+ };
77
+ }
78
+ function validateWorkItemDraft(draft, opts = {}) {
79
+ const out = [];
80
+ if (!isRecord(draft)) {
81
+ return [issue("malformed-draft", "WorkItemDraft must be an object", opts.workItemId)];
82
+ }
83
+ if (typeof draft.summary !== "string") {
84
+ out.push(issue("missing-required-field", "WorkItemDraft.summary is required", opts.workItemId));
85
+ } else if (draft.summary.trim() === "") {
86
+ out.push(issue("missing-required-field", "WorkItemDraft.summary is required", opts.workItemId));
87
+ }
88
+ const criteria = draft.acceptanceCriteria === void 0 || Array.isArray(draft.acceptanceCriteria) ? draft.acceptanceCriteria : void 0;
89
+ if (draft.acceptanceCriteria !== void 0 && criteria === void 0) {
90
+ out.push(
91
+ issue(
92
+ "malformed-draft",
93
+ "WorkItemDraft.acceptanceCriteria must be an array",
94
+ opts.workItemId
95
+ )
96
+ );
97
+ }
98
+ out.push(...validateAcceptanceCriteria(criteria ?? [], opts));
99
+ if (draft.verificationPlan !== void 0 && !isVerificationPlanShape(draft.verificationPlan)) {
100
+ out.push(
101
+ issue("malformed-draft", "WorkItemDraft.verificationPlan is malformed", opts.workItemId)
102
+ );
103
+ }
104
+ if (draft.verificationSteps !== void 0 && !Array.isArray(draft.verificationSteps)) {
105
+ out.push(
106
+ issue("malformed-draft", "WorkItemDraft.verificationSteps must be an array", opts.workItemId)
107
+ );
108
+ }
109
+ const plan = normalizePlanFromUnknown(draft);
110
+ if (plan !== void 0) {
111
+ out.push(...validateVerificationPlan(plan, criteria ?? [], opts));
112
+ }
113
+ return out;
114
+ }
115
+ function validateAcceptanceCriteria(criteria, opts = {}) {
116
+ const out = [];
117
+ const seen = /* @__PURE__ */ new Set();
118
+ for (const criterion of criteria) {
119
+ if (!isRecord(criterion)) {
120
+ out.push(issue("malformed-draft", "AcceptanceCriterion must be an object", opts.workItemId));
121
+ continue;
122
+ }
123
+ if (typeof criterion.criterionId !== "string" || criterion.criterionId === "") {
124
+ out.push(
125
+ issue(
126
+ "missing-required-field",
127
+ "AcceptanceCriterion.criterionId is required",
128
+ opts.workItemId
129
+ )
130
+ );
131
+ continue;
132
+ }
133
+ if (seen.has(criterion.criterionId)) {
134
+ out.push(
135
+ issue(
136
+ "duplicate-id",
137
+ `Duplicate acceptance criterion id '${criterion.criterionId}'`,
138
+ opts.workItemId,
139
+ { criterionId: criterion.criterionId }
140
+ )
141
+ );
142
+ }
143
+ seen.add(criterion.criterionId);
144
+ if (typeof criterion.statement !== "string" || criterion.statement.trim() === "") {
145
+ out.push(
146
+ issue(
147
+ "missing-required-field",
148
+ "AcceptanceCriterion.statement is required",
149
+ opts.workItemId,
150
+ { criterionId: criterion.criterionId }
151
+ )
152
+ );
153
+ }
154
+ }
155
+ return out;
156
+ }
157
+ function validateVerificationPlan(plan, criteria = [], opts = {}) {
158
+ const out = [];
159
+ if (!isRecord(plan) || !Array.isArray(plan.steps)) {
160
+ return [issue("malformed-draft", "VerificationPlan.steps must be an array", opts.workItemId)];
161
+ }
162
+ const criterionIds = new Set(criteria.map((criterion) => criterion.criterionId));
163
+ const stepIds = /* @__PURE__ */ new Set();
164
+ const modes = new Set(opts.allowedModes ?? ["auto", "manual", "hybrid"]);
165
+ const effectKinds = new Set(opts.allowedEffectKinds ?? ["verification"]);
166
+ for (const step of plan.steps) {
167
+ if (!isRecord(step)) {
168
+ out.push(issue("malformed-draft", "VerificationStep must be an object", opts.workItemId));
169
+ continue;
170
+ }
171
+ if (typeof step.stepId !== "string" || step.stepId === "") {
172
+ out.push(
173
+ issue("missing-required-field", "VerificationStep.stepId is required", opts.workItemId)
174
+ );
175
+ continue;
176
+ }
177
+ if (stepIds.has(step.stepId)) {
178
+ out.push(
179
+ issue("duplicate-id", `Duplicate verification step id '${step.stepId}'`, opts.workItemId, {
180
+ stepId: step.stepId
181
+ })
182
+ );
183
+ }
184
+ stepIds.add(step.stepId);
185
+ if (typeof step.mode !== "string" || !modes.has(step.mode)) {
186
+ out.push(
187
+ issue(
188
+ "unsupported-mode",
189
+ `Unsupported verification step mode '${step.mode}'`,
190
+ opts.workItemId,
191
+ { stepId: step.stepId }
192
+ )
193
+ );
194
+ }
195
+ if (step.effectKind !== void 0 && (typeof step.effectKind !== "string" || !effectKinds.has(step.effectKind))) {
196
+ out.push(
197
+ issue(
198
+ "unsupported-effect-kind",
199
+ `Unsupported verification effect kind '${step.effectKind}'`,
200
+ opts.workItemId,
201
+ { stepId: step.stepId }
202
+ )
203
+ );
204
+ }
205
+ const verifiesCriteriaIds = Array.isArray(step.verifiesCriteriaIds) ? step.verifiesCriteriaIds : [];
206
+ for (const criterionId of verifiesCriteriaIds) {
207
+ if (!criterionIds.has(criterionId)) {
208
+ out.push(
209
+ issue("dangling-ref", `Unknown acceptance criterion '${criterionId}'`, opts.workItemId, {
210
+ stepId: step.stepId,
211
+ criterionId
212
+ })
213
+ );
214
+ }
215
+ }
216
+ }
217
+ for (const step of plan.steps) {
218
+ if (!isRecord(step) || typeof step.stepId !== "string") continue;
219
+ const dependsOnStepIds = Array.isArray(step.dependsOnStepIds) ? step.dependsOnStepIds : [];
220
+ for (const depId of dependsOnStepIds) {
221
+ if (!stepIds.has(depId)) {
222
+ out.push(
223
+ issue("dangling-ref", `Unknown verification dependency '${depId}'`, opts.workItemId, {
224
+ stepId: step.stepId
225
+ })
226
+ );
227
+ }
228
+ }
229
+ }
230
+ const cycle = findCycle(
231
+ plan.steps.filter(
232
+ (step) => isRecord(step) && typeof step.stepId === "string" && Array.isArray(step.dependsOnStepIds)
233
+ )
234
+ );
235
+ if (cycle !== void 0) {
236
+ out.push(
237
+ issue(
238
+ "cyclic-dependency",
239
+ `Verification step cycle detected: ${cycle.join(" -> ")}`,
240
+ opts.workItemId,
241
+ { stepId: cycle[0] }
242
+ )
243
+ );
244
+ }
245
+ return out;
246
+ }
247
+ function workItemAuthoringProjector(graph, opts) {
248
+ const name = opts.name ?? "workItemAuthoring";
249
+ const runtime = graph.node(
250
+ [opts.facts],
251
+ (ctx) => {
252
+ const state = ctx.state.get() ?? {
253
+ workItems: /* @__PURE__ */ new Map(),
254
+ seenEvents: /* @__PURE__ */ new Set(),
255
+ statusSeq: 0,
256
+ auditSeq: 0
257
+ };
258
+ for (const raw of depBatch(ctx, 0) ?? [])
259
+ reduceAuthoring(ctx, state, raw, opts.policy);
260
+ ctx.state.set(state);
261
+ },
262
+ {
263
+ name: `${name}/runtime`,
264
+ factory: "workItemAuthoringProjector",
265
+ partial: true,
266
+ completeWhenDepsComplete: false,
267
+ errorWhenDepsError: false
268
+ }
269
+ );
270
+ return {
271
+ workItems: project(
272
+ graph,
273
+ runtime,
274
+ `${name}/workItems`,
275
+ "workItemAuthoringWorkItems",
276
+ (fact) => fact.kind === "work-item" ? fact.value : void 0
277
+ ),
278
+ status: project(
279
+ graph,
280
+ runtime,
281
+ `${name}/status`,
282
+ "workItemAuthoringStatus",
283
+ (fact) => fact.kind === "status" ? fact.value : void 0
284
+ ),
285
+ issues: project(
286
+ graph,
287
+ runtime,
288
+ `${name}/issues`,
289
+ "workItemAuthoringIssues",
290
+ (fact) => fact.kind === "issue" ? fact.value : void 0
291
+ ),
292
+ audit: project(
293
+ graph,
294
+ runtime,
295
+ `${name}/audit`,
296
+ "workItemAuthoringAudit",
297
+ (fact) => fact.kind === "audit" ? fact.value : void 0
298
+ )
299
+ };
300
+ }
301
+ function workItemVerificationRequestLowerer(graph, opts) {
302
+ const name = opts.name ?? "workItemVerificationRequests";
303
+ const deps = [opts.workItems];
304
+ const dispatchIntentIndex = opts.dispatchIntents === void 0 ? -1 : deps.push(opts.dispatchIntents) - 1;
305
+ const verificationResultIndex = opts.verificationResults === void 0 ? -1 : deps.push(opts.verificationResults) - 1;
306
+ const runtime = graph.node(
307
+ deps,
308
+ (ctx) => {
309
+ const state = ctx.state.get() ?? {
310
+ workItems: /* @__PURE__ */ new Map(),
311
+ emittedKeys: /* @__PURE__ */ new Set(),
312
+ passedSteps: /* @__PURE__ */ new Map(),
313
+ statusSeq: 0,
314
+ auditSeq: 0
315
+ };
316
+ for (const raw of depBatch(ctx, 0) ?? []) {
317
+ const workItem = raw;
318
+ state.workItems.set(workItem.workItemId, workItem);
319
+ lowerPlan(ctx, state, workItem, opts.policy);
320
+ }
321
+ if (dispatchIntentIndex >= 0) {
322
+ for (const raw of depBatch(ctx, dispatchIntentIndex) ?? [])
323
+ lowerIntent(ctx, state, raw, opts.policy);
324
+ }
325
+ if (verificationResultIndex >= 0) {
326
+ for (const raw of depBatch(ctx, verificationResultIndex) ?? [])
327
+ recordVerificationResult(ctx, state, raw, opts.policy);
328
+ }
329
+ ctx.state.set(state);
330
+ },
331
+ {
332
+ name: `${name}/runtime`,
333
+ factory: "workItemVerificationRequestLowerer",
334
+ partial: true,
335
+ completeWhenDepsComplete: false,
336
+ errorWhenDepsError: false
337
+ }
338
+ );
339
+ return {
340
+ effectRequests: project(
341
+ graph,
342
+ runtime,
343
+ `${name}/effectRequests`,
344
+ "workItemVerificationEffectRequests",
345
+ (fact) => fact.kind === "request" ? fact.value : void 0
346
+ ),
347
+ status: project(
348
+ graph,
349
+ runtime,
350
+ `${name}/status`,
351
+ "workItemVerificationRequestStatus",
352
+ (fact) => fact.kind === "status" ? fact.value : void 0
353
+ ),
354
+ issues: project(
355
+ graph,
356
+ runtime,
357
+ `${name}/issues`,
358
+ "workItemVerificationRequestIssues",
359
+ (fact) => fact.kind === "issue" ? fact.value : void 0
360
+ ),
361
+ audit: project(
362
+ graph,
363
+ runtime,
364
+ `${name}/audit`,
365
+ "workItemVerificationRequestAudit",
366
+ (fact) => fact.kind === "audit" ? fact.value : void 0
367
+ )
368
+ };
369
+ }
370
+ function workItemVerificationResultMapper(graph, opts) {
371
+ const name = opts.name ?? "workItemVerificationResults";
372
+ const deps = opts.policies === void 0 ? [opts.workItems, opts.evidence] : [opts.workItems, opts.evidence, opts.policies];
373
+ const runtime = graph.node(
374
+ deps,
375
+ (ctx) => {
376
+ const state = ctx.state.get() ?? {
377
+ workItems: /* @__PURE__ */ new Map(),
378
+ policies: /* @__PURE__ */ new Map(),
379
+ evidenceById: /* @__PURE__ */ new Map(),
380
+ resultEvidence: /* @__PURE__ */ new Set(),
381
+ proposalKeys: /* @__PURE__ */ new Set(),
382
+ statusSeq: 0,
383
+ auditSeq: 0
384
+ };
385
+ for (const raw of depBatch(ctx, 0) ?? []) {
386
+ const workItem = raw;
387
+ state.workItems.set(workItem.workItemId, workItem);
388
+ replayEvidence(ctx, state, workItem.workItemId);
389
+ }
390
+ if (opts.policies !== void 0) {
391
+ for (const raw of depBatch(ctx, 2) ?? []) {
392
+ const policy = raw;
393
+ const issues = validateMappingPolicy(policy);
394
+ if (issues.length > 0) {
395
+ for (const item of issues) emit(ctx, "issue", item);
396
+ emitResultStatus(ctx, state, {
397
+ state: "rejected",
398
+ code: "policy-mismatch",
399
+ metadata: { policyId: isRecord(policy) ? policy.policyId : void 0 }
400
+ });
401
+ continue;
402
+ }
403
+ state.policies.set(policy.policyId, policy);
404
+ }
405
+ for (const evidence of state.evidenceById.values()) {
406
+ mapEvidence(ctx, state, evidence, true);
407
+ }
408
+ }
409
+ for (const raw of depBatch(ctx, 1) ?? [])
410
+ mapEvidence(ctx, state, raw);
411
+ ctx.state.set(state);
412
+ },
413
+ {
414
+ name: `${name}/runtime`,
415
+ factory: "workItemVerificationResultMapper",
416
+ partial: true,
417
+ completeWhenDepsComplete: false,
418
+ errorWhenDepsError: false
419
+ }
420
+ );
421
+ return {
422
+ results: project(
423
+ graph,
424
+ runtime,
425
+ `${name}/results`,
426
+ "workItemVerificationResults",
427
+ (fact) => fact.kind === "result" ? fact.value : void 0
428
+ ),
429
+ proposals: project(
430
+ graph,
431
+ runtime,
432
+ `${name}/proposals`,
433
+ "workItemVerificationProposals",
434
+ (fact) => fact.kind === "proposal" ? fact.value : void 0
435
+ ),
436
+ status: project(
437
+ graph,
438
+ runtime,
439
+ `${name}/status`,
440
+ "workItemVerificationResultStatus",
441
+ (fact) => fact.kind === "status" ? fact.value : void 0
442
+ ),
443
+ issues: project(
444
+ graph,
445
+ runtime,
446
+ `${name}/issues`,
447
+ "workItemVerificationResultIssues",
448
+ (fact) => fact.kind === "issue" ? fact.value : void 0
449
+ ),
450
+ audit: project(
451
+ graph,
452
+ runtime,
453
+ `${name}/audit`,
454
+ "workItemVerificationResultAudit",
455
+ (fact) => fact.kind === "audit" ? fact.value : void 0
456
+ )
457
+ };
458
+ }
459
+ function validateWorkItemEffectPlan(proposal, workItem, policy = {}) {
460
+ const out = [];
461
+ if (!isRecord(proposal) || proposal.kind !== "work-item-effect-plan-proposed" || typeof proposal.planId !== "string" || proposal.planId.trim() === "" || typeof proposal.workItemId !== "string" || proposal.workItemId.trim() === "" || typeof proposal.executionInputRevision !== "number" || !Array.isArray(proposal.members)) {
462
+ return [
463
+ issue(
464
+ "malformed-draft",
465
+ "WorkItemEffectPlanProposed requires planId, workItemId, executionInputRevision, and members",
466
+ isRecord(proposal) && typeof proposal.workItemId === "string" ? proposal.workItemId : void 0
467
+ )
468
+ ];
469
+ }
470
+ if (proposal.joinPolicy !== void 0 && !isWorkItemEffectPlanJoinPolicy(proposal.joinPolicy)) {
471
+ out.push(
472
+ issue(
473
+ "policy-mismatch",
474
+ `Unsupported WorkItemEffectPlan join policy '${proposal.joinPolicy}'`,
475
+ proposal.workItemId,
476
+ { planId: proposal.planId, joinPolicy: proposal.joinPolicy }
477
+ )
478
+ );
479
+ }
480
+ if (workItem === void 0) {
481
+ out.push(
482
+ issue(
483
+ "dangling-ref",
484
+ `WorkItemEffectPlan '${proposal.planId}' references unknown WorkItem '${proposal.workItemId}'`,
485
+ proposal.workItemId,
486
+ { planId: proposal.planId }
487
+ )
488
+ );
489
+ } else if (proposal.executionInputRevision !== workItem.executionInputRevision) {
490
+ out.push(
491
+ issue(
492
+ "stale-execution-input",
493
+ `WorkItemEffectPlan '${proposal.planId}' targets stale execution input`,
494
+ proposal.workItemId,
495
+ {
496
+ planId: proposal.planId,
497
+ proposedRevision: proposal.executionInputRevision,
498
+ currentRevision: workItem.executionInputRevision
499
+ }
500
+ )
501
+ );
502
+ }
503
+ const memberIds = /* @__PURE__ */ new Set();
504
+ const allowedEffectKinds = policy.allowedEffectKinds === void 0 ? void 0 : new Set(policy.allowedEffectKinds);
505
+ for (const member of proposal.members) {
506
+ if (!isRecord(member)) {
507
+ out.push(
508
+ issue(
509
+ "malformed-draft",
510
+ "WorkItemEffectPlan member must be an object",
511
+ proposal.workItemId,
512
+ {
513
+ planId: proposal.planId
514
+ }
515
+ )
516
+ );
517
+ continue;
518
+ }
519
+ if (typeof member.memberId !== "string" || member.memberId.trim() === "") {
520
+ out.push(
521
+ issue(
522
+ "missing-required-field",
523
+ "WorkItemEffectPlan memberId is required",
524
+ proposal.workItemId,
525
+ { planId: proposal.planId }
526
+ )
527
+ );
528
+ continue;
529
+ }
530
+ if (memberIds.has(member.memberId)) {
531
+ out.push(
532
+ issue(
533
+ "duplicate-id",
534
+ `Duplicate WorkItemEffectPlan member id '${member.memberId}'`,
535
+ proposal.workItemId,
536
+ { planId: proposal.planId, planMemberId: member.memberId }
537
+ )
538
+ );
539
+ }
540
+ memberIds.add(member.memberId);
541
+ if (typeof member.effectKind !== "string" || member.effectKind.trim() === "") {
542
+ out.push(
543
+ issue(
544
+ "missing-required-field",
545
+ "WorkItemEffectPlan member effectKind is required",
546
+ proposal.workItemId,
547
+ { planId: proposal.planId, planMemberId: member.memberId }
548
+ )
549
+ );
550
+ } else if (allowedEffectKinds !== void 0 && !allowedEffectKinds.has(member.effectKind)) {
551
+ out.push(
552
+ issue(
553
+ "unsupported-effect-kind",
554
+ `Unsupported WorkItemEffectPlan effect kind '${member.effectKind}'`,
555
+ proposal.workItemId,
556
+ { planId: proposal.planId, planMemberId: member.memberId }
557
+ )
558
+ );
559
+ }
560
+ if (!isRecord(member.goal)) {
561
+ out.push(
562
+ issue(
563
+ "missing-required-field",
564
+ "WorkItemEffectPlan member goal is required",
565
+ proposal.workItemId,
566
+ { planId: proposal.planId, planMemberId: member.memberId }
567
+ )
568
+ );
569
+ }
570
+ for (const field of [
571
+ "dependsOnMemberIds",
572
+ "contextRefs",
573
+ "requirements",
574
+ "policyRefs",
575
+ "sourceRefs"
576
+ ]) {
577
+ if (member[field] !== void 0 && !Array.isArray(member[field])) {
578
+ out.push(
579
+ issue(
580
+ "malformed-draft",
581
+ `WorkItemEffectPlan member ${field} must be an array`,
582
+ proposal.workItemId,
583
+ { planId: proposal.planId, planMemberId: member.memberId, field }
584
+ )
585
+ );
586
+ }
587
+ }
588
+ }
589
+ for (const member of proposal.members) {
590
+ if (!isRecord(member) || typeof member.memberId !== "string") continue;
591
+ const deps = Array.isArray(member.dependsOnMemberIds) ? member.dependsOnMemberIds : [];
592
+ for (const depId of deps) {
593
+ if (!memberIds.has(depId)) {
594
+ out.push(
595
+ issue(
596
+ "dangling-ref",
597
+ `Unknown WorkItemEffectPlan dependency '${depId}'`,
598
+ proposal.workItemId,
599
+ { planId: proposal.planId, planMemberId: member.memberId, depId }
600
+ )
601
+ );
602
+ }
603
+ }
604
+ }
605
+ const cycle = findPlanCycle(
606
+ proposal.members.filter(
607
+ (member) => isRecord(member) && typeof member.memberId === "string" && Array.isArray(member.dependsOnMemberIds)
608
+ )
609
+ );
610
+ if (cycle !== void 0) {
611
+ out.push(
612
+ issue(
613
+ "cyclic-dependency",
614
+ `WorkItemEffectPlan member cycle detected: ${cycle.join(" -> ")}`,
615
+ proposal.workItemId,
616
+ { planId: proposal.planId, planMemberId: cycle[0] }
617
+ )
618
+ );
619
+ }
620
+ return out;
621
+ }
622
+ function workItemEffectPlanProjector(graph, opts) {
623
+ const name = opts.name ?? "workItemEffectPlans";
624
+ const deps = [opts.workItems, opts.proposals];
625
+ const evidenceIndex = opts.evidence === void 0 ? -1 : deps.push(opts.evidence) - 1;
626
+ const resultIndex = opts.effectRunResults === void 0 ? -1 : deps.push(opts.effectRunResults) - 1;
627
+ const now = opts.now ?? Date.now;
628
+ const runtime = graph.node(
629
+ deps,
630
+ (ctx) => {
631
+ const state = ctx.state.get() ?? emptyPlanState();
632
+ for (const raw of depBatch(ctx, 0) ?? []) {
633
+ const workItem = raw;
634
+ state.workItems.set(workItem.workItemId, workItem);
635
+ for (const proposal of state.proposals.values()) {
636
+ if (proposal.workItemId === workItem.workItemId)
637
+ admitPlan(ctx, state, proposal, opts.policy, now);
638
+ }
639
+ }
640
+ for (const raw of depBatch(ctx, 1) ?? []) {
641
+ const proposal = raw;
642
+ if (isRecord(proposal) && typeof proposal.planId === "string" && typeof proposal.workItemId === "string") {
643
+ const key = planKey(
644
+ proposal.workItemId,
645
+ proposal.planId,
646
+ proposal.executionInputRevision
647
+ );
648
+ if (key !== void 0) state.proposals.set(key, proposal);
649
+ }
650
+ admitPlan(ctx, state, proposal, opts.policy, now);
651
+ }
652
+ if (evidenceIndex >= 0) {
653
+ for (const raw of depBatch(ctx, evidenceIndex) ?? [])
654
+ recordPlanEvidence(ctx, state, raw);
655
+ }
656
+ if (resultIndex >= 0) {
657
+ for (const raw of depBatch(ctx, resultIndex) ?? [])
658
+ recordPlanResult(ctx, state, raw);
659
+ }
660
+ drainPlanWork(ctx, state, opts.policy);
661
+ ctx.state.set(state);
662
+ },
663
+ {
664
+ name: `${name}/runtime`,
665
+ factory: "workItemEffectPlanProjector",
666
+ partial: true,
667
+ completeWhenDepsComplete: false,
668
+ errorWhenDepsError: false
669
+ }
670
+ );
671
+ return {
672
+ admitted: project(
673
+ graph,
674
+ runtime,
675
+ `${name}/admitted`,
676
+ "workItemEffectPlansAdmitted",
677
+ (fact) => fact.kind === "admitted" ? fact.value : void 0
678
+ ),
679
+ rejected: project(
680
+ graph,
681
+ runtime,
682
+ `${name}/rejected`,
683
+ "workItemEffectPlansRejected",
684
+ (fact) => fact.kind === "rejected" ? fact.value : void 0
685
+ ),
686
+ effectRequests: project(
687
+ graph,
688
+ runtime,
689
+ `${name}/effectRequests`,
690
+ "workItemEffectPlanEffectRequests",
691
+ (fact) => fact.kind === "request" ? fact.value : void 0
692
+ ),
693
+ results: project(
694
+ graph,
695
+ runtime,
696
+ `${name}/results`,
697
+ "workItemEffectPlanResults",
698
+ (fact) => fact.kind === "result" ? fact.value : void 0
699
+ ),
700
+ status: project(
701
+ graph,
702
+ runtime,
703
+ `${name}/status`,
704
+ "workItemEffectPlanStatus",
705
+ (fact) => fact.kind === "status" ? fact.value : void 0
706
+ ),
707
+ issues: project(
708
+ graph,
709
+ runtime,
710
+ `${name}/issues`,
711
+ "workItemEffectPlanIssues",
712
+ (fact) => fact.kind === "issue" ? fact.value : void 0
713
+ ),
714
+ audit: project(
715
+ graph,
716
+ runtime,
717
+ `${name}/audit`,
718
+ "workItemEffectPlanAudit",
719
+ (fact) => fact.kind === "audit" ? fact.value : void 0
720
+ )
721
+ };
722
+ }
723
+ function emptyPlanState() {
724
+ return {
725
+ workItems: /* @__PURE__ */ new Map(),
726
+ proposals: /* @__PURE__ */ new Map(),
727
+ admitted: /* @__PURE__ */ new Map(),
728
+ rejected: /* @__PURE__ */ new Set(),
729
+ emittedMemberKeys: /* @__PURE__ */ new Set(),
730
+ statusKeys: /* @__PURE__ */ new Set(),
731
+ resultKeys: /* @__PURE__ */ new Set(),
732
+ requestByEffectRun: /* @__PURE__ */ new Map(),
733
+ requestByRequestId: /* @__PURE__ */ new Map(),
734
+ memberEvidence: /* @__PURE__ */ new Map(),
735
+ pendingEvidence: /* @__PURE__ */ new Map(),
736
+ pendingResults: /* @__PURE__ */ new Map(),
737
+ unmatchedEvidence: /* @__PURE__ */ new Set(),
738
+ unmatchedResults: /* @__PURE__ */ new Set(),
739
+ statusSeq: 0,
740
+ auditSeq: 0
741
+ };
742
+ }
743
+ function admitPlan(ctx, state, proposal, policy, now) {
744
+ if (!isRecord(proposal) || typeof proposal.planId !== "string") {
745
+ const issues2 = validateWorkItemEffectPlan(proposal, void 0, policy);
746
+ emitPlanIssues(ctx, state, issues2);
747
+ return;
748
+ }
749
+ const key = planKey(proposal.workItemId, proposal.planId, proposal.executionInputRevision);
750
+ if (key === void 0) {
751
+ const issues2 = validateWorkItemEffectPlan(proposal, void 0, policy);
752
+ emitPlanIssues(ctx, state, issues2);
753
+ return;
754
+ }
755
+ if (state.admitted.has(key) || state.rejected.has(key)) return;
756
+ const workItem = state.workItems.get(proposal.workItemId);
757
+ if (workItem === void 0) {
758
+ emitPlanStatusOnce(ctx, state, `${key}:deferred:missing-work-item`, {
759
+ workItemId: proposal.workItemId,
760
+ planId: proposal.planId,
761
+ executionInputRevision: proposal.executionInputRevision,
762
+ state: "deferred",
763
+ message: `WorkItemEffectPlan '${proposal.planId}' is waiting for WorkItem '${proposal.workItemId}'`,
764
+ sourceRefs: proposal.sourceRefs,
765
+ metadata: { reason: "missing-work-item" }
766
+ });
767
+ return;
768
+ }
769
+ const issues = validateWorkItemEffectPlan(proposal, workItem, policy);
770
+ if (issues.length > 0) {
771
+ state.rejected.add(key);
772
+ emitPlanIssues(ctx, state, issues);
773
+ const rejected = {
774
+ kind: "work-item-effect-plan-rejected",
775
+ planId: proposal.planId,
776
+ workItemId: proposal.workItemId,
777
+ executionInputRevision: proposal.executionInputRevision,
778
+ issues,
779
+ sourceRefs: proposal.sourceRefs,
780
+ rejectedAtMs: now(),
781
+ metadata: proposal.metadata
782
+ };
783
+ emitPlan(ctx, "rejected", rejected);
784
+ emitPlanStatus(ctx, state, {
785
+ workItemId: proposal.workItemId,
786
+ planId: proposal.planId,
787
+ executionInputRevision: proposal.executionInputRevision,
788
+ state: "rejected",
789
+ issues,
790
+ sourceRefs: proposal.sourceRefs,
791
+ metadata: { issueCodes: issues.map((item) => item.code) }
792
+ });
793
+ return;
794
+ }
795
+ const snapshot = normalizeEffectPlanSnapshot(proposal, policy);
796
+ const admitted = {
797
+ kind: "work-item-effect-plan-admitted",
798
+ planId: snapshot.planId,
799
+ workItemId: snapshot.workItemId,
800
+ executionInputRevision: snapshot.executionInputRevision,
801
+ plan: snapshot,
802
+ sourceRefs: immutableClone(proposal.sourceRefs),
803
+ admittedAtMs: now(),
804
+ metadata: immutableClone(proposal.metadata)
805
+ };
806
+ state.admitted.set(key, admitted);
807
+ emitPlan(ctx, "admitted", admitted);
808
+ emitPlanStatus(ctx, state, {
809
+ workItemId: admitted.workItemId,
810
+ planId: admitted.planId,
811
+ executionInputRevision: admitted.executionInputRevision,
812
+ state: "eligible",
813
+ sourceRefs: admitted.sourceRefs,
814
+ metadata: { memberCount: admitted.plan.members.length }
815
+ });
816
+ }
817
+ function drainPlanWork(ctx, state, policy) {
818
+ const maxPasses = state.admitted.size + state.pendingEvidence.size + state.pendingResults.size + state.emittedMemberKeys.size + 1;
819
+ for (let pass = 0; pass < maxPasses; pass += 1) {
820
+ let changed = false;
821
+ for (const admitted of state.admitted.values()) {
822
+ changed = lowerEligiblePlanMembers(ctx, state, admitted, policy) || changed;
823
+ derivePlanResult(ctx, state, admitted);
824
+ }
825
+ changed = replayPendingPlanFacts(ctx, state) || changed;
826
+ if (!changed) break;
827
+ }
828
+ for (const admitted of state.admitted.values()) derivePlanResult(ctx, state, admitted);
829
+ }
830
+ function lowerEligiblePlanMembers(ctx, state, admitted, policy) {
831
+ if (isAdmittedPlanStale(state, admitted)) {
832
+ emitStaleAdmittedPlanOnce(ctx, state, admitted);
833
+ return false;
834
+ }
835
+ let changed = false;
836
+ for (const member of admitted.plan.members) {
837
+ const coord = memberCoord(admitted, member.memberId);
838
+ if (state.memberEvidence.has(coord)) continue;
839
+ const missing = (member.dependsOnMemberIds ?? []).filter(
840
+ (memberId) => !memberSucceeded(state, admitted, memberId)
841
+ );
842
+ if (missing.length > 0) {
843
+ emitPlanStatusOnce(ctx, state, `${coord}:blocked:${missing.join(",")}`, {
844
+ workItemId: admitted.workItemId,
845
+ planId: admitted.planId,
846
+ executionInputRevision: admitted.executionInputRevision,
847
+ state: "blocked",
848
+ planMemberId: member.memberId,
849
+ issues: [
850
+ issue(
851
+ "blocked-prerequisite",
852
+ `WorkItemEffectPlan member '${member.memberId}' is blocked by prerequisites`,
853
+ admitted.workItemId,
854
+ { planId: admitted.planId, planMemberId: member.memberId, missingMemberIds: missing }
855
+ )
856
+ ],
857
+ sourceRefs: member.sourceRefs,
858
+ metadata: { missingMemberIds: missing }
859
+ });
860
+ continue;
861
+ }
862
+ if (state.emittedMemberKeys.has(coord)) continue;
863
+ state.emittedMemberKeys.add(coord);
864
+ changed = true;
865
+ const request = requestFromPlanMember(admitted, member, policy);
866
+ state.requestByEffectRun.set(request.effectRunId, request);
867
+ state.requestByRequestId.set(request.requestId, request);
868
+ emitPlan(ctx, "request", request);
869
+ emitPlanStatus(ctx, state, {
870
+ workItemId: admitted.workItemId,
871
+ planId: admitted.planId,
872
+ executionInputRevision: admitted.executionInputRevision,
873
+ state: "requested",
874
+ planMemberId: member.memberId,
875
+ requestId: request.requestId,
876
+ effectRunId: request.effectRunId,
877
+ sourceRefs: request.sourceRefs,
878
+ metadata: { effectKind: request.effectKind }
879
+ });
880
+ }
881
+ return changed;
882
+ }
883
+ function recordPlanEvidence(ctx, state, evidence) {
884
+ const coordinate = planCoordinateFromEvidence(state, evidence);
885
+ if (coordinate === void 0) {
886
+ state.pendingEvidence.set(evidence.evidenceId, evidence);
887
+ emitUnmatchedEvidence(ctx, state, `evidence:${evidence.evidenceId}`, evidence.workItemId, {
888
+ evidenceId: evidence.evidenceId,
889
+ effectRunId: evidence.effectRunId
890
+ });
891
+ return false;
892
+ }
893
+ if (emitConflictingPlanEvidenceCoordinate(ctx, state, evidence, coordinate)) return true;
894
+ const key = requiredPlanKey(
895
+ coordinate.workItemId,
896
+ coordinate.planId,
897
+ coordinate.executionInputRevision
898
+ );
899
+ const admitted = state.admitted.get(key);
900
+ if (admitted === void 0) {
901
+ state.pendingEvidence.set(evidence.evidenceId, evidence);
902
+ emitUnmatchedEvidence(ctx, state, `evidence:${evidence.evidenceId}`, coordinate.workItemId, {
903
+ evidenceId: evidence.evidenceId,
904
+ effectRunId: evidence.effectRunId,
905
+ planId: coordinate.planId,
906
+ planMemberId: coordinate.planMemberId,
907
+ executionInputRevision: coordinate.executionInputRevision
908
+ });
909
+ return false;
910
+ }
911
+ if (isAdmittedPlanStale(state, admitted)) {
912
+ emitStaleAdmittedPlanOnce(ctx, state, admitted);
913
+ return true;
914
+ }
915
+ if (!hasPlanMember(admitted, coordinate.planMemberId)) {
916
+ emitUnknownPlanMember(ctx, state, admitted, coordinate.planMemberId, {
917
+ evidenceId: evidence.evidenceId,
918
+ effectRunId: evidence.effectRunId
919
+ });
920
+ return true;
921
+ }
922
+ const recorded = recordMemberEvidence(ctx, state, admitted, coordinate.planMemberId, {
923
+ status: evidence.status,
924
+ requestId: coordinate.requestId ?? coordinate.request?.requestId,
925
+ effectRunId: evidence.effectRunId,
926
+ evidenceId: evidence.evidenceId,
927
+ effectRunResultId: evidence.effectRunResultId,
928
+ sourceRefs: evidence.sourceRefs
929
+ });
930
+ if (!recorded) return true;
931
+ emitPlanStatus(ctx, state, {
932
+ workItemId: coordinate.workItemId,
933
+ planId: coordinate.planId,
934
+ executionInputRevision: coordinate.executionInputRevision,
935
+ state: evidence.status === "completed" ? "completed" : "failed",
936
+ planMemberId: coordinate.planMemberId,
937
+ requestId: coordinate.requestId ?? coordinate.request?.requestId,
938
+ effectRunId: evidence.effectRunId,
939
+ evidenceId: evidence.evidenceId,
940
+ effectRunResultId: evidence.effectRunResultId,
941
+ sourceRefs: evidence.sourceRefs,
942
+ metadata: { evidenceStatus: evidence.status }
943
+ });
944
+ return true;
945
+ }
946
+ function emitConflictingPlanEvidenceCoordinate(ctx, state, evidence, coordinate) {
947
+ const expectedRequest = planRequestForCoordinate(state, coordinate);
948
+ const expectedRequestIdMismatch = expectedRequest !== void 0 && evidence.requestId !== void 0 && evidence.requestId !== expectedRequest.requestId;
949
+ if (expectedRequest !== void 0 && (expectedRequestIdMismatch || evidence.effectRunId !== expectedRequest.effectRunId)) {
950
+ emitPlanEvidenceCoordinateMismatch(ctx, state, evidence, coordinate, expectedRequest);
951
+ return true;
952
+ }
953
+ const requestRefs = [
954
+ evidence.requestId === void 0 ? void 0 : state.requestByRequestId.get(evidence.requestId),
955
+ state.requestByEffectRun.get(evidence.effectRunId)
956
+ ].filter((request) => request !== void 0);
957
+ const conflicting = requestRefs.find(
958
+ (request) => !requestMatchesPlanCoordinate(request, coordinate) || !requestMatchesEvidenceIdentity(request, evidence)
959
+ );
960
+ if (conflicting === void 0) return false;
961
+ emitPlanEvidenceCoordinateMismatch(ctx, state, evidence, coordinate, conflicting);
962
+ return true;
963
+ }
964
+ function emitPlanEvidenceCoordinateMismatch(ctx, state, evidence, coordinate, conflicting) {
965
+ const item = issue(
966
+ "dangling-ref",
967
+ "WorkItemEffectPlan evidence request/effectRun coordinates do not match its plan member coordinates",
968
+ evidence.workItemId,
969
+ {
970
+ evidenceId: evidence.evidenceId,
971
+ requestId: evidence.requestId,
972
+ effectRunId: evidence.effectRunId,
973
+ planId: coordinate.planId,
974
+ planMemberId: coordinate.planMemberId,
975
+ executionInputRevision: coordinate.executionInputRevision,
976
+ requestPlanId: conflicting.planId,
977
+ requestPlanMemberId: conflicting.planMemberId,
978
+ requestExecutionInputRevision: conflicting.executionInputRevision
979
+ }
980
+ );
981
+ emitPlan(ctx, "issue", item);
982
+ emitPlanStatus(ctx, state, {
983
+ workItemId: coordinate.workItemId,
984
+ planId: coordinate.planId,
985
+ executionInputRevision: coordinate.executionInputRevision,
986
+ state: "rejected",
987
+ planMemberId: coordinate.planMemberId,
988
+ requestId: evidence.requestId,
989
+ effectRunId: evidence.effectRunId,
990
+ evidenceId: evidence.evidenceId,
991
+ issues: [item],
992
+ sourceRefs: evidence.sourceRefs,
993
+ metadata: item.metadata
994
+ });
995
+ }
996
+ function requestMatchesPlanCoordinate(request, coordinate) {
997
+ return request.workItemId === coordinate.workItemId && request.planId === coordinate.planId && request.planMemberId === coordinate.planMemberId && request.executionInputRevision === coordinate.executionInputRevision;
998
+ }
999
+ function requestMatchesEvidenceIdentity(request, evidence) {
1000
+ return (evidence.requestId === void 0 || evidence.requestId === request.requestId) && evidence.effectRunId === request.effectRunId;
1001
+ }
1002
+ function planRequestForCoordinate(state, coordinate) {
1003
+ for (const request of state.requestByRequestId.values()) {
1004
+ if (requestMatchesPlanCoordinate(request, coordinate)) return request;
1005
+ }
1006
+ return void 0;
1007
+ }
1008
+ function recordPlanResult(ctx, state, result) {
1009
+ const coordinate = planCoordinateFromResult(state, result);
1010
+ if (coordinate === void 0) {
1011
+ state.pendingResults.set(result.resultId, result);
1012
+ emitUnmatchedEvidence(ctx, state, `result:${result.resultId}`, void 0, {
1013
+ effectRunResultId: result.resultId,
1014
+ effectRunId: result.effectRunId
1015
+ });
1016
+ return false;
1017
+ }
1018
+ const key = requiredPlanKey(
1019
+ coordinate.workItemId,
1020
+ coordinate.planId,
1021
+ coordinate.executionInputRevision
1022
+ );
1023
+ const admitted = state.admitted.get(key);
1024
+ if (admitted === void 0) {
1025
+ state.pendingResults.set(result.resultId, result);
1026
+ emitUnmatchedEvidence(ctx, state, `result:${result.resultId}`, coordinate.workItemId, {
1027
+ effectRunResultId: result.resultId,
1028
+ effectRunId: result.effectRunId,
1029
+ planId: coordinate.planId,
1030
+ planMemberId: coordinate.planMemberId,
1031
+ executionInputRevision: coordinate.executionInputRevision
1032
+ });
1033
+ return false;
1034
+ }
1035
+ if (isAdmittedPlanStale(state, admitted)) {
1036
+ emitStaleAdmittedPlanOnce(ctx, state, admitted);
1037
+ return true;
1038
+ }
1039
+ if (!hasPlanMember(admitted, coordinate.planMemberId)) {
1040
+ emitUnknownPlanMember(ctx, state, admitted, coordinate.planMemberId, {
1041
+ effectRunResultId: result.resultId,
1042
+ effectRunId: result.effectRunId
1043
+ });
1044
+ return true;
1045
+ }
1046
+ const recorded = recordMemberEvidence(ctx, state, admitted, coordinate.planMemberId, {
1047
+ status: result.status,
1048
+ requestId: coordinate.request?.requestId,
1049
+ effectRunId: result.effectRunId,
1050
+ effectRunResultId: result.resultId,
1051
+ sourceRefs: result.sourceRefs
1052
+ });
1053
+ if (!recorded) return true;
1054
+ emitPlanStatus(ctx, state, {
1055
+ workItemId: coordinate.workItemId,
1056
+ planId: coordinate.planId,
1057
+ executionInputRevision: coordinate.executionInputRevision,
1058
+ state: result.status === "completed" ? "completed" : "failed",
1059
+ planMemberId: coordinate.planMemberId,
1060
+ requestId: coordinate.request?.requestId,
1061
+ effectRunId: result.effectRunId,
1062
+ effectRunResultId: result.resultId,
1063
+ sourceRefs: result.sourceRefs,
1064
+ metadata: { resultStatus: result.status }
1065
+ });
1066
+ return true;
1067
+ }
1068
+ function replayPendingPlanFacts(ctx, state) {
1069
+ let changed = false;
1070
+ for (const [evidenceId, evidence] of [...state.pendingEvidence]) {
1071
+ if (recordPlanEvidence(ctx, state, evidence)) {
1072
+ state.pendingEvidence.delete(evidenceId);
1073
+ changed = true;
1074
+ }
1075
+ }
1076
+ for (const [resultId, result] of [...state.pendingResults]) {
1077
+ if (recordPlanResult(ctx, state, result)) {
1078
+ state.pendingResults.delete(resultId);
1079
+ changed = true;
1080
+ }
1081
+ }
1082
+ return changed;
1083
+ }
1084
+ function planCoordinateFromEvidence(state, evidence) {
1085
+ const topLevelRequest = evidence.requestId === void 0 ? void 0 : state.requestByRequestId.get(evidence.requestId);
1086
+ const effectRunRequest = state.requestByEffectRun.get(evidence.effectRunId);
1087
+ if (evidence.planId !== void 0 && evidence.planMemberId !== void 0 && evidence.executionInputRevision !== void 0) {
1088
+ return {
1089
+ workItemId: evidence.workItemId,
1090
+ planId: evidence.planId,
1091
+ executionInputRevision: evidence.executionInputRevision,
1092
+ planMemberId: evidence.planMemberId,
1093
+ requestId: topLevelRequest?.requestId ?? effectRunRequest?.requestId ?? evidence.requestId,
1094
+ request: topLevelRequest ?? effectRunRequest
1095
+ };
1096
+ }
1097
+ const request = effectRunRequest;
1098
+ if (request?.planId !== void 0 && request.planMemberId !== void 0 && request.executionInputRevision !== void 0) {
1099
+ return {
1100
+ workItemId: request.workItemId,
1101
+ planId: request.planId,
1102
+ executionInputRevision: request.executionInputRevision,
1103
+ planMemberId: request.planMemberId,
1104
+ requestId: request.requestId,
1105
+ request
1106
+ };
1107
+ }
1108
+ const planId = stringMetadata(evidence.metadata, "planId");
1109
+ const planMemberId = stringMetadata(evidence.metadata, "planMemberId");
1110
+ const executionInputRevision = numberMetadata(evidence.metadata, "executionInputRevision");
1111
+ const requestId = stringMetadata(evidence.metadata, "requestId");
1112
+ if (planId === void 0 || planMemberId === void 0 || executionInputRevision === void 0)
1113
+ return void 0;
1114
+ return {
1115
+ workItemId: evidence.workItemId,
1116
+ planId,
1117
+ executionInputRevision,
1118
+ planMemberId,
1119
+ requestId
1120
+ };
1121
+ }
1122
+ function planCoordinateFromResult(state, result) {
1123
+ const request = state.requestByEffectRun.get(result.effectRunId);
1124
+ if (request?.planId !== void 0 && request.planMemberId !== void 0 && request.executionInputRevision !== void 0) {
1125
+ return {
1126
+ workItemId: request.workItemId,
1127
+ planId: request.planId,
1128
+ executionInputRevision: request.executionInputRevision,
1129
+ planMemberId: request.planMemberId,
1130
+ requestId: request.requestId,
1131
+ request
1132
+ };
1133
+ }
1134
+ const workItemId = sourceRefId(result.subjectRefs, "work-item") ?? sourceRefId(result.sourceRefs, "work-item");
1135
+ const planId = stringMetadata(result.metadata, "planId");
1136
+ const planMemberId = stringMetadata(result.metadata, "planMemberId");
1137
+ const executionInputRevision = numberMetadata(result.metadata, "executionInputRevision");
1138
+ if (workItemId === void 0 || planId === void 0 || planMemberId === void 0 || executionInputRevision === void 0)
1139
+ return void 0;
1140
+ return { workItemId, planId, executionInputRevision, planMemberId };
1141
+ }
1142
+ function recordMemberEvidence(ctx, state, admitted, planMemberId, evidence) {
1143
+ const coord = memberCoord(admitted, planMemberId);
1144
+ const existing = state.memberEvidence.get(coord);
1145
+ if (existing !== void 0) {
1146
+ const duplicateIssue = issue(
1147
+ "duplicate-suppressed",
1148
+ `WorkItemEffectPlan member '${planMemberId}' already has terminal evidence`,
1149
+ admitted.workItemId,
1150
+ {
1151
+ planId: admitted.planId,
1152
+ planMemberId,
1153
+ existingEvidenceId: existing.evidenceId,
1154
+ existingEffectRunResultId: existing.effectRunResultId,
1155
+ evidenceId: evidence.evidenceId,
1156
+ effectRunResultId: evidence.effectRunResultId
1157
+ }
1158
+ );
1159
+ emitPlan(ctx, "issue", duplicateIssue);
1160
+ emitPlanStatus(ctx, state, {
1161
+ workItemId: admitted.workItemId,
1162
+ planId: admitted.planId,
1163
+ executionInputRevision: admitted.executionInputRevision,
1164
+ state: "duplicate",
1165
+ planMemberId,
1166
+ requestId: evidence.requestId,
1167
+ effectRunId: evidence.effectRunId,
1168
+ evidenceId: evidence.evidenceId,
1169
+ effectRunResultId: evidence.effectRunResultId,
1170
+ issues: [duplicateIssue],
1171
+ sourceRefs: evidence.sourceRefs
1172
+ });
1173
+ return false;
1174
+ }
1175
+ state.memberEvidence.set(coord, evidence);
1176
+ return true;
1177
+ }
1178
+ function hasPlanMember(admitted, planMemberId) {
1179
+ return admitted.plan.members.some((member) => member.memberId === planMemberId);
1180
+ }
1181
+ function isAdmittedPlanStale(state, admitted) {
1182
+ const current = state.workItems.get(admitted.workItemId);
1183
+ return current !== void 0 && current.executionInputRevision !== admitted.executionInputRevision;
1184
+ }
1185
+ function emitStaleAdmittedPlanOnce(ctx, state, admitted) {
1186
+ const current = state.workItems.get(admitted.workItemId);
1187
+ emitPlanStatusOnce(ctx, state, `${memberCoord(admitted, "plan")}:stale`, {
1188
+ workItemId: admitted.workItemId,
1189
+ planId: admitted.planId,
1190
+ executionInputRevision: admitted.executionInputRevision,
1191
+ state: "stale",
1192
+ issues: [
1193
+ issue(
1194
+ "stale-execution-input",
1195
+ `WorkItemEffectPlan '${admitted.planId}' targets stale execution input`,
1196
+ admitted.workItemId,
1197
+ {
1198
+ planId: admitted.planId,
1199
+ proposedRevision: admitted.executionInputRevision,
1200
+ currentRevision: current?.executionInputRevision
1201
+ }
1202
+ )
1203
+ ],
1204
+ sourceRefs: admitted.sourceRefs,
1205
+ metadata: { currentRevision: current?.executionInputRevision }
1206
+ });
1207
+ }
1208
+ function emitUnknownPlanMember(ctx, state, admitted, planMemberId, metadata) {
1209
+ const item = issue(
1210
+ "dangling-ref",
1211
+ `WorkItemEffectPlan evidence/result references unknown member '${planMemberId}'`,
1212
+ admitted.workItemId,
1213
+ { planId: admitted.planId, planMemberId, ...metadata }
1214
+ );
1215
+ emitPlan(ctx, "issue", item);
1216
+ emitPlanStatus(ctx, state, {
1217
+ workItemId: admitted.workItemId,
1218
+ planId: admitted.planId,
1219
+ executionInputRevision: admitted.executionInputRevision,
1220
+ state: "rejected",
1221
+ planMemberId,
1222
+ issues: [item],
1223
+ sourceRefs: admitted.sourceRefs,
1224
+ metadata
1225
+ });
1226
+ }
1227
+ function emitUnmatchedEvidence(ctx, state, key, workItemId, metadata) {
1228
+ const seen = key.startsWith("evidence:") ? state.unmatchedEvidence : state.unmatchedResults;
1229
+ if (seen.has(key)) return;
1230
+ seen.add(key);
1231
+ const item = issue(
1232
+ "dangling-ref",
1233
+ "WorkItemEffectPlan evidence/result could not be joined to an admitted plan member",
1234
+ workItemId,
1235
+ metadata
1236
+ );
1237
+ emitPlan(ctx, "issue", item);
1238
+ emitPlanStatus(ctx, state, {
1239
+ workItemId: workItemId ?? "unknown",
1240
+ planId: typeof metadata.planId === "string" ? metadata.planId : "unknown",
1241
+ executionInputRevision: typeof metadata.executionInputRevision === "number" ? metadata.executionInputRevision : 0,
1242
+ state: "deferred",
1243
+ issues: [item],
1244
+ metadata
1245
+ });
1246
+ }
1247
+ function derivePlanResult(ctx, state, admitted) {
1248
+ const requiredMembers = admitted.plan.members.filter((member) => member.required !== false);
1249
+ if (requiredMembers.length === 0) return;
1250
+ const memberResults = [];
1251
+ for (const member of admitted.plan.members) {
1252
+ const evidence = state.memberEvidence.get(memberCoord(admitted, member.memberId));
1253
+ if (evidence === void 0) continue;
1254
+ memberResults.push({
1255
+ planMemberId: member.memberId,
1256
+ status: evidence.status,
1257
+ requestId: evidence.requestId,
1258
+ effectRunId: evidence.effectRunId,
1259
+ evidenceId: evidence.evidenceId,
1260
+ effectRunResultId: evidence.effectRunResultId
1261
+ });
1262
+ }
1263
+ const hasRequiredFailed = requiredMembers.some((member) => {
1264
+ const evidence = state.memberEvidence.get(memberCoord(admitted, member.memberId));
1265
+ return evidence !== void 0 && evidence.status !== "completed";
1266
+ });
1267
+ const settledRequiredCount = requiredMembers.filter(
1268
+ (member) => state.memberEvidence.has(memberCoord(admitted, member.memberId))
1269
+ ).length;
1270
+ const allRequiredSettled = settledRequiredCount === requiredMembers.length;
1271
+ const requiredBlockedByFailure = requiredMembers.some(
1272
+ (member) => memberBlockedByFailure(state, admitted, member.memberId, /* @__PURE__ */ new Set())
1273
+ );
1274
+ if (!hasRequiredFailed && !allRequiredSettled && !requiredBlockedByFailure) return;
1275
+ const status = admitted.plan.joinPolicy === "evidence-only" ? "evidence-only" : hasRequiredFailed || requiredBlockedByFailure ? "failed" : "succeeded";
1276
+ const key = memberCoord(admitted, "result");
1277
+ if (state.resultKeys.has(key)) return;
1278
+ state.resultKeys.add(key);
1279
+ const result = {
1280
+ kind: "work-item-effect-plan-result",
1281
+ resultId: `work-item-effect-plan-result:${admitted.workItemId}:${admitted.executionInputRevision}:${admitted.planId}`,
1282
+ workItemId: admitted.workItemId,
1283
+ planId: admitted.planId,
1284
+ executionInputRevision: admitted.executionInputRevision,
1285
+ status,
1286
+ memberResults,
1287
+ sourceRefs: admitted.sourceRefs
1288
+ };
1289
+ emitPlan(ctx, "result", result);
1290
+ emitPlanStatus(ctx, state, {
1291
+ workItemId: admitted.workItemId,
1292
+ planId: admitted.planId,
1293
+ executionInputRevision: admitted.executionInputRevision,
1294
+ state: status === "succeeded" || status === "evidence-only" ? "completed" : "failed",
1295
+ sourceRefs: admitted.sourceRefs,
1296
+ metadata: { resultId: result.resultId, resultStatus: status }
1297
+ });
1298
+ }
1299
+ function normalizeEffectPlanSnapshot(proposal, policy) {
1300
+ const joinPolicy = proposal.joinPolicy ?? policy?.joinPolicy ?? "all-required";
1301
+ const members = proposal.members.map(
1302
+ (member) => Object.freeze({
1303
+ ...member,
1304
+ goal: immutableClone(member.goal),
1305
+ dependsOnMemberIds: immutableClone(member.dependsOnMemberIds ?? []),
1306
+ contextRefs: immutableClone(member.contextRefs),
1307
+ requirements: immutableClone(member.requirements),
1308
+ capacityHints: immutableClone(member.capacityHints),
1309
+ limits: immutableClone(member.limits),
1310
+ policyRefs: immutableClone(member.policyRefs),
1311
+ sourceRefs: immutableClone(member.sourceRefs),
1312
+ metadata: immutableClone(member.metadata)
1313
+ })
1314
+ );
1315
+ return Object.freeze({
1316
+ planId: proposal.planId,
1317
+ workItemId: proposal.workItemId,
1318
+ executionInputRevision: proposal.executionInputRevision,
1319
+ members: Object.freeze(members),
1320
+ joinPolicy,
1321
+ limits: immutableClone(proposal.limits),
1322
+ policyRefs: immutableClone(proposal.policyRefs),
1323
+ sourceRefs: immutableClone(proposal.sourceRefs),
1324
+ metadata: immutableClone(proposal.metadata)
1325
+ });
1326
+ }
1327
+ function requestFromPlanMember(admitted, member, policy) {
1328
+ const requestId = `work-item:${admitted.workItemId}:effect-plan:${admitted.executionInputRevision}:${admitted.planId}:${member.memberId}`;
1329
+ const policyRefs = policy?.policyId === void 0 ? [...admitted.plan.policyRefs ?? [], ...member.policyRefs ?? []] : [
1330
+ ...admitted.plan.policyRefs ?? [],
1331
+ ...member.policyRefs ?? [],
1332
+ ref("work-item-effect-plan-policy", policy.policyId)
1333
+ ];
1334
+ return {
1335
+ kind: "work-item-effect-requested",
1336
+ requestId,
1337
+ workItemId: admitted.workItemId,
1338
+ effectRunId: `effect-run:${requestId}`,
1339
+ effectKind: member.effectKind,
1340
+ executionInputRevision: admitted.executionInputRevision,
1341
+ planId: admitted.planId,
1342
+ planMemberId: member.memberId,
1343
+ sourceRefs: [
1344
+ ref("work-item", admitted.workItemId),
1345
+ ref("work-item-revision", `${admitted.workItemId}:${admitted.executionInputRevision}`),
1346
+ ref("work-item-effect-plan", admitted.planId),
1347
+ ref("work-item-effect-plan-member", member.memberId),
1348
+ ...admitted.plan.sourceRefs ?? [],
1349
+ ...member.sourceRefs ?? []
1350
+ ],
1351
+ goal: member.goal,
1352
+ policyRefs: policyRefs.length === 0 ? void 0 : policyRefs,
1353
+ limits: member.limits ?? admitted.plan.limits,
1354
+ idempotencyKey: member.idempotencyKey ?? `${admitted.workItemId}:effect-plan:${admitted.executionInputRevision}:${admitted.planId}:${member.memberId}`,
1355
+ metadata: {
1356
+ ...member.metadata ?? {},
1357
+ executionInputRevision: admitted.executionInputRevision,
1358
+ planId: admitted.planId,
1359
+ planMemberId: member.memberId,
1360
+ ...member.contextRefs === void 0 ? {} : { contextRefs: member.contextRefs },
1361
+ ...member.requirements === void 0 ? {} : { requirements: member.requirements },
1362
+ ...member.capacityHints === void 0 ? {} : { capacityHints: member.capacityHints }
1363
+ }
1364
+ };
1365
+ }
1366
+ function immutableClone(value) {
1367
+ if (Array.isArray(value)) return Object.freeze(value.map((item) => immutableClone(item)));
1368
+ if (!isRecord(value)) return value;
1369
+ const out = {};
1370
+ for (const [key, child] of Object.entries(value)) out[key] = immutableClone(child);
1371
+ return Object.freeze(out);
1372
+ }
1373
+ function stringMetadata(metadata, key) {
1374
+ const value = metadata?.[key];
1375
+ return typeof value === "string" && value !== "" ? value : void 0;
1376
+ }
1377
+ function numberMetadata(metadata, key) {
1378
+ const value = metadata?.[key];
1379
+ return typeof value === "number" ? value : void 0;
1380
+ }
1381
+ function sourceRefId(refs2, kind) {
1382
+ return refs2?.find((sourceRef) => sourceRef.kind === kind)?.id;
1383
+ }
1384
+ function memberSucceeded(state, admitted, memberId) {
1385
+ return state.memberEvidence.get(memberCoord(admitted, memberId))?.status === "completed";
1386
+ }
1387
+ function memberBlockedByFailure(state, admitted, memberId, seen) {
1388
+ if (seen.has(memberId)) return false;
1389
+ seen.add(memberId);
1390
+ const evidence = state.memberEvidence.get(memberCoord(admitted, memberId));
1391
+ if (evidence !== void 0) return evidence.status !== "completed";
1392
+ const member = admitted.plan.members.find((item) => item.memberId === memberId);
1393
+ return (member?.dependsOnMemberIds ?? []).some(
1394
+ (depId) => memberBlockedByFailure(state, admitted, depId, seen)
1395
+ );
1396
+ }
1397
+ function memberCoord(admitted, memberId) {
1398
+ return `${admitted.workItemId}:${admitted.executionInputRevision}:${admitted.planId}:${memberId}`;
1399
+ }
1400
+ function planKey(workItemId, planId, executionInputRevision) {
1401
+ if (workItemId === void 0 || planId === void 0 || executionInputRevision === void 0)
1402
+ return void 0;
1403
+ return `${workItemId}:${executionInputRevision}:${planId}`;
1404
+ }
1405
+ function requiredPlanKey(workItemId, planId, executionInputRevision) {
1406
+ return `${workItemId}:${executionInputRevision}:${planId}`;
1407
+ }
1408
+ function emitPlanIssues(ctx, state, issues) {
1409
+ for (const item of issues) emitPlan(ctx, "issue", item);
1410
+ if (issues.length > 0) {
1411
+ state.auditSeq += 1;
1412
+ emitPlan(ctx, "audit", {
1413
+ id: `work-item-effect-plan-issue:${state.auditSeq}`,
1414
+ kind: "work-item-effect-plan-issue",
1415
+ subjectId: issues[0]?.subjectId,
1416
+ message: issues[0]?.message,
1417
+ issueCode: issues[0]?.code,
1418
+ metadata: { issueCodes: issues.map((item) => item.code) }
1419
+ });
1420
+ }
1421
+ }
1422
+ function emitPlanStatusOnce(ctx, state, key, status) {
1423
+ if (state.statusKeys.has(key)) return;
1424
+ state.statusKeys.add(key);
1425
+ emitPlanStatus(ctx, state, status);
1426
+ }
1427
+ function emitPlanStatus(ctx, state, status) {
1428
+ state.statusSeq += 1;
1429
+ const statusFact = {
1430
+ kind: "work-item-effect-plan-status",
1431
+ statusId: `work-item-effect-plan-status:${state.statusSeq}`,
1432
+ ...status
1433
+ };
1434
+ emitPlan(ctx, "status", statusFact);
1435
+ state.auditSeq += 1;
1436
+ emitPlan(ctx, "audit", {
1437
+ id: `work-item-effect-plan-status:${state.auditSeq}`,
1438
+ kind: "work-item-effect-plan-status",
1439
+ subjectId: status.workItemId,
1440
+ message: status.message,
1441
+ sourceRefs: status.sourceRefs,
1442
+ metadata: {
1443
+ statusId: statusFact.statusId,
1444
+ state: status.state,
1445
+ planId: status.planId,
1446
+ planMemberId: status.planMemberId,
1447
+ executionInputRevision: status.executionInputRevision,
1448
+ ...status.metadata ?? {}
1449
+ }
1450
+ });
1451
+ }
1452
+ function emitPlan(ctx, kind, value) {
1453
+ ctx.down([["DATA", { kind, value }]]);
1454
+ }
1455
+ function isWorkItemEffectPlanJoinPolicy(value) {
1456
+ return value === "all-required" || value === "evidence-only";
1457
+ }
1458
+ function findPlanCycle(members) {
1459
+ const byId = new Map(members.map((member) => [member.memberId, member.dependsOnMemberIds ?? []]));
1460
+ const visiting = /* @__PURE__ */ new Set();
1461
+ const visited = /* @__PURE__ */ new Set();
1462
+ const stack = [];
1463
+ const visit = (id) => {
1464
+ if (visiting.has(id)) return [...stack.slice(stack.indexOf(id)), id];
1465
+ if (visited.has(id)) return void 0;
1466
+ visiting.add(id);
1467
+ stack.push(id);
1468
+ for (const dep of byId.get(id) ?? []) {
1469
+ if (!byId.has(dep)) continue;
1470
+ const cycle = visit(dep);
1471
+ if (cycle !== void 0) return cycle;
1472
+ }
1473
+ stack.pop();
1474
+ visiting.delete(id);
1475
+ visited.add(id);
1476
+ return void 0;
1477
+ };
1478
+ for (const member of members) {
1479
+ const cycle = visit(member.memberId);
1480
+ if (cycle !== void 0) return cycle;
1481
+ }
1482
+ return void 0;
1483
+ }
1484
+ function reduceAuthoring(ctx, state, input, policy) {
1485
+ if (input.kind === "work-item-spawn-proposed") {
1486
+ const issues2 = validateWorkItemDraft(input.draft, { workItemId: input.parentWorkItemId });
1487
+ if (issues2.length > 0) {
1488
+ for (const item of issues2) emit(ctx, "issue", item);
1489
+ emitStatus(ctx, state, {
1490
+ state: "rejected",
1491
+ code: issues2[0]?.code,
1492
+ workItemId: input.parentWorkItemId,
1493
+ message: issues2[0]?.message,
1494
+ metadata: { proposalId: input.proposalId }
1495
+ });
1496
+ return;
1497
+ }
1498
+ emitStatus(ctx, state, {
1499
+ state: "deferred",
1500
+ workItemId: input.parentWorkItemId,
1501
+ message: `WorkItem spawn proposal '${input.proposalId}' carries draft data but is not applied`,
1502
+ metadata: { proposalId: input.proposalId }
1503
+ });
1504
+ return;
1505
+ }
1506
+ if (state.seenEvents.has(input.eventId)) {
1507
+ emit(
1508
+ ctx,
1509
+ "issue",
1510
+ issue("duplicate-id", `Duplicate WorkItem authoring id '${input.eventId}'`, input.workItemId)
1511
+ );
1512
+ return;
1513
+ }
1514
+ state.seenEvents.add(input.eventId);
1515
+ if (input.kind === "work-item-created") {
1516
+ if (state.workItems.has(input.workItemId)) {
1517
+ emit(
1518
+ ctx,
1519
+ "issue",
1520
+ issue("duplicate-id", `Duplicate WorkItem '${input.workItemId}'`, input.workItemId)
1521
+ );
1522
+ emitStatus(ctx, state, {
1523
+ state: "duplicate",
1524
+ code: "duplicate-id",
1525
+ workItemId: input.workItemId,
1526
+ metadata: { eventId: input.eventId }
1527
+ });
1528
+ return;
1529
+ }
1530
+ const issues2 = validateWorkItemDraft(input.draft, { workItemId: input.workItemId });
1531
+ if (issues2.length > 0) {
1532
+ reject(ctx, state, input.workItemId, issues2);
1533
+ return;
1534
+ }
1535
+ const projection = {
1536
+ ...input.draft,
1537
+ verificationPlan: normalizePlan(input.draft),
1538
+ workItemId: input.workItemId,
1539
+ authoringRevision: 1,
1540
+ executionInputRevision: 1,
1541
+ lastEventId: input.eventId,
1542
+ revisionSourceRefs: refs("work-item-authoring-fact", input.eventId, input.sourceRefs),
1543
+ createdAtMs: input.createdAtMs,
1544
+ updatedAtMs: input.createdAtMs
1545
+ };
1546
+ accept(ctx, state, projection);
1547
+ return;
1548
+ }
1549
+ const existing = state.workItems.get(input.workItemId);
1550
+ if (existing === void 0) {
1551
+ emit(
1552
+ ctx,
1553
+ "issue",
1554
+ issue(
1555
+ "dangling-ref",
1556
+ `Authoring fact '${input.eventId}' references unknown WorkItem '${input.workItemId}'`,
1557
+ input.workItemId
1558
+ )
1559
+ );
1560
+ return;
1561
+ }
1562
+ if (input.kind === "work-item-patched") {
1563
+ if (!isRecord(input.patch)) {
1564
+ reject(ctx, state, input.workItemId, [
1565
+ issue("invalid-patch", "WorkItemPatch must be an object", input.workItemId)
1566
+ ]);
1567
+ return;
1568
+ }
1569
+ const invalidKeys = Object.keys(input.patch).filter((key) => !draftPatchKeys.has(key));
1570
+ if (invalidKeys.length > 0) {
1571
+ reject(ctx, state, input.workItemId, [
1572
+ issue(
1573
+ "invalid-patch",
1574
+ `WorkItemPatch contains unsupported keys: ${invalidKeys.join(", ")}`,
1575
+ input.workItemId,
1576
+ {
1577
+ invalidKeys
1578
+ }
1579
+ )
1580
+ ]);
1581
+ return;
1582
+ }
1583
+ const draft = applyDraftPatch(existing, input.patch);
1584
+ const issues2 = validateWorkItemDraft(draft, { workItemId: input.workItemId });
1585
+ if (issues2.length > 0) {
1586
+ reject(ctx, state, input.workItemId, issues2);
1587
+ return;
1588
+ }
1589
+ const touched = touchesExecutionRelevant(
1590
+ input.patch,
1591
+ executionRelevant(policy, input.executionRelevantFields)
1592
+ );
1593
+ accept(ctx, state, {
1594
+ ...existing,
1595
+ ...draft,
1596
+ authoringRevision: existing.authoringRevision + 1,
1597
+ executionInputRevision: touched ? existing.executionInputRevision + 1 : existing.executionInputRevision,
1598
+ lastEventId: input.eventId,
1599
+ revisionSourceRefs: refs("work-item-authoring-fact", input.eventId, input.sourceRefs),
1600
+ updatedAtMs: input.patchedAtMs
1601
+ });
1602
+ return;
1603
+ }
1604
+ if (input.kind === "acceptance-criteria-changed") {
1605
+ const issues2 = validateAcceptanceCriteria(input.acceptanceCriteria, {
1606
+ workItemId: input.workItemId
1607
+ });
1608
+ if (issues2.length > 0) {
1609
+ reject(ctx, state, input.workItemId, issues2);
1610
+ return;
1611
+ }
1612
+ accept(ctx, state, {
1613
+ ...existing,
1614
+ acceptanceCriteria: input.acceptanceCriteria,
1615
+ authoringRevision: existing.authoringRevision + 1,
1616
+ executionInputRevision: existing.executionInputRevision + 1,
1617
+ lastEventId: input.eventId,
1618
+ revisionSourceRefs: refs("work-item-authoring-fact", input.eventId, input.sourceRefs),
1619
+ updatedAtMs: input.changedAtMs
1620
+ });
1621
+ return;
1622
+ }
1623
+ const issues = validateVerificationPlan(
1624
+ input.verificationPlan,
1625
+ existing.acceptanceCriteria ?? [],
1626
+ { workItemId: input.workItemId }
1627
+ );
1628
+ if (issues.length > 0) {
1629
+ reject(ctx, state, input.workItemId, issues);
1630
+ return;
1631
+ }
1632
+ accept(ctx, state, {
1633
+ ...existing,
1634
+ verificationPlan: input.verificationPlan,
1635
+ verificationSteps: input.verificationPlan.steps,
1636
+ authoringRevision: existing.authoringRevision + 1,
1637
+ executionInputRevision: existing.executionInputRevision + 1,
1638
+ lastEventId: input.eventId,
1639
+ revisionSourceRefs: refs("work-item-authoring-fact", input.eventId, input.sourceRefs),
1640
+ updatedAtMs: input.changedAtMs
1641
+ });
1642
+ }
1643
+ function lowerPlan(ctx, state, workItem, policy) {
1644
+ const plan = normalizePlan(workItem);
1645
+ if (plan === void 0) {
1646
+ emitRequestStatus(ctx, state, {
1647
+ state: "needs-human-review",
1648
+ code: "verification-unplanned",
1649
+ workItemId: workItem.workItemId
1650
+ });
1651
+ return;
1652
+ }
1653
+ const issues = validateVerificationPlan(plan, workItem.acceptanceCriteria ?? [], {
1654
+ workItemId: workItem.workItemId,
1655
+ allowedModes: policy?.allowedModes,
1656
+ allowedEffectKinds: policy?.allowedEffectKinds
1657
+ });
1658
+ if (issues.length > 0) {
1659
+ for (const item of issues) emit(ctx, "issue", item);
1660
+ return;
1661
+ }
1662
+ if (policy?.autoRun === false) {
1663
+ emitRequestStatus(ctx, state, {
1664
+ state: "deferred",
1665
+ code: "policy-mismatch",
1666
+ workItemId: workItem.workItemId,
1667
+ revision: workItem.authoringRevision,
1668
+ executionInputRevision: workItem.executionInputRevision,
1669
+ metadata: { policyId: policy.policyId, reason: "auto-run-disabled" }
1670
+ });
1671
+ return;
1672
+ }
1673
+ for (const step of plan.steps) {
1674
+ if (isStepSatisfied(state, workItem, step.stepId)) {
1675
+ emitRequestStatus(ctx, state, {
1676
+ state: "duplicate",
1677
+ code: "duplicate-suppressed",
1678
+ workItemId: workItem.workItemId,
1679
+ revision: workItem.authoringRevision,
1680
+ executionInputRevision: workItem.executionInputRevision,
1681
+ stepId: step.stepId,
1682
+ message: `Verification step '${step.stepId}' already has valid evidence`
1683
+ });
1684
+ continue;
1685
+ }
1686
+ if (step.mode === "manual") {
1687
+ emitRequestStatus(ctx, state, {
1688
+ state: "needs-human-review",
1689
+ code: "manual-review-required",
1690
+ workItemId: workItem.workItemId,
1691
+ stepId: step.stepId
1692
+ });
1693
+ continue;
1694
+ }
1695
+ const missingPrerequisites = (step.dependsOnStepIds ?? []).filter(
1696
+ (stepId) => !isStepSatisfied(state, workItem, stepId)
1697
+ );
1698
+ if (missingPrerequisites.length > 0) {
1699
+ emitRequestStatus(ctx, state, {
1700
+ state: "blocked",
1701
+ code: "blocked-prerequisite",
1702
+ workItemId: workItem.workItemId,
1703
+ stepId: step.stepId,
1704
+ metadata: { missingStepIds: missingPrerequisites }
1705
+ });
1706
+ continue;
1707
+ }
1708
+ emitRequest(ctx, state, requestFromStep(workItem, plan, step, policy));
1709
+ }
1710
+ }
1711
+ function lowerIntent(ctx, state, intent, policy) {
1712
+ const workItem = state.workItems.get(intent.workItemId);
1713
+ if (workItem === void 0) {
1714
+ emit(
1715
+ ctx,
1716
+ "issue",
1717
+ issue(
1718
+ "dangling-ref",
1719
+ `Dispatch intent '${intent.intentId}' references unknown WorkItem '${intent.workItemId}'`,
1720
+ intent.workItemId
1721
+ )
1722
+ );
1723
+ return;
1724
+ }
1725
+ if (intent.executionInputRevision !== workItem.executionInputRevision) {
1726
+ emit(
1727
+ ctx,
1728
+ "issue",
1729
+ issue(
1730
+ "stale-execution-input",
1731
+ `Dispatch intent '${intent.intentId}' targets stale execution input`,
1732
+ intent.workItemId,
1733
+ {
1734
+ intentRevision: intent.executionInputRevision,
1735
+ currentRevision: workItem.executionInputRevision,
1736
+ stalePolicy: policy?.stalePolicy ?? "review"
1737
+ }
1738
+ )
1739
+ );
1740
+ emitRequestStatus(ctx, state, {
1741
+ state: "stale",
1742
+ code: "stale-execution-input",
1743
+ workItemId: intent.workItemId,
1744
+ executionInputRevision: workItem.executionInputRevision,
1745
+ metadata: { intentId: intent.intentId }
1746
+ });
1747
+ return;
1748
+ }
1749
+ const effectKind = intent.effectKind ?? intent.targetKind;
1750
+ const allowedEffectKinds = new Set(policy?.allowedEffectKinds ?? ["verification"]);
1751
+ if (!allowedEffectKinds.has(effectKind)) {
1752
+ emit(
1753
+ ctx,
1754
+ "issue",
1755
+ issue(
1756
+ "unsupported-effect-kind",
1757
+ `Dispatch intent '${intent.intentId}' targets unsupported effect kind '${effectKind}'`,
1758
+ intent.workItemId,
1759
+ { intentId: intent.intentId, effectKind }
1760
+ )
1761
+ );
1762
+ emitRequestStatus(ctx, state, {
1763
+ state: "rejected",
1764
+ code: "unsupported-effect-kind",
1765
+ workItemId: intent.workItemId,
1766
+ executionInputRevision: workItem.executionInputRevision,
1767
+ metadata: { intentId: intent.intentId, effectKind }
1768
+ });
1769
+ return;
1770
+ }
1771
+ emitRequest(ctx, state, requestFromIntent(workItem, intent));
1772
+ }
1773
+ function recordVerificationResult(ctx, state, result, policy) {
1774
+ if (result.status !== "passed") return;
1775
+ const workItem = state.workItems.get(result.workItemId);
1776
+ if (workItem === void 0) {
1777
+ emit(
1778
+ ctx,
1779
+ "issue",
1780
+ issue(
1781
+ "dangling-ref",
1782
+ `Verification result '${result.resultId}' references unknown WorkItem '${result.workItemId}'`,
1783
+ result.workItemId
1784
+ )
1785
+ );
1786
+ return;
1787
+ }
1788
+ if (result.executionInputRevision !== workItem.executionInputRevision) {
1789
+ emit(
1790
+ ctx,
1791
+ "issue",
1792
+ issue(
1793
+ "stale-revision",
1794
+ `Verification result '${result.resultId}' targets stale execution input`,
1795
+ result.workItemId
1796
+ )
1797
+ );
1798
+ return;
1799
+ }
1800
+ const key = revisionKey(result.workItemId, result.executionInputRevision);
1801
+ const passedSteps = state.passedSteps.get(key) ?? /* @__PURE__ */ new Set();
1802
+ for (const stepId of result.verificationStepIds) passedSteps.add(stepId);
1803
+ state.passedSteps.set(key, passedSteps);
1804
+ lowerPlan(ctx, state, workItem, policy);
1805
+ }
1806
+ function mapEvidence(ctx, state, evidence, replay = false) {
1807
+ if (!replay && state.evidenceById.has(evidence.evidenceId)) {
1808
+ emit(
1809
+ ctx,
1810
+ "issue",
1811
+ issue(
1812
+ "duplicate-suppressed",
1813
+ `Duplicate evidence '${evidence.evidenceId}'`,
1814
+ evidence.workItemId
1815
+ )
1816
+ );
1817
+ return;
1818
+ }
1819
+ state.evidenceById.set(evidence.evidenceId, evidence);
1820
+ const workItem = state.workItems.get(evidence.workItemId);
1821
+ if (workItem === void 0) {
1822
+ emit(
1823
+ ctx,
1824
+ "issue",
1825
+ issue(
1826
+ "dangling-ref",
1827
+ `Evidence '${evidence.evidenceId}' references unknown WorkItem '${evidence.workItemId}'`,
1828
+ evidence.workItemId
1829
+ )
1830
+ );
1831
+ return;
1832
+ }
1833
+ const revision = typeof evidence.metadata?.executionInputRevision === "number" ? evidence.metadata.executionInputRevision : void 0;
1834
+ if (revision !== workItem.executionInputRevision) {
1835
+ emit(
1836
+ ctx,
1837
+ "issue",
1838
+ issue(
1839
+ "stale-revision",
1840
+ `Evidence '${evidence.evidenceId}' targets stale revision`,
1841
+ evidence.workItemId
1842
+ )
1843
+ );
1844
+ emitResultStatus(ctx, state, {
1845
+ state: "stale",
1846
+ code: "stale-revision",
1847
+ workItemId: evidence.workItemId,
1848
+ executionInputRevision: workItem.executionInputRevision
1849
+ });
1850
+ return;
1851
+ }
1852
+ const stepIds = stringArray(evidence.metadata?.verificationStepIds);
1853
+ const criterionIds = stringArray(evidence.metadata?.acceptanceCriterionIds);
1854
+ if (stepIds.length === 0 || criterionIds.length === 0) {
1855
+ emit(
1856
+ ctx,
1857
+ "issue",
1858
+ issue(
1859
+ "ambiguous-coverage",
1860
+ `Evidence '${evidence.evidenceId}' lacks coverage refs`,
1861
+ evidence.workItemId
1862
+ )
1863
+ );
1864
+ return;
1865
+ }
1866
+ const coverageIssue = validateEvidenceCoverage(workItem, stepIds, criterionIds);
1867
+ if (coverageIssue !== void 0) {
1868
+ emit(ctx, "issue", {
1869
+ ...coverageIssue,
1870
+ message: `Evidence '${evidence.evidenceId}' has invalid verification coverage: ${coverageIssue.message}`
1871
+ });
1872
+ emitResultStatus(ctx, state, {
1873
+ state: "rejected",
1874
+ code: coverageIssue.code,
1875
+ workItemId: evidence.workItemId,
1876
+ executionInputRevision: workItem.executionInputRevision,
1877
+ metadata: { evidenceId: evidence.evidenceId }
1878
+ });
1879
+ return;
1880
+ }
1881
+ const result = {
1882
+ kind: "verification-result-recorded",
1883
+ resultId: `verification-result:${evidence.evidenceId}`,
1884
+ workItemId: evidence.workItemId,
1885
+ evidenceId: evidence.evidenceId,
1886
+ effectRunId: evidence.effectRunId,
1887
+ effectRunResultId: evidence.effectRunResultId,
1888
+ executionInputRevision: revision,
1889
+ verificationStepIds: stepIds,
1890
+ acceptanceCriterionIds: criterionIds,
1891
+ status: resultStatus(evidence.status),
1892
+ output: evidence.output,
1893
+ error: evidence.error,
1894
+ reason: evidence.reason,
1895
+ sourceRefs: evidence.sourceRefs,
1896
+ recordedAtMs: evidence.recordedAtMs,
1897
+ metadata: evidence.metadata
1898
+ };
1899
+ if (!state.resultEvidence.has(evidence.evidenceId)) {
1900
+ state.resultEvidence.add(evidence.evidenceId);
1901
+ emit(ctx, "result", result);
1902
+ emitResultStatus(ctx, state, {
1903
+ state: "result-recorded",
1904
+ workItemId: evidence.workItemId,
1905
+ executionInputRevision: revision,
1906
+ metadata: { resultId: result.resultId }
1907
+ });
1908
+ }
1909
+ const policyIds = [
1910
+ ...new Set(
1911
+ (evidence.sourceRefs ?? []).filter((sourceRef) => sourceRef.kind === "work-item-verification-mapping-policy").map((sourceRef) => sourceRef.id)
1912
+ )
1913
+ ];
1914
+ if (policyIds.length === 0) return;
1915
+ for (const policyId of policyIds) {
1916
+ const policy = state.policies.get(policyId);
1917
+ if (policy === void 0) {
1918
+ if (!replay) {
1919
+ emit(
1920
+ ctx,
1921
+ "issue",
1922
+ issue(
1923
+ "missing-policy",
1924
+ `Missing verification mapping policy '${policyId}'`,
1925
+ evidence.workItemId,
1926
+ { policyId }
1927
+ )
1928
+ );
1929
+ emitResultStatus(ctx, state, {
1930
+ state: "deferred",
1931
+ code: "missing-policy",
1932
+ workItemId: evidence.workItemId,
1933
+ executionInputRevision: revision,
1934
+ metadata: { evidenceId: evidence.evidenceId, policyId }
1935
+ });
1936
+ }
1937
+ continue;
1938
+ }
1939
+ for (const [index, spec] of (policy.actionProposals ?? []).entries()) {
1940
+ if (spec.behavior !== void 0 && spec.behavior !== "propose") {
1941
+ emit(ctx, "issue", actionProposalIssue(policy, spec, evidence, "unsupported behavior"));
1942
+ continue;
1943
+ }
1944
+ if (spec.actionKind.length === 0) {
1945
+ emit(ctx, "issue", actionProposalIssue(policy, spec, evidence, "empty actionKind"));
1946
+ continue;
1947
+ }
1948
+ if (spec.statuses !== void 0 && !spec.statuses.includes(evidence.status)) continue;
1949
+ const outputKind = evidence.output?.kind;
1950
+ if (spec.outputKinds !== void 0 && (outputKind === void 0 || !spec.outputKinds.includes(outputKind)))
1951
+ continue;
1952
+ const proposalKey = `${evidence.evidenceId}:${policy.policyId}:${index}:${spec.actionKind}`;
1953
+ if (state.proposalKeys.has(proposalKey)) continue;
1954
+ state.proposalKeys.add(proposalKey);
1955
+ emit(ctx, "proposal", {
1956
+ kind: "work-item-domain-action-proposal",
1957
+ proposalId: `verification:${result.resultId}:${policy.policyId}:${index}:${spec.actionKind}`,
1958
+ workItemId: result.workItemId,
1959
+ actionKind: spec.actionKind,
1960
+ effectRunId: result.effectRunId,
1961
+ effectRunResultId: result.effectRunResultId,
1962
+ evidenceId: result.evidenceId,
1963
+ policyId: policy.policyId,
1964
+ payload: actionProposalPayload(spec, evidence, result),
1965
+ reason: spec.reason ?? evidence.reason,
1966
+ sourceRefs: [
1967
+ ref("work-item-evidence", evidence.evidenceId),
1968
+ ref("verification-result", result.resultId),
1969
+ ref("effect-run-result", result.effectRunResultId),
1970
+ ref("work-item-verification-mapping-policy", policy.policyId)
1971
+ ],
1972
+ metadata: {
1973
+ ...policy.metadata ?? {},
1974
+ ...spec.metadata ?? {},
1975
+ resultStatus: evidence.status
1976
+ }
1977
+ });
1978
+ emitResultStatus(ctx, state, {
1979
+ state: "domain-action-proposed",
1980
+ workItemId: evidence.workItemId,
1981
+ executionInputRevision: revision,
1982
+ metadata: { actionKind: spec.actionKind, policyId: policy.policyId }
1983
+ });
1984
+ }
1985
+ }
1986
+ }
1987
+ function requestFromStep(workItem, plan, step, policy) {
1988
+ const requestId = `work-item:${workItem.workItemId}:verification:${workItem.executionInputRevision}:${plan.planId}:${step.stepId}`;
1989
+ const effectKind = step.effectKind ?? "verification";
1990
+ const criterionIds = step.verifiesCriteriaIds ?? (workItem.acceptanceCriteria ?? []).map((criterion) => criterion.criterionId);
1991
+ const goal = goalWithInlineInput(
1992
+ step.goal ?? { kind: effectKind, summary: step.title ?? workItem.summary },
1993
+ step.input,
1994
+ `verification-step:${step.stepId}:input`,
1995
+ effectKind,
1996
+ step.contextRefs
1997
+ );
1998
+ return {
1999
+ kind: "work-item-effect-requested",
2000
+ requestId,
2001
+ workItemId: workItem.workItemId,
2002
+ effectRunId: `effect-run:${requestId}`,
2003
+ effectKind,
2004
+ executionInputRevision: workItem.executionInputRevision,
2005
+ sourceRefs: [
2006
+ ref("work-item", workItem.workItemId),
2007
+ ref("work-item-revision", `${workItem.workItemId}:${workItem.executionInputRevision}`),
2008
+ ref("verification-plan", plan.planId),
2009
+ ref("verification-step", step.stepId),
2010
+ ...plan.sourceRefs ?? [],
2011
+ ...step.sourceRefs ?? []
2012
+ ],
2013
+ goal,
2014
+ policyRefs: policy?.policyId === void 0 ? step.policyRefs : [
2015
+ ...step.policyRefs ?? [],
2016
+ ref("work-item-verification-lowerer-policy", policy.policyId)
2017
+ ],
2018
+ idempotencyKey: `${workItem.workItemId}:verification:${workItem.executionInputRevision}:${plan.planId}:${step.stepId}`,
2019
+ metadata: {
2020
+ ...step.metadata ?? {},
2021
+ executionInputRevision: workItem.executionInputRevision,
2022
+ verificationPlanId: plan.planId,
2023
+ verificationStepIds: [step.stepId],
2024
+ acceptanceCriterionIds: criterionIds,
2025
+ ...step.contextRefs === void 0 ? {} : { contextRefs: step.contextRefs },
2026
+ ...step.requirements === void 0 ? {} : { requirements: step.requirements },
2027
+ ...step.capacityHints === void 0 ? {} : { capacityHints: step.capacityHints }
2028
+ }
2029
+ };
2030
+ }
2031
+ function requestFromIntent(workItem, intent) {
2032
+ const requestId = `work-item:${workItem.workItemId}:dispatch:${workItem.executionInputRevision}:${intent.intentId}`;
2033
+ const effectKind = intent.effectKind ?? intent.targetKind;
2034
+ return {
2035
+ kind: "work-item-effect-requested",
2036
+ requestId,
2037
+ workItemId: workItem.workItemId,
2038
+ effectRunId: `effect-run:${requestId}`,
2039
+ effectKind,
2040
+ executionInputRevision: workItem.executionInputRevision,
2041
+ sourceRefs: [
2042
+ ref("work-item", workItem.workItemId),
2043
+ ref("work-item-dispatch-intent", intent.intentId),
2044
+ ...intent.sourceRefs ?? []
2045
+ ],
2046
+ goal: intent.goal ?? { kind: effectKind, summary: intent.reason ?? workItem.summary },
2047
+ policyRefs: intent.policyRefs,
2048
+ limits: intent.limits,
2049
+ idempotencyKey: intent.idempotencyKey ?? `${workItem.workItemId}:dispatch:${workItem.executionInputRevision}:${intent.intentId}`,
2050
+ metadata: {
2051
+ ...intent.metadata ?? {},
2052
+ executionInputRevision: workItem.executionInputRevision,
2053
+ verificationStepIds: intent.stepIds ?? [],
2054
+ acceptanceCriterionIds: intent.acceptanceCriterionIds ?? [],
2055
+ ...intent.contextRefs === void 0 ? {} : { contextRefs: intent.contextRefs },
2056
+ ...intent.requirements === void 0 ? {} : { requirements: intent.requirements },
2057
+ ...intent.capacityHints === void 0 ? {} : { capacityHints: intent.capacityHints }
2058
+ }
2059
+ };
2060
+ }
2061
+ function accept(ctx, state, projection) {
2062
+ state.workItems.set(projection.workItemId, projection);
2063
+ emit(ctx, "work-item", projection);
2064
+ emitStatus(ctx, state, {
2065
+ state: "projected",
2066
+ workItemId: projection.workItemId,
2067
+ revision: projection.authoringRevision,
2068
+ executionInputRevision: projection.executionInputRevision,
2069
+ metadata: { lastEventId: projection.lastEventId }
2070
+ });
2071
+ }
2072
+ function reject(ctx, state, workItemId, issues) {
2073
+ for (const item of issues) emit(ctx, "issue", item);
2074
+ emitStatus(ctx, state, {
2075
+ state: "rejected",
2076
+ code: issues[0]?.code,
2077
+ workItemId,
2078
+ message: issues[0]?.message
2079
+ });
2080
+ }
2081
+ function emitRequest(ctx, state, request) {
2082
+ const key = request.idempotencyKey ?? request.requestId;
2083
+ if (state.emittedKeys.has(key)) {
2084
+ emitRequestStatus(ctx, state, {
2085
+ state: "duplicate",
2086
+ code: "duplicate-suppressed",
2087
+ workItemId: request.workItemId,
2088
+ metadata: { requestId: request.requestId }
2089
+ });
2090
+ return;
2091
+ }
2092
+ state.emittedKeys.add(key);
2093
+ emit(ctx, "request", request);
2094
+ emitRequestStatus(ctx, state, {
2095
+ state: "request-emitted",
2096
+ workItemId: request.workItemId,
2097
+ executionInputRevision: request.executionInputRevision ?? request.metadata?.executionInputRevision,
2098
+ metadata: { requestId: request.requestId }
2099
+ });
2100
+ }
2101
+ function emitStatus(ctx, state, status) {
2102
+ state.statusSeq += 1;
2103
+ const statusFact = {
2104
+ kind: "work-item-validation-status",
2105
+ statusId: `work-item-authoring-status:${state.statusSeq}`,
2106
+ ...status
2107
+ };
2108
+ emit(ctx, "status", statusFact);
2109
+ emitAudit(ctx, state, "work-item-authoring-status", statusFact);
2110
+ }
2111
+ function emitRequestStatus(ctx, state, status) {
2112
+ state.statusSeq += 1;
2113
+ const statusFact = {
2114
+ kind: "work-item-validation-status",
2115
+ statusId: `work-item-verification-request-status:${state.statusSeq}`,
2116
+ ...status
2117
+ };
2118
+ emit(ctx, "status", statusFact);
2119
+ emitAudit(ctx, state, "work-item-verification-request-status", statusFact);
2120
+ }
2121
+ function emitResultStatus(ctx, state, status) {
2122
+ state.statusSeq += 1;
2123
+ const statusFact = {
2124
+ kind: "work-item-validation-status",
2125
+ statusId: `work-item-verification-result-status:${state.statusSeq}`,
2126
+ ...status
2127
+ };
2128
+ emit(ctx, "status", statusFact);
2129
+ emitAudit(ctx, state, "work-item-verification-result-status", statusFact);
2130
+ }
2131
+ function emitAudit(ctx, state, kind, status) {
2132
+ state.auditSeq += 1;
2133
+ emit(ctx, "audit", {
2134
+ id: `${kind}:${state.auditSeq}`,
2135
+ kind,
2136
+ subjectId: status.workItemId,
2137
+ message: status.message,
2138
+ issueCode: status.code,
2139
+ sourceRefs: status.sourceRefs,
2140
+ metadata: {
2141
+ statusId: status.statusId,
2142
+ state: status.state,
2143
+ revision: status.revision,
2144
+ executionInputRevision: status.executionInputRevision,
2145
+ ...status.metadata ?? {}
2146
+ }
2147
+ });
2148
+ }
2149
+ function emit(ctx, kind, value) {
2150
+ ctx.down([["DATA", { kind, value }]]);
2151
+ }
2152
+ function project(graph, runtime, name, factory, select) {
2153
+ return graph.node(
2154
+ [runtime],
2155
+ (ctx) => {
2156
+ for (const raw of depBatch(ctx, 0) ?? []) {
2157
+ const selected = select(raw);
2158
+ if (selected !== void 0) ctx.down([["DATA", selected]]);
2159
+ }
2160
+ },
2161
+ { name, factory, partial: true, completeWhenDepsComplete: false, errorWhenDepsError: false }
2162
+ );
2163
+ }
2164
+ function normalizePlan(draft) {
2165
+ if (draft.verificationPlan !== void 0) return draft.verificationPlan;
2166
+ if (draft.verificationSteps !== void 0)
2167
+ return { planId: "default", steps: draft.verificationSteps };
2168
+ return void 0;
2169
+ }
2170
+ function normalizePlanFromUnknown(draft) {
2171
+ const verificationPlan = draft.verificationPlan;
2172
+ if (verificationPlan !== void 0) {
2173
+ if (!isRecord(verificationPlan) || !Array.isArray(verificationPlan.steps)) {
2174
+ return { planId: "malformed", steps: [] };
2175
+ }
2176
+ return verificationPlan;
2177
+ }
2178
+ const verificationSteps = draft.verificationSteps;
2179
+ if (verificationSteps !== void 0) {
2180
+ if (!Array.isArray(verificationSteps)) return { planId: "malformed", steps: [] };
2181
+ return { planId: "default", steps: verificationSteps };
2182
+ }
2183
+ return void 0;
2184
+ }
2185
+ function isVerificationPlanShape(value) {
2186
+ return isRecord(value) && typeof value.planId === "string" && Array.isArray(value.steps);
2187
+ }
2188
+ function applyDraftPatch(existing, patch) {
2189
+ return {
2190
+ summary: patchValue(patch, existing, "summary"),
2191
+ detail: patchValue(patch, existing, "detail"),
2192
+ detailRefs: patchValue(patch, existing, "detailRefs"),
2193
+ acceptanceCriteria: patchValue(patch, existing, "acceptanceCriteria"),
2194
+ verificationPlan: patchValue(patch, existing, "verificationPlan"),
2195
+ verificationSteps: patchValue(patch, existing, "verificationSteps"),
2196
+ kind: patchValue(patch, existing, "kind"),
2197
+ priority: patchValue(patch, existing, "priority"),
2198
+ tags: patchValue(patch, existing, "tags"),
2199
+ owner: patchValue(patch, existing, "owner"),
2200
+ assignee: patchValue(patch, existing, "assignee"),
2201
+ deadlineMs: patchValue(patch, existing, "deadlineMs"),
2202
+ customFields: patchValue(patch, existing, "customFields"),
2203
+ sourceRefs: patchValue(patch, existing, "sourceRefs"),
2204
+ metadata: patchValue(patch, existing, "metadata")
2205
+ };
2206
+ }
2207
+ function patchValue(patch, existing, key) {
2208
+ return Object.hasOwn(patch, key) ? patch[key] : existing[key];
2209
+ }
2210
+ function validateEvidenceCoverage(workItem, stepIds, criterionIds) {
2211
+ const plan = normalizePlan(workItem);
2212
+ const validStepIds = new Set((plan?.steps ?? []).map((step) => step.stepId));
2213
+ const validCriterionIds = new Set(
2214
+ (workItem.acceptanceCriteria ?? []).map((criterion) => criterion.criterionId)
2215
+ );
2216
+ for (const stepId of stepIds) {
2217
+ if (!validStepIds.has(stepId)) {
2218
+ return issue("dangling-ref", `unknown verification step '${stepId}'`, workItem.workItemId, {
2219
+ stepId
2220
+ });
2221
+ }
2222
+ }
2223
+ for (const criterionId of criterionIds) {
2224
+ if (!validCriterionIds.has(criterionId)) {
2225
+ return issue(
2226
+ "dangling-ref",
2227
+ `unknown acceptance criterion '${criterionId}'`,
2228
+ workItem.workItemId,
2229
+ { criterionId }
2230
+ );
2231
+ }
2232
+ }
2233
+ return void 0;
2234
+ }
2235
+ function executionRelevant(policy, fields) {
2236
+ return /* @__PURE__ */ new Set([
2237
+ ...executionRelevantDefaults,
2238
+ ...policy?.executionRelevantFields ?? [],
2239
+ ...fields ?? []
2240
+ ]);
2241
+ }
2242
+ function touchesExecutionRelevant(patch, relevantFields) {
2243
+ const paths = patchPaths(patch);
2244
+ for (const path of paths) {
2245
+ if (relevantFields.has(path)) return true;
2246
+ }
2247
+ return false;
2248
+ }
2249
+ function patchPaths(patch) {
2250
+ const paths = [];
2251
+ for (const [key, value] of Object.entries(patch)) {
2252
+ paths.push(key);
2253
+ if (isRecord(value)) {
2254
+ for (const childKey of Object.keys(value)) paths.push(`${key}.${childKey}`);
2255
+ }
2256
+ }
2257
+ return paths;
2258
+ }
2259
+ function isStepSatisfied(state, workItem, stepId) {
2260
+ return state.passedSteps.get(revisionKey(workItem.workItemId, workItem.executionInputRevision))?.has(stepId) === true;
2261
+ }
2262
+ function revisionKey(workItemId, executionInputRevision) {
2263
+ return `${workItemId}:${executionInputRevision}`;
2264
+ }
2265
+ function replayEvidence(ctx, state, workItemId) {
2266
+ for (const evidence of state.evidenceById.values()) {
2267
+ if (evidence.workItemId === workItemId) mapEvidence(ctx, state, evidence, true);
2268
+ }
2269
+ }
2270
+ function validateMappingPolicy(policy) {
2271
+ if (!isRecord(policy) || policy.kind !== "work-item-verification-mapping-policy" || typeof policy.policyId !== "string" || policy.policyId.trim() === "") {
2272
+ return [
2273
+ issue(
2274
+ "policy-mismatch",
2275
+ "WorkItemVerificationMappingPolicy requires kind and policyId",
2276
+ void 0
2277
+ )
2278
+ ];
2279
+ }
2280
+ if (policy.actionProposals !== void 0 && !Array.isArray(policy.actionProposals)) {
2281
+ return [
2282
+ issue(
2283
+ "policy-mismatch",
2284
+ "WorkItemVerificationMappingPolicy.actionProposals must be an array",
2285
+ void 0,
2286
+ {
2287
+ policyId: policy.policyId
2288
+ }
2289
+ )
2290
+ ];
2291
+ }
2292
+ const out = [];
2293
+ for (const [index, spec] of (policy.actionProposals ?? []).entries()) {
2294
+ if (!isRecord(spec) || typeof spec.actionKind !== "string") {
2295
+ out.push(
2296
+ issue("policy-mismatch", "WorkItem action proposal requires actionKind", void 0, {
2297
+ policyId: policy.policyId,
2298
+ index
2299
+ })
2300
+ );
2301
+ }
2302
+ }
2303
+ return out;
2304
+ }
2305
+ function findCycle(steps) {
2306
+ const byId = new Map(steps.map((step) => [step.stepId, step.dependsOnStepIds ?? []]));
2307
+ const visiting = /* @__PURE__ */ new Set();
2308
+ const visited = /* @__PURE__ */ new Set();
2309
+ const stack = [];
2310
+ const visit = (id) => {
2311
+ if (visiting.has(id)) return [...stack.slice(stack.indexOf(id)), id];
2312
+ if (visited.has(id)) return void 0;
2313
+ visiting.add(id);
2314
+ stack.push(id);
2315
+ for (const dep of byId.get(id) ?? []) {
2316
+ if (!byId.has(dep)) continue;
2317
+ const cycle = visit(dep);
2318
+ if (cycle !== void 0) return cycle;
2319
+ }
2320
+ stack.pop();
2321
+ visiting.delete(id);
2322
+ visited.add(id);
2323
+ return void 0;
2324
+ };
2325
+ for (const step of steps) {
2326
+ const cycle = visit(step.stepId);
2327
+ if (cycle !== void 0) return cycle;
2328
+ }
2329
+ return void 0;
2330
+ }
2331
+ function resultStatus(status) {
2332
+ if (status === "completed") return "passed";
2333
+ if (status === "failed") return "failed";
2334
+ if (status === "blocked") return "blocked";
2335
+ if (status === "canceled") return "canceled";
2336
+ if (status === "timeout") return "timeout";
2337
+ return "waived";
2338
+ }
2339
+ function goalWithInlineInput(goal, input, inputId, inputKind, subjectRefs) {
2340
+ if (input === void 0 || goal.input !== void 0) return goal;
2341
+ return {
2342
+ ...goal,
2343
+ input: {
2344
+ inputId,
2345
+ inputKind,
2346
+ dataMode: "inline",
2347
+ value: input,
2348
+ subjectRefs
2349
+ }
2350
+ };
2351
+ }
2352
+ function actionProposalPayload(spec, evidence, result) {
2353
+ if (spec.payload !== void 0) return spec.payload;
2354
+ if (spec.payloadFrom === "effect-run-result")
2355
+ return { kind: "effect-run-result-ref", resultId: result.effectRunResultId };
2356
+ if (spec.payloadFrom === "output") return evidence.output;
2357
+ if (spec.payloadFrom === "evidence")
2358
+ return { kind: "work-item-evidence-ref", evidenceId: evidence.evidenceId };
2359
+ return void 0;
2360
+ }
2361
+ function actionProposalIssue(policy, spec, evidence, reason) {
2362
+ return issue(
2363
+ "policy-mismatch",
2364
+ `Verification mapping policy '${policy.policyId}' has an invalid action proposal: ${reason}`,
2365
+ evidence.workItemId,
2366
+ { policyId: policy.policyId, actionKind: spec.actionKind }
2367
+ );
2368
+ }
2369
+ function issue(code, message, workItemId, metadata) {
2370
+ return {
2371
+ kind: "issue",
2372
+ code,
2373
+ message,
2374
+ severity: "error",
2375
+ source: "work-item-scheduling",
2376
+ subjectId: workItemId,
2377
+ metadata
2378
+ };
2379
+ }
2380
+ function refs(kind, id, rest) {
2381
+ return [ref(kind, id), ...rest ?? []];
2382
+ }
2383
+ function ref(kind, id) {
2384
+ return { kind, id };
2385
+ }
2386
+ function stringArray(value) {
2387
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
2388
+ }
2389
+ function isRecord(value) {
2390
+ return value !== null && typeof value === "object";
2391
+ }
2392
+
2393
+ export {
2394
+ workItemCreatedFromDraft,
2395
+ workItemSpawnProposed,
2396
+ acceptanceCriteriaChanged,
2397
+ verificationPlanChanged,
2398
+ validateWorkItemDraft,
2399
+ validateAcceptanceCriteria,
2400
+ validateVerificationPlan,
2401
+ workItemAuthoringProjector,
2402
+ workItemVerificationRequestLowerer,
2403
+ workItemVerificationResultMapper,
2404
+ validateWorkItemEffectPlan,
2405
+ workItemEffectPlanProjector
2406
+ };
2407
+ //# sourceMappingURL=chunk-6XAIOL3X.js.map