@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,2164 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/solutions/work-item/actions.ts
21
+ var actions_exports = {};
22
+ __export(actions_exports, {
23
+ workItemDomainActionAdmissionProjector: () => workItemDomainActionAdmissionProjector,
24
+ workItemDomainActionApplicationProjector: () => workItemDomainActionApplicationProjector,
25
+ workItemDomainActionApplyPolicy: () => workItemDomainActionApplyPolicy,
26
+ workItemDomainActionCapabilityGuardProjector: () => workItemDomainActionCapabilityGuardProjector,
27
+ workItemDomainActionProposal: () => workItemDomainActionProposal,
28
+ workItemDomainActionProposalIntake: () => workItemDomainActionProposalIntake,
29
+ workItemDomainActionProposalIntakeProjector: () => workItemDomainActionProposalIntakeProjector
30
+ });
31
+ module.exports = __toCommonJS(actions_exports);
32
+
33
+ // src/protocol/messages.ts
34
+ var SENTINEL = void 0;
35
+
36
+ // src/ctx/types.ts
37
+ function depWaves(ctx, depIndex) {
38
+ return ctx.waveData[depIndex] ?? [];
39
+ }
40
+ function depBatch(ctx, depIndex) {
41
+ const waves = depWaves(ctx, depIndex);
42
+ if (waves.length === 0) return null;
43
+ const flattened = waves.flat().filter((v) => v !== SENTINEL);
44
+ return flattened.length === 0 ? [] : flattened;
45
+ }
46
+
47
+ // src/solutions/work-item/scheduling.ts
48
+ function validateAcceptanceCriteria(criteria, opts = {}) {
49
+ const out = [];
50
+ const seen = /* @__PURE__ */ new Set();
51
+ for (const criterion of criteria) {
52
+ if (!isRecord(criterion)) {
53
+ out.push(issue("malformed-draft", "AcceptanceCriterion must be an object", opts.workItemId));
54
+ continue;
55
+ }
56
+ if (typeof criterion.criterionId !== "string" || criterion.criterionId === "") {
57
+ out.push(
58
+ issue(
59
+ "missing-required-field",
60
+ "AcceptanceCriterion.criterionId is required",
61
+ opts.workItemId
62
+ )
63
+ );
64
+ continue;
65
+ }
66
+ if (seen.has(criterion.criterionId)) {
67
+ out.push(
68
+ issue(
69
+ "duplicate-id",
70
+ `Duplicate acceptance criterion id '${criterion.criterionId}'`,
71
+ opts.workItemId,
72
+ { criterionId: criterion.criterionId }
73
+ )
74
+ );
75
+ }
76
+ seen.add(criterion.criterionId);
77
+ if (typeof criterion.statement !== "string" || criterion.statement.trim() === "") {
78
+ out.push(
79
+ issue(
80
+ "missing-required-field",
81
+ "AcceptanceCriterion.statement is required",
82
+ opts.workItemId,
83
+ { criterionId: criterion.criterionId }
84
+ )
85
+ );
86
+ }
87
+ }
88
+ return out;
89
+ }
90
+ function validateVerificationPlan(plan, criteria = [], opts = {}) {
91
+ const out = [];
92
+ if (!isRecord(plan) || !Array.isArray(plan.steps)) {
93
+ return [issue("malformed-draft", "VerificationPlan.steps must be an array", opts.workItemId)];
94
+ }
95
+ const criterionIds = new Set(criteria.map((criterion) => criterion.criterionId));
96
+ const stepIds = /* @__PURE__ */ new Set();
97
+ const modes = new Set(opts.allowedModes ?? ["auto", "manual", "hybrid"]);
98
+ const effectKinds = new Set(opts.allowedEffectKinds ?? ["verification"]);
99
+ for (const step of plan.steps) {
100
+ if (!isRecord(step)) {
101
+ out.push(issue("malformed-draft", "VerificationStep must be an object", opts.workItemId));
102
+ continue;
103
+ }
104
+ if (typeof step.stepId !== "string" || step.stepId === "") {
105
+ out.push(
106
+ issue("missing-required-field", "VerificationStep.stepId is required", opts.workItemId)
107
+ );
108
+ continue;
109
+ }
110
+ if (stepIds.has(step.stepId)) {
111
+ out.push(
112
+ issue("duplicate-id", `Duplicate verification step id '${step.stepId}'`, opts.workItemId, {
113
+ stepId: step.stepId
114
+ })
115
+ );
116
+ }
117
+ stepIds.add(step.stepId);
118
+ if (typeof step.mode !== "string" || !modes.has(step.mode)) {
119
+ out.push(
120
+ issue(
121
+ "unsupported-mode",
122
+ `Unsupported verification step mode '${step.mode}'`,
123
+ opts.workItemId,
124
+ { stepId: step.stepId }
125
+ )
126
+ );
127
+ }
128
+ if (step.effectKind !== void 0 && (typeof step.effectKind !== "string" || !effectKinds.has(step.effectKind))) {
129
+ out.push(
130
+ issue(
131
+ "unsupported-effect-kind",
132
+ `Unsupported verification effect kind '${step.effectKind}'`,
133
+ opts.workItemId,
134
+ { stepId: step.stepId }
135
+ )
136
+ );
137
+ }
138
+ const verifiesCriteriaIds = Array.isArray(step.verifiesCriteriaIds) ? step.verifiesCriteriaIds : [];
139
+ for (const criterionId of verifiesCriteriaIds) {
140
+ if (!criterionIds.has(criterionId)) {
141
+ out.push(
142
+ issue("dangling-ref", `Unknown acceptance criterion '${criterionId}'`, opts.workItemId, {
143
+ stepId: step.stepId,
144
+ criterionId
145
+ })
146
+ );
147
+ }
148
+ }
149
+ }
150
+ for (const step of plan.steps) {
151
+ if (!isRecord(step) || typeof step.stepId !== "string") continue;
152
+ const dependsOnStepIds = Array.isArray(step.dependsOnStepIds) ? step.dependsOnStepIds : [];
153
+ for (const depId of dependsOnStepIds) {
154
+ if (!stepIds.has(depId)) {
155
+ out.push(
156
+ issue("dangling-ref", `Unknown verification dependency '${depId}'`, opts.workItemId, {
157
+ stepId: step.stepId
158
+ })
159
+ );
160
+ }
161
+ }
162
+ }
163
+ const cycle = findCycle(
164
+ plan.steps.filter(
165
+ (step) => isRecord(step) && typeof step.stepId === "string" && Array.isArray(step.dependsOnStepIds)
166
+ )
167
+ );
168
+ if (cycle !== void 0) {
169
+ out.push(
170
+ issue(
171
+ "cyclic-dependency",
172
+ `Verification step cycle detected: ${cycle.join(" -> ")}`,
173
+ opts.workItemId,
174
+ { stepId: cycle[0] }
175
+ )
176
+ );
177
+ }
178
+ return out;
179
+ }
180
+ function findCycle(steps) {
181
+ const byId = new Map(steps.map((step) => [step.stepId, step.dependsOnStepIds ?? []]));
182
+ const visiting = /* @__PURE__ */ new Set();
183
+ const visited = /* @__PURE__ */ new Set();
184
+ const stack = [];
185
+ const visit = (id) => {
186
+ if (visiting.has(id)) return [...stack.slice(stack.indexOf(id)), id];
187
+ if (visited.has(id)) return void 0;
188
+ visiting.add(id);
189
+ stack.push(id);
190
+ for (const dep of byId.get(id) ?? []) {
191
+ if (!byId.has(dep)) continue;
192
+ const cycle = visit(dep);
193
+ if (cycle !== void 0) return cycle;
194
+ }
195
+ stack.pop();
196
+ visiting.delete(id);
197
+ visited.add(id);
198
+ return void 0;
199
+ };
200
+ for (const step of steps) {
201
+ const cycle = visit(step.stepId);
202
+ if (cycle !== void 0) return cycle;
203
+ }
204
+ return void 0;
205
+ }
206
+ function issue(code, message, workItemId, metadata) {
207
+ return {
208
+ kind: "issue",
209
+ code,
210
+ message,
211
+ severity: "error",
212
+ source: "work-item-scheduling",
213
+ subjectId: workItemId,
214
+ metadata
215
+ };
216
+ }
217
+ function isRecord(value) {
218
+ return value !== null && typeof value === "object";
219
+ }
220
+
221
+ // src/orchestration/work-item-runtime.ts
222
+ function workItemDomainActionAdmissionProjector(graph, opts) {
223
+ const name = opts.name ?? "workItemDomainActionAdmissions";
224
+ const policyDeps = opts.admissionPolicies ?? [];
225
+ const policyStart = 2;
226
+ const now = opts.now ?? Date.now;
227
+ const runtime = graph.node(
228
+ [opts.proposals, opts.decisions, ...policyDeps],
229
+ (ctx) => {
230
+ const state = ctx.state.get() ?? emptyWorkItemDomainActionAdmissionState();
231
+ for (const raw of depBatch(ctx, 0) ?? []) {
232
+ const proposal = raw;
233
+ if (state.proposals.has(proposal.proposalId)) {
234
+ emitWorkItemAdmissionIssue(
235
+ ctx,
236
+ state,
237
+ `duplicate-admission-proposal:${proposal.proposalId}`,
238
+ "duplicate-work-item-domain-action-proposal",
239
+ `WorkItemDomainActionProposal '${proposal.proposalId}' was already seen by the admission projector`,
240
+ proposal.workItemId,
241
+ workItemAdmissionProposalRefs(proposal)
242
+ );
243
+ continue;
244
+ }
245
+ state.proposals.set(proposal.proposalId, proposal);
246
+ }
247
+ forEachPolicyDepBatch(ctx, policyStart, policyDeps.length, (raw) => {
248
+ const policy = raw;
249
+ state.policies.set(policy.policyId, policy);
250
+ });
251
+ for (const raw of depBatch(ctx, 1) ?? []) {
252
+ const decision = raw;
253
+ if (state.decisions.has(decision.decisionId)) {
254
+ emitWorkItemAdmissionIssue(
255
+ ctx,
256
+ state,
257
+ `duplicate-admission-decision:${decision.decisionId}`,
258
+ "duplicate-work-item-domain-action-admission-decision",
259
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' was already seen by the admission projector`,
260
+ decision.proposalId,
261
+ workItemAdmissionDecisionRefs(decision)
262
+ );
263
+ continue;
264
+ }
265
+ state.decisions.set(decision.decisionId, decision);
266
+ }
267
+ evaluateWorkItemDomainActionAdmissions(ctx, state, now());
268
+ ctx.state.set(state);
269
+ },
270
+ { name: `${name}/runtime`, factory: "workItemDomainActionAdmissionProjector", partial: true }
271
+ );
272
+ return {
273
+ admissions: projectRuntimeFact(
274
+ graph,
275
+ runtime,
276
+ `${name}/admissions`,
277
+ "workItemDomainActionAdmissions",
278
+ (fact) => fact.kind === "admission" ? fact.admission : void 0
279
+ ),
280
+ status: projectRuntimeFact(
281
+ graph,
282
+ runtime,
283
+ `${name}/status`,
284
+ "workItemDomainActionAdmissionStatus",
285
+ (fact) => fact.kind === "status" ? fact.status : void 0
286
+ ),
287
+ issues: projectRuntimeFact(
288
+ graph,
289
+ runtime,
290
+ `${name}/issues`,
291
+ "workItemDomainActionAdmissionIssues",
292
+ (fact) => fact.kind === "issue" ? fact.issue : void 0
293
+ ),
294
+ audit: projectRuntimeFact(
295
+ graph,
296
+ runtime,
297
+ `${name}/audit`,
298
+ "workItemDomainActionAdmissionAudit",
299
+ (fact) => fact.kind === "audit" ? fact.audit : void 0
300
+ ),
301
+ views: graph.node(
302
+ [runtime],
303
+ (ctx) => {
304
+ const state = ctx.state.get() ?? {
305
+ admissionsByProposal: /* @__PURE__ */ new Map(),
306
+ admissionsByWorkItem: /* @__PURE__ */ new Map(),
307
+ issues: [],
308
+ audit: []
309
+ };
310
+ for (const raw of depBatch(ctx, 0) ?? []) {
311
+ const fact = raw;
312
+ if (fact.kind === "admission") {
313
+ const admission = fact.admission;
314
+ state.admissionsByProposal.set(admission.proposalId, admission);
315
+ const byWorkItem = state.admissionsByWorkItem.get(admission.workItemId) ?? [];
316
+ byWorkItem.push(admission);
317
+ state.admissionsByWorkItem.set(admission.workItemId, byWorkItem);
318
+ } else if (fact.kind === "issue") state.issues.push(fact.issue);
319
+ else if (fact.kind === "audit") state.audit.push(fact.audit);
320
+ }
321
+ ctx.state.set(state);
322
+ ctx.down([["DATA", freezeWorkItemDomainActionAdmissionViews(state)]]);
323
+ },
324
+ { name: `${name}/views`, factory: "workItemDomainActionAdmissionViews" }
325
+ )
326
+ };
327
+ }
328
+ function evaluateWorkItemDomainActionAdmissions(ctx, state, admittedAtMs) {
329
+ let emitted = true;
330
+ let passes = 0;
331
+ while (emitted && passes <= state.decisions.size) {
332
+ emitted = false;
333
+ passes += 1;
334
+ for (const decision of state.decisions.values()) {
335
+ if (state.terminalDecisionIds.has(decision.decisionId)) continue;
336
+ emitted = evaluateWorkItemDomainActionAdmission(ctx, state, decision, admittedAtMs) || emitted;
337
+ }
338
+ }
339
+ }
340
+ function evaluateWorkItemDomainActionAdmission(ctx, state, decision, admittedAtMs) {
341
+ const proposal = state.proposals.get(decision.proposalId);
342
+ const proposalRefs = workItemAdmissionDecisionRefs(decision, proposal);
343
+ const subjectId = proposal?.workItemId ?? decision.proposalId;
344
+ if (proposal === void 0) {
345
+ emitWorkItemAdmissionIssue(
346
+ ctx,
347
+ state,
348
+ `missing-admission-proposal:${decision.decisionId}:${decision.proposalId}`,
349
+ "missing-work-item-domain-action-admission-proposal",
350
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references missing proposal '${decision.proposalId}'`,
351
+ subjectId,
352
+ proposalRefs
353
+ );
354
+ return false;
355
+ }
356
+ const staleProposalRef = (decision.sourceRefs ?? []).find(
357
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-proposal" && sourceRef.id !== decision.proposalId && sourceRef.id !== decision.targetProposalId
358
+ );
359
+ if (staleProposalRef !== void 0) {
360
+ emitWorkItemAdmissionIssue(
361
+ ctx,
362
+ state,
363
+ `stale-admission-proposal-ref:${decision.decisionId}:${staleProposalRef.id}`,
364
+ "stale-work-item-domain-action-admission-proposal-ref",
365
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries stale proposal ref '${staleProposalRef.id}'`,
366
+ proposal.workItemId,
367
+ proposalRefs
368
+ );
369
+ state.terminalDecisionIds.add(decision.decisionId);
370
+ return false;
371
+ }
372
+ const policy = admissionPolicyForDecision(state, decision);
373
+ if (typeof policy === "string") {
374
+ emitWorkItemAdmissionIssue(
375
+ ctx,
376
+ state,
377
+ `${policy}:${decision.decisionId}:${decision.policyId ?? "missing"}`,
378
+ policy,
379
+ admissionPolicyIssueMessage(policy, decision),
380
+ proposal.workItemId,
381
+ proposalRefs
382
+ );
383
+ if (policy === "stale-work-item-domain-action-admission-policy-ref")
384
+ state.terminalDecisionIds.add(decision.decisionId);
385
+ return false;
386
+ }
387
+ if (policy !== void 0) {
388
+ const policyIssue = validateWorkItemAdmissionPolicy(policy, decision, proposal);
389
+ if (policyIssue !== void 0) {
390
+ emitWorkItemAdmissionIssue(
391
+ ctx,
392
+ state,
393
+ `${policyIssue.code}:${decision.decisionId}:${policy.policyId}`,
394
+ policyIssue.code,
395
+ policyIssue.message,
396
+ proposal.workItemId,
397
+ workItemAdmissionDecisionRefs(decision, proposal, policy)
398
+ );
399
+ return false;
400
+ }
401
+ }
402
+ const mergeIssue = validateWorkItemAdmissionMergeTarget(state, decision);
403
+ if (mergeIssue !== void 0) {
404
+ emitWorkItemAdmissionIssue(
405
+ ctx,
406
+ state,
407
+ `${mergeIssue.code}:${decision.decisionId}:${decision.targetProposalId ?? ""}:${decision.targetAdmissionId ?? ""}`,
408
+ mergeIssue.code,
409
+ mergeIssue.message,
410
+ proposal.workItemId,
411
+ proposalRefs
412
+ );
413
+ if (mergeIssue.code !== "unknown-work-item-domain-action-admission-merge-target")
414
+ state.terminalDecisionIds.add(decision.decisionId);
415
+ return false;
416
+ }
417
+ if (state.admissionsById.has(decision.admissionId)) {
418
+ emitWorkItemAdmissionIssue(
419
+ ctx,
420
+ state,
421
+ `duplicate-admission-id:${decision.admissionId}`,
422
+ "duplicate-work-item-domain-action-admission",
423
+ `WorkItemDomainActionAdmission '${decision.admissionId}' was already emitted`,
424
+ proposal.workItemId,
425
+ proposalRefs
426
+ );
427
+ state.terminalDecisionIds.add(decision.decisionId);
428
+ return false;
429
+ }
430
+ if (state.admissionsByProposal.has(decision.proposalId)) {
431
+ emitWorkItemAdmissionIssue(
432
+ ctx,
433
+ state,
434
+ `duplicate-admission-proposal-decision:${decision.proposalId}:${decision.decisionId}`,
435
+ "duplicate-work-item-domain-action-admission-proposal",
436
+ `WorkItemDomainActionProposal '${decision.proposalId}' already has an admission decision`,
437
+ proposal.workItemId,
438
+ proposalRefs
439
+ );
440
+ state.terminalDecisionIds.add(decision.decisionId);
441
+ return false;
442
+ }
443
+ const admissionState = admissionStateForOutcome(decision.outcome);
444
+ if (admissionState === void 0) {
445
+ emitWorkItemAdmissionIssue(
446
+ ctx,
447
+ state,
448
+ `unsupported-admission-outcome:${decision.decisionId}:${String(decision.outcome)}`,
449
+ "unsupported-work-item-domain-action-admission-outcome",
450
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' uses unsupported outcome '${String(decision.outcome)}'`,
451
+ proposal.workItemId,
452
+ proposalRefs
453
+ );
454
+ state.terminalDecisionIds.add(decision.decisionId);
455
+ return false;
456
+ }
457
+ const admission = {
458
+ kind: "work-item-domain-action-admission",
459
+ admissionId: decision.admissionId,
460
+ proposalId: proposal.proposalId,
461
+ workItemId: proposal.workItemId,
462
+ actionKind: proposal.actionKind,
463
+ state: admissionState,
464
+ decisionId: decision.decisionId,
465
+ policyId: decision.policyId,
466
+ reason: decision.reason,
467
+ targetProposalId: decision.targetProposalId,
468
+ targetAdmissionId: decision.targetAdmissionId,
469
+ sourceRefs: workItemAdmissionDecisionRefs(decision, proposal, policy),
470
+ admittedAtMs: decision.decidedAtMs ?? admittedAtMs,
471
+ metadata: {
472
+ ...proposal.metadata ?? {},
473
+ ...policy?.metadata ?? {},
474
+ ...decision.metadata ?? {}
475
+ }
476
+ };
477
+ state.admissionsById.set(admission.admissionId, admission);
478
+ state.admissionsByProposal.set(admission.proposalId, admission);
479
+ state.terminalDecisionIds.add(decision.decisionId);
480
+ state.statusSeq += 1;
481
+ state.auditSeq += 1;
482
+ const statusState = workItemAdmissionStatusState(admission.state);
483
+ const status = {
484
+ kind: "work-item-status",
485
+ statusId: `${proposal.workItemId}:${statusState}:${state.statusSeq}`,
486
+ workItemId: proposal.workItemId,
487
+ state: statusState,
488
+ sourceRefs: admission.sourceRefs,
489
+ effectRunId: proposal.effectRunId,
490
+ evidenceId: proposal.evidenceId,
491
+ proposalId: proposal.proposalId,
492
+ metadata: {
493
+ actionKind: proposal.actionKind,
494
+ admissionId: admission.admissionId,
495
+ decisionId: decision.decisionId,
496
+ policyId: decision.policyId
497
+ }
498
+ };
499
+ const audit = {
500
+ id: `${proposal.workItemId}:${statusState}:${state.auditSeq}`,
501
+ kind: `work-item-domain-action-${admission.state}`,
502
+ subjectId: proposal.workItemId,
503
+ sourceRefs: admission.sourceRefs,
504
+ metadata: {
505
+ actionKind: proposal.actionKind,
506
+ admissionId: admission.admissionId,
507
+ decisionId: decision.decisionId,
508
+ policyId: decision.policyId,
509
+ proposalId: proposal.proposalId
510
+ }
511
+ };
512
+ ctx.down([
513
+ ["DATA", { kind: "admission", admission }],
514
+ ["DATA", { kind: "status", status }],
515
+ ["DATA", { kind: "audit", audit }]
516
+ ]);
517
+ return true;
518
+ }
519
+ function admissionPolicyForDecision(state, decision) {
520
+ if (decision.policyId === void 0) return void 0;
521
+ const stalePolicyRef = (decision.sourceRefs ?? []).find(
522
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-admission-policy" && sourceRef.id !== decision.policyId
523
+ );
524
+ if (stalePolicyRef !== void 0) return "stale-work-item-domain-action-admission-policy-ref";
525
+ return state.policies.get(decision.policyId) ?? "missing-work-item-domain-action-admission-policy";
526
+ }
527
+ function admissionPolicyIssueMessage(code, decision) {
528
+ if (code === "missing-work-item-domain-action-admission-policy") {
529
+ return `WorkItemDomainActionAdmissionPolicy '${decision.policyId}' was referenced for WorkItem action admission but not present`;
530
+ }
531
+ return `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries a stale admission policy source ref`;
532
+ }
533
+ function validateWorkItemAdmissionPolicy(policy, decision, proposal) {
534
+ if (policy.actionKinds !== void 0 && !policy.actionKinds.includes(proposal.actionKind)) {
535
+ return {
536
+ code: "work-item-domain-action-admission-policy-mismatch",
537
+ message: `WorkItemDomainActionAdmissionPolicy '${policy.policyId}' does not apply to actionKind '${proposal.actionKind}'`
538
+ };
539
+ }
540
+ if (policy.allowedOutcomes !== void 0 && !policy.allowedOutcomes.includes(decision.outcome)) {
541
+ return {
542
+ code: "unsupported-work-item-domain-action-admission-outcome",
543
+ message: `WorkItemDomainActionAdmissionPolicy '${policy.policyId}' does not allow outcome '${decision.outcome}'`
544
+ };
545
+ }
546
+ return void 0;
547
+ }
548
+ function validateWorkItemAdmissionMergeTarget(state, decision) {
549
+ const hasTargetProposal = decision.targetProposalId !== void 0;
550
+ const hasTargetAdmission = decision.targetAdmissionId !== void 0;
551
+ if (decision.outcome !== "merge") {
552
+ if (hasTargetProposal || hasTargetAdmission) {
553
+ return {
554
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
555
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries a merge target for non-merge outcome '${decision.outcome}'`
556
+ };
557
+ }
558
+ return void 0;
559
+ }
560
+ if (hasTargetProposal === hasTargetAdmission) {
561
+ return {
562
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
563
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' must reference exactly one merge target`
564
+ };
565
+ }
566
+ if (decision.targetProposalId === decision.proposalId) {
567
+ return {
568
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
569
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' cannot merge a proposal into itself`
570
+ };
571
+ }
572
+ if (decision.targetProposalId !== void 0 && !state.proposals.has(decision.targetProposalId)) {
573
+ return {
574
+ code: "unknown-work-item-domain-action-admission-merge-target",
575
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references unknown target proposal '${decision.targetProposalId}'`
576
+ };
577
+ }
578
+ if (decision.targetAdmissionId !== void 0 && !state.admissionsById.has(decision.targetAdmissionId)) {
579
+ return {
580
+ code: "unknown-work-item-domain-action-admission-merge-target",
581
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references unknown target admission '${decision.targetAdmissionId}'`
582
+ };
583
+ }
584
+ return void 0;
585
+ }
586
+ function admissionStateForOutcome(outcome) {
587
+ if (outcome === "admit") return "admitted";
588
+ if (outcome === "reject") return "rejected";
589
+ if (outcome === "defer") return "deferred";
590
+ if (outcome === "merge") return "merged";
591
+ return void 0;
592
+ }
593
+ function workItemAdmissionStatusState(state) {
594
+ if (state === "admitted") return "domain-action-admitted";
595
+ if (state === "rejected") return "domain-action-rejected";
596
+ if (state === "deferred") return "domain-action-deferred";
597
+ return "domain-action-merged";
598
+ }
599
+ function emitWorkItemAdmissionIssue(ctx, state, key, code, message, subjectId, sourceRefs2) {
600
+ if (state.issueKeys.has(key)) return;
601
+ state.issueKeys.add(key);
602
+ state.issueSeq += 1;
603
+ state.statusSeq += 1;
604
+ state.auditSeq += 1;
605
+ const issue2 = dataIssue(code, message, { subjectId, refs: sourceRefs2 });
606
+ const status = {
607
+ kind: "work-item-status",
608
+ statusId: `${subjectId ?? "work-item"}:mapping-issue:${state.statusSeq}`,
609
+ workItemId: subjectId ?? "unknown",
610
+ state: "mapping-issue",
611
+ sourceRefs: sourceRefs2,
612
+ issues: [issue2]
613
+ };
614
+ const audit = {
615
+ id: `${subjectId ?? "work-item"}:${code}:${state.auditSeq}`,
616
+ kind: "work-item-domain-action-admission-issue",
617
+ subjectId,
618
+ issueCode: code,
619
+ message,
620
+ sourceRefs: sourceRefs2
621
+ };
622
+ ctx.down([
623
+ ["DATA", { kind: "issue", issue: issue2 }],
624
+ ["DATA", { kind: "status", status }],
625
+ ["DATA", { kind: "audit", audit }]
626
+ ]);
627
+ }
628
+ function emptyWorkItemDomainActionAdmissionState() {
629
+ return {
630
+ proposals: /* @__PURE__ */ new Map(),
631
+ policies: /* @__PURE__ */ new Map(),
632
+ decisions: /* @__PURE__ */ new Map(),
633
+ admissionsById: /* @__PURE__ */ new Map(),
634
+ admissionsByProposal: /* @__PURE__ */ new Map(),
635
+ terminalDecisionIds: /* @__PURE__ */ new Set(),
636
+ issueKeys: /* @__PURE__ */ new Set(),
637
+ statusSeq: 0,
638
+ issueSeq: 0,
639
+ auditSeq: 0
640
+ };
641
+ }
642
+ function freezeWorkItemDomainActionAdmissionViews(state) {
643
+ return {
644
+ admissionsByProposal: new Map(state.admissionsByProposal),
645
+ admissionsByWorkItem: new Map(
646
+ Array.from(state.admissionsByWorkItem, ([key, value]) => [key, Object.freeze([...value])])
647
+ ),
648
+ issues: Object.freeze([...state.issues]),
649
+ audit: Object.freeze([...state.audit])
650
+ };
651
+ }
652
+ function workItemAdmissionProposalRefs(proposal) {
653
+ return uniqueSourceRefs([
654
+ ref("work-item", proposal.workItemId),
655
+ ref("work-item-domain-action-proposal", proposal.proposalId),
656
+ ref("effect-run", proposal.effectRunId),
657
+ ref("effect-run-result", proposal.effectRunResultId),
658
+ ref("work-item-evidence", proposal.evidenceId),
659
+ ref("work-item-effect-mapping-policy", proposal.policyId),
660
+ ...proposal.sourceRefs ?? []
661
+ ]);
662
+ }
663
+ function workItemAdmissionDecisionRefs(decision, proposal, policy) {
664
+ return uniqueSourceRefs([
665
+ ...proposal === void 0 ? [] : workItemAdmissionProposalRefs(proposal),
666
+ ref("work-item-domain-action-admission-decision", decision.decisionId),
667
+ ref("work-item-domain-action-admission", decision.admissionId),
668
+ ref("work-item-domain-action-proposal", decision.proposalId),
669
+ ...decision.policyId === void 0 ? [] : [ref("work-item-domain-action-admission-policy", decision.policyId)],
670
+ ...policy === void 0 ? [] : [ref("work-item-domain-action-admission-policy", policy.policyId)],
671
+ ...decision.targetProposalId === void 0 ? [] : [ref("work-item-domain-action-proposal", decision.targetProposalId)],
672
+ ...decision.targetAdmissionId === void 0 ? [] : [ref("work-item-domain-action-admission", decision.targetAdmissionId)],
673
+ ...decision.sourceRefs ?? []
674
+ ]);
675
+ }
676
+ function uniqueSourceRefs(sourceRefs2) {
677
+ const seen = /* @__PURE__ */ new Set();
678
+ const unique = [];
679
+ for (const sourceRef of sourceRefs2) {
680
+ const key = sourceRefKey(sourceRef);
681
+ if (seen.has(key)) continue;
682
+ seen.add(key);
683
+ unique.push(sourceRef);
684
+ }
685
+ return unique;
686
+ }
687
+ function sourceRefKey(sourceRef) {
688
+ return `${sourceRef.kind}:${sourceRef.id}:${JSON.stringify(sourceRef.metadata ?? {})}`;
689
+ }
690
+ function projectRuntimeFact(graph, runtime, name, factory, pick) {
691
+ return graph.node(
692
+ [runtime],
693
+ (ctx) => {
694
+ for (const fact of depBatch(ctx, 0) ?? []) {
695
+ const typed = fact;
696
+ const value = pick(typed);
697
+ if (value !== void 0) ctx.down([["DATA", value]]);
698
+ }
699
+ },
700
+ { name, factory }
701
+ );
702
+ }
703
+ function forEachPolicyDepBatch(ctx, start, count, fn) {
704
+ for (let i = 0; i < count; i += 1) {
705
+ for (const value of depBatch(ctx, start + i) ?? []) fn(value);
706
+ }
707
+ }
708
+ function dataIssue(code, message, opts = {}) {
709
+ return {
710
+ kind: "issue",
711
+ code,
712
+ message,
713
+ severity: opts.severity ?? "error",
714
+ subjectId: opts.subjectId,
715
+ refs: opts.refs?.map((r) => `${r.kind}:${r.id}`),
716
+ details: opts.details
717
+ };
718
+ }
719
+ function ref(kind, id) {
720
+ return { kind, id };
721
+ }
722
+
723
+ // src/solutions/work-item/actions.ts
724
+ var patchFieldKeys = /* @__PURE__ */ new Set([
725
+ "summary",
726
+ "detail",
727
+ "detailRefs",
728
+ "kind",
729
+ "priority",
730
+ "tags",
731
+ "owner",
732
+ "assignee",
733
+ "deadlineMs",
734
+ "customFields",
735
+ "sourceRefs",
736
+ "metadata"
737
+ ]);
738
+ function workItemDomainActionProposal(proposalId, workItemId, actionKind, opts = {}) {
739
+ return {
740
+ kind: "work-item-domain-action-proposal",
741
+ proposalId,
742
+ workItemId,
743
+ actionKind,
744
+ effectRunId: opts.effectRunId ?? `domain-action:${proposalId}:effect-run`,
745
+ effectRunResultId: opts.effectRunResultId ?? `domain-action:${proposalId}:effect-run-result`,
746
+ evidenceId: opts.evidenceId ?? `domain-action:${proposalId}:evidence`,
747
+ policyId: opts.policyId ?? "domain-action-proposal",
748
+ payload: opts.payload,
749
+ reason: opts.reason,
750
+ sourceRefs: opts.sourceRefs,
751
+ proposedAtMs: opts.proposedAtMs,
752
+ metadata: opts.metadata
753
+ };
754
+ }
755
+ function workItemDomainActionProposalIntake(proposalId, workItemId, actionKind, opts = {}) {
756
+ return {
757
+ kind: "work-item-domain-action-proposal-intake",
758
+ proposalId,
759
+ workItemId,
760
+ actionKind,
761
+ payload: opts.payload,
762
+ reason: opts.reason,
763
+ policyId: opts.policyId,
764
+ effectRunId: opts.effectRunId,
765
+ effectRunResultId: opts.effectRunResultId,
766
+ evidenceId: opts.evidenceId,
767
+ proposedAtMs: opts.proposedAtMs,
768
+ sourceRefs: opts.sourceRefs,
769
+ metadata: opts.metadata
770
+ };
771
+ }
772
+ function workItemDomainActionApplyPolicy(policyId, opts = {}) {
773
+ return {
774
+ kind: "work-item-domain-action-apply-policy",
775
+ policyId,
776
+ actionKinds: opts.actionKinds,
777
+ patch: opts.patch,
778
+ spawn: opts.spawn,
779
+ metadata: opts.metadata
780
+ };
781
+ }
782
+ function workItemDomainActionProposalIntakeProjector(graph, opts) {
783
+ const name = opts.name ?? "workItemDomainActionIntake";
784
+ const now = opts.now ?? Date.now;
785
+ const runtime = graph.node(
786
+ [opts.proposals],
787
+ (ctx) => {
788
+ const state = ctx.state.get() ?? {
789
+ proposals: /* @__PURE__ */ new Set(),
790
+ statusSeq: 0,
791
+ auditSeq: 0
792
+ };
793
+ for (const raw of depBatch(ctx, 0) ?? []) reduceProposalIntake(ctx, state, raw, now());
794
+ ctx.state.set(state);
795
+ },
796
+ {
797
+ name: `${name}/runtime`,
798
+ factory: "workItemDomainActionProposalIntakeProjector",
799
+ partial: true,
800
+ completeWhenDepsComplete: false,
801
+ errorWhenDepsError: false
802
+ }
803
+ );
804
+ return {
805
+ proposals: project(
806
+ graph,
807
+ runtime,
808
+ `${name}/proposals`,
809
+ "workItemDomainActionProposals",
810
+ (fact) => fact.kind === "proposal" ? fact.value : void 0
811
+ ),
812
+ status: project(
813
+ graph,
814
+ runtime,
815
+ `${name}/status`,
816
+ "workItemDomainActionStatus",
817
+ (fact) => fact.kind === "status" ? fact.value : void 0
818
+ ),
819
+ issues: project(
820
+ graph,
821
+ runtime,
822
+ `${name}/issues`,
823
+ "workItemDomainActionIssues",
824
+ (fact) => fact.kind === "issue" ? fact.value : void 0
825
+ ),
826
+ audit: project(
827
+ graph,
828
+ runtime,
829
+ `${name}/audit`,
830
+ "workItemDomainActionAudit",
831
+ (fact) => fact.kind === "audit" ? fact.value : void 0
832
+ )
833
+ };
834
+ }
835
+ function workItemDomainActionApplicationProjector(graph, opts) {
836
+ const name = opts.name ?? "workItemDomainActionApplication";
837
+ const deps = opts.applyPolicies === void 0 ? [opts.proposals, opts.admissions, opts.workItems] : [opts.proposals, opts.admissions, opts.workItems, opts.applyPolicies];
838
+ const runtime = graph.node(
839
+ deps,
840
+ (ctx) => {
841
+ const state = ctx.state.get() ?? {
842
+ proposals: /* @__PURE__ */ new Map(),
843
+ admissions: /* @__PURE__ */ new Map(),
844
+ workItems: /* @__PURE__ */ new Map(),
845
+ policies: /* @__PURE__ */ new Map(),
846
+ appliedAdmissions: /* @__PURE__ */ new Set(),
847
+ emittedFactIds: /* @__PURE__ */ new Set(),
848
+ issueKeys: /* @__PURE__ */ new Set(),
849
+ statusSeq: 0,
850
+ auditSeq: 0
851
+ };
852
+ for (const raw of depBatch(ctx, 0) ?? []) {
853
+ const proposal = raw;
854
+ if (state.proposals.has(proposal.proposalId)) {
855
+ emitApplicationIssue(
856
+ ctx,
857
+ state,
858
+ `duplicate-proposal:${proposal.proposalId}`,
859
+ "duplicate-suppressed",
860
+ `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`,
861
+ proposal.workItemId,
862
+ proposal.sourceRefs
863
+ );
864
+ continue;
865
+ }
866
+ state.proposals.set(proposal.proposalId, proposal);
867
+ }
868
+ for (const raw of depBatch(ctx, 2) ?? []) {
869
+ const workItem = raw;
870
+ state.workItems.set(workItem.workItemId, workItem);
871
+ }
872
+ if (opts.applyPolicies !== void 0) {
873
+ for (const raw of depBatch(ctx, 3) ?? []) {
874
+ const policy = raw;
875
+ state.policies.set(policy.policyId, policy);
876
+ }
877
+ }
878
+ for (const raw of depBatch(ctx, 1) ?? []) {
879
+ const admission = raw;
880
+ if (state.admissions.has(admission.admissionId)) {
881
+ emitApplicationIssue(
882
+ ctx,
883
+ state,
884
+ `duplicate-admission:${admission.admissionId}`,
885
+ "duplicate-suppressed",
886
+ `Duplicate WorkItem domain action admission '${admission.admissionId}' suppressed`,
887
+ admission.workItemId,
888
+ admissionRefs(admission)
889
+ );
890
+ continue;
891
+ }
892
+ state.admissions.set(admission.admissionId, admission);
893
+ }
894
+ for (const admission of state.admissions.values()) applyAdmission(ctx, state, admission);
895
+ ctx.state.set(state);
896
+ },
897
+ {
898
+ name: `${name}/runtime`,
899
+ factory: "workItemDomainActionApplicationProjector",
900
+ partial: true,
901
+ completeWhenDepsComplete: false,
902
+ errorWhenDepsError: false
903
+ }
904
+ );
905
+ return {
906
+ authoringFacts: project(
907
+ graph,
908
+ runtime,
909
+ `${name}/authoringFacts`,
910
+ "workItemDomainActionAuthoringFacts",
911
+ (fact) => fact.kind === "authoring-fact" ? fact.value : void 0
912
+ ),
913
+ applications: project(
914
+ graph,
915
+ runtime,
916
+ `${name}/applications`,
917
+ "workItemDomainActionApplications",
918
+ (fact) => fact.kind === "application" ? fact.value : void 0
919
+ ),
920
+ status: project(
921
+ graph,
922
+ runtime,
923
+ `${name}/status`,
924
+ "workItemDomainActionStatus",
925
+ (fact) => fact.kind === "status" ? fact.value : void 0
926
+ ),
927
+ issues: project(
928
+ graph,
929
+ runtime,
930
+ `${name}/issues`,
931
+ "workItemDomainActionIssues",
932
+ (fact) => fact.kind === "issue" ? fact.value : void 0
933
+ ),
934
+ audit: project(
935
+ graph,
936
+ runtime,
937
+ `${name}/audit`,
938
+ "workItemDomainActionAudit",
939
+ (fact) => fact.kind === "audit" ? fact.value : void 0
940
+ )
941
+ };
942
+ }
943
+ function workItemDomainActionCapabilityGuardProjector(graph, opts) {
944
+ const name = opts.name ?? "workItemDomainActionCapabilityGuard";
945
+ const deps = opts.capabilityAdmissionStatus === void 0 ? [opts.proposals, opts.capabilityAdmissions, opts.guardPolicies] : [
946
+ opts.proposals,
947
+ opts.capabilityAdmissions,
948
+ opts.guardPolicies,
949
+ opts.capabilityAdmissionStatus
950
+ ];
951
+ const statusIndex = opts.capabilityAdmissionStatus === void 0 ? -1 : 3;
952
+ const now = opts.now ?? Date.now;
953
+ const runtime = graph.node(
954
+ deps,
955
+ (ctx) => {
956
+ const state = ctx.state.get() ?? {
957
+ proposals: /* @__PURE__ */ new Map(),
958
+ admissionsByCapability: /* @__PURE__ */ new Map(),
959
+ issueStatusesByCapability: /* @__PURE__ */ new Map(),
960
+ issueStatusesWithoutCapability: [],
961
+ policies: /* @__PURE__ */ new Map(),
962
+ emittedProposalDecisions: /* @__PURE__ */ new Set(),
963
+ emittedStatusKeys: /* @__PURE__ */ new Set(),
964
+ issueKeys: /* @__PURE__ */ new Set(),
965
+ statusSeq: 0,
966
+ auditSeq: 0
967
+ };
968
+ for (const raw of depBatch(ctx, 2) ?? []) {
969
+ const policyIssue = capabilityGuardPolicyIssue(raw);
970
+ if (policyIssue !== void 0) {
971
+ emitCapabilityGuardIssue(
972
+ ctx,
973
+ state,
974
+ `malformed-policy:${recordString(raw, "policyId") ?? "unknown"}`,
975
+ policyIssue
976
+ );
977
+ continue;
978
+ }
979
+ const policy = raw;
980
+ state.policies.set(policy.policyId, policy);
981
+ }
982
+ for (const raw of depBatch(ctx, 1) ?? []) {
983
+ const admissionIssue = capabilityAdmissionIssue(raw);
984
+ if (admissionIssue !== void 0) {
985
+ emitCapabilityGuardIssue(
986
+ ctx,
987
+ state,
988
+ `malformed-admission:${recordString(raw, "admissionId") ?? "unknown"}`,
989
+ admissionIssue
990
+ );
991
+ continue;
992
+ }
993
+ const admission = raw;
994
+ const capabilityKey = capabilityBoundaryRefId(admission.capability);
995
+ const byCapability = state.admissionsByCapability.get(capabilityKey) ?? [];
996
+ if (!byCapability.some((item) => item.admissionId === admission.admissionId)) {
997
+ state.admissionsByCapability.set(capabilityKey, [...byCapability, admission]);
998
+ }
999
+ }
1000
+ if (statusIndex >= 0) {
1001
+ for (const raw of depBatch(ctx, statusIndex) ?? []) {
1002
+ const statusIssue = capabilityAdmissionStatusIssue(raw);
1003
+ if (statusIssue !== void 0) {
1004
+ emitCapabilityGuardIssue(
1005
+ ctx,
1006
+ state,
1007
+ `malformed-capability-status:${recordString(raw, "statusId") ?? "unknown"}`,
1008
+ statusIssue
1009
+ );
1010
+ continue;
1011
+ }
1012
+ const status = raw;
1013
+ if (status.state !== "capability-admission-issue") continue;
1014
+ const capabilityId = status.capabilityId;
1015
+ const capabilityKind = status.capabilityKind;
1016
+ if (capabilityId !== void 0 && capabilityKind !== void 0) {
1017
+ const capabilityKey = capabilityBoundaryRefId({
1018
+ id: capabilityId,
1019
+ kind: capabilityKind
1020
+ });
1021
+ const statuses = state.issueStatusesByCapability.get(capabilityKey) ?? [];
1022
+ if (!statuses.some((item) => item.statusId === status.statusId)) {
1023
+ state.issueStatusesByCapability.set(capabilityKey, [...statuses, status]);
1024
+ }
1025
+ } else if (!state.issueStatusesWithoutCapability.some((item) => item.statusId === status.statusId)) {
1026
+ state.issueStatusesWithoutCapability.push(status);
1027
+ }
1028
+ for (const proposal of state.proposals.values())
1029
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1030
+ }
1031
+ }
1032
+ for (const raw of depBatch(ctx, 0) ?? []) {
1033
+ const proposalIssue = capabilityGuardProposalIssue(raw);
1034
+ if (proposalIssue !== void 0) {
1035
+ emitCapabilityGuardIssue(
1036
+ ctx,
1037
+ state,
1038
+ `malformed-proposal:${recordString(raw, "proposalId") ?? "unknown"}`,
1039
+ proposalIssue
1040
+ );
1041
+ continue;
1042
+ }
1043
+ const proposal = raw;
1044
+ state.proposals.set(proposal.proposalId, proposal);
1045
+ }
1046
+ for (const proposal of state.proposals.values())
1047
+ evaluateCapabilityGuardProposal(ctx, state, proposal, now());
1048
+ ctx.state.set(state);
1049
+ },
1050
+ {
1051
+ name: `${name}/runtime`,
1052
+ factory: "workItemDomainActionCapabilityGuardProjector",
1053
+ partial: true,
1054
+ completeWhenDepsComplete: false,
1055
+ errorWhenDepsError: false
1056
+ }
1057
+ );
1058
+ return {
1059
+ decisions: project(
1060
+ graph,
1061
+ runtime,
1062
+ `${name}/decisions`,
1063
+ "workItemDomainActionCapabilityGuardDecisions",
1064
+ (fact) => fact.kind === "decision" ? fact.value : void 0
1065
+ ),
1066
+ status: project(
1067
+ graph,
1068
+ runtime,
1069
+ `${name}/status`,
1070
+ "workItemDomainActionCapabilityGuardStatus",
1071
+ (fact) => fact.kind === "status" ? fact.value : void 0
1072
+ ),
1073
+ issues: project(
1074
+ graph,
1075
+ runtime,
1076
+ `${name}/issues`,
1077
+ "workItemDomainActionCapabilityGuardIssues",
1078
+ (fact) => fact.kind === "issue" ? fact.value : void 0
1079
+ ),
1080
+ audit: project(
1081
+ graph,
1082
+ runtime,
1083
+ `${name}/audit`,
1084
+ "workItemDomainActionCapabilityGuardAudit",
1085
+ (fact) => fact.kind === "audit" ? fact.value : void 0
1086
+ )
1087
+ };
1088
+ }
1089
+ function evaluateCapabilityGuardProposal(ctx, state, proposal, decidedAtMs) {
1090
+ if (state.emittedProposalDecisions.has(proposal.proposalId)) return;
1091
+ const policy = selectCapabilityGuardPolicy(state, proposal);
1092
+ if (typeof policy === "string") {
1093
+ emitCapabilityGuardIssue(
1094
+ ctx,
1095
+ state,
1096
+ `policy:${proposal.proposalId}:${policy}`,
1097
+ dataIssue2(policy, capabilityGuardPolicyMessage(policy, proposal), {
1098
+ subjectId: proposal.workItemId,
1099
+ refs: [ref2("work-item-domain-action-proposal", proposal.proposalId)]
1100
+ })
1101
+ );
1102
+ return;
1103
+ }
1104
+ for (const status of state.issueStatusesWithoutCapability)
1105
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1106
+ for (const capabilityRef of policy.capabilityRefs) {
1107
+ for (const status of state.issueStatusesByCapability.get(
1108
+ capabilityBoundaryRefId(capabilityRef)
1109
+ ) ?? [])
1110
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1111
+ }
1112
+ const admissions = policy.capabilityRefs.map(
1113
+ (capabilityRef) => latestCapabilityAdmission(state, policy, capabilityRef)
1114
+ );
1115
+ const missingCapabilityRefs = policy.capabilityRefs.filter(
1116
+ (_, index) => admissions[index] === void 0
1117
+ );
1118
+ const deferredCapabilityRefs = admissions.filter((admission) => admission !== void 0).filter((admission) => admission.state === "deferred").map((admission) => capabilityBoundaryRefId(admission.capability));
1119
+ if (missingCapabilityRefs.length > 0 || deferredCapabilityRefs.length > 0) {
1120
+ emitCapabilityGuardStatusOnce(
1121
+ ctx,
1122
+ state,
1123
+ `deferred:${proposal.proposalId}:${policy.policyId}:missing=${missingCapabilityRefs.map(capabilityBoundaryRefId).join(",")}:deferred=${deferredCapabilityRefs.join(",")}`,
1124
+ {
1125
+ state: "deferred",
1126
+ workItemId: proposal.workItemId,
1127
+ proposalId: proposal.proposalId,
1128
+ actionKind: proposal.actionKind,
1129
+ policyId: policy.policyId,
1130
+ capabilityRefs: policy.capabilityRefs,
1131
+ admissionSubjectIds: policy.admissionSubjectIds,
1132
+ message: "WorkItem domain action is waiting for capability admission",
1133
+ sourceRefs: capabilityGuardRefs(proposal, policy, admissions),
1134
+ metadata: {
1135
+ missingCapabilityRefs: missingCapabilityRefs.map(capabilityBoundaryRefId),
1136
+ deferredCapabilityRefs
1137
+ }
1138
+ }
1139
+ );
1140
+ return;
1141
+ }
1142
+ const presentAdmissions = admissions.filter(
1143
+ (admission) => admission !== void 0
1144
+ );
1145
+ const blocked = presentAdmissions.filter((admission) => admission.state === "blocked");
1146
+ const outcome = blocked.length === 0 ? "admit" : "reject";
1147
+ const decision = {
1148
+ kind: "work-item-domain-action-admission-decision",
1149
+ decisionId: `capability-guard:${proposal.proposalId}:decision`,
1150
+ admissionId: `capability-guard:${proposal.proposalId}:admission`,
1151
+ proposalId: proposal.proposalId,
1152
+ outcome,
1153
+ reason: blocked.length === 0 ? "Capability guard admitted required capabilities" : "Capability guard rejected blocked capabilities",
1154
+ decidedAtMs,
1155
+ sourceRefs: capabilityGuardRefs(proposal, policy, presentAdmissions),
1156
+ metadata: {
1157
+ capabilityGuardPolicyId: policy.policyId,
1158
+ capabilityRefs: policy.capabilityRefs.map(capabilityBoundaryRefId),
1159
+ admissionSubjectIds: policy.admissionSubjectIds,
1160
+ blockedCapabilityRefs: blocked.map(
1161
+ (admission) => capabilityBoundaryRefId(admission.capability)
1162
+ )
1163
+ }
1164
+ };
1165
+ state.emittedProposalDecisions.add(proposal.proposalId);
1166
+ emitCapabilityGuard(ctx, "decision", decision);
1167
+ emitCapabilityGuardStatus(ctx, state, {
1168
+ state: outcome === "admit" ? "admitted" : "rejected",
1169
+ workItemId: proposal.workItemId,
1170
+ proposalId: proposal.proposalId,
1171
+ actionKind: proposal.actionKind,
1172
+ policyId: policy.policyId,
1173
+ capabilityRefs: policy.capabilityRefs,
1174
+ admissionSubjectIds: policy.admissionSubjectIds,
1175
+ admissionIds: presentAdmissions.map((admission) => admission.admissionId),
1176
+ sourceRefs: decision.sourceRefs,
1177
+ metadata: { decisionId: decision.decisionId, admissionId: decision.admissionId }
1178
+ });
1179
+ }
1180
+ function capabilityGuardProposalIssue(proposal) {
1181
+ if (!isRecord2(proposal) || proposal.kind !== "work-item-domain-action-proposal" || typeof proposal.proposalId !== "string" || proposal.proposalId.length === 0 || typeof proposal.workItemId !== "string" || proposal.workItemId.length === 0 || typeof proposal.actionKind !== "string" || proposal.actionKind.length === 0 || proposal.sourceRefs !== void 0 && !isSourceRefArray(proposal.sourceRefs)) {
1182
+ return dataIssue2(
1183
+ "malformed-work-item-domain-action-capability-guard-proposal",
1184
+ "WorkItem domain action capability guard requires valid proposal DATA facts",
1185
+ { subjectId: recordString(proposal, "workItemId") }
1186
+ );
1187
+ }
1188
+ return void 0;
1189
+ }
1190
+ function capabilityGuardPolicyIssue(policy) {
1191
+ if (!isRecord2(policy) || policy.kind !== "work-item-domain-action-capability-guard-policy" || typeof policy.policyId !== "string" || policy.policyId.length === 0 || !Array.isArray(policy.capabilityRefs) || policy.capabilityRefs.length === 0 || !policy.capabilityRefs.every(isBoundaryCapabilityRef) || !Array.isArray(policy.admissionSubjectIds) || policy.admissionSubjectIds.length === 0 || !policy.admissionSubjectIds.every((id) => typeof id === "string" && id.length > 0) || policy.actionKinds !== void 0 && (!Array.isArray(policy.actionKinds) || !policy.actionKinds.every((kind) => typeof kind === "string" && kind.length > 0))) {
1192
+ return dataIssue2(
1193
+ "malformed-work-item-domain-action-capability-guard-policy",
1194
+ "WorkItem domain action capability guard policy requires policyId, capabilityRefs, and admissionSubjectIds",
1195
+ {
1196
+ subjectId: recordString(policy, "policyId")
1197
+ }
1198
+ );
1199
+ }
1200
+ return void 0;
1201
+ }
1202
+ function capabilityAdmissionIssue(admission) {
1203
+ if (!isRecord2(admission) || admission.kind !== "capability-admission" || typeof admission.admissionId !== "string" || admission.admissionId.length === 0 || typeof admission.proposalId !== "string" || admission.proposalId.length === 0 || typeof admission.subjectId !== "string" || admission.subjectId.length === 0 || !isBoundaryCapabilityRef(admission.capability) || !isCapabilityAdmissionState(admission.state) || typeof admission.decisionId !== "string" || admission.decisionId.length === 0 || admission.sourceRefs !== void 0 && !isSourceRefArray(admission.sourceRefs)) {
1204
+ return dataIssue2(
1205
+ "malformed-capability-admission",
1206
+ "WorkItem domain action capability guard requires valid CapabilityAdmission DATA facts",
1207
+ { subjectId: recordString(admission, "subjectId") }
1208
+ );
1209
+ }
1210
+ return void 0;
1211
+ }
1212
+ function capabilityAdmissionStatusIssue(status) {
1213
+ if (!isRecord2(status) || status.kind !== "capability-admission-status" || typeof status.statusId !== "string" || status.statusId.length === 0 || !isCapabilityAdmissionStatusState(status.state)) {
1214
+ return dataIssue2(
1215
+ "malformed-capability-admission-status",
1216
+ "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
1217
+ { subjectId: recordString(status, "subjectId") }
1218
+ );
1219
+ }
1220
+ const hasCapabilityId = status.capabilityId !== void 0;
1221
+ const hasCapabilityKind = status.capabilityKind !== void 0;
1222
+ if (hasCapabilityId !== hasCapabilityKind || hasCapabilityId && (typeof status.capabilityId !== "string" || status.capabilityId.length === 0 || !isBoundaryCapabilityKind(status.capabilityKind)) || status.sourceRefs !== void 0 && !isSourceRefArray(status.sourceRefs) || status.issues !== void 0 && !isDataIssueArray(status.issues)) {
1223
+ return dataIssue2(
1224
+ "malformed-capability-admission-status",
1225
+ "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
1226
+ { subjectId: recordString(status, "subjectId") }
1227
+ );
1228
+ }
1229
+ return void 0;
1230
+ }
1231
+ function isCapabilityAdmissionState(value) {
1232
+ return value === "allowed" || value === "blocked" || value === "deferred";
1233
+ }
1234
+ function isCapabilityAdmissionStatusState(value) {
1235
+ return value === "capability-admission-allowed" || value === "capability-admission-blocked" || value === "capability-admission-deferred" || value === "capability-admission-issue";
1236
+ }
1237
+ function isSourceRefArray(value) {
1238
+ return Array.isArray(value) && value.every(
1239
+ (item) => isRecord2(item) && typeof item.kind === "string" && typeof item.id === "string"
1240
+ );
1241
+ }
1242
+ function isDataIssueArray(value) {
1243
+ return Array.isArray(value) && value.every(isDataIssue);
1244
+ }
1245
+ function isDataIssue(value) {
1246
+ return isRecord2(value) && value.kind === "issue" && typeof value.code === "string" && value.code.length > 0 && typeof value.message === "string" && value.message.length > 0;
1247
+ }
1248
+ function isBoundaryCapabilityRef(value) {
1249
+ return isRecord2(value) && typeof value.id === "string" && value.id.length > 0 && isBoundaryCapabilityKind(value.kind) && typeof value.required === "boolean" && (value.sourceRefs === void 0 || Array.isArray(value.sourceRefs) && value.sourceRefs.every((sourceRef) => typeof sourceRef === "string"));
1250
+ }
1251
+ function isBoundaryCapabilityKind(value) {
1252
+ return value === "auth" || value === "permission" || value === "config" || value === "resource";
1253
+ }
1254
+ function selectCapabilityGuardPolicy(state, proposal) {
1255
+ const explicitId = stringMetadata(proposal.metadata, "capabilityGuardPolicyId") ?? proposal.sourceRefs?.find(
1256
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-capability-guard-policy"
1257
+ )?.id;
1258
+ if (explicitId !== void 0)
1259
+ return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-capability-guard-policy";
1260
+ const matching = [...state.policies.values()].filter(
1261
+ (policy) => policy.actionKinds === void 0 || policy.actionKinds.includes(proposal.actionKind)
1262
+ );
1263
+ if (matching.length === 0) return "missing-policy";
1264
+ if (matching.length > 1) return "policy-mismatch";
1265
+ return matching[0];
1266
+ }
1267
+ function latestCapabilityAdmission(state, policy, capabilityRef) {
1268
+ const admissions = state.admissionsByCapability.get(capabilityBoundaryRefId(capabilityRef)) ?? [];
1269
+ for (let index = admissions.length - 1; index >= 0; index -= 1) {
1270
+ const admission = admissions[index];
1271
+ if (admission !== void 0 && policy.admissionSubjectIds.includes(admission.subjectId))
1272
+ return admission;
1273
+ }
1274
+ return void 0;
1275
+ }
1276
+ function emitCapabilityStatusIssueForProposal(ctx, state, proposal, status) {
1277
+ const policy = selectCapabilityGuardPolicy(state, proposal);
1278
+ if (typeof policy === "string") return;
1279
+ if (status.subjectId !== void 0 && !policy.admissionSubjectIds.includes(status.subjectId))
1280
+ return;
1281
+ const capabilityId = status.capabilityId;
1282
+ const capabilityKind = status.capabilityKind;
1283
+ const statusCapabilityKey = capabilityId === void 0 || capabilityKind === void 0 ? void 0 : capabilityBoundaryRefId({ id: capabilityId, kind: capabilityKind });
1284
+ if (statusCapabilityKey !== void 0 && !policy.capabilityRefs.some(
1285
+ (capabilityRef) => capabilityBoundaryRefId(capabilityRef) === statusCapabilityKey
1286
+ ))
1287
+ return;
1288
+ const issue2 = status.issues?.[0] ?? dataIssue2(
1289
+ "capability-admission-status-issue",
1290
+ "Capability admission status reported an issue",
1291
+ { subjectId: proposal.workItemId }
1292
+ );
1293
+ emitCapabilityGuardIssue(
1294
+ ctx,
1295
+ state,
1296
+ `capability-status:${proposal.proposalId}:${status.statusId}`,
1297
+ dataIssue2(issue2.code, issue2.message, {
1298
+ subjectId: proposal.workItemId,
1299
+ refs: uniqueSourceRefs2([
1300
+ ...capabilityGuardRefs(proposal, policy),
1301
+ ...status.sourceRefs ?? []
1302
+ ]),
1303
+ metadata: {
1304
+ ...statusCapabilityKey === void 0 ? {} : { capabilityRef: statusCapabilityKey },
1305
+ capabilityAdmissionStatusId: status.statusId
1306
+ }
1307
+ })
1308
+ );
1309
+ }
1310
+ function capabilityGuardPolicyMessage(code, proposal) {
1311
+ if (code === "missing-policy")
1312
+ return `WorkItem domain action '${proposal.proposalId}' has no capability guard policy`;
1313
+ if (code === "unknown-work-item-domain-action-capability-guard-policy")
1314
+ return `WorkItem domain action '${proposal.proposalId}' references a missing capability guard policy`;
1315
+ return `WorkItem domain action '${proposal.proposalId}' matches multiple capability guard policies`;
1316
+ }
1317
+ function capabilityGuardRefs(proposal, policy, admissions = []) {
1318
+ return uniqueSourceRefs2([
1319
+ ref2("work-item", proposal.workItemId),
1320
+ ref2("work-item-domain-action-proposal", proposal.proposalId),
1321
+ ref2("work-item-domain-action-capability-guard-policy", policy.policyId),
1322
+ ...admissions.filter((admission) => admission !== void 0).flatMap((admission) => [
1323
+ ref2("capability-admission", admission.admissionId),
1324
+ ref2("capability-admission-proposal", admission.proposalId),
1325
+ ref2("boundary-capability", capabilityBoundaryRefId(admission.capability)),
1326
+ ...admission.sourceRefs ?? []
1327
+ ]),
1328
+ ...proposal.sourceRefs ?? []
1329
+ ]);
1330
+ }
1331
+ function capabilityBoundaryRefId(capability) {
1332
+ return `${capability.kind}:${capability.id}`;
1333
+ }
1334
+ function emitCapabilityGuardStatus(ctx, state, status) {
1335
+ state.statusSeq += 1;
1336
+ const statusFact = {
1337
+ kind: "work-item-domain-action-capability-guard-status",
1338
+ statusId: `work-item-domain-action-capability-guard-status:${state.statusSeq}`,
1339
+ ...status
1340
+ };
1341
+ emitCapabilityGuard(ctx, "status", statusFact);
1342
+ state.auditSeq += 1;
1343
+ emitCapabilityGuard(ctx, "audit", {
1344
+ id: `work-item-domain-action-capability-guard-status:${state.auditSeq}`,
1345
+ kind: "work-item-domain-action-capability-guard-status",
1346
+ subjectId: status.workItemId,
1347
+ message: status.message,
1348
+ sourceRefs: status.sourceRefs,
1349
+ metadata: {
1350
+ statusId: statusFact.statusId,
1351
+ state: status.state,
1352
+ proposalId: status.proposalId,
1353
+ policyId: status.policyId,
1354
+ ...status.metadata ?? {}
1355
+ }
1356
+ });
1357
+ }
1358
+ function emitCapabilityGuardStatusOnce(ctx, state, key, status) {
1359
+ if (state.emittedStatusKeys.has(key)) return;
1360
+ state.emittedStatusKeys.add(key);
1361
+ emitCapabilityGuardStatus(ctx, state, status);
1362
+ }
1363
+ function emitCapabilityGuardIssue(ctx, state, key, issue2) {
1364
+ if (state.issueKeys.has(key)) return;
1365
+ state.issueKeys.add(key);
1366
+ emitCapabilityGuard(ctx, "issue", issue2);
1367
+ emitCapabilityGuardStatus(ctx, state, {
1368
+ state: "issue",
1369
+ workItemId: issue2.subjectId,
1370
+ issues: [issue2],
1371
+ message: issue2.message,
1372
+ metadata: { issueCode: issue2.code }
1373
+ });
1374
+ }
1375
+ function emitCapabilityGuard(ctx, kind, value) {
1376
+ ctx.down([["DATA", { kind, value }]]);
1377
+ }
1378
+ function reduceProposalIntake(ctx, state, input, proposedAtMs) {
1379
+ const proposal = normalizeProposal(input, proposedAtMs);
1380
+ if (typeof proposal === "string") {
1381
+ const issue2 = dataIssue2("malformed-domain-action-proposal", proposal);
1382
+ emitIntake(ctx, "issue", issue2);
1383
+ emitIntakeStatus(ctx, state, {
1384
+ state: "rejected",
1385
+ code: issue2.code,
1386
+ message: issue2.message
1387
+ });
1388
+ return;
1389
+ }
1390
+ if (state.proposals.has(proposal.proposalId)) {
1391
+ emitIntakeStatus(ctx, state, {
1392
+ state: "duplicate",
1393
+ code: "duplicate-suppressed",
1394
+ workItemId: proposal.workItemId,
1395
+ proposalId: proposal.proposalId,
1396
+ actionKind: proposal.actionKind,
1397
+ message: `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`
1398
+ });
1399
+ return;
1400
+ }
1401
+ state.proposals.add(proposal.proposalId);
1402
+ emitIntake(ctx, "proposal", proposal);
1403
+ emitIntakeStatus(ctx, state, {
1404
+ state: "proposed",
1405
+ workItemId: proposal.workItemId,
1406
+ proposalId: proposal.proposalId,
1407
+ actionKind: proposal.actionKind,
1408
+ sourceRefs: proposal.sourceRefs
1409
+ });
1410
+ }
1411
+ function normalizeProposal(input, proposedAtMs) {
1412
+ if (!isRecord2(input)) return "WorkItemDomainActionProposal intake must be an object";
1413
+ if (input.kind !== "work-item-domain-action-proposal" && input.kind !== "work-item-domain-action-proposal-intake")
1414
+ return "WorkItemDomainActionProposal intake has unsupported kind";
1415
+ if (typeof input.proposalId !== "string" || input.proposalId.trim() === "")
1416
+ return "WorkItemDomainActionProposal.proposalId is required";
1417
+ if (typeof input.workItemId !== "string" || input.workItemId.trim() === "")
1418
+ return "WorkItemDomainActionProposal.workItemId is required";
1419
+ if (typeof input.actionKind !== "string" || input.actionKind.trim() === "")
1420
+ return "WorkItemDomainActionProposal.actionKind is required";
1421
+ if (input.kind === "work-item-domain-action-proposal") {
1422
+ if (typeof input.effectRunId !== "string")
1423
+ return "WorkItemDomainActionProposal.effectRunId is required";
1424
+ if (typeof input.effectRunResultId !== "string")
1425
+ return "WorkItemDomainActionProposal.effectRunResultId is required";
1426
+ if (typeof input.evidenceId !== "string")
1427
+ return "WorkItemDomainActionProposal.evidenceId is required";
1428
+ if (typeof input.policyId !== "string")
1429
+ return "WorkItemDomainActionProposal.policyId is required";
1430
+ return input;
1431
+ }
1432
+ return workItemDomainActionProposal(
1433
+ input.proposalId,
1434
+ input.workItemId,
1435
+ input.actionKind,
1436
+ {
1437
+ payload: input.payload,
1438
+ reason: typeof input.reason === "string" ? input.reason : void 0,
1439
+ policyId: typeof input.policyId === "string" ? input.policyId : void 0,
1440
+ effectRunId: typeof input.effectRunId === "string" ? input.effectRunId : void 0,
1441
+ effectRunResultId: typeof input.effectRunResultId === "string" ? input.effectRunResultId : void 0,
1442
+ evidenceId: typeof input.evidenceId === "string" ? input.evidenceId : void 0,
1443
+ proposedAtMs: typeof input.proposedAtMs === "number" ? input.proposedAtMs : proposedAtMs,
1444
+ sourceRefs: sourceRefs(input.sourceRefs),
1445
+ metadata: isRecord2(input.metadata) ? input.metadata : void 0
1446
+ }
1447
+ );
1448
+ }
1449
+ function applyAdmission(ctx, state, admission) {
1450
+ if (state.appliedAdmissions.has(admission.admissionId)) return;
1451
+ const proposal = state.proposals.get(admission.proposalId);
1452
+ if (proposal === void 0) {
1453
+ emitApplicationIssue(
1454
+ ctx,
1455
+ state,
1456
+ `missing-proposal:${admission.admissionId}:${admission.proposalId}`,
1457
+ "dangling-ref",
1458
+ `Admission '${admission.admissionId}' cannot apply without proposal '${admission.proposalId}'`,
1459
+ admission.workItemId,
1460
+ admissionRefs(admission)
1461
+ );
1462
+ return;
1463
+ }
1464
+ if (admission.state !== "admitted") {
1465
+ state.appliedAdmissions.add(admission.admissionId);
1466
+ emitApplication(ctx, state, admission, proposal, admission.state, []);
1467
+ return;
1468
+ }
1469
+ const mismatch = admissionProposalMismatch(admission, proposal);
1470
+ if (mismatch !== void 0) {
1471
+ state.appliedAdmissions.add(admission.admissionId);
1472
+ emitApplicationIssue(
1473
+ ctx,
1474
+ state,
1475
+ `admission-proposal-mismatch:${admission.admissionId}:${mismatch.field}`,
1476
+ "dangling-ref",
1477
+ mismatch.message,
1478
+ admission.workItemId,
1479
+ admissionRefs(admission, proposal),
1480
+ {
1481
+ field: mismatch.field,
1482
+ admissionValue: mismatch.admissionValue,
1483
+ proposalValue: mismatch.proposalValue
1484
+ }
1485
+ );
1486
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
1487
+ code: "dangling-ref",
1488
+ message: mismatch.message
1489
+ });
1490
+ return;
1491
+ }
1492
+ const workItem = state.workItems.get(admission.workItemId);
1493
+ if (workItem === void 0) {
1494
+ emitApplicationIssue(
1495
+ ctx,
1496
+ state,
1497
+ `missing-work-item:${admission.admissionId}:${admission.workItemId}`,
1498
+ "dangling-ref",
1499
+ `Admission '${admission.admissionId}' references unknown WorkItem '${admission.workItemId}'`,
1500
+ admission.workItemId,
1501
+ admissionRefs(admission, proposal)
1502
+ );
1503
+ return;
1504
+ }
1505
+ const metadataConflict = conflictingApplicationMetadata(proposal, admission);
1506
+ if (metadataConflict !== void 0) {
1507
+ state.appliedAdmissions.add(admission.admissionId);
1508
+ emitApplicationIssue(
1509
+ ctx,
1510
+ state,
1511
+ `metadata-conflict:${admission.admissionId}:${metadataConflict.field}`,
1512
+ metadataConflict.code,
1513
+ metadataConflict.message,
1514
+ admission.workItemId,
1515
+ admissionRefs(admission, proposal),
1516
+ {
1517
+ field: metadataConflict.field,
1518
+ admissionValue: metadataConflict.admissionValue,
1519
+ proposalValue: metadataConflict.proposalValue
1520
+ }
1521
+ );
1522
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
1523
+ code: metadataConflict.code,
1524
+ message: metadataConflict.message
1525
+ });
1526
+ return;
1527
+ }
1528
+ const stale = staleRevision(proposal, admission, workItem);
1529
+ if (stale !== void 0) {
1530
+ state.appliedAdmissions.add(admission.admissionId);
1531
+ emitApplicationIssue(
1532
+ ctx,
1533
+ state,
1534
+ `stale:${admission.admissionId}:${stale.kind}:${stale.expected}:${stale.current}`,
1535
+ stale.kind,
1536
+ `Admission '${admission.admissionId}' targets stale WorkItem revision`,
1537
+ admission.workItemId,
1538
+ admissionRefs(admission, proposal),
1539
+ { expected: stale.expected, current: stale.current }
1540
+ );
1541
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
1542
+ code: stale.kind,
1543
+ message: "Stale WorkItem revision"
1544
+ });
1545
+ return;
1546
+ }
1547
+ const policyResult = selectApplyPolicy(state, proposal, admission);
1548
+ if (typeof policyResult === "string") {
1549
+ emitApplicationIssue(
1550
+ ctx,
1551
+ state,
1552
+ `policy:${admission.admissionId}:${policyResult}`,
1553
+ policyResult,
1554
+ applyPolicyMessage(policyResult, proposal, admission),
1555
+ admission.workItemId,
1556
+ admissionRefs(admission, proposal)
1557
+ );
1558
+ return;
1559
+ }
1560
+ const output = lowerAction(ctx, state, workItem, proposal, admission, policyResult);
1561
+ if (output === void 0) {
1562
+ state.appliedAdmissions.add(admission.admissionId);
1563
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
1564
+ code: "invalid-action",
1565
+ message: "WorkItem domain action application rejected; see emitted issues",
1566
+ policyId: policyResult.policyId
1567
+ });
1568
+ return;
1569
+ }
1570
+ const duplicateFactId = firstDuplicateFactId(state, output.facts);
1571
+ if (duplicateFactId !== void 0) {
1572
+ state.appliedAdmissions.add(admission.admissionId);
1573
+ emitApplicationIssue(
1574
+ ctx,
1575
+ state,
1576
+ `duplicate-authoring-fact:${admission.admissionId}:${duplicateFactId}`,
1577
+ "duplicate-suppressed",
1578
+ `WorkItem domain action application '${admission.admissionId}' would duplicate authoring fact '${duplicateFactId}'`,
1579
+ admission.workItemId,
1580
+ admissionRefs(admission, proposal, policyResult),
1581
+ { eventId: duplicateFactId }
1582
+ );
1583
+ emitApplication(ctx, state, admission, proposal, "duplicate", [], {
1584
+ code: "duplicate-suppressed",
1585
+ message: "Duplicate WorkItem authoring fact suppressed atomically",
1586
+ policyId: policyResult.policyId
1587
+ });
1588
+ return;
1589
+ }
1590
+ state.appliedAdmissions.add(admission.admissionId);
1591
+ for (const fact of output.facts) claimFactId(state, fact.eventId);
1592
+ for (const fact of output.facts) emitApplicationFact(ctx, "authoring-fact", fact);
1593
+ emitApplication(ctx, state, admission, proposal, output.state, output.facts, {
1594
+ code: output.code,
1595
+ message: output.message,
1596
+ policyId: policyResult.policyId
1597
+ });
1598
+ }
1599
+ function lowerAction(ctx, state, workItem, proposal, admission, policy) {
1600
+ if (!policyAllowsAction(policy, proposal.actionKind)) {
1601
+ emitApplicationIssue(
1602
+ ctx,
1603
+ state,
1604
+ `policy-action:${admission.admissionId}:${policy.policyId}:${proposal.actionKind}`,
1605
+ "policy-mismatch",
1606
+ `Apply policy '${policy.policyId}' does not allow actionKind '${proposal.actionKind}'`,
1607
+ proposal.workItemId,
1608
+ admissionRefs(admission, proposal, policy)
1609
+ );
1610
+ return { state: "policy-rejected", facts: [], code: "policy-mismatch" };
1611
+ }
1612
+ if (proposal.actionKind === "patch") {
1613
+ const lowered = lowerPatchAction(ctx, state, workItem, proposal, admission, policy);
1614
+ if (lowered === void 0) return void 0;
1615
+ return { state: "applied", facts: lowered };
1616
+ }
1617
+ if (proposal.actionKind === "mark-verified" || proposal.actionKind === "require-review") {
1618
+ return {
1619
+ state: "proposal-only",
1620
+ facts: [],
1621
+ code: "domain-fact-unimplemented",
1622
+ message: `Action '${proposal.actionKind}' recorded as visible application status only; no WorkItem domain mutation fact was emitted`
1623
+ };
1624
+ }
1625
+ if (proposal.actionKind === "spawn-proposed" || proposal.actionKind === "spawn-child") {
1626
+ return lowerSpawnAction(ctx, state, proposal, admission, policy);
1627
+ }
1628
+ emitApplicationIssue(
1629
+ ctx,
1630
+ state,
1631
+ `unsupported-action:${admission.admissionId}:${proposal.actionKind}`,
1632
+ "unsupported-effect-kind",
1633
+ `Unsupported WorkItem domain actionKind '${proposal.actionKind}'`,
1634
+ proposal.workItemId,
1635
+ admissionRefs(admission, proposal, policy)
1636
+ );
1637
+ return { state: "rejected", facts: [], code: "unsupported-effect-kind" };
1638
+ }
1639
+ function lowerPatchAction(ctx, state, workItem, proposal, admission, policy) {
1640
+ const payload = normalizePatchPayload(proposal.payload);
1641
+ if (typeof payload === "string") {
1642
+ emitApplicationIssue(
1643
+ ctx,
1644
+ state,
1645
+ `invalid-patch:${admission.admissionId}`,
1646
+ "invalid-patch",
1647
+ payload,
1648
+ proposal.workItemId,
1649
+ admissionRefs(admission, proposal, policy)
1650
+ );
1651
+ return void 0;
1652
+ }
1653
+ const splitPayload = splitDedicatedPatchFields(payload, workItem);
1654
+ const facts = [];
1655
+ if (splitPayload.patch !== void 0) {
1656
+ const invalid = invalidPatchKeys(splitPayload.patch, policy);
1657
+ if (invalid.length > 0) {
1658
+ emitApplicationIssue(
1659
+ ctx,
1660
+ state,
1661
+ `invalid-patch-fields:${admission.admissionId}:${invalid.join(",")}`,
1662
+ "invalid-patch",
1663
+ `Patch action uses unsupported fields: ${invalid.join(", ")}`,
1664
+ proposal.workItemId,
1665
+ admissionRefs(admission, proposal, policy),
1666
+ { invalidFields: invalid }
1667
+ );
1668
+ return void 0;
1669
+ }
1670
+ facts.push({
1671
+ kind: "work-item-patched",
1672
+ eventId: splitPayload.eventId ?? `${admission.admissionId}:work-item-patched`,
1673
+ workItemId: workItem.workItemId,
1674
+ patch: splitPayload.patch,
1675
+ executionRelevantFields: splitPayload.executionRelevantFields ?? policy.patch?.executionRelevantFields,
1676
+ authorId: splitPayload.authorId,
1677
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1678
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
1679
+ });
1680
+ }
1681
+ if (splitPayload.acceptanceCriteria !== void 0) {
1682
+ if (!allowsAcceptanceCriteria(policy)) {
1683
+ emitApplicationIssue(
1684
+ ctx,
1685
+ state,
1686
+ `ac-policy:${admission.admissionId}`,
1687
+ "policy-mismatch",
1688
+ `Apply policy '${policy.policyId}' does not allow acceptance criteria changes`,
1689
+ proposal.workItemId,
1690
+ admissionRefs(admission, proposal, policy)
1691
+ );
1692
+ return void 0;
1693
+ }
1694
+ const issues = validateAcceptanceCriteria(splitPayload.acceptanceCriteria, {
1695
+ workItemId: workItem.workItemId
1696
+ });
1697
+ if (issues.length > 0) {
1698
+ for (const item of issues) emitApplicationFact(ctx, "issue", item);
1699
+ emitApplicationStatus(ctx, state, {
1700
+ state: "rejected",
1701
+ code: issues[0]?.code,
1702
+ message: issues[0]?.message,
1703
+ workItemId: workItem.workItemId,
1704
+ proposalId: proposal.proposalId,
1705
+ admissionId: admission.admissionId,
1706
+ actionKind: proposal.actionKind,
1707
+ sourceRefs: admissionRefs(admission, proposal, policy)
1708
+ });
1709
+ return void 0;
1710
+ }
1711
+ facts.push({
1712
+ kind: "acceptance-criteria-changed",
1713
+ eventId: `${admission.admissionId}:acceptance-criteria-changed`,
1714
+ workItemId: workItem.workItemId,
1715
+ acceptanceCriteria: splitPayload.acceptanceCriteria,
1716
+ authorId: splitPayload.authorId,
1717
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1718
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
1719
+ });
1720
+ }
1721
+ if (splitPayload.verificationPlan !== void 0) {
1722
+ if (!allowsVerificationPlan(policy)) {
1723
+ emitApplicationIssue(
1724
+ ctx,
1725
+ state,
1726
+ `plan-policy:${admission.admissionId}`,
1727
+ "policy-mismatch",
1728
+ `Apply policy '${policy.policyId}' does not allow verification plan changes`,
1729
+ proposal.workItemId,
1730
+ admissionRefs(admission, proposal, policy)
1731
+ );
1732
+ return void 0;
1733
+ }
1734
+ const issues = validateVerificationPlan(
1735
+ splitPayload.verificationPlan,
1736
+ splitPayload.acceptanceCriteria ?? workItem.acceptanceCriteria ?? [],
1737
+ { workItemId: workItem.workItemId }
1738
+ );
1739
+ if (issues.length > 0) {
1740
+ for (const item of issues) emitApplicationFact(ctx, "issue", item);
1741
+ emitApplicationStatus(ctx, state, {
1742
+ state: "rejected",
1743
+ code: issues[0]?.code,
1744
+ message: issues[0]?.message,
1745
+ workItemId: workItem.workItemId,
1746
+ proposalId: proposal.proposalId,
1747
+ admissionId: admission.admissionId,
1748
+ actionKind: proposal.actionKind,
1749
+ sourceRefs: admissionRefs(admission, proposal, policy)
1750
+ });
1751
+ return void 0;
1752
+ }
1753
+ facts.push({
1754
+ kind: "verification-plan-changed",
1755
+ eventId: `${admission.admissionId}:verification-plan-changed`,
1756
+ workItemId: workItem.workItemId,
1757
+ verificationPlan: splitPayload.verificationPlan,
1758
+ authorId: splitPayload.authorId,
1759
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1760
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
1761
+ });
1762
+ }
1763
+ if (facts.length === 0) {
1764
+ emitApplicationIssue(
1765
+ ctx,
1766
+ state,
1767
+ `empty-patch:${admission.admissionId}`,
1768
+ "invalid-patch",
1769
+ "Patch action payload did not contain patch, acceptanceCriteria, or verificationPlan",
1770
+ proposal.workItemId,
1771
+ admissionRefs(admission, proposal, policy)
1772
+ );
1773
+ return void 0;
1774
+ }
1775
+ return facts;
1776
+ }
1777
+ function lowerSpawnAction(ctx, state, proposal, admission, policy) {
1778
+ if (policy.spawn?.create !== true) {
1779
+ return {
1780
+ state: "proposal-only",
1781
+ facts: [],
1782
+ message: "Spawn action remains proposal/admission only without explicit create policy"
1783
+ };
1784
+ }
1785
+ emitApplicationIssue(
1786
+ ctx,
1787
+ state,
1788
+ `spawn-create-policy:${admission.admissionId}:${policy.policyId}`,
1789
+ "policy-mismatch",
1790
+ `Spawn create policy '${policy.policyId}' is incomplete: child creation requires an explicit create/link/idempotency policy surface`,
1791
+ proposal.workItemId,
1792
+ admissionRefs(admission, proposal, policy),
1793
+ {
1794
+ requires: ["linkParent", "idempotencyKey", "maxChildrenPerAdmission", "link-fact-vocabulary"]
1795
+ }
1796
+ );
1797
+ return {
1798
+ state: "proposal-only",
1799
+ facts: [],
1800
+ code: "policy-mismatch",
1801
+ message: "Spawn action remains proposal/admission only until explicit create/link policy is available"
1802
+ };
1803
+ }
1804
+ function normalizePatchPayload(payload) {
1805
+ if (!isRecord2(payload)) return "Patch action payload must be an object";
1806
+ if ("patch" in payload || "acceptanceCriteria" in payload || "verificationPlan" in payload || "executionRelevantFields" in payload) {
1807
+ if ("patch" in payload && payload.patch !== void 0 && !isRecord2(payload.patch))
1808
+ return "Patch action payload.patch must be an object";
1809
+ if ("acceptanceCriteria" in payload && payload.acceptanceCriteria !== void 0 && !Array.isArray(payload.acceptanceCriteria))
1810
+ return "Patch action payload.acceptanceCriteria must be an array";
1811
+ if ("verificationPlan" in payload && payload.verificationPlan !== void 0 && !isRecord2(payload.verificationPlan))
1812
+ return "Patch action payload.verificationPlan must be an object";
1813
+ const inlinePatch = inlinePatchFields(payload);
1814
+ const explicitPatch = isRecord2(payload.patch) ? payload.patch : void 0;
1815
+ const patch = explicitPatch === void 0 ? inlinePatch : { ...inlinePatch, ...explicitPatch };
1816
+ return {
1817
+ ...payload,
1818
+ patch: Object.keys(patch).length === 0 ? void 0 : patch
1819
+ };
1820
+ }
1821
+ return { patch: payload };
1822
+ }
1823
+ function inlinePatchFields(payload) {
1824
+ const patch = {};
1825
+ for (const [key, value] of Object.entries(payload)) {
1826
+ if (key === "metadata") continue;
1827
+ if (patchFieldKeys.has(key)) patch[key] = value;
1828
+ }
1829
+ return patch;
1830
+ }
1831
+ function splitDedicatedPatchFields(payload, workItem) {
1832
+ if (!isRecord2(payload.patch)) return payload;
1833
+ const patchRecord = payload.patch;
1834
+ const patch = {};
1835
+ for (const [key, value] of Object.entries(patchRecord)) {
1836
+ if (key === "acceptanceCriteria" || key === "verificationPlan" || key === "verificationSteps")
1837
+ continue;
1838
+ patch[key] = value;
1839
+ }
1840
+ const acceptanceCriteria = payload.acceptanceCriteria ?? (Array.isArray(patchRecord.acceptanceCriteria) ? patchRecord.acceptanceCriteria : void 0);
1841
+ const verificationPlan = payload.verificationPlan ?? (isRecord2(patchRecord.verificationPlan) ? patchRecord.verificationPlan : Array.isArray(patchRecord.verificationSteps) ? {
1842
+ ...workItem.verificationPlan ?? { planId: "default" },
1843
+ steps: patchRecord.verificationSteps
1844
+ } : void 0);
1845
+ return {
1846
+ ...payload,
1847
+ patch: Object.keys(patch).length === 0 ? void 0 : patch,
1848
+ acceptanceCriteria,
1849
+ verificationPlan
1850
+ };
1851
+ }
1852
+ function invalidPatchKeys(patch, policy) {
1853
+ const allowed = new Set(policy.patch?.allowedFields ?? Array.from(patchFieldKeys));
1854
+ return Object.keys(patch).filter((key) => !patchFieldKeys.has(key) || !allowed.has(key));
1855
+ }
1856
+ function allowsAcceptanceCriteria(policy) {
1857
+ if (policy.patch?.allowAcceptanceCriteria === false) return false;
1858
+ const allowed = policy.patch?.allowedFields;
1859
+ return allowed === void 0 || allowed.includes("acceptanceCriteria") || policy.patch?.allowAcceptanceCriteria === true;
1860
+ }
1861
+ function allowsVerificationPlan(policy) {
1862
+ if (policy.patch?.allowVerificationPlan === false) return false;
1863
+ const allowed = policy.patch?.allowedFields;
1864
+ return allowed === void 0 || allowed.includes("verificationPlan") || allowed.includes("verificationSteps") || policy.patch?.allowVerificationPlan === true;
1865
+ }
1866
+ function selectApplyPolicy(state, proposal, admission) {
1867
+ const explicitId = explicitApplyPolicyId(proposal, admission);
1868
+ if (explicitId !== void 0)
1869
+ return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-apply-policy";
1870
+ const matching = Array.from(state.policies.values()).filter(
1871
+ (policy) => policyAllowsAction(policy, proposal.actionKind)
1872
+ );
1873
+ if (matching.length === 0) return "missing-policy";
1874
+ if (matching.length > 1) return "policy-mismatch";
1875
+ return matching[0];
1876
+ }
1877
+ function explicitApplyPolicyId(proposal, admission) {
1878
+ const metadataPolicy = stringMetadata(admission.metadata, "applyPolicyId") ?? stringMetadata(proposal.metadata, "applyPolicyId");
1879
+ if (metadataPolicy !== void 0) return metadataPolicy;
1880
+ return [...admission.sourceRefs ?? [], ...proposal.sourceRefs ?? []].find(
1881
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-apply-policy"
1882
+ )?.id;
1883
+ }
1884
+ function policyAllowsAction(policy, actionKind) {
1885
+ return policy.actionKinds === void 0 || policy.actionKinds.includes(actionKind);
1886
+ }
1887
+ function admissionProposalMismatch(admission, proposal) {
1888
+ if (admission.workItemId !== proposal.workItemId)
1889
+ return {
1890
+ field: "workItemId",
1891
+ admissionValue: admission.workItemId,
1892
+ proposalValue: proposal.workItemId,
1893
+ message: `Admission '${admission.admissionId}' workItemId does not match proposal '${proposal.proposalId}'`
1894
+ };
1895
+ if (admission.actionKind !== proposal.actionKind)
1896
+ return {
1897
+ field: "actionKind",
1898
+ admissionValue: admission.actionKind,
1899
+ proposalValue: proposal.actionKind,
1900
+ message: `Admission '${admission.admissionId}' actionKind does not match proposal '${proposal.proposalId}'`
1901
+ };
1902
+ return void 0;
1903
+ }
1904
+ function conflictingApplicationMetadata(proposal, admission) {
1905
+ const authoringRevision = conflictingMetadataNumber(proposal, admission, "authoringRevision");
1906
+ if (authoringRevision !== void 0)
1907
+ return {
1908
+ field: "authoringRevision",
1909
+ code: "stale-revision",
1910
+ ...authoringRevision,
1911
+ message: `Admission '${admission.admissionId}' carries conflicting authoringRevision metadata`
1912
+ };
1913
+ const executionInputRevision = conflictingMetadataNumber(
1914
+ proposal,
1915
+ admission,
1916
+ "executionInputRevision"
1917
+ );
1918
+ if (executionInputRevision !== void 0)
1919
+ return {
1920
+ field: "executionInputRevision",
1921
+ code: "stale-execution-input",
1922
+ ...executionInputRevision,
1923
+ message: `Admission '${admission.admissionId}' carries conflicting executionInputRevision metadata`
1924
+ };
1925
+ const applyPolicyId = conflictingMetadataString(proposal, admission, "applyPolicyId");
1926
+ if (applyPolicyId !== void 0)
1927
+ return {
1928
+ field: "applyPolicyId",
1929
+ code: "policy-mismatch",
1930
+ ...applyPolicyId,
1931
+ message: `Admission '${admission.admissionId}' carries conflicting applyPolicyId metadata`
1932
+ };
1933
+ return void 0;
1934
+ }
1935
+ function conflictingMetadataNumber(proposal, admission, key) {
1936
+ const proposalValue = numberMetadata(proposal.metadata, key);
1937
+ const admissionValue = numberMetadata(admission.metadata, key);
1938
+ if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1939
+ return void 0;
1940
+ return { proposalValue, admissionValue };
1941
+ }
1942
+ function conflictingMetadataString(proposal, admission, key) {
1943
+ const proposalValue = stringMetadata(proposal.metadata, key);
1944
+ const admissionValue = stringMetadata(admission.metadata, key);
1945
+ if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1946
+ return void 0;
1947
+ return { proposalValue, admissionValue };
1948
+ }
1949
+ function staleRevision(proposal, admission, workItem) {
1950
+ const authoringRevision = numberMetadata(admission.metadata, "authoringRevision") ?? numberMetadata(proposal.metadata, "authoringRevision");
1951
+ if (authoringRevision !== void 0 && authoringRevision !== workItem.authoringRevision)
1952
+ return {
1953
+ kind: "stale-revision",
1954
+ expected: authoringRevision,
1955
+ current: workItem.authoringRevision
1956
+ };
1957
+ const executionInputRevision = numberMetadata(admission.metadata, "executionInputRevision") ?? numberMetadata(proposal.metadata, "executionInputRevision");
1958
+ if (executionInputRevision !== void 0 && executionInputRevision !== workItem.executionInputRevision)
1959
+ return {
1960
+ kind: "stale-execution-input",
1961
+ expected: executionInputRevision,
1962
+ current: workItem.executionInputRevision
1963
+ };
1964
+ return void 0;
1965
+ }
1966
+ function applyPolicyMessage(code, proposal, admission) {
1967
+ if (code === "missing-policy")
1968
+ return `Admitted action '${admission.admissionId}' requires an explicit apply policy`;
1969
+ if (code === "unknown-work-item-domain-action-apply-policy")
1970
+ return `Admitted action '${admission.admissionId}' references a missing apply policy`;
1971
+ return `Admitted action '${proposal.proposalId}' matches multiple apply policies`;
1972
+ }
1973
+ function emitApplication(ctx, state, admission, proposal, applicationState, facts, opts = {}) {
1974
+ const producedFactIds = facts.map((fact) => fact.eventId);
1975
+ const application = {
1976
+ kind: "work-item-domain-action-application",
1977
+ applicationId: `${admission.admissionId}:application`,
1978
+ admissionId: admission.admissionId,
1979
+ proposalId: proposal.proposalId,
1980
+ workItemId: proposal.workItemId,
1981
+ actionKind: proposal.actionKind,
1982
+ state: applicationState,
1983
+ producedFactIds,
1984
+ reason: admission.reason ?? proposal.reason,
1985
+ sourceRefs: admissionRefs(admission, proposal),
1986
+ metadata: { policyId: opts.policyId, code: opts.code }
1987
+ };
1988
+ emitApplicationFact(ctx, "application", application);
1989
+ emitApplicationStatus(ctx, state, {
1990
+ state: applicationState,
1991
+ code: opts.code,
1992
+ message: opts.message,
1993
+ workItemId: proposal.workItemId,
1994
+ proposalId: proposal.proposalId,
1995
+ admissionId: admission.admissionId,
1996
+ actionKind: proposal.actionKind,
1997
+ sourceRefs: application.sourceRefs,
1998
+ metadata: { producedFactIds, policyId: opts.policyId }
1999
+ });
2000
+ }
2001
+ function emitApplicationIssue(ctx, state, key, code, message, workItemId, sourceRefs2, metadata) {
2002
+ if (state.issueKeys.has(key)) return;
2003
+ state.issueKeys.add(key);
2004
+ const item = dataIssue2(code, message, { subjectId: workItemId, refs: sourceRefs2, metadata });
2005
+ emitApplicationFact(ctx, "issue", item);
2006
+ emitApplicationStatus(ctx, state, {
2007
+ state: code === "missing-policy" ? "missing-policy" : "rejected",
2008
+ code,
2009
+ message,
2010
+ workItemId,
2011
+ sourceRefs: sourceRefs2,
2012
+ metadata
2013
+ });
2014
+ }
2015
+ function emitIntakeStatus(ctx, state, status) {
2016
+ state.statusSeq += 1;
2017
+ const statusFact = {
2018
+ kind: "work-item-domain-action-status",
2019
+ statusId: `work-item-domain-action-intake-status:${state.statusSeq}`,
2020
+ ...status
2021
+ };
2022
+ emitIntake(ctx, "status", statusFact);
2023
+ emitIntakeAudit(ctx, state, "work-item-domain-action-intake-status", statusFact);
2024
+ }
2025
+ function emitApplicationStatus(ctx, state, status) {
2026
+ state.statusSeq += 1;
2027
+ const statusFact = {
2028
+ kind: "work-item-domain-action-status",
2029
+ statusId: `work-item-domain-action-application-status:${state.statusSeq}`,
2030
+ ...status
2031
+ };
2032
+ emitApplicationFact(ctx, "status", statusFact);
2033
+ emitApplicationAudit(ctx, state, "work-item-domain-action-application-status", statusFact);
2034
+ }
2035
+ function emitIntakeAudit(ctx, state, kind, status) {
2036
+ state.auditSeq += 1;
2037
+ emitIntake(ctx, "audit", auditRecord(kind, state.auditSeq, status));
2038
+ }
2039
+ function emitApplicationAudit(ctx, state, kind, status) {
2040
+ state.auditSeq += 1;
2041
+ emitApplicationFact(ctx, "audit", auditRecord(kind, state.auditSeq, status));
2042
+ }
2043
+ function auditRecord(kind, seq, status) {
2044
+ return {
2045
+ id: `${kind}:${seq}`,
2046
+ kind,
2047
+ subjectId: status.workItemId,
2048
+ message: status.message,
2049
+ issueCode: status.code,
2050
+ sourceRefs: status.sourceRefs,
2051
+ metadata: {
2052
+ statusId: status.statusId,
2053
+ state: status.state,
2054
+ proposalId: status.proposalId,
2055
+ admissionId: status.admissionId,
2056
+ actionKind: status.actionKind,
2057
+ ...status.metadata ?? {}
2058
+ }
2059
+ };
2060
+ }
2061
+ function emitIntake(ctx, kind, value) {
2062
+ ctx.down([["DATA", { kind, value }]]);
2063
+ }
2064
+ function emitApplicationFact(ctx, kind, value) {
2065
+ ctx.down([["DATA", { kind, value }]]);
2066
+ }
2067
+ function project(graph, runtime, name, factory, select) {
2068
+ return graph.node(
2069
+ [runtime],
2070
+ (ctx) => {
2071
+ for (const raw of depBatch(ctx, 0) ?? []) {
2072
+ const selected = select(raw);
2073
+ if (selected !== void 0) ctx.down([["DATA", selected]]);
2074
+ }
2075
+ },
2076
+ { name, factory, partial: true, completeWhenDepsComplete: false, errorWhenDepsError: false }
2077
+ );
2078
+ }
2079
+ function firstDuplicateFactId(state, facts) {
2080
+ const pending = /* @__PURE__ */ new Set();
2081
+ for (const fact of facts) {
2082
+ if (state.emittedFactIds.has(fact.eventId) || pending.has(fact.eventId)) return fact.eventId;
2083
+ pending.add(fact.eventId);
2084
+ }
2085
+ return void 0;
2086
+ }
2087
+ function claimFactId(state, factId) {
2088
+ if (state.emittedFactIds.has(factId)) return false;
2089
+ state.emittedFactIds.add(factId);
2090
+ return true;
2091
+ }
2092
+ function admissionRefs(admission, proposal, policy) {
2093
+ return uniqueSourceRefs2([
2094
+ ref2("work-item-domain-action-admission", admission.admissionId),
2095
+ ref2("work-item-domain-action-proposal", admission.proposalId),
2096
+ ...proposal === void 0 ? [] : [
2097
+ ref2("work-item", proposal.workItemId),
2098
+ ref2("work-item-evidence", proposal.evidenceId),
2099
+ ...proposal.sourceRefs ?? []
2100
+ ],
2101
+ ...policy === void 0 ? [] : [ref2("work-item-domain-action-apply-policy", policy.policyId)],
2102
+ ...admission.sourceRefs ?? []
2103
+ ]);
2104
+ }
2105
+ function actionSourceRefs(admission, proposal, policy) {
2106
+ return admissionRefs(admission, proposal, policy);
2107
+ }
2108
+ function dataIssue2(code, message, opts = {}) {
2109
+ return {
2110
+ kind: "issue",
2111
+ code,
2112
+ message,
2113
+ severity: "error",
2114
+ source: "work-item-actions",
2115
+ subjectId: opts.subjectId,
2116
+ refs: opts.refs?.map((sourceRef) => `${sourceRef.kind}:${sourceRef.id}`),
2117
+ metadata: opts.metadata
2118
+ };
2119
+ }
2120
+ function uniqueSourceRefs2(sourceRefs2) {
2121
+ const seen = /* @__PURE__ */ new Set();
2122
+ const out = [];
2123
+ for (const sourceRef of sourceRefs2) {
2124
+ const key = `${sourceRef.kind}:${sourceRef.id}:${JSON.stringify(sourceRef.metadata ?? {})}`;
2125
+ if (seen.has(key)) continue;
2126
+ seen.add(key);
2127
+ out.push(sourceRef);
2128
+ }
2129
+ return out;
2130
+ }
2131
+ function sourceRefs(value) {
2132
+ if (!Array.isArray(value)) return void 0;
2133
+ return value.filter(
2134
+ (item) => isRecord2(item) && typeof item.kind === "string" && typeof item.id === "string"
2135
+ );
2136
+ }
2137
+ function numberMetadata(metadata, key) {
2138
+ const value = metadata?.[key];
2139
+ return typeof value === "number" ? value : void 0;
2140
+ }
2141
+ function stringMetadata(metadata, key) {
2142
+ const value = metadata?.[key];
2143
+ return typeof value === "string" ? value : void 0;
2144
+ }
2145
+ function ref2(kind, id) {
2146
+ return { kind, id };
2147
+ }
2148
+ function recordString(value, key) {
2149
+ return isRecord2(value) && typeof value[key] === "string" ? value[key] : void 0;
2150
+ }
2151
+ function isRecord2(value) {
2152
+ return value !== null && typeof value === "object";
2153
+ }
2154
+ // Annotate the CommonJS export names for ESM import in node:
2155
+ 0 && (module.exports = {
2156
+ workItemDomainActionAdmissionProjector,
2157
+ workItemDomainActionApplicationProjector,
2158
+ workItemDomainActionApplyPolicy,
2159
+ workItemDomainActionCapabilityGuardProjector,
2160
+ workItemDomainActionProposal,
2161
+ workItemDomainActionProposalIntake,
2162
+ workItemDomainActionProposalIntakeProjector
2163
+ });
2164
+ //# sourceMappingURL=actions.cjs.map