@graphrefly/ts 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/dist/actions-types-CSC3NMDl.d.ts +657 -0
  2. package/dist/actions-types-wl9Mgkmr.d.cts +657 -0
  3. package/dist/adapters/index.cjs +5157 -2951
  4. package/dist/adapters/index.cjs.map +1 -1
  5. package/dist/adapters/index.d.cts +207 -70
  6. package/dist/adapters/index.d.ts +207 -70
  7. package/dist/adapters/index.js +3738 -1688
  8. package/dist/adapters/index.js.map +1 -1
  9. package/dist/adapters/nestjs/microservices.cjs +841 -0
  10. package/dist/adapters/nestjs/microservices.cjs.map +1 -0
  11. package/dist/adapters/nestjs/microservices.d.cts +45 -0
  12. package/dist/adapters/nestjs/microservices.d.ts +45 -0
  13. package/dist/adapters/nestjs/microservices.js +206 -0
  14. package/dist/adapters/nestjs/microservices.js.map +1 -0
  15. package/dist/adapters/nestjs/native.cjs +1391 -0
  16. package/dist/adapters/nestjs/native.cjs.map +1 -0
  17. package/dist/adapters/nestjs/native.d.cts +111 -0
  18. package/dist/adapters/nestjs/native.d.ts +111 -0
  19. package/dist/adapters/nestjs/native.js +577 -0
  20. package/dist/adapters/nestjs/native.js.map +1 -0
  21. package/dist/adapters/nestjs/websockets.cjs +924 -0
  22. package/dist/adapters/nestjs/websockets.cjs.map +1 -0
  23. package/dist/adapters/nestjs/websockets.d.cts +47 -0
  24. package/dist/adapters/nestjs/websockets.d.ts +47 -0
  25. package/dist/adapters/nestjs/websockets.js +286 -0
  26. package/dist/adapters/nestjs/websockets.js.map +1 -0
  27. package/dist/adapters/nestjs.cjs +1085 -0
  28. package/dist/adapters/nestjs.cjs.map +1 -0
  29. package/dist/adapters/nestjs.d.cts +385 -0
  30. package/dist/adapters/nestjs.d.ts +385 -0
  31. package/dist/adapters/nestjs.js +112 -0
  32. package/dist/adapters/nestjs.js.map +1 -0
  33. package/dist/adapters/observe-storage.d.cts +3 -3
  34. package/dist/adapters/observe-storage.d.ts +3 -3
  35. package/dist/adapters/observe-storage.js +4 -4
  36. package/dist/adapters/react.cjs.map +1 -1
  37. package/dist/adapters/react.d.cts +2 -2
  38. package/dist/adapters/react.d.ts +2 -2
  39. package/dist/adapters/react.js +1 -1
  40. package/dist/adapters/solid.cjs.map +1 -1
  41. package/dist/adapters/solid.d.cts +2 -2
  42. package/dist/adapters/solid.d.ts +2 -2
  43. package/dist/adapters/solid.js +1 -1
  44. package/dist/adapters/svelte.cjs.map +1 -1
  45. package/dist/adapters/svelte.d.cts +2 -2
  46. package/dist/adapters/svelte.d.ts +2 -2
  47. package/dist/adapters/svelte.js +1 -1
  48. package/dist/adapters/vue.cjs.map +1 -1
  49. package/dist/adapters/vue.d.cts +2 -2
  50. package/dist/adapters/vue.d.ts +2 -2
  51. package/dist/adapters/vue.js +1 -1
  52. package/dist/{agent-runtime-DZTJ3C-p.d.cts → agent-runtime-types-core-CaXfKNtY.d.cts} +171 -320
  53. package/dist/{agent-runtime-BesGDZcB.d.ts → agent-runtime-types-core-hU299uIC.d.ts} +171 -320
  54. package/dist/agent-runtime-types-tool-BEpSINol.d.ts +695 -0
  55. package/dist/agent-runtime-types-tool-DninPEzk.d.cts +695 -0
  56. package/dist/agentic-memory-retention-BmGX368S.d.ts +14 -0
  57. package/dist/agentic-memory-retention-Ih1qhX9Z.d.cts +14 -0
  58. package/dist/{agentic-memory-BmRCvh0d.d.ts → agentic-memory-types-CVSUS6XR.d.ts} +13 -57
  59. package/dist/{agentic-memory-DfuVZ-lY.d.cts → agentic-memory-types-FnnYlVUs.d.cts} +13 -57
  60. package/dist/{capability-admission-g0mn9hpq.d.ts → capability-admission-BW2CziT6.d.ts} +3 -3
  61. package/dist/{capability-admission-B0BzqAm5.d.cts → capability-admission-lwSecxXs.d.cts} +3 -3
  62. package/dist/chunk-2KUAG2GZ.js +9693 -0
  63. package/dist/chunk-2KUAG2GZ.js.map +1 -0
  64. package/dist/chunk-2NJP6GO4.js +1320 -0
  65. package/dist/chunk-2NJP6GO4.js.map +1 -0
  66. package/dist/{chunk-YDSIVHRR.js → chunk-4NWSNI4K.js} +1598 -1584
  67. package/dist/chunk-4NWSNI4K.js.map +1 -0
  68. package/dist/{chunk-Z2ANQ6JW.js → chunk-4Q77MMJY.js} +2 -2
  69. package/dist/chunk-6E76H4OU.js +132 -0
  70. package/dist/chunk-6E76H4OU.js.map +1 -0
  71. package/dist/chunk-7GOTIIQ7.js +819 -0
  72. package/dist/chunk-7GOTIIQ7.js.map +1 -0
  73. package/dist/{chunk-IXZBUWSP.js → chunk-7HZRJMN6.js} +2 -2
  74. package/dist/{chunk-SS2A464I.js → chunk-CJIFGJQG.js} +3 -3
  75. package/dist/{chunk-V7CIJE4B.js → chunk-CX6B6PO2.js} +92 -9
  76. package/dist/chunk-CX6B6PO2.js.map +1 -0
  77. package/dist/{chunk-FBUU43PM.js → chunk-E4QCH32M.js} +448 -446
  78. package/dist/chunk-E4QCH32M.js.map +1 -0
  79. package/dist/{chunk-HKK2JD7Z.js → chunk-ECURQ3HD.js} +12 -125
  80. package/dist/chunk-ECURQ3HD.js.map +1 -0
  81. package/dist/{chunk-3JR3EDB2.js → chunk-EOKT4QFF.js} +121 -115
  82. package/dist/chunk-EOKT4QFF.js.map +1 -0
  83. package/dist/{chunk-K3FXTC3I.js → chunk-HJACH5PU.js} +3 -3
  84. package/dist/{chunk-GTPCOEOZ.js → chunk-IDMLXLLG.js} +3 -3
  85. package/dist/{chunk-DKP56CSW.js → chunk-JKAYLDQV.js} +2 -2
  86. package/dist/{chunk-4VLAQHZI.js → chunk-K7FB3JTD.js} +17 -1
  87. package/dist/chunk-K7FB3JTD.js.map +1 -0
  88. package/dist/{chunk-H75VXTGT.js → chunk-L6LDXRWE.js} +3 -3
  89. package/dist/{chunk-H75VXTGT.js.map → chunk-L6LDXRWE.js.map} +1 -1
  90. package/dist/{chunk-YXMZ2N6J.js → chunk-M7J6Z4IJ.js} +1071 -1025
  91. package/dist/chunk-M7J6Z4IJ.js.map +1 -0
  92. package/dist/chunk-MQEQMS7B.js +1009 -0
  93. package/dist/chunk-MQEQMS7B.js.map +1 -0
  94. package/dist/chunk-MTELVIYR.js +1421 -0
  95. package/dist/chunk-MTELVIYR.js.map +1 -0
  96. package/dist/{chunk-QFY4AFY4.js → chunk-PVC7WDKI.js} +58 -52
  97. package/dist/chunk-PVC7WDKI.js.map +1 -0
  98. package/dist/{chunk-VTHLCFN4.js → chunk-RAHNUYA5.js} +2 -2
  99. package/dist/{chunk-XKXWK2KP.js → chunk-SHZDP2MQ.js} +1157 -1021
  100. package/dist/chunk-SHZDP2MQ.js.map +1 -0
  101. package/dist/{chunk-CZNV3VXM.js → chunk-SIDJO2T4.js} +11 -11
  102. package/dist/chunk-STXRMPW4.js +4131 -0
  103. package/dist/chunk-STXRMPW4.js.map +1 -0
  104. package/dist/{chunk-2747WN4Y.js → chunk-TPND5MJS.js} +3 -3
  105. package/dist/chunk-TQPCAIQI.js +612 -0
  106. package/dist/chunk-TQPCAIQI.js.map +1 -0
  107. package/dist/{chunk-43BKLFZU.js → chunk-YDWBXXQZ.js} +10 -10
  108. package/dist/{chunk-6PHB5CJS.js → chunk-ZLFRB6FI.js} +2 -2
  109. package/dist/composition/index.cjs +1228 -1076
  110. package/dist/composition/index.cjs.map +1 -1
  111. package/dist/composition/index.d.cts +3 -3
  112. package/dist/composition/index.d.ts +3 -3
  113. package/dist/composition/index.js +4 -4
  114. package/dist/core/index.cjs +1198 -1046
  115. package/dist/core/index.cjs.map +1 -1
  116. package/dist/core/index.d.cts +1 -1
  117. package/dist/core/index.d.ts +1 -1
  118. package/dist/core/index.js +2 -2
  119. package/dist/cqrs/index.d.cts +3 -3
  120. package/dist/cqrs/index.d.ts +3 -3
  121. package/dist/cqrs/messaging.d.cts +4 -4
  122. package/dist/cqrs/messaging.d.ts +4 -4
  123. package/dist/cqrs/work-queue.d.cts +5 -5
  124. package/dist/cqrs/work-queue.d.ts +5 -5
  125. package/dist/data-structures/index.cjs +1226 -1074
  126. package/dist/data-structures/index.cjs.map +1 -1
  127. package/dist/data-structures/index.d.cts +8 -7
  128. package/dist/data-structures/index.d.ts +8 -7
  129. package/dist/data-structures/index.js +6 -5
  130. package/dist/{describe-BpyJuWkw.d.ts → describe-B_A5fbXH.d.ts} +1 -1
  131. package/dist/{describe-DYMw_l1C.d.cts → describe-CQRrkv-Q.d.cts} +1 -1
  132. package/dist/executors/tool-provider-adapters.cjs +3091 -0
  133. package/dist/executors/tool-provider-adapters.cjs.map +1 -0
  134. package/dist/executors/tool-provider-adapters.d.cts +174 -0
  135. package/dist/executors/tool-provider-adapters.d.ts +174 -0
  136. package/dist/executors/tool-provider-adapters.js +1336 -0
  137. package/dist/executors/tool-provider-adapters.js.map +1 -0
  138. package/dist/executors/tool-provider-runtime.cjs +5178 -0
  139. package/dist/executors/tool-provider-runtime.cjs.map +1 -0
  140. package/dist/executors/tool-provider-runtime.d.cts +17 -0
  141. package/dist/executors/tool-provider-runtime.d.ts +17 -0
  142. package/dist/executors/tool-provider-runtime.js +15 -0
  143. package/dist/executors/tool-provider-runtime.js.map +1 -0
  144. package/dist/executors/tool-provider.cjs +6392 -0
  145. package/dist/executors/tool-provider.cjs.map +1 -0
  146. package/dist/executors/tool-provider.d.cts +60 -0
  147. package/dist/executors/tool-provider.d.ts +60 -0
  148. package/dist/executors/tool-provider.js +89 -0
  149. package/dist/executors/tool-provider.js.map +1 -0
  150. package/dist/executors/work-queue.d.cts +6 -6
  151. package/dist/executors/work-queue.d.ts +6 -6
  152. package/dist/graph/index.cjs +1499 -1341
  153. package/dist/graph/index.cjs.map +1 -1
  154. package/dist/graph/index.d.cts +9 -8
  155. package/dist/graph/index.d.ts +9 -8
  156. package/dist/graph/index.js +23 -22
  157. package/dist/{graph-DCEWh4T2.d.cts → graph-CWK3HLPB.d.cts} +133 -131
  158. package/dist/{graph-D-1-SQeC.d.ts → graph-ho5sotHP.d.ts} +133 -131
  159. package/dist/{index-Bmxeu0nK.d.ts → index-CQWcE0Dw.d.ts} +18 -4
  160. package/dist/{index-72VZC0-E.d.cts → index-DHA1i67c.d.cts} +18 -4
  161. package/dist/index.cjs +3397 -3140
  162. package/dist/index.cjs.map +1 -1
  163. package/dist/index.d.cts +12 -9
  164. package/dist/index.d.ts +12 -9
  165. package/dist/index.js +110 -109
  166. package/dist/inspection/boundary.d.cts +4 -4
  167. package/dist/inspection/boundary.d.ts +4 -4
  168. package/dist/measurements-C0mAvWU1.d.cts +164 -0
  169. package/dist/measurements-OMpCeBwh.d.ts +164 -0
  170. package/dist/messaging/index.cjs +57 -51
  171. package/dist/messaging/index.cjs.map +1 -1
  172. package/dist/messaging/index.d.cts +11 -276
  173. package/dist/messaging/index.d.ts +11 -276
  174. package/dist/messaging/index.js +1 -1
  175. package/dist/operators/index.cjs +1228 -1076
  176. package/dist/operators/index.cjs.map +1 -1
  177. package/dist/operators/index.d.cts +5 -5
  178. package/dist/operators/index.d.ts +5 -5
  179. package/dist/operators/index.js +5 -5
  180. package/dist/orchestration/index.cjs +8844 -6071
  181. package/dist/orchestration/index.cjs.map +1 -1
  182. package/dist/orchestration/index.d.cts +171 -224
  183. package/dist/orchestration/index.d.ts +171 -224
  184. package/dist/orchestration/index.js +42 -991
  185. package/dist/orchestration/index.js.map +1 -1
  186. package/dist/orchestration/messaging.d.cts +5 -8
  187. package/dist/orchestration/messaging.d.ts +5 -8
  188. package/dist/orchestration/work-queue.cjs +1243 -5
  189. package/dist/orchestration/work-queue.cjs.map +1 -1
  190. package/dist/orchestration/work-queue.d.cts +121 -10
  191. package/dist/orchestration/work-queue.d.ts +121 -10
  192. package/dist/orchestration/work-queue.js +1067 -4
  193. package/dist/orchestration/work-queue.js.map +1 -1
  194. package/dist/patterns/event-flow.cjs +6 -20
  195. package/dist/patterns/event-flow.cjs.map +1 -1
  196. package/dist/patterns/event-flow.d.cts +4 -4
  197. package/dist/patterns/event-flow.d.ts +4 -4
  198. package/dist/patterns/event-flow.js +2 -2
  199. package/dist/patterns/index.cjs +453 -465
  200. package/dist/patterns/index.cjs.map +1 -1
  201. package/dist/patterns/index.d.cts +6 -5
  202. package/dist/patterns/index.d.ts +6 -5
  203. package/dist/patterns/index.js +3 -3
  204. package/dist/process-types-C9uMYz3i.d.ts +200 -0
  205. package/dist/process-types-h3uRlzDc.d.cts +200 -0
  206. package/dist/{reactive-collection-DNV0-gFi.d.cts → reactive-collection-B9R0Bl1P.d.cts} +4 -34
  207. package/dist/{reactive-collection-BAmfrGjd.d.ts → reactive-collection-BXFrH0U2.d.ts} +4 -34
  208. package/dist/{reactive-collection-storage-BNEldDyi.d.cts → reactive-collection-storage-BLGv8Xp8.d.cts} +5 -5
  209. package/dist/{reactive-collection-storage-YZsAQsWK.d.ts → reactive-collection-storage-a4zD3665.d.ts} +5 -5
  210. package/dist/{reactive-map-DRD1LJ2H.d.cts → reactive-map-C_8sOfdS.d.cts} +3 -2
  211. package/dist/{reactive-map-EsDiCmJk.d.ts → reactive-map-jle5dnok.d.ts} +3 -2
  212. package/dist/render/index.d.cts +2 -2
  213. package/dist/render/index.d.ts +2 -2
  214. package/dist/scheduled-readiness-5rwQlyjV.d.ts +91 -0
  215. package/dist/scheduled-readiness-DpRY8jI0.d.cts +91 -0
  216. package/dist/semantic-memory-graph-C2ZUwIlq.d.ts +30 -0
  217. package/dist/semantic-memory-graph-DlZBD_Eu.d.cts +30 -0
  218. package/dist/{semantic-memory-graph-DKuNzuWw.d.cts → semantic-memory-graph-types-BvzdqmkY.d.cts} +2 -28
  219. package/dist/{semantic-memory-graph-uwbwJdhe.d.ts → semantic-memory-graph-types-Ci-OtahO.d.ts} +2 -28
  220. package/dist/solutions/index.cjs +6353 -6169
  221. package/dist/solutions/index.cjs.map +1 -1
  222. package/dist/solutions/index.d.cts +12 -10
  223. package/dist/solutions/index.d.ts +12 -10
  224. package/dist/solutions/index.js +5 -5
  225. package/dist/solutions/reactive-layout/browser/index.cjs +116 -108
  226. package/dist/solutions/reactive-layout/browser/index.cjs.map +1 -1
  227. package/dist/solutions/reactive-layout/browser/index.d.cts +4 -4
  228. package/dist/solutions/reactive-layout/browser/index.d.ts +4 -4
  229. package/dist/solutions/reactive-layout/browser/index.js +3 -3
  230. package/dist/solutions/reactive-layout/index.cjs +3578 -3350
  231. package/dist/solutions/reactive-layout/index.cjs.map +1 -1
  232. package/dist/solutions/reactive-layout/index.d.cts +32 -576
  233. package/dist/solutions/reactive-layout/index.d.ts +32 -576
  234. package/dist/solutions/reactive-layout/index.js +65 -5
  235. package/dist/solutions/reactive-layout/node-canvas/index.cjs +127 -117
  236. package/dist/solutions/reactive-layout/node-canvas/index.cjs.map +1 -1
  237. package/dist/solutions/reactive-layout/node-canvas/index.d.cts +4 -4
  238. package/dist/solutions/reactive-layout/node-canvas/index.d.ts +4 -4
  239. package/dist/solutions/reactive-layout/node-canvas/index.js +3 -3
  240. package/dist/solutions/reactive-layout/react-native/index.cjs +127 -117
  241. package/dist/solutions/reactive-layout/react-native/index.cjs.map +1 -1
  242. package/dist/solutions/reactive-layout/react-native/index.d.cts +4 -4
  243. package/dist/solutions/reactive-layout/react-native/index.d.ts +4 -4
  244. package/dist/solutions/reactive-layout/react-native/index.js +3 -3
  245. package/dist/solutions/reactive-layout/skia/index.cjs +127 -117
  246. package/dist/solutions/reactive-layout/skia/index.cjs.map +1 -1
  247. package/dist/solutions/reactive-layout/skia/index.d.cts +4 -4
  248. package/dist/solutions/reactive-layout/skia/index.d.ts +4 -4
  249. package/dist/solutions/reactive-layout/skia/index.js +3 -3
  250. package/dist/solutions/work-item/actions.cjs +1609 -1428
  251. package/dist/solutions/work-item/actions.cjs.map +1 -1
  252. package/dist/solutions/work-item/actions.d.cts +23 -184
  253. package/dist/solutions/work-item/actions.d.ts +23 -184
  254. package/dist/solutions/work-item/actions.js +1558 -934
  255. package/dist/solutions/work-item/actions.js.map +1 -1
  256. package/dist/solutions/work-item/scheduling.cjs +9181 -1838
  257. package/dist/solutions/work-item/scheduling.cjs.map +1 -1
  258. package/dist/solutions/work-item/scheduling.d.cts +1763 -328
  259. package/dist/solutions/work-item/scheduling.d.ts +1763 -328
  260. package/dist/solutions/work-item/scheduling.js +117 -3
  261. package/dist/solutions/work-item/work-queue.d.cts +7 -7
  262. package/dist/solutions/work-item/work-queue.d.ts +7 -7
  263. package/dist/sources/browser.cjs +1318 -1083
  264. package/dist/sources/browser.cjs.map +1 -1
  265. package/dist/sources/browser.d.cts +4 -4
  266. package/dist/sources/browser.d.ts +4 -4
  267. package/dist/sources/browser.js +4 -4
  268. package/dist/sources/index.cjs +1318 -1083
  269. package/dist/sources/index.cjs.map +1 -1
  270. package/dist/sources/index.d.cts +4 -4
  271. package/dist/sources/index.d.ts +4 -4
  272. package/dist/sources/index.js +4 -4
  273. package/dist/sources/node.d.cts +3 -3
  274. package/dist/sources/node.d.ts +3 -3
  275. package/dist/storage/browser.cjs +16 -0
  276. package/dist/storage/browser.cjs.map +1 -1
  277. package/dist/storage/browser.js +3 -3
  278. package/dist/storage/index.cjs +16 -0
  279. package/dist/storage/index.cjs.map +1 -1
  280. package/dist/storage/index.d.cts +5 -4
  281. package/dist/storage/index.d.ts +5 -4
  282. package/dist/storage/index.js +6 -6
  283. package/dist/storage/node.cjs +16 -0
  284. package/dist/storage/node.cjs.map +1 -1
  285. package/dist/storage/node.js +3 -3
  286. package/dist/{store-C-joM4gh.d.ts → store-BmtEs9mG.d.ts} +1 -1
  287. package/dist/{store-CNJwmT-h.d.cts → store-PAAsYvML.d.cts} +1 -1
  288. package/dist/types-BRNKoFHj.d.ts +357 -0
  289. package/dist/{types-CcPIn7sy.d.cts → types-BS6CyR-x.d.cts} +27 -108
  290. package/dist/types-BWK2ay3e.d.cts +457 -0
  291. package/dist/types-BXKSAoE1.d.cts +357 -0
  292. package/dist/types-BaPpZItj.d.ts +457 -0
  293. package/dist/types-BhveCMg5.d.cts +274 -0
  294. package/dist/{types-BsJvElYZ.d.ts → types-C9NOgNJw.d.ts} +27 -108
  295. package/dist/types-CTsQ8Ww4.d.ts +274 -0
  296. package/dist/types-DL_05n2M.d.ts +34 -0
  297. package/dist/types-XDoqxYO9.d.cts +34 -0
  298. package/dist/{work-item-runtime-C3M79vE9.d.ts → work-item-runtime-types-BqtWnSCS.d.ts} +3 -93
  299. package/dist/{work-item-runtime-qaVgsL0T.d.cts → work-item-runtime-types-CHO03AKh.d.cts} +3 -93
  300. package/dist/work-queue/index.cjs +957 -953
  301. package/dist/work-queue/index.cjs.map +1 -1
  302. package/dist/work-queue/index.d.cts +9 -357
  303. package/dist/work-queue/index.d.ts +9 -357
  304. package/dist/work-queue/index.js +957 -953
  305. package/dist/work-queue/index.js.map +1 -1
  306. package/package.json +603 -513
  307. package/dist/chunk-3JR3EDB2.js.map +0 -1
  308. package/dist/chunk-4VLAQHZI.js.map +0 -1
  309. package/dist/chunk-6XAIOL3X.js +0 -2407
  310. package/dist/chunk-6XAIOL3X.js.map +0 -1
  311. package/dist/chunk-FBUU43PM.js.map +0 -1
  312. package/dist/chunk-HKK2JD7Z.js.map +0 -1
  313. package/dist/chunk-PC3BTTBE.js +0 -3217
  314. package/dist/chunk-PC3BTTBE.js.map +0 -1
  315. package/dist/chunk-QFY4AFY4.js.map +0 -1
  316. package/dist/chunk-V7CIJE4B.js.map +0 -1
  317. package/dist/chunk-XKXWK2KP.js.map +0 -1
  318. package/dist/chunk-YDSIVHRR.js.map +0 -1
  319. package/dist/chunk-YXMZ2N6J.js.map +0 -1
  320. /package/dist/{chunk-Z2ANQ6JW.js.map → chunk-4Q77MMJY.js.map} +0 -0
  321. /package/dist/{chunk-IXZBUWSP.js.map → chunk-7HZRJMN6.js.map} +0 -0
  322. /package/dist/{chunk-SS2A464I.js.map → chunk-CJIFGJQG.js.map} +0 -0
  323. /package/dist/{chunk-K3FXTC3I.js.map → chunk-HJACH5PU.js.map} +0 -0
  324. /package/dist/{chunk-GTPCOEOZ.js.map → chunk-IDMLXLLG.js.map} +0 -0
  325. /package/dist/{chunk-DKP56CSW.js.map → chunk-JKAYLDQV.js.map} +0 -0
  326. /package/dist/{chunk-VTHLCFN4.js.map → chunk-RAHNUYA5.js.map} +0 -0
  327. /package/dist/{chunk-CZNV3VXM.js.map → chunk-SIDJO2T4.js.map} +0 -0
  328. /package/dist/{chunk-2747WN4Y.js.map → chunk-TPND5MJS.js.map} +0 -0
  329. /package/dist/{chunk-43BKLFZU.js.map → chunk-YDWBXXQZ.js.map} +0 -0
  330. /package/dist/{chunk-6PHB5CJS.js.map → chunk-ZLFRB6FI.js.map} +0 -0
@@ -1,743 +1,722 @@
1
1
  import {
2
2
  validateAcceptanceCriteria,
3
- validateVerificationPlan
4
- } from "../../chunk-6XAIOL3X.js";
5
- import {
6
- workItemDomainActionAdmissionProjector
7
- } from "../../chunk-PC3BTTBE.js";
3
+ validateVerificationPlan,
4
+ validateWorkItemDraft
5
+ } from "../../chunk-2KUAG2GZ.js";
8
6
  import {
9
7
  depBatch
10
8
  } from "../../chunk-WQIA3GFB.js";
11
9
  import "../../chunk-S6HXABGL.js";
12
10
  import "../../chunk-DGUM43GV.js";
13
11
 
14
- // src/solutions/work-item/actions.ts
15
- var patchFieldKeys = /* @__PURE__ */ new Set([
16
- "summary",
17
- "detail",
18
- "detailRefs",
19
- "kind",
20
- "priority",
21
- "tags",
22
- "owner",
23
- "assignee",
24
- "deadlineMs",
25
- "customFields",
26
- "sourceRefs",
27
- "metadata"
28
- ]);
29
- function workItemDomainActionProposal(proposalId, workItemId, actionKind, opts = {}) {
30
- return {
31
- kind: "work-item-domain-action-proposal",
32
- proposalId,
33
- workItemId,
34
- actionKind,
35
- effectRunId: opts.effectRunId ?? `domain-action:${proposalId}:effect-run`,
36
- effectRunResultId: opts.effectRunResultId ?? `domain-action:${proposalId}:effect-run-result`,
37
- evidenceId: opts.evidenceId ?? `domain-action:${proposalId}:evidence`,
38
- policyId: opts.policyId ?? "domain-action-proposal",
39
- payload: opts.payload,
40
- reason: opts.reason,
41
- sourceRefs: opts.sourceRefs,
42
- proposedAtMs: opts.proposedAtMs,
43
- metadata: opts.metadata
12
+ // src/orchestration/work-item-runtime-shared.ts
13
+ function emitWorkItemAdmissionIssue(ctx, state, key, code, message, subjectId, sourceRefs2) {
14
+ if (state.issueKeys.has(key)) return;
15
+ state.issueKeys.add(key);
16
+ state.issueSeq += 1;
17
+ state.statusSeq += 1;
18
+ state.auditSeq += 1;
19
+ const issue = dataIssue(code, message, { subjectId, refs: sourceRefs2 });
20
+ const status = {
21
+ kind: "work-item-status",
22
+ statusId: `${subjectId ?? "work-item"}:mapping-issue:${state.statusSeq}`,
23
+ workItemId: subjectId ?? "unknown",
24
+ state: "mapping-issue",
25
+ sourceRefs: sourceRefs2,
26
+ issues: [issue]
27
+ };
28
+ const audit = {
29
+ id: `${subjectId ?? "work-item"}:${code}:${state.auditSeq}`,
30
+ kind: "work-item-domain-action-admission-issue",
31
+ subjectId,
32
+ issueCode: code,
33
+ message,
34
+ sourceRefs: sourceRefs2
44
35
  };
36
+ ctx.down([
37
+ ["DATA", { kind: "issue", issue }],
38
+ ["DATA", { kind: "status", status }],
39
+ ["DATA", { kind: "audit", audit }]
40
+ ]);
45
41
  }
46
- function workItemDomainActionProposalIntake(proposalId, workItemId, actionKind, opts = {}) {
42
+ function emptyWorkItemDomainActionAdmissionState() {
47
43
  return {
48
- kind: "work-item-domain-action-proposal-intake",
49
- proposalId,
50
- workItemId,
51
- actionKind,
52
- payload: opts.payload,
53
- reason: opts.reason,
54
- policyId: opts.policyId,
55
- effectRunId: opts.effectRunId,
56
- effectRunResultId: opts.effectRunResultId,
57
- evidenceId: opts.evidenceId,
58
- proposedAtMs: opts.proposedAtMs,
59
- sourceRefs: opts.sourceRefs,
60
- metadata: opts.metadata
44
+ proposals: /* @__PURE__ */ new Map(),
45
+ policies: /* @__PURE__ */ new Map(),
46
+ decisions: /* @__PURE__ */ new Map(),
47
+ admissionsById: /* @__PURE__ */ new Map(),
48
+ admissionsByProposal: /* @__PURE__ */ new Map(),
49
+ terminalDecisionIds: /* @__PURE__ */ new Set(),
50
+ issueKeys: /* @__PURE__ */ new Set(),
51
+ statusSeq: 0,
52
+ issueSeq: 0,
53
+ auditSeq: 0
61
54
  };
62
55
  }
63
- function workItemDomainActionApplyPolicy(policyId, opts = {}) {
56
+ function freezeWorkItemDomainActionAdmissionViews(state) {
64
57
  return {
65
- kind: "work-item-domain-action-apply-policy",
66
- policyId,
67
- actionKinds: opts.actionKinds,
68
- patch: opts.patch,
69
- spawn: opts.spawn,
70
- metadata: opts.metadata
58
+ admissionsByProposal: new Map(state.admissionsByProposal),
59
+ admissionsByWorkItem: new Map(
60
+ Array.from(state.admissionsByWorkItem, ([key, value]) => [key, Object.freeze([...value])])
61
+ ),
62
+ issues: Object.freeze([...state.issues]),
63
+ audit: Object.freeze([...state.audit])
71
64
  };
72
65
  }
73
- function workItemDomainActionProposalIntakeProjector(graph, opts) {
74
- const name = opts.name ?? "workItemDomainActionIntake";
75
- const now = opts.now ?? Date.now;
76
- const runtime = graph.node(
77
- [opts.proposals],
66
+ function workItemAdmissionProposalRefs(proposal) {
67
+ return uniqueSourceRefs([
68
+ ref("work-item", proposal.workItemId),
69
+ ref("work-item-domain-action-proposal", proposal.proposalId),
70
+ ref("effect-run", proposal.effectRunId),
71
+ ref("effect-run-result", proposal.effectRunResultId),
72
+ ref("work-item-evidence", proposal.evidenceId),
73
+ ref("work-item-effect-mapping-policy", proposal.policyId),
74
+ ...proposal.sourceRefs ?? []
75
+ ]);
76
+ }
77
+ function workItemAdmissionDecisionRefs(decision, proposal, policy) {
78
+ return uniqueSourceRefs([
79
+ ...proposal === void 0 ? [] : workItemAdmissionProposalRefs(proposal),
80
+ ref("work-item-domain-action-admission-decision", decision.decisionId),
81
+ ref("work-item-domain-action-admission", decision.admissionId),
82
+ ref("work-item-domain-action-proposal", decision.proposalId),
83
+ ...decision.policyId === void 0 ? [] : [ref("work-item-domain-action-admission-policy", decision.policyId)],
84
+ ...policy === void 0 ? [] : [ref("work-item-domain-action-admission-policy", policy.policyId)],
85
+ ...decision.targetProposalId === void 0 ? [] : [ref("work-item-domain-action-proposal", decision.targetProposalId)],
86
+ ...decision.targetAdmissionId === void 0 ? [] : [ref("work-item-domain-action-admission", decision.targetAdmissionId)],
87
+ ...decision.sourceRefs ?? []
88
+ ]);
89
+ }
90
+ function uniqueSourceRefs(sourceRefs2) {
91
+ const seen = /* @__PURE__ */ new Set();
92
+ const unique = [];
93
+ for (const sourceRef of sourceRefs2) {
94
+ const key = sourceRefKey(sourceRef);
95
+ if (seen.has(key)) continue;
96
+ seen.add(key);
97
+ unique.push(sourceRef);
98
+ }
99
+ return unique;
100
+ }
101
+ function sourceRefKey(sourceRef) {
102
+ return `${sourceRef.kind}:${sourceRef.id}:${JSON.stringify(sourceRef.metadata ?? {})}`;
103
+ }
104
+ function projectRuntimeFact(graph, runtime, name, factory, pick) {
105
+ return graph.node(
106
+ [runtime],
78
107
  (ctx) => {
79
- const state = ctx.state.get() ?? {
80
- proposals: /* @__PURE__ */ new Set(),
81
- statusSeq: 0,
82
- auditSeq: 0
83
- };
84
- for (const raw of depBatch(ctx, 0) ?? []) reduceProposalIntake(ctx, state, raw, now());
85
- ctx.state.set(state);
108
+ for (const fact of depBatch(ctx, 0) ?? []) {
109
+ const typed = fact;
110
+ const value = pick(typed);
111
+ if (value !== void 0) ctx.down([["DATA", value]]);
112
+ }
86
113
  },
87
- {
88
- name: `${name}/runtime`,
89
- factory: "workItemDomainActionProposalIntakeProjector",
90
- partial: true,
91
- completeWhenDepsComplete: false,
92
- errorWhenDepsError: false
93
- }
114
+ { name, factory }
94
115
  );
116
+ }
117
+ function forEachPolicyDepBatch(ctx, start, count, fn) {
118
+ for (let i = 0; i < count; i += 1) {
119
+ for (const value of depBatch(ctx, start + i) ?? []) fn(value);
120
+ }
121
+ }
122
+ function dataIssue(code, message, opts = {}) {
95
123
  return {
96
- proposals: project(
97
- graph,
98
- runtime,
99
- `${name}/proposals`,
100
- "workItemDomainActionProposals",
101
- (fact) => fact.kind === "proposal" ? fact.value : void 0
102
- ),
103
- status: project(
104
- graph,
105
- runtime,
106
- `${name}/status`,
107
- "workItemDomainActionStatus",
108
- (fact) => fact.kind === "status" ? fact.value : void 0
109
- ),
110
- issues: project(
111
- graph,
112
- runtime,
113
- `${name}/issues`,
114
- "workItemDomainActionIssues",
115
- (fact) => fact.kind === "issue" ? fact.value : void 0
116
- ),
117
- audit: project(
118
- graph,
119
- runtime,
120
- `${name}/audit`,
121
- "workItemDomainActionAudit",
122
- (fact) => fact.kind === "audit" ? fact.value : void 0
123
- )
124
+ kind: "issue",
125
+ code,
126
+ message,
127
+ severity: opts.severity ?? "error",
128
+ subjectId: opts.subjectId,
129
+ refs: opts.refs?.map((r) => `${r.kind}:${r.id}`),
130
+ details: opts.details
124
131
  };
125
132
  }
126
- function workItemDomainActionApplicationProjector(graph, opts) {
127
- const name = opts.name ?? "workItemDomainActionApplication";
128
- const deps = opts.applyPolicies === void 0 ? [opts.proposals, opts.admissions, opts.workItems] : [opts.proposals, opts.admissions, opts.workItems, opts.applyPolicies];
133
+ function ref(kind, id) {
134
+ return { kind, id };
135
+ }
136
+
137
+ // src/orchestration/work-item-runtime-admission.ts
138
+ function workItemDomainActionAdmissionProjector(graph, opts) {
139
+ const name = opts.name ?? "workItemDomainActionAdmissions";
140
+ const policyDeps = opts.admissionPolicies ?? [];
141
+ const policyStart = 2;
142
+ const now = opts.now ?? Date.now;
129
143
  const runtime = graph.node(
130
- deps,
144
+ [opts.proposals, opts.decisions, ...policyDeps],
131
145
  (ctx) => {
132
- const state = ctx.state.get() ?? {
133
- proposals: /* @__PURE__ */ new Map(),
134
- admissions: /* @__PURE__ */ new Map(),
135
- workItems: /* @__PURE__ */ new Map(),
136
- policies: /* @__PURE__ */ new Map(),
137
- appliedAdmissions: /* @__PURE__ */ new Set(),
138
- emittedFactIds: /* @__PURE__ */ new Set(),
139
- issueKeys: /* @__PURE__ */ new Set(),
140
- statusSeq: 0,
141
- auditSeq: 0
142
- };
146
+ const state = ctx.state.get() ?? emptyWorkItemDomainActionAdmissionState();
143
147
  for (const raw of depBatch(ctx, 0) ?? []) {
144
148
  const proposal = raw;
145
149
  if (state.proposals.has(proposal.proposalId)) {
146
- emitApplicationIssue(
150
+ emitWorkItemAdmissionIssue(
147
151
  ctx,
148
152
  state,
149
- `duplicate-proposal:${proposal.proposalId}`,
150
- "duplicate-suppressed",
151
- `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`,
153
+ `duplicate-admission-proposal:${proposal.proposalId}`,
154
+ "duplicate-work-item-domain-action-proposal",
155
+ `WorkItemDomainActionProposal '${proposal.proposalId}' was already seen by the admission projector`,
152
156
  proposal.workItemId,
153
- proposal.sourceRefs
157
+ workItemAdmissionProposalRefs(proposal)
154
158
  );
155
159
  continue;
156
160
  }
157
161
  state.proposals.set(proposal.proposalId, proposal);
158
162
  }
159
- for (const raw of depBatch(ctx, 2) ?? []) {
160
- const workItem = raw;
161
- state.workItems.set(workItem.workItemId, workItem);
162
- }
163
- if (opts.applyPolicies !== void 0) {
164
- for (const raw of depBatch(ctx, 3) ?? []) {
165
- const policy = raw;
166
- state.policies.set(policy.policyId, policy);
167
- }
168
- }
163
+ forEachPolicyDepBatch(ctx, policyStart, policyDeps.length, (raw) => {
164
+ const policy = raw;
165
+ state.policies.set(policy.policyId, policy);
166
+ });
169
167
  for (const raw of depBatch(ctx, 1) ?? []) {
170
- const admission = raw;
171
- if (state.admissions.has(admission.admissionId)) {
172
- emitApplicationIssue(
168
+ const decision = raw;
169
+ if (state.decisions.has(decision.decisionId)) {
170
+ emitWorkItemAdmissionIssue(
173
171
  ctx,
174
172
  state,
175
- `duplicate-admission:${admission.admissionId}`,
176
- "duplicate-suppressed",
177
- `Duplicate WorkItem domain action admission '${admission.admissionId}' suppressed`,
178
- admission.workItemId,
179
- admissionRefs(admission)
173
+ `duplicate-admission-decision:${decision.decisionId}`,
174
+ "duplicate-work-item-domain-action-admission-decision",
175
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' was already seen by the admission projector`,
176
+ decision.proposalId,
177
+ workItemAdmissionDecisionRefs(decision)
180
178
  );
181
179
  continue;
182
180
  }
183
- state.admissions.set(admission.admissionId, admission);
181
+ state.decisions.set(decision.decisionId, decision);
184
182
  }
185
- for (const admission of state.admissions.values()) applyAdmission(ctx, state, admission);
183
+ evaluateWorkItemDomainActionAdmissions(ctx, state, now());
186
184
  ctx.state.set(state);
187
185
  },
188
- {
189
- name: `${name}/runtime`,
190
- factory: "workItemDomainActionApplicationProjector",
191
- partial: true,
192
- completeWhenDepsComplete: false,
193
- errorWhenDepsError: false
194
- }
186
+ { name: `${name}/runtime`, factory: "workItemDomainActionAdmissionProjector", partial: true }
195
187
  );
196
188
  return {
197
- authoringFacts: project(
198
- graph,
199
- runtime,
200
- `${name}/authoringFacts`,
201
- "workItemDomainActionAuthoringFacts",
202
- (fact) => fact.kind === "authoring-fact" ? fact.value : void 0
203
- ),
204
- applications: project(
189
+ admissions: projectRuntimeFact(
205
190
  graph,
206
191
  runtime,
207
- `${name}/applications`,
208
- "workItemDomainActionApplications",
209
- (fact) => fact.kind === "application" ? fact.value : void 0
192
+ `${name}/admissions`,
193
+ "workItemDomainActionAdmissions",
194
+ (fact) => fact.kind === "admission" ? fact.admission : void 0
210
195
  ),
211
- status: project(
196
+ status: projectRuntimeFact(
212
197
  graph,
213
198
  runtime,
214
199
  `${name}/status`,
215
- "workItemDomainActionStatus",
216
- (fact) => fact.kind === "status" ? fact.value : void 0
200
+ "workItemDomainActionAdmissionStatus",
201
+ (fact) => fact.kind === "status" ? fact.status : void 0
217
202
  ),
218
- issues: project(
203
+ issues: projectRuntimeFact(
219
204
  graph,
220
205
  runtime,
221
206
  `${name}/issues`,
222
- "workItemDomainActionIssues",
223
- (fact) => fact.kind === "issue" ? fact.value : void 0
207
+ "workItemDomainActionAdmissionIssues",
208
+ (fact) => fact.kind === "issue" ? fact.issue : void 0
224
209
  ),
225
- audit: project(
210
+ audit: projectRuntimeFact(
226
211
  graph,
227
212
  runtime,
228
213
  `${name}/audit`,
229
- "workItemDomainActionAudit",
230
- (fact) => fact.kind === "audit" ? fact.value : void 0
214
+ "workItemDomainActionAdmissionAudit",
215
+ (fact) => fact.kind === "audit" ? fact.audit : void 0
216
+ ),
217
+ views: graph.node(
218
+ [runtime],
219
+ (ctx) => {
220
+ const state = ctx.state.get() ?? {
221
+ admissionsByProposal: /* @__PURE__ */ new Map(),
222
+ admissionsByWorkItem: /* @__PURE__ */ new Map(),
223
+ issues: [],
224
+ audit: []
225
+ };
226
+ for (const raw of depBatch(ctx, 0) ?? []) {
227
+ const fact = raw;
228
+ if (fact.kind === "admission") {
229
+ const admission = fact.admission;
230
+ state.admissionsByProposal.set(admission.proposalId, admission);
231
+ const byWorkItem = state.admissionsByWorkItem.get(admission.workItemId) ?? [];
232
+ byWorkItem.push(admission);
233
+ state.admissionsByWorkItem.set(admission.workItemId, byWorkItem);
234
+ } else if (fact.kind === "issue") state.issues.push(fact.issue);
235
+ else if (fact.kind === "audit") state.audit.push(fact.audit);
236
+ }
237
+ ctx.state.set(state);
238
+ ctx.down([["DATA", freezeWorkItemDomainActionAdmissionViews(state)]]);
239
+ },
240
+ { name: `${name}/views`, factory: "workItemDomainActionAdmissionViews" }
231
241
  )
232
242
  };
233
243
  }
234
- function workItemDomainActionCapabilityGuardProjector(graph, opts) {
235
- const name = opts.name ?? "workItemDomainActionCapabilityGuard";
236
- const deps = opts.capabilityAdmissionStatus === void 0 ? [opts.proposals, opts.capabilityAdmissions, opts.guardPolicies] : [
237
- opts.proposals,
238
- opts.capabilityAdmissions,
239
- opts.guardPolicies,
240
- opts.capabilityAdmissionStatus
241
- ];
242
- const statusIndex = opts.capabilityAdmissionStatus === void 0 ? -1 : 3;
243
- const now = opts.now ?? Date.now;
244
- const runtime = graph.node(
245
- deps,
246
- (ctx) => {
247
- const state = ctx.state.get() ?? {
248
- proposals: /* @__PURE__ */ new Map(),
249
- admissionsByCapability: /* @__PURE__ */ new Map(),
250
- issueStatusesByCapability: /* @__PURE__ */ new Map(),
251
- issueStatusesWithoutCapability: [],
252
- policies: /* @__PURE__ */ new Map(),
253
- emittedProposalDecisions: /* @__PURE__ */ new Set(),
254
- emittedStatusKeys: /* @__PURE__ */ new Set(),
255
- issueKeys: /* @__PURE__ */ new Set(),
256
- statusSeq: 0,
257
- auditSeq: 0
258
- };
259
- for (const raw of depBatch(ctx, 2) ?? []) {
260
- const policyIssue = capabilityGuardPolicyIssue(raw);
261
- if (policyIssue !== void 0) {
262
- emitCapabilityGuardIssue(
263
- ctx,
264
- state,
265
- `malformed-policy:${recordString(raw, "policyId") ?? "unknown"}`,
266
- policyIssue
267
- );
268
- continue;
269
- }
270
- const policy = raw;
271
- state.policies.set(policy.policyId, policy);
272
- }
273
- for (const raw of depBatch(ctx, 1) ?? []) {
274
- const admissionIssue = capabilityAdmissionIssue(raw);
275
- if (admissionIssue !== void 0) {
276
- emitCapabilityGuardIssue(
277
- ctx,
278
- state,
279
- `malformed-admission:${recordString(raw, "admissionId") ?? "unknown"}`,
280
- admissionIssue
281
- );
282
- continue;
283
- }
284
- const admission = raw;
285
- const capabilityKey = capabilityBoundaryRefId(admission.capability);
286
- const byCapability = state.admissionsByCapability.get(capabilityKey) ?? [];
287
- if (!byCapability.some((item) => item.admissionId === admission.admissionId)) {
288
- state.admissionsByCapability.set(capabilityKey, [...byCapability, admission]);
289
- }
290
- }
291
- if (statusIndex >= 0) {
292
- for (const raw of depBatch(ctx, statusIndex) ?? []) {
293
- const statusIssue = capabilityAdmissionStatusIssue(raw);
294
- if (statusIssue !== void 0) {
295
- emitCapabilityGuardIssue(
296
- ctx,
297
- state,
298
- `malformed-capability-status:${recordString(raw, "statusId") ?? "unknown"}`,
299
- statusIssue
300
- );
301
- continue;
302
- }
303
- const status = raw;
304
- if (status.state !== "capability-admission-issue") continue;
305
- const capabilityId = status.capabilityId;
306
- const capabilityKind = status.capabilityKind;
307
- if (capabilityId !== void 0 && capabilityKind !== void 0) {
308
- const capabilityKey = capabilityBoundaryRefId({
309
- id: capabilityId,
310
- kind: capabilityKind
311
- });
312
- const statuses = state.issueStatusesByCapability.get(capabilityKey) ?? [];
313
- if (!statuses.some((item) => item.statusId === status.statusId)) {
314
- state.issueStatusesByCapability.set(capabilityKey, [...statuses, status]);
315
- }
316
- } else if (!state.issueStatusesWithoutCapability.some((item) => item.statusId === status.statusId)) {
317
- state.issueStatusesWithoutCapability.push(status);
318
- }
319
- for (const proposal of state.proposals.values())
320
- emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
321
- }
322
- }
323
- for (const raw of depBatch(ctx, 0) ?? []) {
324
- const proposalIssue = capabilityGuardProposalIssue(raw);
325
- if (proposalIssue !== void 0) {
326
- emitCapabilityGuardIssue(
327
- ctx,
328
- state,
329
- `malformed-proposal:${recordString(raw, "proposalId") ?? "unknown"}`,
330
- proposalIssue
331
- );
332
- continue;
333
- }
334
- const proposal = raw;
335
- state.proposals.set(proposal.proposalId, proposal);
336
- }
337
- for (const proposal of state.proposals.values())
338
- evaluateCapabilityGuardProposal(ctx, state, proposal, now());
339
- ctx.state.set(state);
340
- },
341
- {
342
- name: `${name}/runtime`,
343
- factory: "workItemDomainActionCapabilityGuardProjector",
344
- partial: true,
345
- completeWhenDepsComplete: false,
346
- errorWhenDepsError: false
244
+ function evaluateWorkItemDomainActionAdmissions(ctx, state, admittedAtMs) {
245
+ let emitted = true;
246
+ let passes = 0;
247
+ while (emitted && passes <= state.decisions.size) {
248
+ emitted = false;
249
+ passes += 1;
250
+ for (const decision of state.decisions.values()) {
251
+ if (state.terminalDecisionIds.has(decision.decisionId)) continue;
252
+ emitted = evaluateWorkItemDomainActionAdmission(ctx, state, decision, admittedAtMs) || emitted;
347
253
  }
348
- );
349
- return {
350
- decisions: project(
351
- graph,
352
- runtime,
353
- `${name}/decisions`,
354
- "workItemDomainActionCapabilityGuardDecisions",
355
- (fact) => fact.kind === "decision" ? fact.value : void 0
356
- ),
357
- status: project(
358
- graph,
359
- runtime,
360
- `${name}/status`,
361
- "workItemDomainActionCapabilityGuardStatus",
362
- (fact) => fact.kind === "status" ? fact.value : void 0
363
- ),
364
- issues: project(
365
- graph,
366
- runtime,
367
- `${name}/issues`,
368
- "workItemDomainActionCapabilityGuardIssues",
369
- (fact) => fact.kind === "issue" ? fact.value : void 0
370
- ),
371
- audit: project(
372
- graph,
373
- runtime,
374
- `${name}/audit`,
375
- "workItemDomainActionCapabilityGuardAudit",
376
- (fact) => fact.kind === "audit" ? fact.value : void 0
377
- )
378
- };
254
+ }
379
255
  }
380
- function evaluateCapabilityGuardProposal(ctx, state, proposal, decidedAtMs) {
381
- if (state.emittedProposalDecisions.has(proposal.proposalId)) return;
382
- const policy = selectCapabilityGuardPolicy(state, proposal);
256
+ function evaluateWorkItemDomainActionAdmission(ctx, state, decision, admittedAtMs) {
257
+ const proposal = state.proposals.get(decision.proposalId);
258
+ const proposalRefs = workItemAdmissionDecisionRefs(decision, proposal);
259
+ const subjectId = proposal?.workItemId ?? decision.proposalId;
260
+ if (proposal === void 0) {
261
+ emitWorkItemAdmissionIssue(
262
+ ctx,
263
+ state,
264
+ `missing-admission-proposal:${decision.decisionId}:${decision.proposalId}`,
265
+ "missing-work-item-domain-action-admission-proposal",
266
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references missing proposal '${decision.proposalId}'`,
267
+ subjectId,
268
+ proposalRefs
269
+ );
270
+ return false;
271
+ }
272
+ const staleProposalRef = (decision.sourceRefs ?? []).find(
273
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-proposal" && sourceRef.id !== decision.proposalId && sourceRef.id !== decision.targetProposalId
274
+ );
275
+ if (staleProposalRef !== void 0) {
276
+ emitWorkItemAdmissionIssue(
277
+ ctx,
278
+ state,
279
+ `stale-admission-proposal-ref:${decision.decisionId}:${staleProposalRef.id}`,
280
+ "stale-work-item-domain-action-admission-proposal-ref",
281
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries stale proposal ref '${staleProposalRef.id}'`,
282
+ proposal.workItemId,
283
+ proposalRefs
284
+ );
285
+ state.terminalDecisionIds.add(decision.decisionId);
286
+ return false;
287
+ }
288
+ const policy = admissionPolicyForDecision(state, decision);
383
289
  if (typeof policy === "string") {
384
- emitCapabilityGuardIssue(
290
+ emitWorkItemAdmissionIssue(
385
291
  ctx,
386
292
  state,
387
- `policy:${proposal.proposalId}:${policy}`,
388
- dataIssue(policy, capabilityGuardPolicyMessage(policy, proposal), {
389
- subjectId: proposal.workItemId,
390
- refs: [ref("work-item-domain-action-proposal", proposal.proposalId)]
391
- })
293
+ `${policy}:${decision.decisionId}:${decision.policyId ?? "missing"}`,
294
+ policy,
295
+ admissionPolicyIssueMessage(policy, decision),
296
+ proposal.workItemId,
297
+ proposalRefs
392
298
  );
393
- return;
299
+ if (policy === "stale-work-item-domain-action-admission-policy-ref")
300
+ state.terminalDecisionIds.add(decision.decisionId);
301
+ return false;
394
302
  }
395
- for (const status of state.issueStatusesWithoutCapability)
396
- emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
397
- for (const capabilityRef of policy.capabilityRefs) {
398
- for (const status of state.issueStatusesByCapability.get(
399
- capabilityBoundaryRefId(capabilityRef)
400
- ) ?? [])
401
- emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
303
+ if (policy !== void 0) {
304
+ const policyIssue = validateWorkItemAdmissionPolicy(policy, decision, proposal);
305
+ if (policyIssue !== void 0) {
306
+ emitWorkItemAdmissionIssue(
307
+ ctx,
308
+ state,
309
+ `${policyIssue.code}:${decision.decisionId}:${policy.policyId}`,
310
+ policyIssue.code,
311
+ policyIssue.message,
312
+ proposal.workItemId,
313
+ workItemAdmissionDecisionRefs(decision, proposal, policy)
314
+ );
315
+ return false;
316
+ }
402
317
  }
403
- const admissions = policy.capabilityRefs.map(
404
- (capabilityRef) => latestCapabilityAdmission(state, policy, capabilityRef)
405
- );
406
- const missingCapabilityRefs = policy.capabilityRefs.filter(
407
- (_, index) => admissions[index] === void 0
408
- );
409
- const deferredCapabilityRefs = admissions.filter((admission) => admission !== void 0).filter((admission) => admission.state === "deferred").map((admission) => capabilityBoundaryRefId(admission.capability));
410
- if (missingCapabilityRefs.length > 0 || deferredCapabilityRefs.length > 0) {
411
- emitCapabilityGuardStatusOnce(
318
+ const mergeIssue = validateWorkItemAdmissionMergeTarget(state, decision);
319
+ if (mergeIssue !== void 0) {
320
+ emitWorkItemAdmissionIssue(
412
321
  ctx,
413
322
  state,
414
- `deferred:${proposal.proposalId}:${policy.policyId}:missing=${missingCapabilityRefs.map(capabilityBoundaryRefId).join(",")}:deferred=${deferredCapabilityRefs.join(",")}`,
415
- {
416
- state: "deferred",
417
- workItemId: proposal.workItemId,
418
- proposalId: proposal.proposalId,
419
- actionKind: proposal.actionKind,
420
- policyId: policy.policyId,
421
- capabilityRefs: policy.capabilityRefs,
422
- admissionSubjectIds: policy.admissionSubjectIds,
423
- message: "WorkItem domain action is waiting for capability admission",
424
- sourceRefs: capabilityGuardRefs(proposal, policy, admissions),
425
- metadata: {
426
- missingCapabilityRefs: missingCapabilityRefs.map(capabilityBoundaryRefId),
427
- deferredCapabilityRefs
428
- }
429
- }
323
+ `${mergeIssue.code}:${decision.decisionId}:${decision.targetProposalId ?? ""}:${decision.targetAdmissionId ?? ""}`,
324
+ mergeIssue.code,
325
+ mergeIssue.message,
326
+ proposal.workItemId,
327
+ proposalRefs
430
328
  );
431
- return;
329
+ if (mergeIssue.code !== "unknown-work-item-domain-action-admission-merge-target")
330
+ state.terminalDecisionIds.add(decision.decisionId);
331
+ return false;
432
332
  }
433
- const presentAdmissions = admissions.filter(
434
- (admission) => admission !== void 0
435
- );
436
- const blocked = presentAdmissions.filter((admission) => admission.state === "blocked");
437
- const outcome = blocked.length === 0 ? "admit" : "reject";
438
- const decision = {
439
- kind: "work-item-domain-action-admission-decision",
440
- decisionId: `capability-guard:${proposal.proposalId}:decision`,
441
- admissionId: `capability-guard:${proposal.proposalId}:admission`,
333
+ if (state.admissionsById.has(decision.admissionId)) {
334
+ emitWorkItemAdmissionIssue(
335
+ ctx,
336
+ state,
337
+ `duplicate-admission-id:${decision.admissionId}`,
338
+ "duplicate-work-item-domain-action-admission",
339
+ `WorkItemDomainActionAdmission '${decision.admissionId}' was already emitted`,
340
+ proposal.workItemId,
341
+ proposalRefs
342
+ );
343
+ state.terminalDecisionIds.add(decision.decisionId);
344
+ return false;
345
+ }
346
+ if (state.admissionsByProposal.has(decision.proposalId)) {
347
+ emitWorkItemAdmissionIssue(
348
+ ctx,
349
+ state,
350
+ `duplicate-admission-proposal-decision:${decision.proposalId}:${decision.decisionId}`,
351
+ "duplicate-work-item-domain-action-admission-proposal",
352
+ `WorkItemDomainActionProposal '${decision.proposalId}' already has an admission decision`,
353
+ proposal.workItemId,
354
+ proposalRefs
355
+ );
356
+ state.terminalDecisionIds.add(decision.decisionId);
357
+ return false;
358
+ }
359
+ const admissionState = admissionStateForOutcome(decision.outcome);
360
+ if (admissionState === void 0) {
361
+ emitWorkItemAdmissionIssue(
362
+ ctx,
363
+ state,
364
+ `unsupported-admission-outcome:${decision.decisionId}:${String(decision.outcome)}`,
365
+ "unsupported-work-item-domain-action-admission-outcome",
366
+ `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' uses unsupported outcome '${String(decision.outcome)}'`,
367
+ proposal.workItemId,
368
+ proposalRefs
369
+ );
370
+ state.terminalDecisionIds.add(decision.decisionId);
371
+ return false;
372
+ }
373
+ const admission = {
374
+ kind: "work-item-domain-action-admission",
375
+ admissionId: decision.admissionId,
442
376
  proposalId: proposal.proposalId,
443
- outcome,
444
- reason: blocked.length === 0 ? "Capability guard admitted required capabilities" : "Capability guard rejected blocked capabilities",
445
- decidedAtMs,
446
- sourceRefs: capabilityGuardRefs(proposal, policy, presentAdmissions),
377
+ workItemId: proposal.workItemId,
378
+ actionKind: proposal.actionKind,
379
+ state: admissionState,
380
+ decisionId: decision.decisionId,
381
+ policyId: decision.policyId,
382
+ reason: decision.reason,
383
+ targetProposalId: decision.targetProposalId,
384
+ targetAdmissionId: decision.targetAdmissionId,
385
+ sourceRefs: workItemAdmissionDecisionRefs(decision, proposal, policy),
386
+ admittedAtMs: decision.decidedAtMs ?? admittedAtMs,
447
387
  metadata: {
448
- capabilityGuardPolicyId: policy.policyId,
449
- capabilityRefs: policy.capabilityRefs.map(capabilityBoundaryRefId),
450
- admissionSubjectIds: policy.admissionSubjectIds,
451
- blockedCapabilityRefs: blocked.map(
452
- (admission) => capabilityBoundaryRefId(admission.capability)
453
- )
388
+ ...proposal.metadata ?? {},
389
+ ...policy?.metadata ?? {},
390
+ ...decision.metadata ?? {}
454
391
  }
455
392
  };
456
- state.emittedProposalDecisions.add(proposal.proposalId);
457
- emitCapabilityGuard(ctx, "decision", decision);
458
- emitCapabilityGuardStatus(ctx, state, {
459
- state: outcome === "admit" ? "admitted" : "rejected",
393
+ state.admissionsById.set(admission.admissionId, admission);
394
+ state.admissionsByProposal.set(admission.proposalId, admission);
395
+ state.terminalDecisionIds.add(decision.decisionId);
396
+ state.statusSeq += 1;
397
+ state.auditSeq += 1;
398
+ const statusState = workItemAdmissionStatusState(admission.state);
399
+ const status = {
400
+ kind: "work-item-status",
401
+ statusId: `${proposal.workItemId}:${statusState}:${state.statusSeq}`,
460
402
  workItemId: proposal.workItemId,
403
+ state: statusState,
404
+ sourceRefs: admission.sourceRefs,
405
+ effectRunId: proposal.effectRunId,
406
+ evidenceId: proposal.evidenceId,
461
407
  proposalId: proposal.proposalId,
462
- actionKind: proposal.actionKind,
463
- policyId: policy.policyId,
464
- capabilityRefs: policy.capabilityRefs,
465
- admissionSubjectIds: policy.admissionSubjectIds,
466
- admissionIds: presentAdmissions.map((admission) => admission.admissionId),
467
- sourceRefs: decision.sourceRefs,
468
- metadata: { decisionId: decision.decisionId, admissionId: decision.admissionId }
469
- });
408
+ metadata: {
409
+ actionKind: proposal.actionKind,
410
+ admissionId: admission.admissionId,
411
+ decisionId: decision.decisionId,
412
+ policyId: decision.policyId
413
+ }
414
+ };
415
+ const audit = {
416
+ id: `${proposal.workItemId}:${statusState}:${state.auditSeq}`,
417
+ kind: `work-item-domain-action-${admission.state}`,
418
+ subjectId: proposal.workItemId,
419
+ sourceRefs: admission.sourceRefs,
420
+ metadata: {
421
+ actionKind: proposal.actionKind,
422
+ admissionId: admission.admissionId,
423
+ decisionId: decision.decisionId,
424
+ policyId: decision.policyId,
425
+ proposalId: proposal.proposalId
426
+ }
427
+ };
428
+ ctx.down([
429
+ ["DATA", { kind: "admission", admission }],
430
+ ["DATA", { kind: "status", status }],
431
+ ["DATA", { kind: "audit", audit }]
432
+ ]);
433
+ return true;
470
434
  }
471
- function capabilityGuardProposalIssue(proposal) {
472
- if (!isRecord(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)) {
473
- return dataIssue(
474
- "malformed-work-item-domain-action-capability-guard-proposal",
475
- "WorkItem domain action capability guard requires valid proposal DATA facts",
476
- { subjectId: recordString(proposal, "workItemId") }
477
- );
478
- }
479
- return void 0;
435
+ function admissionPolicyForDecision(state, decision) {
436
+ if (decision.policyId === void 0) return void 0;
437
+ const stalePolicyRef = (decision.sourceRefs ?? []).find(
438
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-admission-policy" && sourceRef.id !== decision.policyId
439
+ );
440
+ if (stalePolicyRef !== void 0) return "stale-work-item-domain-action-admission-policy-ref";
441
+ return state.policies.get(decision.policyId) ?? "missing-work-item-domain-action-admission-policy";
480
442
  }
481
- function capabilityGuardPolicyIssue(policy) {
482
- if (!isRecord(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))) {
483
- return dataIssue(
484
- "malformed-work-item-domain-action-capability-guard-policy",
485
- "WorkItem domain action capability guard policy requires policyId, capabilityRefs, and admissionSubjectIds",
486
- {
487
- subjectId: recordString(policy, "policyId")
488
- }
489
- );
443
+ function admissionPolicyIssueMessage(code, decision) {
444
+ if (code === "missing-work-item-domain-action-admission-policy") {
445
+ return `WorkItemDomainActionAdmissionPolicy '${decision.policyId}' was referenced for WorkItem action admission but not present`;
490
446
  }
491
- return void 0;
447
+ return `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries a stale admission policy source ref`;
492
448
  }
493
- function capabilityAdmissionIssue(admission) {
494
- if (!isRecord(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)) {
495
- return dataIssue(
496
- "malformed-capability-admission",
497
- "WorkItem domain action capability guard requires valid CapabilityAdmission DATA facts",
498
- { subjectId: recordString(admission, "subjectId") }
499
- );
449
+ function validateWorkItemAdmissionPolicy(policy, decision, proposal) {
450
+ if (policy.actionKinds !== void 0 && !policy.actionKinds.includes(proposal.actionKind)) {
451
+ return {
452
+ code: "work-item-domain-action-admission-policy-mismatch",
453
+ message: `WorkItemDomainActionAdmissionPolicy '${policy.policyId}' does not apply to actionKind '${proposal.actionKind}'`
454
+ };
455
+ }
456
+ if (policy.allowedOutcomes !== void 0 && !policy.allowedOutcomes.includes(decision.outcome)) {
457
+ return {
458
+ code: "unsupported-work-item-domain-action-admission-outcome",
459
+ message: `WorkItemDomainActionAdmissionPolicy '${policy.policyId}' does not allow outcome '${decision.outcome}'`
460
+ };
500
461
  }
501
462
  return void 0;
502
463
  }
503
- function capabilityAdmissionStatusIssue(status) {
504
- if (!isRecord(status) || status.kind !== "capability-admission-status" || typeof status.statusId !== "string" || status.statusId.length === 0 || !isCapabilityAdmissionStatusState(status.state)) {
505
- return dataIssue(
506
- "malformed-capability-admission-status",
507
- "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
508
- { subjectId: recordString(status, "subjectId") }
509
- );
510
- }
511
- const hasCapabilityId = status.capabilityId !== void 0;
512
- const hasCapabilityKind = status.capabilityKind !== void 0;
513
- 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)) {
514
- return dataIssue(
515
- "malformed-capability-admission-status",
516
- "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
517
- { subjectId: recordString(status, "subjectId") }
518
- );
464
+ function validateWorkItemAdmissionMergeTarget(state, decision) {
465
+ const hasTargetProposal = decision.targetProposalId !== void 0;
466
+ const hasTargetAdmission = decision.targetAdmissionId !== void 0;
467
+ if (decision.outcome !== "merge") {
468
+ if (hasTargetProposal || hasTargetAdmission) {
469
+ return {
470
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
471
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' carries a merge target for non-merge outcome '${decision.outcome}'`
472
+ };
473
+ }
474
+ return void 0;
519
475
  }
520
- return void 0;
521
- }
522
- function isCapabilityAdmissionState(value) {
523
- return value === "allowed" || value === "blocked" || value === "deferred";
524
- }
525
- function isCapabilityAdmissionStatusState(value) {
526
- return value === "capability-admission-allowed" || value === "capability-admission-blocked" || value === "capability-admission-deferred" || value === "capability-admission-issue";
527
- }
528
- function isSourceRefArray(value) {
529
- return Array.isArray(value) && value.every(
530
- (item) => isRecord(item) && typeof item.kind === "string" && typeof item.id === "string"
531
- );
532
- }
533
- function isDataIssueArray(value) {
534
- return Array.isArray(value) && value.every(isDataIssue);
535
- }
536
- function isDataIssue(value) {
537
- return isRecord(value) && value.kind === "issue" && typeof value.code === "string" && value.code.length > 0 && typeof value.message === "string" && value.message.length > 0;
538
- }
539
- function isBoundaryCapabilityRef(value) {
540
- return isRecord(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"));
541
- }
542
- function isBoundaryCapabilityKind(value) {
543
- return value === "auth" || value === "permission" || value === "config" || value === "resource";
544
- }
545
- function selectCapabilityGuardPolicy(state, proposal) {
546
- const explicitId = stringMetadata(proposal.metadata, "capabilityGuardPolicyId") ?? proposal.sourceRefs?.find(
547
- (sourceRef) => sourceRef.kind === "work-item-domain-action-capability-guard-policy"
548
- )?.id;
549
- if (explicitId !== void 0)
550
- return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-capability-guard-policy";
551
- const matching = [...state.policies.values()].filter(
552
- (policy) => policy.actionKinds === void 0 || policy.actionKinds.includes(proposal.actionKind)
553
- );
554
- if (matching.length === 0) return "missing-policy";
555
- if (matching.length > 1) return "policy-mismatch";
556
- return matching[0];
557
- }
558
- function latestCapabilityAdmission(state, policy, capabilityRef) {
559
- const admissions = state.admissionsByCapability.get(capabilityBoundaryRefId(capabilityRef)) ?? [];
560
- for (let index = admissions.length - 1; index >= 0; index -= 1) {
561
- const admission = admissions[index];
562
- if (admission !== void 0 && policy.admissionSubjectIds.includes(admission.subjectId))
563
- return admission;
476
+ if (hasTargetProposal === hasTargetAdmission) {
477
+ return {
478
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
479
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' must reference exactly one merge target`
480
+ };
481
+ }
482
+ if (decision.targetProposalId === decision.proposalId) {
483
+ return {
484
+ code: "ambiguous-work-item-domain-action-admission-merge-target",
485
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' cannot merge a proposal into itself`
486
+ };
487
+ }
488
+ if (decision.targetProposalId !== void 0 && !state.proposals.has(decision.targetProposalId)) {
489
+ return {
490
+ code: "unknown-work-item-domain-action-admission-merge-target",
491
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references unknown target proposal '${decision.targetProposalId}'`
492
+ };
493
+ }
494
+ if (decision.targetAdmissionId !== void 0 && !state.admissionsById.has(decision.targetAdmissionId)) {
495
+ return {
496
+ code: "unknown-work-item-domain-action-admission-merge-target",
497
+ message: `WorkItemDomainActionAdmissionDecision '${decision.decisionId}' references unknown target admission '${decision.targetAdmissionId}'`
498
+ };
564
499
  }
565
500
  return void 0;
566
501
  }
567
- function emitCapabilityStatusIssueForProposal(ctx, state, proposal, status) {
568
- const policy = selectCapabilityGuardPolicy(state, proposal);
569
- if (typeof policy === "string") return;
570
- if (status.subjectId !== void 0 && !policy.admissionSubjectIds.includes(status.subjectId))
571
- return;
572
- const capabilityId = status.capabilityId;
573
- const capabilityKind = status.capabilityKind;
574
- const statusCapabilityKey = capabilityId === void 0 || capabilityKind === void 0 ? void 0 : capabilityBoundaryRefId({ id: capabilityId, kind: capabilityKind });
575
- if (statusCapabilityKey !== void 0 && !policy.capabilityRefs.some(
576
- (capabilityRef) => capabilityBoundaryRefId(capabilityRef) === statusCapabilityKey
577
- ))
578
- return;
579
- const issue = status.issues?.[0] ?? dataIssue(
580
- "capability-admission-status-issue",
581
- "Capability admission status reported an issue",
582
- { subjectId: proposal.workItemId }
583
- );
584
- emitCapabilityGuardIssue(
585
- ctx,
586
- state,
587
- `capability-status:${proposal.proposalId}:${status.statusId}`,
588
- dataIssue(issue.code, issue.message, {
589
- subjectId: proposal.workItemId,
590
- refs: uniqueSourceRefs([
591
- ...capabilityGuardRefs(proposal, policy),
592
- ...status.sourceRefs ?? []
593
- ]),
594
- metadata: {
595
- ...statusCapabilityKey === void 0 ? {} : { capabilityRef: statusCapabilityKey },
596
- capabilityAdmissionStatusId: status.statusId
597
- }
598
- })
599
- );
600
- }
601
- function capabilityGuardPolicyMessage(code, proposal) {
602
- if (code === "missing-policy")
603
- return `WorkItem domain action '${proposal.proposalId}' has no capability guard policy`;
604
- if (code === "unknown-work-item-domain-action-capability-guard-policy")
605
- return `WorkItem domain action '${proposal.proposalId}' references a missing capability guard policy`;
606
- return `WorkItem domain action '${proposal.proposalId}' matches multiple capability guard policies`;
607
- }
608
- function capabilityGuardRefs(proposal, policy, admissions = []) {
609
- return uniqueSourceRefs([
610
- ref("work-item", proposal.workItemId),
611
- ref("work-item-domain-action-proposal", proposal.proposalId),
612
- ref("work-item-domain-action-capability-guard-policy", policy.policyId),
613
- ...admissions.filter((admission) => admission !== void 0).flatMap((admission) => [
614
- ref("capability-admission", admission.admissionId),
615
- ref("capability-admission-proposal", admission.proposalId),
616
- ref("boundary-capability", capabilityBoundaryRefId(admission.capability)),
617
- ...admission.sourceRefs ?? []
618
- ]),
619
- ...proposal.sourceRefs ?? []
620
- ]);
502
+ function admissionStateForOutcome(outcome) {
503
+ if (outcome === "admit") return "admitted";
504
+ if (outcome === "reject") return "rejected";
505
+ if (outcome === "defer") return "deferred";
506
+ if (outcome === "merge") return "merged";
507
+ return void 0;
621
508
  }
622
- function capabilityBoundaryRefId(capability) {
623
- return `${capability.kind}:${capability.id}`;
509
+ function workItemAdmissionStatusState(state) {
510
+ if (state === "admitted") return "domain-action-admitted";
511
+ if (state === "rejected") return "domain-action-rejected";
512
+ if (state === "deferred") return "domain-action-deferred";
513
+ return "domain-action-merged";
624
514
  }
625
- function emitCapabilityGuardStatus(ctx, state, status) {
626
- state.statusSeq += 1;
627
- const statusFact = {
628
- kind: "work-item-domain-action-capability-guard-status",
629
- statusId: `work-item-domain-action-capability-guard-status:${state.statusSeq}`,
630
- ...status
631
- };
632
- emitCapabilityGuard(ctx, "status", statusFact);
633
- state.auditSeq += 1;
634
- emitCapabilityGuard(ctx, "audit", {
635
- id: `work-item-domain-action-capability-guard-status:${state.auditSeq}`,
636
- kind: "work-item-domain-action-capability-guard-status",
515
+
516
+ // src/solutions/work-item/actions-shared.ts
517
+ function auditRecord(kind, seq, status) {
518
+ return {
519
+ id: `${kind}:${seq}`,
520
+ kind,
637
521
  subjectId: status.workItemId,
638
522
  message: status.message,
523
+ issueCode: status.code,
639
524
  sourceRefs: status.sourceRefs,
640
525
  metadata: {
641
- statusId: statusFact.statusId,
526
+ statusId: status.statusId,
642
527
  state: status.state,
643
528
  proposalId: status.proposalId,
644
- policyId: status.policyId,
529
+ admissionId: status.admissionId,
530
+ actionKind: status.actionKind,
645
531
  ...status.metadata ?? {}
646
532
  }
647
- });
648
- }
649
- function emitCapabilityGuardStatusOnce(ctx, state, key, status) {
650
- if (state.emittedStatusKeys.has(key)) return;
651
- state.emittedStatusKeys.add(key);
652
- emitCapabilityGuardStatus(ctx, state, status);
653
- }
654
- function emitCapabilityGuardIssue(ctx, state, key, issue) {
655
- if (state.issueKeys.has(key)) return;
656
- state.issueKeys.add(key);
657
- emitCapabilityGuard(ctx, "issue", issue);
658
- emitCapabilityGuardStatus(ctx, state, {
659
- state: "issue",
660
- workItemId: issue.subjectId,
661
- issues: [issue],
662
- message: issue.message,
663
- metadata: { issueCode: issue.code }
664
- });
533
+ };
665
534
  }
666
- function emitCapabilityGuard(ctx, kind, value) {
667
- ctx.down([["DATA", { kind, value }]]);
535
+ function project(graph, runtime, name, factory, select) {
536
+ return graph.node(
537
+ [runtime],
538
+ (ctx) => {
539
+ for (const raw of depBatch(ctx, 0) ?? []) {
540
+ const selected = select(raw);
541
+ if (selected !== void 0) ctx.down([["DATA", selected]]);
542
+ }
543
+ },
544
+ { name, factory, partial: true, completeWhenDepsComplete: false, errorWhenDepsError: false }
545
+ );
668
546
  }
669
- function reduceProposalIntake(ctx, state, input, proposedAtMs) {
670
- const proposal = normalizeProposal(input, proposedAtMs);
671
- if (typeof proposal === "string") {
672
- const issue = dataIssue("malformed-domain-action-proposal", proposal);
673
- emitIntake(ctx, "issue", issue);
674
- emitIntakeStatus(ctx, state, {
675
- state: "rejected",
676
- code: issue.code,
677
- message: issue.message
678
- });
679
- return;
680
- }
681
- if (state.proposals.has(proposal.proposalId)) {
682
- emitIntakeStatus(ctx, state, {
683
- state: "duplicate",
684
- code: "duplicate-suppressed",
685
- workItemId: proposal.workItemId,
686
- proposalId: proposal.proposalId,
687
- actionKind: proposal.actionKind,
688
- message: `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`
689
- });
690
- return;
691
- }
692
- state.proposals.add(proposal.proposalId);
693
- emitIntake(ctx, "proposal", proposal);
694
- emitIntakeStatus(ctx, state, {
695
- state: "proposed",
696
- workItemId: proposal.workItemId,
697
- proposalId: proposal.proposalId,
698
- actionKind: proposal.actionKind,
699
- sourceRefs: proposal.sourceRefs
700
- });
547
+ function dataIssue2(code, message, opts = {}) {
548
+ return {
549
+ kind: "issue",
550
+ code,
551
+ message,
552
+ severity: "error",
553
+ source: "work-item-actions",
554
+ subjectId: opts.subjectId,
555
+ refs: opts.refs?.map((sourceRef) => `${sourceRef.kind}:${sourceRef.id}`),
556
+ metadata: opts.metadata
557
+ };
701
558
  }
702
- function normalizeProposal(input, proposedAtMs) {
703
- if (!isRecord(input)) return "WorkItemDomainActionProposal intake must be an object";
704
- if (input.kind !== "work-item-domain-action-proposal" && input.kind !== "work-item-domain-action-proposal-intake")
705
- return "WorkItemDomainActionProposal intake has unsupported kind";
706
- if (typeof input.proposalId !== "string" || input.proposalId.trim() === "")
707
- return "WorkItemDomainActionProposal.proposalId is required";
708
- if (typeof input.workItemId !== "string" || input.workItemId.trim() === "")
709
- return "WorkItemDomainActionProposal.workItemId is required";
710
- if (typeof input.actionKind !== "string" || input.actionKind.trim() === "")
711
- return "WorkItemDomainActionProposal.actionKind is required";
712
- if (input.kind === "work-item-domain-action-proposal") {
713
- if (typeof input.effectRunId !== "string")
714
- return "WorkItemDomainActionProposal.effectRunId is required";
715
- if (typeof input.effectRunResultId !== "string")
716
- return "WorkItemDomainActionProposal.effectRunResultId is required";
717
- if (typeof input.evidenceId !== "string")
718
- return "WorkItemDomainActionProposal.evidenceId is required";
719
- if (typeof input.policyId !== "string")
720
- return "WorkItemDomainActionProposal.policyId is required";
721
- return input;
559
+ function uniqueSourceRefs2(sourceRefs2) {
560
+ const seen = /* @__PURE__ */ new Set();
561
+ const out = [];
562
+ for (const sourceRef of sourceRefs2) {
563
+ const key = `${sourceRef.kind}:${sourceRef.id}:${JSON.stringify(sourceRef.metadata ?? {})}`;
564
+ if (seen.has(key)) continue;
565
+ seen.add(key);
566
+ out.push(sourceRef);
722
567
  }
723
- return workItemDomainActionProposal(
724
- input.proposalId,
725
- input.workItemId,
726
- input.actionKind,
727
- {
728
- payload: input.payload,
729
- reason: typeof input.reason === "string" ? input.reason : void 0,
730
- policyId: typeof input.policyId === "string" ? input.policyId : void 0,
731
- effectRunId: typeof input.effectRunId === "string" ? input.effectRunId : void 0,
732
- effectRunResultId: typeof input.effectRunResultId === "string" ? input.effectRunResultId : void 0,
733
- evidenceId: typeof input.evidenceId === "string" ? input.evidenceId : void 0,
734
- proposedAtMs: typeof input.proposedAtMs === "number" ? input.proposedAtMs : proposedAtMs,
735
- sourceRefs: sourceRefs(input.sourceRefs),
736
- metadata: isRecord(input.metadata) ? input.metadata : void 0
737
- }
738
- );
568
+ return out;
739
569
  }
740
- function applyAdmission(ctx, state, admission) {
570
+ function sourceRefs(value) {
571
+ if (!Array.isArray(value)) return void 0;
572
+ return value.filter(
573
+ (item) => isRecord(item) && typeof item.kind === "string" && typeof item.id === "string"
574
+ );
575
+ }
576
+ function numberMetadata(metadata, key) {
577
+ const value = metadata?.[key];
578
+ return typeof value === "number" ? value : void 0;
579
+ }
580
+ function stringMetadata(metadata, key) {
581
+ const value = metadata?.[key];
582
+ return typeof value === "string" ? value : void 0;
583
+ }
584
+ function ref2(kind, id) {
585
+ return { kind, id };
586
+ }
587
+ function recordString(value, key) {
588
+ return isRecord(value) && typeof value[key] === "string" ? value[key] : void 0;
589
+ }
590
+ function isRecord(value) {
591
+ return value !== null && typeof value === "object";
592
+ }
593
+
594
+ // src/solutions/work-item/actions-types.ts
595
+ var patchFieldKeys = /* @__PURE__ */ new Set([
596
+ "summary",
597
+ "detail",
598
+ "detailRefs",
599
+ "kind",
600
+ "priority",
601
+ "tags",
602
+ "owner",
603
+ "assignee",
604
+ "deadlineMs",
605
+ "customFields",
606
+ "sourceRefs",
607
+ "metadata"
608
+ ]);
609
+
610
+ // src/solutions/work-item/actions-application.ts
611
+ function workItemDomainActionApplicationProjector(graph, opts) {
612
+ const name = opts.name ?? "workItemDomainActionApplication";
613
+ const deps = opts.applyPolicies === void 0 ? [opts.proposals, opts.admissions, opts.workItems] : [opts.proposals, opts.admissions, opts.workItems, opts.applyPolicies];
614
+ const runtime = graph.node(
615
+ deps,
616
+ (ctx) => {
617
+ const state = ctx.state.get() ?? {
618
+ proposals: /* @__PURE__ */ new Map(),
619
+ admissions: /* @__PURE__ */ new Map(),
620
+ workItems: /* @__PURE__ */ new Map(),
621
+ policies: /* @__PURE__ */ new Map(),
622
+ appliedAdmissions: /* @__PURE__ */ new Set(),
623
+ emittedFactIds: /* @__PURE__ */ new Set(),
624
+ issueKeys: /* @__PURE__ */ new Set(),
625
+ statusSeq: 0,
626
+ auditSeq: 0
627
+ };
628
+ for (const raw of depBatch(ctx, 0) ?? []) {
629
+ const proposal = raw;
630
+ if (state.proposals.has(proposal.proposalId)) {
631
+ emitApplicationIssue(
632
+ ctx,
633
+ state,
634
+ `duplicate-proposal:${proposal.proposalId}`,
635
+ "duplicate-suppressed",
636
+ `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`,
637
+ proposal.workItemId,
638
+ proposal.sourceRefs
639
+ );
640
+ continue;
641
+ }
642
+ state.proposals.set(proposal.proposalId, proposal);
643
+ }
644
+ for (const raw of depBatch(ctx, 2) ?? []) {
645
+ const workItem = raw;
646
+ state.workItems.set(workItem.workItemId, workItem);
647
+ }
648
+ if (opts.applyPolicies !== void 0) {
649
+ for (const raw of depBatch(ctx, 3) ?? []) {
650
+ const policy = raw;
651
+ state.policies.set(policy.policyId, policy);
652
+ }
653
+ }
654
+ for (const raw of depBatch(ctx, 1) ?? []) {
655
+ const admission = raw;
656
+ if (state.admissions.has(admission.admissionId)) {
657
+ emitApplicationIssue(
658
+ ctx,
659
+ state,
660
+ `duplicate-admission:${admission.admissionId}`,
661
+ "duplicate-suppressed",
662
+ `Duplicate WorkItem domain action admission '${admission.admissionId}' suppressed`,
663
+ admission.workItemId,
664
+ admissionRefs(admission)
665
+ );
666
+ continue;
667
+ }
668
+ state.admissions.set(admission.admissionId, admission);
669
+ }
670
+ for (const admission of state.admissions.values()) applyAdmission(ctx, state, admission);
671
+ ctx.state.set(state);
672
+ },
673
+ {
674
+ name: `${name}/runtime`,
675
+ factory: "workItemDomainActionApplicationProjector",
676
+ partial: true,
677
+ completeWhenDepsComplete: false,
678
+ errorWhenDepsError: false
679
+ }
680
+ );
681
+ return {
682
+ authoringFacts: project(
683
+ graph,
684
+ runtime,
685
+ `${name}/authoringFacts`,
686
+ "workItemDomainActionAuthoringFacts",
687
+ (fact) => fact.kind === "authoring-fact" ? fact.value : void 0
688
+ ),
689
+ applications: project(
690
+ graph,
691
+ runtime,
692
+ `${name}/applications`,
693
+ "workItemDomainActionApplications",
694
+ (fact) => fact.kind === "application" ? fact.value : void 0
695
+ ),
696
+ status: project(
697
+ graph,
698
+ runtime,
699
+ `${name}/status`,
700
+ "workItemDomainActionStatus",
701
+ (fact) => fact.kind === "status" ? fact.value : void 0
702
+ ),
703
+ issues: project(
704
+ graph,
705
+ runtime,
706
+ `${name}/issues`,
707
+ "workItemDomainActionIssues",
708
+ (fact) => fact.kind === "issue" ? fact.value : void 0
709
+ ),
710
+ audit: project(
711
+ graph,
712
+ runtime,
713
+ `${name}/audit`,
714
+ "workItemDomainActionAudit",
715
+ (fact) => fact.kind === "audit" ? fact.value : void 0
716
+ )
717
+ };
718
+ }
719
+ function applyAdmission(ctx, state, admission) {
741
720
  if (state.appliedAdmissions.has(admission.admissionId)) return;
742
721
  const proposal = state.proposals.get(admission.proposalId);
743
722
  if (proposal === void 0) {
@@ -1073,24 +1052,136 @@ function lowerSpawnAction(ctx, state, proposal, admission, policy) {
1073
1052
  message: "Spawn action remains proposal/admission only without explicit create policy"
1074
1053
  };
1075
1054
  }
1076
- emitApplicationIssue(
1077
- ctx,
1078
- state,
1079
- `spawn-create-policy:${admission.admissionId}:${policy.policyId}`,
1080
- "policy-mismatch",
1081
- `Spawn create policy '${policy.policyId}' is incomplete: child creation requires an explicit create/link/idempotency policy surface`,
1082
- proposal.workItemId,
1083
- admissionRefs(admission, proposal, policy),
1084
- {
1085
- requires: ["linkParent", "idempotencyKey", "maxChildrenPerAdmission", "link-fact-vocabulary"]
1086
- }
1087
- );
1088
- return {
1089
- state: "proposal-only",
1090
- facts: [],
1091
- code: "policy-mismatch",
1092
- message: "Spawn action remains proposal/admission only until explicit create/link policy is available"
1055
+ const policyIssue = validateSpawnCreatePolicy(policy, proposal);
1056
+ if (policyIssue !== void 0) {
1057
+ emitApplicationIssue(
1058
+ ctx,
1059
+ state,
1060
+ `spawn-create-policy:${admission.admissionId}:${policy.policyId}:${policyIssue.field}`,
1061
+ "policy-mismatch",
1062
+ policyIssue.message,
1063
+ proposal.workItemId,
1064
+ admissionRefs(admission, proposal, policy),
1065
+ { field: policyIssue.field }
1066
+ );
1067
+ return {
1068
+ state: "policy-rejected",
1069
+ facts: [],
1070
+ code: "policy-mismatch",
1071
+ message: policyIssue.message
1072
+ };
1073
+ }
1074
+ const payload = normalizeSpawnPayload(proposal.payload);
1075
+ if (typeof payload === "string") {
1076
+ emitApplicationIssue(
1077
+ ctx,
1078
+ state,
1079
+ `invalid-spawn-payload:${admission.admissionId}`,
1080
+ "invalid-patch",
1081
+ payload,
1082
+ proposal.workItemId,
1083
+ admissionRefs(admission, proposal, policy)
1084
+ );
1085
+ return { state: "rejected", facts: [], code: "invalid-patch", message: payload };
1086
+ }
1087
+ const childWorkItemId = payload.childWorkItemId ?? payload.workItemId ?? policy.spawn.childWorkItemId ?? (policy.spawn.childIdPrefix === void 0 ? void 0 : `${policy.spawn.childIdPrefix}${admission.admissionId}`);
1088
+ if (childWorkItemId === void 0 || childWorkItemId.trim() === "") {
1089
+ const message = "Spawn create action requires a childWorkItemId or create policy child id";
1090
+ emitApplicationIssue(
1091
+ ctx,
1092
+ state,
1093
+ `missing-spawn-child-id:${admission.admissionId}`,
1094
+ "missing-required-field",
1095
+ message,
1096
+ proposal.workItemId,
1097
+ admissionRefs(admission, proposal, policy)
1098
+ );
1099
+ return { state: "rejected", facts: [], code: "missing-required-field", message };
1100
+ }
1101
+ if (state.workItems.has(childWorkItemId)) {
1102
+ const message = `Spawn create action would duplicate WorkItem '${childWorkItemId}'`;
1103
+ emitApplicationIssue(
1104
+ ctx,
1105
+ state,
1106
+ `duplicate-spawn-child:${admission.admissionId}:${childWorkItemId}`,
1107
+ "duplicate-id",
1108
+ message,
1109
+ childWorkItemId,
1110
+ admissionRefs(admission, proposal, policy)
1111
+ );
1112
+ return { state: "duplicate", facts: [], code: "duplicate-id", message };
1113
+ }
1114
+ if (payload.draft === void 0) {
1115
+ const message = "Spawn create action requires a draft payload";
1116
+ emitApplicationIssue(
1117
+ ctx,
1118
+ state,
1119
+ `missing-spawn-draft:${admission.admissionId}`,
1120
+ "missing-required-field",
1121
+ message,
1122
+ childWorkItemId,
1123
+ admissionRefs(admission, proposal, policy)
1124
+ );
1125
+ return { state: "rejected", facts: [], code: "missing-required-field", message };
1126
+ }
1127
+ const issues = validateWorkItemDraft(payload.draft, { workItemId: childWorkItemId });
1128
+ if (issues.length > 0) {
1129
+ for (const item of issues) emitApplicationFact(ctx, "issue", item);
1130
+ return {
1131
+ state: "rejected",
1132
+ facts: [],
1133
+ code: issues[0]?.code,
1134
+ message: issues[0]?.message
1135
+ };
1136
+ }
1137
+ const metadata = {
1138
+ ...payload.metadata ?? {},
1139
+ actionKind: proposal.actionKind,
1140
+ parentWorkItemId: policy.spawn.linkParent === true ? proposal.workItemId : void 0,
1141
+ sourceProposalId: proposal.proposalId,
1142
+ idempotencyKey: payload.idempotencyKey ?? policy.spawn.idempotencyKey
1143
+ };
1144
+ const created = {
1145
+ kind: "work-item-created",
1146
+ eventId: payload.eventId ?? `${admission.admissionId}:work-item-created:${childWorkItemId}`,
1147
+ workItemId: childWorkItemId,
1148
+ draft: payload.draft,
1149
+ authorId: payload.authorId,
1150
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1151
+ metadata
1093
1152
  };
1153
+ return { state: "applied", facts: [created] };
1154
+ }
1155
+ function validateSpawnCreatePolicy(policy, proposal) {
1156
+ if (policy.spawn?.idempotencyKey === void 0 || policy.spawn.idempotencyKey.trim() === "") {
1157
+ return {
1158
+ field: "idempotencyKey",
1159
+ message: `Spawn create policy '${policy.policyId}' requires an idempotencyKey`
1160
+ };
1161
+ }
1162
+ if (policy.spawn.maxChildrenPerAdmission === void 0 || policy.spawn.maxChildrenPerAdmission < 1) {
1163
+ return {
1164
+ field: "maxChildrenPerAdmission",
1165
+ message: `Spawn create policy '${policy.policyId}' requires maxChildrenPerAdmission >= 1`
1166
+ };
1167
+ }
1168
+ if (proposal.actionKind === "spawn-child" && policy.spawn.linkParent !== true) {
1169
+ return {
1170
+ field: "linkParent",
1171
+ message: `Spawn child create policy '${policy.policyId}' requires linkParent: true`
1172
+ };
1173
+ }
1174
+ return void 0;
1175
+ }
1176
+ function normalizeSpawnPayload(payload) {
1177
+ if (!isRecord(payload)) return "Spawn action payload must be an object";
1178
+ if ("draft" in payload && payload.draft !== void 0 && !isRecord(payload.draft)) {
1179
+ return "Spawn action payload.draft must be an object";
1180
+ }
1181
+ if ("metadata" in payload && payload.metadata !== void 0 && !isRecord(payload.metadata)) {
1182
+ return "Spawn action payload.metadata must be an object";
1183
+ }
1184
+ return payload;
1094
1185
  }
1095
1186
  function normalizePatchPayload(payload) {
1096
1187
  if (!isRecord(payload)) return "Patch action payload must be an object";
@@ -1109,338 +1200,871 @@ function normalizePatchPayload(payload) {
1109
1200
  patch: Object.keys(patch).length === 0 ? void 0 : patch
1110
1201
  };
1111
1202
  }
1112
- return { patch: payload };
1203
+ return { patch: payload };
1204
+ }
1205
+ function inlinePatchFields(payload) {
1206
+ const patch = {};
1207
+ for (const [key, value] of Object.entries(payload)) {
1208
+ if (key === "metadata") continue;
1209
+ if (patchFieldKeys.has(key)) patch[key] = value;
1210
+ }
1211
+ return patch;
1212
+ }
1213
+ function splitDedicatedPatchFields(payload, workItem) {
1214
+ if (!isRecord(payload.patch)) return payload;
1215
+ const patchRecord = payload.patch;
1216
+ const patch = {};
1217
+ for (const [key, value] of Object.entries(patchRecord)) {
1218
+ if (key === "acceptanceCriteria" || key === "verificationPlan" || key === "verificationSteps")
1219
+ continue;
1220
+ patch[key] = value;
1221
+ }
1222
+ const acceptanceCriteria = payload.acceptanceCriteria ?? (Array.isArray(patchRecord.acceptanceCriteria) ? patchRecord.acceptanceCriteria : void 0);
1223
+ const verificationPlan = payload.verificationPlan ?? (isRecord(patchRecord.verificationPlan) ? patchRecord.verificationPlan : Array.isArray(patchRecord.verificationSteps) ? {
1224
+ ...workItem.verificationPlan ?? { planId: "default" },
1225
+ steps: patchRecord.verificationSteps
1226
+ } : void 0);
1227
+ return {
1228
+ ...payload,
1229
+ patch: Object.keys(patch).length === 0 ? void 0 : patch,
1230
+ acceptanceCriteria,
1231
+ verificationPlan
1232
+ };
1233
+ }
1234
+ function invalidPatchKeys(patch, policy) {
1235
+ const allowed = new Set(policy.patch?.allowedFields ?? Array.from(patchFieldKeys));
1236
+ return Object.keys(patch).filter((key) => !patchFieldKeys.has(key) || !allowed.has(key));
1237
+ }
1238
+ function allowsAcceptanceCriteria(policy) {
1239
+ if (policy.patch?.allowAcceptanceCriteria === false) return false;
1240
+ const allowed = policy.patch?.allowedFields;
1241
+ return allowed === void 0 || allowed.includes("acceptanceCriteria") || policy.patch?.allowAcceptanceCriteria === true;
1242
+ }
1243
+ function allowsVerificationPlan(policy) {
1244
+ if (policy.patch?.allowVerificationPlan === false) return false;
1245
+ const allowed = policy.patch?.allowedFields;
1246
+ return allowed === void 0 || allowed.includes("verificationPlan") || allowed.includes("verificationSteps") || policy.patch?.allowVerificationPlan === true;
1247
+ }
1248
+ function selectApplyPolicy(state, proposal, admission) {
1249
+ const explicitId = explicitApplyPolicyId(proposal, admission);
1250
+ if (explicitId !== void 0)
1251
+ return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-apply-policy";
1252
+ const matching = Array.from(state.policies.values()).filter(
1253
+ (policy) => policyAllowsAction(policy, proposal.actionKind)
1254
+ );
1255
+ if (matching.length === 0) return "missing-policy";
1256
+ if (matching.length > 1) return "policy-mismatch";
1257
+ return matching[0];
1258
+ }
1259
+ function explicitApplyPolicyId(proposal, admission) {
1260
+ const metadataPolicy = stringMetadata(admission.metadata, "applyPolicyId") ?? stringMetadata(proposal.metadata, "applyPolicyId");
1261
+ if (metadataPolicy !== void 0) return metadataPolicy;
1262
+ return [...admission.sourceRefs ?? [], ...proposal.sourceRefs ?? []].find(
1263
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-apply-policy"
1264
+ )?.id;
1265
+ }
1266
+ function policyAllowsAction(policy, actionKind) {
1267
+ return policy.actionKinds === void 0 || policy.actionKinds.includes(actionKind);
1268
+ }
1269
+ function admissionProposalMismatch(admission, proposal) {
1270
+ if (admission.workItemId !== proposal.workItemId)
1271
+ return {
1272
+ field: "workItemId",
1273
+ admissionValue: admission.workItemId,
1274
+ proposalValue: proposal.workItemId,
1275
+ message: `Admission '${admission.admissionId}' workItemId does not match proposal '${proposal.proposalId}'`
1276
+ };
1277
+ if (admission.actionKind !== proposal.actionKind)
1278
+ return {
1279
+ field: "actionKind",
1280
+ admissionValue: admission.actionKind,
1281
+ proposalValue: proposal.actionKind,
1282
+ message: `Admission '${admission.admissionId}' actionKind does not match proposal '${proposal.proposalId}'`
1283
+ };
1284
+ return void 0;
1285
+ }
1286
+ function conflictingApplicationMetadata(proposal, admission) {
1287
+ const authoringRevision = conflictingMetadataNumber(proposal, admission, "authoringRevision");
1288
+ if (authoringRevision !== void 0)
1289
+ return {
1290
+ field: "authoringRevision",
1291
+ code: "stale-revision",
1292
+ ...authoringRevision,
1293
+ message: `Admission '${admission.admissionId}' carries conflicting authoringRevision metadata`
1294
+ };
1295
+ const executionInputRevision = conflictingMetadataNumber(
1296
+ proposal,
1297
+ admission,
1298
+ "executionInputRevision"
1299
+ );
1300
+ if (executionInputRevision !== void 0)
1301
+ return {
1302
+ field: "executionInputRevision",
1303
+ code: "stale-execution-input",
1304
+ ...executionInputRevision,
1305
+ message: `Admission '${admission.admissionId}' carries conflicting executionInputRevision metadata`
1306
+ };
1307
+ const applyPolicyId = conflictingMetadataString(proposal, admission, "applyPolicyId");
1308
+ if (applyPolicyId !== void 0)
1309
+ return {
1310
+ field: "applyPolicyId",
1311
+ code: "policy-mismatch",
1312
+ ...applyPolicyId,
1313
+ message: `Admission '${admission.admissionId}' carries conflicting applyPolicyId metadata`
1314
+ };
1315
+ return void 0;
1316
+ }
1317
+ function conflictingMetadataNumber(proposal, admission, key) {
1318
+ const proposalValue = numberMetadata(proposal.metadata, key);
1319
+ const admissionValue = numberMetadata(admission.metadata, key);
1320
+ if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1321
+ return void 0;
1322
+ return { proposalValue, admissionValue };
1323
+ }
1324
+ function conflictingMetadataString(proposal, admission, key) {
1325
+ const proposalValue = stringMetadata(proposal.metadata, key);
1326
+ const admissionValue = stringMetadata(admission.metadata, key);
1327
+ if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1328
+ return void 0;
1329
+ return { proposalValue, admissionValue };
1330
+ }
1331
+ function staleRevision(proposal, admission, workItem) {
1332
+ const authoringRevision = numberMetadata(admission.metadata, "authoringRevision") ?? numberMetadata(proposal.metadata, "authoringRevision");
1333
+ if (authoringRevision !== void 0 && authoringRevision !== workItem.authoringRevision)
1334
+ return {
1335
+ kind: "stale-revision",
1336
+ expected: authoringRevision,
1337
+ current: workItem.authoringRevision
1338
+ };
1339
+ const executionInputRevision = numberMetadata(admission.metadata, "executionInputRevision") ?? numberMetadata(proposal.metadata, "executionInputRevision");
1340
+ if (executionInputRevision !== void 0 && executionInputRevision !== workItem.executionInputRevision)
1341
+ return {
1342
+ kind: "stale-execution-input",
1343
+ expected: executionInputRevision,
1344
+ current: workItem.executionInputRevision
1345
+ };
1346
+ return void 0;
1347
+ }
1348
+ function applyPolicyMessage(code, proposal, admission) {
1349
+ if (code === "missing-policy")
1350
+ return `Admitted action '${admission.admissionId}' requires an explicit apply policy`;
1351
+ if (code === "unknown-work-item-domain-action-apply-policy")
1352
+ return `Admitted action '${admission.admissionId}' references a missing apply policy`;
1353
+ return `Admitted action '${proposal.proposalId}' matches multiple apply policies`;
1354
+ }
1355
+ function emitApplication(ctx, state, admission, proposal, applicationState, facts, opts = {}) {
1356
+ const producedFactIds = facts.map((fact) => fact.eventId);
1357
+ const application = {
1358
+ kind: "work-item-domain-action-application",
1359
+ applicationId: `${admission.admissionId}:application`,
1360
+ admissionId: admission.admissionId,
1361
+ proposalId: proposal.proposalId,
1362
+ workItemId: proposal.workItemId,
1363
+ actionKind: proposal.actionKind,
1364
+ state: applicationState,
1365
+ producedFactIds,
1366
+ reason: admission.reason ?? proposal.reason,
1367
+ sourceRefs: admissionRefs(admission, proposal),
1368
+ metadata: { policyId: opts.policyId, code: opts.code }
1369
+ };
1370
+ emitApplicationFact(ctx, "application", application);
1371
+ emitApplicationStatus(ctx, state, {
1372
+ state: applicationState,
1373
+ code: opts.code,
1374
+ message: opts.message,
1375
+ workItemId: proposal.workItemId,
1376
+ proposalId: proposal.proposalId,
1377
+ admissionId: admission.admissionId,
1378
+ actionKind: proposal.actionKind,
1379
+ sourceRefs: application.sourceRefs,
1380
+ metadata: { producedFactIds, policyId: opts.policyId }
1381
+ });
1382
+ }
1383
+ function emitApplicationIssue(ctx, state, key, code, message, workItemId, sourceRefs2, metadata) {
1384
+ if (state.issueKeys.has(key)) return;
1385
+ state.issueKeys.add(key);
1386
+ const item = dataIssue2(code, message, { subjectId: workItemId, refs: sourceRefs2, metadata });
1387
+ emitApplicationFact(ctx, "issue", item);
1388
+ emitApplicationStatus(ctx, state, {
1389
+ state: code === "missing-policy" ? "missing-policy" : "rejected",
1390
+ code,
1391
+ message,
1392
+ workItemId,
1393
+ sourceRefs: sourceRefs2,
1394
+ metadata
1395
+ });
1396
+ }
1397
+ function emitApplicationStatus(ctx, state, status) {
1398
+ state.statusSeq += 1;
1399
+ const statusFact = {
1400
+ kind: "work-item-domain-action-status",
1401
+ statusId: `work-item-domain-action-application-status:${state.statusSeq}`,
1402
+ ...status
1403
+ };
1404
+ emitApplicationFact(ctx, "status", statusFact);
1405
+ emitApplicationAudit(ctx, state, "work-item-domain-action-application-status", statusFact);
1406
+ }
1407
+ function emitApplicationAudit(ctx, state, kind, status) {
1408
+ state.auditSeq += 1;
1409
+ emitApplicationFact(ctx, "audit", auditRecord(kind, state.auditSeq, status));
1410
+ }
1411
+ function emitApplicationFact(ctx, kind, value) {
1412
+ ctx.down([["DATA", { kind, value }]]);
1413
+ }
1414
+ function firstDuplicateFactId(state, facts) {
1415
+ const pending = /* @__PURE__ */ new Set();
1416
+ for (const fact of facts) {
1417
+ if (state.emittedFactIds.has(fact.eventId) || pending.has(fact.eventId)) return fact.eventId;
1418
+ pending.add(fact.eventId);
1419
+ }
1420
+ return void 0;
1421
+ }
1422
+ function claimFactId(state, factId) {
1423
+ if (state.emittedFactIds.has(factId)) return false;
1424
+ state.emittedFactIds.add(factId);
1425
+ return true;
1426
+ }
1427
+ function admissionRefs(admission, proposal, policy) {
1428
+ return uniqueSourceRefs2([
1429
+ ref2("work-item-domain-action-admission", admission.admissionId),
1430
+ ref2("work-item-domain-action-proposal", admission.proposalId),
1431
+ ...proposal === void 0 ? [] : [
1432
+ ref2("work-item", proposal.workItemId),
1433
+ ref2("work-item-evidence", proposal.evidenceId),
1434
+ ...proposal.sourceRefs ?? []
1435
+ ],
1436
+ ...policy === void 0 ? [] : [ref2("work-item-domain-action-apply-policy", policy.policyId)],
1437
+ ...admission.sourceRefs ?? []
1438
+ ]);
1439
+ }
1440
+ function actionSourceRefs(admission, proposal, policy) {
1441
+ return admissionRefs(admission, proposal, policy);
1442
+ }
1443
+
1444
+ // src/solutions/work-item/actions-builders.ts
1445
+ function workItemDomainActionProposal(proposalId, workItemId, actionKind, opts = {}) {
1446
+ return {
1447
+ kind: "work-item-domain-action-proposal",
1448
+ proposalId,
1449
+ workItemId,
1450
+ actionKind,
1451
+ effectRunId: opts.effectRunId ?? `domain-action:${proposalId}:effect-run`,
1452
+ effectRunResultId: opts.effectRunResultId ?? `domain-action:${proposalId}:effect-run-result`,
1453
+ evidenceId: opts.evidenceId ?? `domain-action:${proposalId}:evidence`,
1454
+ policyId: opts.policyId ?? "domain-action-proposal",
1455
+ payload: opts.payload,
1456
+ reason: opts.reason,
1457
+ sourceRefs: opts.sourceRefs,
1458
+ proposedAtMs: opts.proposedAtMs,
1459
+ metadata: opts.metadata
1460
+ };
1461
+ }
1462
+ function workItemDomainActionProposalIntake(proposalId, workItemId, actionKind, opts = {}) {
1463
+ return {
1464
+ kind: "work-item-domain-action-proposal-intake",
1465
+ proposalId,
1466
+ workItemId,
1467
+ actionKind,
1468
+ payload: opts.payload,
1469
+ reason: opts.reason,
1470
+ policyId: opts.policyId,
1471
+ effectRunId: opts.effectRunId,
1472
+ effectRunResultId: opts.effectRunResultId,
1473
+ evidenceId: opts.evidenceId,
1474
+ proposedAtMs: opts.proposedAtMs,
1475
+ sourceRefs: opts.sourceRefs,
1476
+ metadata: opts.metadata
1477
+ };
1478
+ }
1479
+ function workItemDomainActionApplyPolicy(policyId, opts = {}) {
1480
+ return {
1481
+ kind: "work-item-domain-action-apply-policy",
1482
+ policyId,
1483
+ actionKinds: opts.actionKinds,
1484
+ patch: opts.patch,
1485
+ spawn: opts.spawn,
1486
+ metadata: opts.metadata
1487
+ };
1488
+ }
1489
+
1490
+ // src/solutions/work-item/actions-capability-guard.ts
1491
+ function workItemDomainActionCapabilityGuardProjector(graph, opts) {
1492
+ const name = opts.name ?? "workItemDomainActionCapabilityGuard";
1493
+ const deps = opts.capabilityAdmissionStatus === void 0 ? [opts.proposals, opts.capabilityAdmissions, opts.guardPolicies] : [
1494
+ opts.proposals,
1495
+ opts.capabilityAdmissions,
1496
+ opts.guardPolicies,
1497
+ opts.capabilityAdmissionStatus
1498
+ ];
1499
+ const statusIndex = opts.capabilityAdmissionStatus === void 0 ? -1 : 3;
1500
+ const now = opts.now ?? Date.now;
1501
+ const runtime = graph.node(
1502
+ deps,
1503
+ (ctx) => {
1504
+ const state = ctx.state.get() ?? {
1505
+ proposals: /* @__PURE__ */ new Map(),
1506
+ admissionsByCapability: /* @__PURE__ */ new Map(),
1507
+ issueStatusesByCapability: /* @__PURE__ */ new Map(),
1508
+ issueStatusesWithoutCapability: [],
1509
+ policies: /* @__PURE__ */ new Map(),
1510
+ emittedProposalDecisions: /* @__PURE__ */ new Set(),
1511
+ emittedStatusKeys: /* @__PURE__ */ new Set(),
1512
+ issueKeys: /* @__PURE__ */ new Set(),
1513
+ statusSeq: 0,
1514
+ auditSeq: 0
1515
+ };
1516
+ for (const raw of depBatch(ctx, 2) ?? []) {
1517
+ const policyIssue = capabilityGuardPolicyIssue(raw);
1518
+ if (policyIssue !== void 0) {
1519
+ emitCapabilityGuardIssue(
1520
+ ctx,
1521
+ state,
1522
+ `malformed-policy:${recordString(raw, "policyId") ?? "unknown"}`,
1523
+ policyIssue
1524
+ );
1525
+ continue;
1526
+ }
1527
+ const policy = raw;
1528
+ state.policies.set(policy.policyId, policy);
1529
+ }
1530
+ for (const raw of depBatch(ctx, 1) ?? []) {
1531
+ const admissionIssue = capabilityAdmissionIssue(raw);
1532
+ if (admissionIssue !== void 0) {
1533
+ emitCapabilityGuardIssue(
1534
+ ctx,
1535
+ state,
1536
+ `malformed-admission:${recordString(raw, "admissionId") ?? "unknown"}`,
1537
+ admissionIssue
1538
+ );
1539
+ continue;
1540
+ }
1541
+ const admission = raw;
1542
+ const capabilityKey = capabilityBoundaryRefId(admission.capability);
1543
+ const byCapability = state.admissionsByCapability.get(capabilityKey) ?? [];
1544
+ if (!byCapability.some((item) => item.admissionId === admission.admissionId)) {
1545
+ state.admissionsByCapability.set(capabilityKey, [...byCapability, admission]);
1546
+ }
1547
+ }
1548
+ if (statusIndex >= 0) {
1549
+ for (const raw of depBatch(ctx, statusIndex) ?? []) {
1550
+ const statusIssue = capabilityAdmissionStatusIssue(raw);
1551
+ if (statusIssue !== void 0) {
1552
+ emitCapabilityGuardIssue(
1553
+ ctx,
1554
+ state,
1555
+ `malformed-capability-status:${recordString(raw, "statusId") ?? "unknown"}`,
1556
+ statusIssue
1557
+ );
1558
+ continue;
1559
+ }
1560
+ const status = raw;
1561
+ if (status.state !== "capability-admission-issue") continue;
1562
+ const capabilityId = status.capabilityId;
1563
+ const capabilityKind = status.capabilityKind;
1564
+ if (capabilityId !== void 0 && capabilityKind !== void 0) {
1565
+ const capabilityKey = capabilityBoundaryRefId({
1566
+ id: capabilityId,
1567
+ kind: capabilityKind
1568
+ });
1569
+ const statuses = state.issueStatusesByCapability.get(capabilityKey) ?? [];
1570
+ if (!statuses.some((item) => item.statusId === status.statusId)) {
1571
+ state.issueStatusesByCapability.set(capabilityKey, [...statuses, status]);
1572
+ }
1573
+ } else if (!state.issueStatusesWithoutCapability.some((item) => item.statusId === status.statusId)) {
1574
+ state.issueStatusesWithoutCapability.push(status);
1575
+ }
1576
+ for (const proposal of state.proposals.values())
1577
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1578
+ }
1579
+ }
1580
+ for (const raw of depBatch(ctx, 0) ?? []) {
1581
+ const proposalIssue = capabilityGuardProposalIssue(raw);
1582
+ if (proposalIssue !== void 0) {
1583
+ emitCapabilityGuardIssue(
1584
+ ctx,
1585
+ state,
1586
+ `malformed-proposal:${recordString(raw, "proposalId") ?? "unknown"}`,
1587
+ proposalIssue
1588
+ );
1589
+ continue;
1590
+ }
1591
+ const proposal = raw;
1592
+ state.proposals.set(proposal.proposalId, proposal);
1593
+ }
1594
+ for (const proposal of state.proposals.values())
1595
+ evaluateCapabilityGuardProposal(ctx, state, proposal, now());
1596
+ ctx.state.set(state);
1597
+ },
1598
+ {
1599
+ name: `${name}/runtime`,
1600
+ factory: "workItemDomainActionCapabilityGuardProjector",
1601
+ partial: true,
1602
+ completeWhenDepsComplete: false,
1603
+ errorWhenDepsError: false
1604
+ }
1605
+ );
1606
+ return {
1607
+ decisions: project(
1608
+ graph,
1609
+ runtime,
1610
+ `${name}/decisions`,
1611
+ "workItemDomainActionCapabilityGuardDecisions",
1612
+ (fact) => fact.kind === "decision" ? fact.value : void 0
1613
+ ),
1614
+ status: project(
1615
+ graph,
1616
+ runtime,
1617
+ `${name}/status`,
1618
+ "workItemDomainActionCapabilityGuardStatus",
1619
+ (fact) => fact.kind === "status" ? fact.value : void 0
1620
+ ),
1621
+ issues: project(
1622
+ graph,
1623
+ runtime,
1624
+ `${name}/issues`,
1625
+ "workItemDomainActionCapabilityGuardIssues",
1626
+ (fact) => fact.kind === "issue" ? fact.value : void 0
1627
+ ),
1628
+ audit: project(
1629
+ graph,
1630
+ runtime,
1631
+ `${name}/audit`,
1632
+ "workItemDomainActionCapabilityGuardAudit",
1633
+ (fact) => fact.kind === "audit" ? fact.value : void 0
1634
+ )
1635
+ };
1636
+ }
1637
+ function evaluateCapabilityGuardProposal(ctx, state, proposal, decidedAtMs) {
1638
+ if (state.emittedProposalDecisions.has(proposal.proposalId)) return;
1639
+ const policy = selectCapabilityGuardPolicy(state, proposal);
1640
+ if (typeof policy === "string") {
1641
+ emitCapabilityGuardIssue(
1642
+ ctx,
1643
+ state,
1644
+ `policy:${proposal.proposalId}:${policy}`,
1645
+ dataIssue2(policy, capabilityGuardPolicyMessage(policy, proposal), {
1646
+ subjectId: proposal.workItemId,
1647
+ refs: [ref2("work-item-domain-action-proposal", proposal.proposalId)]
1648
+ })
1649
+ );
1650
+ return;
1651
+ }
1652
+ for (const status of state.issueStatusesWithoutCapability)
1653
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1654
+ for (const capabilityRef of policy.capabilityRefs) {
1655
+ for (const status of state.issueStatusesByCapability.get(
1656
+ capabilityBoundaryRefId(capabilityRef)
1657
+ ) ?? [])
1658
+ emitCapabilityStatusIssueForProposal(ctx, state, proposal, status);
1659
+ }
1660
+ const admissions = policy.capabilityRefs.map(
1661
+ (capabilityRef) => latestCapabilityAdmission(state, policy, capabilityRef)
1662
+ );
1663
+ const missingCapabilityRefs = policy.capabilityRefs.filter(
1664
+ (_, index) => admissions[index] === void 0
1665
+ );
1666
+ const deferredCapabilityRefs = admissions.filter((admission) => admission !== void 0).filter((admission) => admission.state === "deferred").map((admission) => capabilityBoundaryRefId(admission.capability));
1667
+ if (missingCapabilityRefs.length > 0 || deferredCapabilityRefs.length > 0) {
1668
+ emitCapabilityGuardStatusOnce(
1669
+ ctx,
1670
+ state,
1671
+ `deferred:${proposal.proposalId}:${policy.policyId}:missing=${missingCapabilityRefs.map(capabilityBoundaryRefId).join(",")}:deferred=${deferredCapabilityRefs.join(",")}`,
1672
+ {
1673
+ state: "deferred",
1674
+ workItemId: proposal.workItemId,
1675
+ proposalId: proposal.proposalId,
1676
+ actionKind: proposal.actionKind,
1677
+ policyId: policy.policyId,
1678
+ capabilityRefs: policy.capabilityRefs,
1679
+ admissionSubjectIds: policy.admissionSubjectIds,
1680
+ message: "WorkItem domain action is waiting for capability admission",
1681
+ sourceRefs: capabilityGuardRefs(proposal, policy, admissions),
1682
+ metadata: {
1683
+ missingCapabilityRefs: missingCapabilityRefs.map(capabilityBoundaryRefId),
1684
+ deferredCapabilityRefs
1685
+ }
1686
+ }
1687
+ );
1688
+ return;
1689
+ }
1690
+ const presentAdmissions = admissions.filter(
1691
+ (admission) => admission !== void 0
1692
+ );
1693
+ const blocked = presentAdmissions.filter((admission) => admission.state === "blocked");
1694
+ const outcome = blocked.length === 0 ? "admit" : "reject";
1695
+ const decision = {
1696
+ kind: "work-item-domain-action-admission-decision",
1697
+ decisionId: `capability-guard:${proposal.proposalId}:decision`,
1698
+ admissionId: `capability-guard:${proposal.proposalId}:admission`,
1699
+ proposalId: proposal.proposalId,
1700
+ outcome,
1701
+ reason: blocked.length === 0 ? "Capability guard admitted required capabilities" : "Capability guard rejected blocked capabilities",
1702
+ decidedAtMs,
1703
+ sourceRefs: capabilityGuardRefs(proposal, policy, presentAdmissions),
1704
+ metadata: {
1705
+ capabilityGuardPolicyId: policy.policyId,
1706
+ capabilityRefs: policy.capabilityRefs.map(capabilityBoundaryRefId),
1707
+ admissionSubjectIds: policy.admissionSubjectIds,
1708
+ blockedCapabilityRefs: blocked.map(
1709
+ (admission) => capabilityBoundaryRefId(admission.capability)
1710
+ )
1711
+ }
1712
+ };
1713
+ state.emittedProposalDecisions.add(proposal.proposalId);
1714
+ emitCapabilityGuard(ctx, "decision", decision);
1715
+ emitCapabilityGuardStatus(ctx, state, {
1716
+ state: outcome === "admit" ? "admitted" : "rejected",
1717
+ workItemId: proposal.workItemId,
1718
+ proposalId: proposal.proposalId,
1719
+ actionKind: proposal.actionKind,
1720
+ policyId: policy.policyId,
1721
+ capabilityRefs: policy.capabilityRefs,
1722
+ admissionSubjectIds: policy.admissionSubjectIds,
1723
+ admissionIds: presentAdmissions.map((admission) => admission.admissionId),
1724
+ sourceRefs: decision.sourceRefs,
1725
+ metadata: { decisionId: decision.decisionId, admissionId: decision.admissionId }
1726
+ });
1727
+ }
1728
+ function capabilityGuardProposalIssue(proposal) {
1729
+ if (!isRecord(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)) {
1730
+ return dataIssue2(
1731
+ "malformed-work-item-domain-action-capability-guard-proposal",
1732
+ "WorkItem domain action capability guard requires valid proposal DATA facts",
1733
+ { subjectId: recordString(proposal, "workItemId") }
1734
+ );
1735
+ }
1736
+ return void 0;
1737
+ }
1738
+ function capabilityGuardPolicyIssue(policy) {
1739
+ if (!isRecord(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))) {
1740
+ return dataIssue2(
1741
+ "malformed-work-item-domain-action-capability-guard-policy",
1742
+ "WorkItem domain action capability guard policy requires policyId, capabilityRefs, and admissionSubjectIds",
1743
+ {
1744
+ subjectId: recordString(policy, "policyId")
1745
+ }
1746
+ );
1747
+ }
1748
+ return void 0;
1749
+ }
1750
+ function capabilityAdmissionIssue(admission) {
1751
+ if (!isRecord(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)) {
1752
+ return dataIssue2(
1753
+ "malformed-capability-admission",
1754
+ "WorkItem domain action capability guard requires valid CapabilityAdmission DATA facts",
1755
+ { subjectId: recordString(admission, "subjectId") }
1756
+ );
1757
+ }
1758
+ return void 0;
1759
+ }
1760
+ function capabilityAdmissionStatusIssue(status) {
1761
+ if (!isRecord(status) || status.kind !== "capability-admission-status" || typeof status.statusId !== "string" || status.statusId.length === 0 || !isCapabilityAdmissionStatusState(status.state)) {
1762
+ return dataIssue2(
1763
+ "malformed-capability-admission-status",
1764
+ "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
1765
+ { subjectId: recordString(status, "subjectId") }
1766
+ );
1767
+ }
1768
+ const hasCapabilityId = status.capabilityId !== void 0;
1769
+ const hasCapabilityKind = status.capabilityKind !== void 0;
1770
+ 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)) {
1771
+ return dataIssue2(
1772
+ "malformed-capability-admission-status",
1773
+ "WorkItem domain action capability guard requires valid CapabilityAdmissionStatus DATA facts",
1774
+ { subjectId: recordString(status, "subjectId") }
1775
+ );
1776
+ }
1777
+ return void 0;
1113
1778
  }
1114
- function inlinePatchFields(payload) {
1115
- const patch = {};
1116
- for (const [key, value] of Object.entries(payload)) {
1117
- if (key === "metadata") continue;
1118
- if (patchFieldKeys.has(key)) patch[key] = value;
1119
- }
1120
- return patch;
1779
+ function isCapabilityAdmissionState(value) {
1780
+ return value === "allowed" || value === "blocked" || value === "deferred";
1121
1781
  }
1122
- function splitDedicatedPatchFields(payload, workItem) {
1123
- if (!isRecord(payload.patch)) return payload;
1124
- const patchRecord = payload.patch;
1125
- const patch = {};
1126
- for (const [key, value] of Object.entries(patchRecord)) {
1127
- if (key === "acceptanceCriteria" || key === "verificationPlan" || key === "verificationSteps")
1128
- continue;
1129
- patch[key] = value;
1130
- }
1131
- const acceptanceCriteria = payload.acceptanceCriteria ?? (Array.isArray(patchRecord.acceptanceCriteria) ? patchRecord.acceptanceCriteria : void 0);
1132
- const verificationPlan = payload.verificationPlan ?? (isRecord(patchRecord.verificationPlan) ? patchRecord.verificationPlan : Array.isArray(patchRecord.verificationSteps) ? {
1133
- ...workItem.verificationPlan ?? { planId: "default" },
1134
- steps: patchRecord.verificationSteps
1135
- } : void 0);
1136
- return {
1137
- ...payload,
1138
- patch: Object.keys(patch).length === 0 ? void 0 : patch,
1139
- acceptanceCriteria,
1140
- verificationPlan
1141
- };
1782
+ function isCapabilityAdmissionStatusState(value) {
1783
+ return value === "capability-admission-allowed" || value === "capability-admission-blocked" || value === "capability-admission-deferred" || value === "capability-admission-issue";
1142
1784
  }
1143
- function invalidPatchKeys(patch, policy) {
1144
- const allowed = new Set(policy.patch?.allowedFields ?? Array.from(patchFieldKeys));
1145
- return Object.keys(patch).filter((key) => !patchFieldKeys.has(key) || !allowed.has(key));
1785
+ function isSourceRefArray(value) {
1786
+ return Array.isArray(value) && value.every(
1787
+ (item) => isRecord(item) && typeof item.kind === "string" && typeof item.id === "string"
1788
+ );
1146
1789
  }
1147
- function allowsAcceptanceCriteria(policy) {
1148
- if (policy.patch?.allowAcceptanceCriteria === false) return false;
1149
- const allowed = policy.patch?.allowedFields;
1150
- return allowed === void 0 || allowed.includes("acceptanceCriteria") || policy.patch?.allowAcceptanceCriteria === true;
1790
+ function isDataIssueArray(value) {
1791
+ return Array.isArray(value) && value.every(isDataIssue);
1151
1792
  }
1152
- function allowsVerificationPlan(policy) {
1153
- if (policy.patch?.allowVerificationPlan === false) return false;
1154
- const allowed = policy.patch?.allowedFields;
1155
- return allowed === void 0 || allowed.includes("verificationPlan") || allowed.includes("verificationSteps") || policy.patch?.allowVerificationPlan === true;
1793
+ function isDataIssue(value) {
1794
+ return isRecord(value) && value.kind === "issue" && typeof value.code === "string" && value.code.length > 0 && typeof value.message === "string" && value.message.length > 0;
1156
1795
  }
1157
- function selectApplyPolicy(state, proposal, admission) {
1158
- const explicitId = explicitApplyPolicyId(proposal, admission);
1796
+ function isBoundaryCapabilityRef(value) {
1797
+ return isRecord(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"));
1798
+ }
1799
+ function isBoundaryCapabilityKind(value) {
1800
+ return value === "auth" || value === "permission" || value === "config" || value === "resource";
1801
+ }
1802
+ function selectCapabilityGuardPolicy(state, proposal) {
1803
+ const explicitId = stringMetadata(proposal.metadata, "capabilityGuardPolicyId") ?? proposal.sourceRefs?.find(
1804
+ (sourceRef) => sourceRef.kind === "work-item-domain-action-capability-guard-policy"
1805
+ )?.id;
1159
1806
  if (explicitId !== void 0)
1160
- return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-apply-policy";
1161
- const matching = Array.from(state.policies.values()).filter(
1162
- (policy) => policyAllowsAction(policy, proposal.actionKind)
1807
+ return state.policies.get(explicitId) ?? "unknown-work-item-domain-action-capability-guard-policy";
1808
+ const matching = [...state.policies.values()].filter(
1809
+ (policy) => policy.actionKinds === void 0 || policy.actionKinds.includes(proposal.actionKind)
1163
1810
  );
1164
1811
  if (matching.length === 0) return "missing-policy";
1165
1812
  if (matching.length > 1) return "policy-mismatch";
1166
1813
  return matching[0];
1167
1814
  }
1168
- function explicitApplyPolicyId(proposal, admission) {
1169
- const metadataPolicy = stringMetadata(admission.metadata, "applyPolicyId") ?? stringMetadata(proposal.metadata, "applyPolicyId");
1170
- if (metadataPolicy !== void 0) return metadataPolicy;
1171
- return [...admission.sourceRefs ?? [], ...proposal.sourceRefs ?? []].find(
1172
- (sourceRef) => sourceRef.kind === "work-item-domain-action-apply-policy"
1173
- )?.id;
1174
- }
1175
- function policyAllowsAction(policy, actionKind) {
1176
- return policy.actionKinds === void 0 || policy.actionKinds.includes(actionKind);
1177
- }
1178
- function admissionProposalMismatch(admission, proposal) {
1179
- if (admission.workItemId !== proposal.workItemId)
1180
- return {
1181
- field: "workItemId",
1182
- admissionValue: admission.workItemId,
1183
- proposalValue: proposal.workItemId,
1184
- message: `Admission '${admission.admissionId}' workItemId does not match proposal '${proposal.proposalId}'`
1185
- };
1186
- if (admission.actionKind !== proposal.actionKind)
1187
- return {
1188
- field: "actionKind",
1189
- admissionValue: admission.actionKind,
1190
- proposalValue: proposal.actionKind,
1191
- message: `Admission '${admission.admissionId}' actionKind does not match proposal '${proposal.proposalId}'`
1192
- };
1815
+ function latestCapabilityAdmission(state, policy, capabilityRef) {
1816
+ const admissions = state.admissionsByCapability.get(capabilityBoundaryRefId(capabilityRef)) ?? [];
1817
+ for (let index = admissions.length - 1; index >= 0; index -= 1) {
1818
+ const admission = admissions[index];
1819
+ if (admission !== void 0 && policy.admissionSubjectIds.includes(admission.subjectId))
1820
+ return admission;
1821
+ }
1193
1822
  return void 0;
1194
1823
  }
1195
- function conflictingApplicationMetadata(proposal, admission) {
1196
- const authoringRevision = conflictingMetadataNumber(proposal, admission, "authoringRevision");
1197
- if (authoringRevision !== void 0)
1198
- return {
1199
- field: "authoringRevision",
1200
- code: "stale-revision",
1201
- ...authoringRevision,
1202
- message: `Admission '${admission.admissionId}' carries conflicting authoringRevision metadata`
1203
- };
1204
- const executionInputRevision = conflictingMetadataNumber(
1205
- proposal,
1206
- admission,
1207
- "executionInputRevision"
1824
+ function emitCapabilityStatusIssueForProposal(ctx, state, proposal, status) {
1825
+ const policy = selectCapabilityGuardPolicy(state, proposal);
1826
+ if (typeof policy === "string") return;
1827
+ if (status.subjectId !== void 0 && !policy.admissionSubjectIds.includes(status.subjectId))
1828
+ return;
1829
+ const capabilityId = status.capabilityId;
1830
+ const capabilityKind = status.capabilityKind;
1831
+ const statusCapabilityKey = capabilityId === void 0 || capabilityKind === void 0 ? void 0 : capabilityBoundaryRefId({ id: capabilityId, kind: capabilityKind });
1832
+ if (statusCapabilityKey !== void 0 && !policy.capabilityRefs.some(
1833
+ (capabilityRef) => capabilityBoundaryRefId(capabilityRef) === statusCapabilityKey
1834
+ ))
1835
+ return;
1836
+ const issue = status.issues?.[0] ?? dataIssue2(
1837
+ "capability-admission-status-issue",
1838
+ "Capability admission status reported an issue",
1839
+ { subjectId: proposal.workItemId }
1840
+ );
1841
+ emitCapabilityGuardIssue(
1842
+ ctx,
1843
+ state,
1844
+ `capability-status:${proposal.proposalId}:${status.statusId}`,
1845
+ dataIssue2(issue.code, issue.message, {
1846
+ subjectId: proposal.workItemId,
1847
+ refs: uniqueSourceRefs2([
1848
+ ...capabilityGuardRefs(proposal, policy),
1849
+ ...status.sourceRefs ?? []
1850
+ ]),
1851
+ metadata: {
1852
+ ...statusCapabilityKey === void 0 ? {} : { capabilityRef: statusCapabilityKey },
1853
+ capabilityAdmissionStatusId: status.statusId
1854
+ }
1855
+ })
1208
1856
  );
1209
- if (executionInputRevision !== void 0)
1210
- return {
1211
- field: "executionInputRevision",
1212
- code: "stale-execution-input",
1213
- ...executionInputRevision,
1214
- message: `Admission '${admission.admissionId}' carries conflicting executionInputRevision metadata`
1215
- };
1216
- const applyPolicyId = conflictingMetadataString(proposal, admission, "applyPolicyId");
1217
- if (applyPolicyId !== void 0)
1218
- return {
1219
- field: "applyPolicyId",
1220
- code: "policy-mismatch",
1221
- ...applyPolicyId,
1222
- message: `Admission '${admission.admissionId}' carries conflicting applyPolicyId metadata`
1223
- };
1224
- return void 0;
1225
- }
1226
- function conflictingMetadataNumber(proposal, admission, key) {
1227
- const proposalValue = numberMetadata(proposal.metadata, key);
1228
- const admissionValue = numberMetadata(admission.metadata, key);
1229
- if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1230
- return void 0;
1231
- return { proposalValue, admissionValue };
1232
- }
1233
- function conflictingMetadataString(proposal, admission, key) {
1234
- const proposalValue = stringMetadata(proposal.metadata, key);
1235
- const admissionValue = stringMetadata(admission.metadata, key);
1236
- if (proposalValue === void 0 || admissionValue === void 0 || proposalValue === admissionValue)
1237
- return void 0;
1238
- return { proposalValue, admissionValue };
1239
- }
1240
- function staleRevision(proposal, admission, workItem) {
1241
- const authoringRevision = numberMetadata(admission.metadata, "authoringRevision") ?? numberMetadata(proposal.metadata, "authoringRevision");
1242
- if (authoringRevision !== void 0 && authoringRevision !== workItem.authoringRevision)
1243
- return {
1244
- kind: "stale-revision",
1245
- expected: authoringRevision,
1246
- current: workItem.authoringRevision
1247
- };
1248
- const executionInputRevision = numberMetadata(admission.metadata, "executionInputRevision") ?? numberMetadata(proposal.metadata, "executionInputRevision");
1249
- if (executionInputRevision !== void 0 && executionInputRevision !== workItem.executionInputRevision)
1250
- return {
1251
- kind: "stale-execution-input",
1252
- expected: executionInputRevision,
1253
- current: workItem.executionInputRevision
1254
- };
1255
- return void 0;
1256
1857
  }
1257
- function applyPolicyMessage(code, proposal, admission) {
1858
+ function capabilityGuardPolicyMessage(code, proposal) {
1258
1859
  if (code === "missing-policy")
1259
- return `Admitted action '${admission.admissionId}' requires an explicit apply policy`;
1260
- if (code === "unknown-work-item-domain-action-apply-policy")
1261
- return `Admitted action '${admission.admissionId}' references a missing apply policy`;
1262
- return `Admitted action '${proposal.proposalId}' matches multiple apply policies`;
1263
- }
1264
- function emitApplication(ctx, state, admission, proposal, applicationState, facts, opts = {}) {
1265
- const producedFactIds = facts.map((fact) => fact.eventId);
1266
- const application = {
1267
- kind: "work-item-domain-action-application",
1268
- applicationId: `${admission.admissionId}:application`,
1269
- admissionId: admission.admissionId,
1270
- proposalId: proposal.proposalId,
1271
- workItemId: proposal.workItemId,
1272
- actionKind: proposal.actionKind,
1273
- state: applicationState,
1274
- producedFactIds,
1275
- reason: admission.reason ?? proposal.reason,
1276
- sourceRefs: admissionRefs(admission, proposal),
1277
- metadata: { policyId: opts.policyId, code: opts.code }
1278
- };
1279
- emitApplicationFact(ctx, "application", application);
1280
- emitApplicationStatus(ctx, state, {
1281
- state: applicationState,
1282
- code: opts.code,
1283
- message: opts.message,
1284
- workItemId: proposal.workItemId,
1285
- proposalId: proposal.proposalId,
1286
- admissionId: admission.admissionId,
1287
- actionKind: proposal.actionKind,
1288
- sourceRefs: application.sourceRefs,
1289
- metadata: { producedFactIds, policyId: opts.policyId }
1290
- });
1291
- }
1292
- function emitApplicationIssue(ctx, state, key, code, message, workItemId, sourceRefs2, metadata) {
1293
- if (state.issueKeys.has(key)) return;
1294
- state.issueKeys.add(key);
1295
- const item = dataIssue(code, message, { subjectId: workItemId, refs: sourceRefs2, metadata });
1296
- emitApplicationFact(ctx, "issue", item);
1297
- emitApplicationStatus(ctx, state, {
1298
- state: code === "missing-policy" ? "missing-policy" : "rejected",
1299
- code,
1300
- message,
1301
- workItemId,
1302
- sourceRefs: sourceRefs2,
1303
- metadata
1304
- });
1860
+ return `WorkItem domain action '${proposal.proposalId}' has no capability guard policy`;
1861
+ if (code === "unknown-work-item-domain-action-capability-guard-policy")
1862
+ return `WorkItem domain action '${proposal.proposalId}' references a missing capability guard policy`;
1863
+ return `WorkItem domain action '${proposal.proposalId}' matches multiple capability guard policies`;
1305
1864
  }
1306
- function emitIntakeStatus(ctx, state, status) {
1307
- state.statusSeq += 1;
1308
- const statusFact = {
1309
- kind: "work-item-domain-action-status",
1310
- statusId: `work-item-domain-action-intake-status:${state.statusSeq}`,
1311
- ...status
1312
- };
1313
- emitIntake(ctx, "status", statusFact);
1314
- emitIntakeAudit(ctx, state, "work-item-domain-action-intake-status", statusFact);
1865
+ function capabilityGuardRefs(proposal, policy, admissions = []) {
1866
+ return uniqueSourceRefs2([
1867
+ ref2("work-item", proposal.workItemId),
1868
+ ref2("work-item-domain-action-proposal", proposal.proposalId),
1869
+ ref2("work-item-domain-action-capability-guard-policy", policy.policyId),
1870
+ ...admissions.filter((admission) => admission !== void 0).flatMap((admission) => [
1871
+ ref2("capability-admission", admission.admissionId),
1872
+ ref2("capability-admission-proposal", admission.proposalId),
1873
+ ref2("boundary-capability", capabilityBoundaryRefId(admission.capability)),
1874
+ ...admission.sourceRefs ?? []
1875
+ ]),
1876
+ ...proposal.sourceRefs ?? []
1877
+ ]);
1315
1878
  }
1316
- function emitApplicationStatus(ctx, state, status) {
1879
+ function capabilityBoundaryRefId(capability) {
1880
+ return `${capability.kind}:${capability.id}`;
1881
+ }
1882
+ function emitCapabilityGuardStatus(ctx, state, status) {
1317
1883
  state.statusSeq += 1;
1318
1884
  const statusFact = {
1319
- kind: "work-item-domain-action-status",
1320
- statusId: `work-item-domain-action-application-status:${state.statusSeq}`,
1885
+ kind: "work-item-domain-action-capability-guard-status",
1886
+ statusId: `work-item-domain-action-capability-guard-status:${state.statusSeq}`,
1321
1887
  ...status
1322
1888
  };
1323
- emitApplicationFact(ctx, "status", statusFact);
1324
- emitApplicationAudit(ctx, state, "work-item-domain-action-application-status", statusFact);
1325
- }
1326
- function emitIntakeAudit(ctx, state, kind, status) {
1327
- state.auditSeq += 1;
1328
- emitIntake(ctx, "audit", auditRecord(kind, state.auditSeq, status));
1329
- }
1330
- function emitApplicationAudit(ctx, state, kind, status) {
1889
+ emitCapabilityGuard(ctx, "status", statusFact);
1331
1890
  state.auditSeq += 1;
1332
- emitApplicationFact(ctx, "audit", auditRecord(kind, state.auditSeq, status));
1333
- }
1334
- function auditRecord(kind, seq, status) {
1335
- return {
1336
- id: `${kind}:${seq}`,
1337
- kind,
1891
+ emitCapabilityGuard(ctx, "audit", {
1892
+ id: `work-item-domain-action-capability-guard-status:${state.auditSeq}`,
1893
+ kind: "work-item-domain-action-capability-guard-status",
1338
1894
  subjectId: status.workItemId,
1339
1895
  message: status.message,
1340
- issueCode: status.code,
1341
1896
  sourceRefs: status.sourceRefs,
1342
1897
  metadata: {
1343
- statusId: status.statusId,
1898
+ statusId: statusFact.statusId,
1344
1899
  state: status.state,
1345
1900
  proposalId: status.proposalId,
1346
- admissionId: status.admissionId,
1347
- actionKind: status.actionKind,
1901
+ policyId: status.policyId,
1348
1902
  ...status.metadata ?? {}
1349
1903
  }
1350
- };
1904
+ });
1351
1905
  }
1352
- function emitIntake(ctx, kind, value) {
1353
- ctx.down([["DATA", { kind, value }]]);
1906
+ function emitCapabilityGuardStatusOnce(ctx, state, key, status) {
1907
+ if (state.emittedStatusKeys.has(key)) return;
1908
+ state.emittedStatusKeys.add(key);
1909
+ emitCapabilityGuardStatus(ctx, state, status);
1354
1910
  }
1355
- function emitApplicationFact(ctx, kind, value) {
1911
+ function emitCapabilityGuardIssue(ctx, state, key, issue) {
1912
+ if (state.issueKeys.has(key)) return;
1913
+ state.issueKeys.add(key);
1914
+ emitCapabilityGuard(ctx, "issue", issue);
1915
+ emitCapabilityGuardStatus(ctx, state, {
1916
+ state: "issue",
1917
+ workItemId: issue.subjectId,
1918
+ issues: [issue],
1919
+ message: issue.message,
1920
+ metadata: { issueCode: issue.code }
1921
+ });
1922
+ }
1923
+ function emitCapabilityGuard(ctx, kind, value) {
1356
1924
  ctx.down([["DATA", { kind, value }]]);
1357
1925
  }
1358
- function project(graph, runtime, name, factory, select) {
1359
- return graph.node(
1360
- [runtime],
1926
+
1927
+ // src/solutions/work-item/actions-intake.ts
1928
+ function workItemDomainActionProposalIntakeProjector(graph, opts) {
1929
+ const name = opts.name ?? "workItemDomainActionIntake";
1930
+ const now = opts.now ?? Date.now;
1931
+ const runtime = graph.node(
1932
+ [opts.proposals],
1361
1933
  (ctx) => {
1362
- for (const raw of depBatch(ctx, 0) ?? []) {
1363
- const selected = select(raw);
1364
- if (selected !== void 0) ctx.down([["DATA", selected]]);
1365
- }
1934
+ const state = ctx.state.get() ?? {
1935
+ proposals: /* @__PURE__ */ new Set(),
1936
+ statusSeq: 0,
1937
+ auditSeq: 0
1938
+ };
1939
+ for (const raw of depBatch(ctx, 0) ?? []) reduceProposalIntake(ctx, state, raw, now());
1940
+ ctx.state.set(state);
1366
1941
  },
1367
- { name, factory, partial: true, completeWhenDepsComplete: false, errorWhenDepsError: false }
1942
+ {
1943
+ name: `${name}/runtime`,
1944
+ factory: "workItemDomainActionProposalIntakeProjector",
1945
+ partial: true,
1946
+ completeWhenDepsComplete: false,
1947
+ errorWhenDepsError: false
1948
+ }
1368
1949
  );
1369
- }
1370
- function firstDuplicateFactId(state, facts) {
1371
- const pending = /* @__PURE__ */ new Set();
1372
- for (const fact of facts) {
1373
- if (state.emittedFactIds.has(fact.eventId) || pending.has(fact.eventId)) return fact.eventId;
1374
- pending.add(fact.eventId);
1375
- }
1376
- return void 0;
1377
- }
1378
- function claimFactId(state, factId) {
1379
- if (state.emittedFactIds.has(factId)) return false;
1380
- state.emittedFactIds.add(factId);
1381
- return true;
1382
- }
1383
- function admissionRefs(admission, proposal, policy) {
1384
- return uniqueSourceRefs([
1385
- ref("work-item-domain-action-admission", admission.admissionId),
1386
- ref("work-item-domain-action-proposal", admission.proposalId),
1387
- ...proposal === void 0 ? [] : [
1388
- ref("work-item", proposal.workItemId),
1389
- ref("work-item-evidence", proposal.evidenceId),
1390
- ...proposal.sourceRefs ?? []
1391
- ],
1392
- ...policy === void 0 ? [] : [ref("work-item-domain-action-apply-policy", policy.policyId)],
1393
- ...admission.sourceRefs ?? []
1394
- ]);
1395
- }
1396
- function actionSourceRefs(admission, proposal, policy) {
1397
- return admissionRefs(admission, proposal, policy);
1398
- }
1399
- function dataIssue(code, message, opts = {}) {
1400
1950
  return {
1401
- kind: "issue",
1402
- code,
1403
- message,
1404
- severity: "error",
1405
- source: "work-item-actions",
1406
- subjectId: opts.subjectId,
1407
- refs: opts.refs?.map((sourceRef) => `${sourceRef.kind}:${sourceRef.id}`),
1408
- metadata: opts.metadata
1951
+ proposals: project(
1952
+ graph,
1953
+ runtime,
1954
+ `${name}/proposals`,
1955
+ "workItemDomainActionProposals",
1956
+ (fact) => fact.kind === "proposal" ? fact.value : void 0
1957
+ ),
1958
+ status: project(
1959
+ graph,
1960
+ runtime,
1961
+ `${name}/status`,
1962
+ "workItemDomainActionStatus",
1963
+ (fact) => fact.kind === "status" ? fact.value : void 0
1964
+ ),
1965
+ issues: project(
1966
+ graph,
1967
+ runtime,
1968
+ `${name}/issues`,
1969
+ "workItemDomainActionIssues",
1970
+ (fact) => fact.kind === "issue" ? fact.value : void 0
1971
+ ),
1972
+ audit: project(
1973
+ graph,
1974
+ runtime,
1975
+ `${name}/audit`,
1976
+ "workItemDomainActionAudit",
1977
+ (fact) => fact.kind === "audit" ? fact.value : void 0
1978
+ )
1409
1979
  };
1410
1980
  }
1411
- function uniqueSourceRefs(sourceRefs2) {
1412
- const seen = /* @__PURE__ */ new Set();
1413
- const out = [];
1414
- for (const sourceRef of sourceRefs2) {
1415
- const key = `${sourceRef.kind}:${sourceRef.id}:${JSON.stringify(sourceRef.metadata ?? {})}`;
1416
- if (seen.has(key)) continue;
1417
- seen.add(key);
1418
- out.push(sourceRef);
1981
+ function reduceProposalIntake(ctx, state, input, proposedAtMs) {
1982
+ const proposal = normalizeProposal(input, proposedAtMs);
1983
+ if (typeof proposal === "string") {
1984
+ const issue = dataIssue2("malformed-domain-action-proposal", proposal);
1985
+ emitIntake(ctx, "issue", issue);
1986
+ emitIntakeStatus(ctx, state, {
1987
+ state: "rejected",
1988
+ code: issue.code,
1989
+ message: issue.message
1990
+ });
1991
+ return;
1419
1992
  }
1420
- return out;
1993
+ if (state.proposals.has(proposal.proposalId)) {
1994
+ emitIntakeStatus(ctx, state, {
1995
+ state: "duplicate",
1996
+ code: "duplicate-suppressed",
1997
+ workItemId: proposal.workItemId,
1998
+ proposalId: proposal.proposalId,
1999
+ actionKind: proposal.actionKind,
2000
+ message: `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`
2001
+ });
2002
+ return;
2003
+ }
2004
+ state.proposals.add(proposal.proposalId);
2005
+ emitIntake(ctx, "proposal", proposal);
2006
+ emitIntakeStatus(ctx, state, {
2007
+ state: "proposed",
2008
+ workItemId: proposal.workItemId,
2009
+ proposalId: proposal.proposalId,
2010
+ actionKind: proposal.actionKind,
2011
+ sourceRefs: proposal.sourceRefs
2012
+ });
1421
2013
  }
1422
- function sourceRefs(value) {
1423
- if (!Array.isArray(value)) return void 0;
1424
- return value.filter(
1425
- (item) => isRecord(item) && typeof item.kind === "string" && typeof item.id === "string"
2014
+ function normalizeProposal(input, proposedAtMs) {
2015
+ if (!isRecord(input)) return "WorkItemDomainActionProposal intake must be an object";
2016
+ if (input.kind !== "work-item-domain-action-proposal" && input.kind !== "work-item-domain-action-proposal-intake")
2017
+ return "WorkItemDomainActionProposal intake has unsupported kind";
2018
+ if (typeof input.proposalId !== "string" || input.proposalId.trim() === "")
2019
+ return "WorkItemDomainActionProposal.proposalId is required";
2020
+ if (typeof input.workItemId !== "string" || input.workItemId.trim() === "")
2021
+ return "WorkItemDomainActionProposal.workItemId is required";
2022
+ if (typeof input.actionKind !== "string" || input.actionKind.trim() === "")
2023
+ return "WorkItemDomainActionProposal.actionKind is required";
2024
+ if (input.kind === "work-item-domain-action-proposal") {
2025
+ if (typeof input.effectRunId !== "string")
2026
+ return "WorkItemDomainActionProposal.effectRunId is required";
2027
+ if (typeof input.effectRunResultId !== "string")
2028
+ return "WorkItemDomainActionProposal.effectRunResultId is required";
2029
+ if (typeof input.evidenceId !== "string")
2030
+ return "WorkItemDomainActionProposal.evidenceId is required";
2031
+ if (typeof input.policyId !== "string")
2032
+ return "WorkItemDomainActionProposal.policyId is required";
2033
+ return input;
2034
+ }
2035
+ return workItemDomainActionProposal(
2036
+ input.proposalId,
2037
+ input.workItemId,
2038
+ input.actionKind,
2039
+ {
2040
+ payload: input.payload,
2041
+ reason: typeof input.reason === "string" ? input.reason : void 0,
2042
+ policyId: typeof input.policyId === "string" ? input.policyId : void 0,
2043
+ effectRunId: typeof input.effectRunId === "string" ? input.effectRunId : void 0,
2044
+ effectRunResultId: typeof input.effectRunResultId === "string" ? input.effectRunResultId : void 0,
2045
+ evidenceId: typeof input.evidenceId === "string" ? input.evidenceId : void 0,
2046
+ proposedAtMs: typeof input.proposedAtMs === "number" ? input.proposedAtMs : proposedAtMs,
2047
+ sourceRefs: sourceRefs(input.sourceRefs),
2048
+ metadata: isRecord(input.metadata) ? input.metadata : void 0
2049
+ }
1426
2050
  );
1427
2051
  }
1428
- function numberMetadata(metadata, key) {
1429
- const value = metadata?.[key];
1430
- return typeof value === "number" ? value : void 0;
1431
- }
1432
- function stringMetadata(metadata, key) {
1433
- const value = metadata?.[key];
1434
- return typeof value === "string" ? value : void 0;
1435
- }
1436
- function ref(kind, id) {
1437
- return { kind, id };
2052
+ function emitIntakeStatus(ctx, state, status) {
2053
+ state.statusSeq += 1;
2054
+ const statusFact = {
2055
+ kind: "work-item-domain-action-status",
2056
+ statusId: `work-item-domain-action-intake-status:${state.statusSeq}`,
2057
+ ...status
2058
+ };
2059
+ emitIntake(ctx, "status", statusFact);
2060
+ emitIntakeAudit(ctx, state, "work-item-domain-action-intake-status", statusFact);
1438
2061
  }
1439
- function recordString(value, key) {
1440
- return isRecord(value) && typeof value[key] === "string" ? value[key] : void 0;
2062
+ function emitIntakeAudit(ctx, state, kind, status) {
2063
+ state.auditSeq += 1;
2064
+ emitIntake(ctx, "audit", auditRecord(kind, state.auditSeq, status));
1441
2065
  }
1442
- function isRecord(value) {
1443
- return value !== null && typeof value === "object";
2066
+ function emitIntake(ctx, kind, value) {
2067
+ ctx.down([["DATA", { kind, value }]]);
1444
2068
  }
1445
2069
  export {
1446
2070
  workItemDomainActionAdmissionProjector,