@graphrefly/ts 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/README.md +135 -0
  2. package/dist/adapters/index.cjs +105 -66
  3. package/dist/adapters/index.cjs.map +1 -1
  4. package/dist/adapters/index.d.cts +11 -136
  5. package/dist/adapters/index.d.ts +11 -136
  6. package/dist/adapters/index.js +27 -225
  7. package/dist/adapters/index.js.map +1 -1
  8. package/dist/adapters/observe-storage.d.cts +4 -4
  9. package/dist/adapters/observe-storage.d.ts +4 -4
  10. package/dist/adapters/observe-storage.js +1 -0
  11. package/dist/adapters/observe-storage.js.map +1 -1
  12. package/dist/adapters/react.cjs +166 -0
  13. package/dist/adapters/react.cjs.map +1 -0
  14. package/dist/adapters/react.d.cts +31 -0
  15. package/dist/adapters/react.d.ts +31 -0
  16. package/dist/adapters/react.js +51 -0
  17. package/dist/adapters/react.js.map +1 -0
  18. package/dist/adapters/solid.cjs +157 -0
  19. package/dist/adapters/solid.cjs.map +1 -0
  20. package/dist/adapters/solid.d.cts +26 -0
  21. package/dist/adapters/solid.d.ts +26 -0
  22. package/dist/adapters/solid.js +48 -0
  23. package/dist/adapters/solid.js.map +1 -0
  24. package/dist/adapters/svelte.cjs +148 -0
  25. package/dist/adapters/svelte.cjs.map +1 -0
  26. package/dist/adapters/svelte.d.cts +31 -0
  27. package/dist/adapters/svelte.d.ts +31 -0
  28. package/dist/adapters/svelte.js +46 -0
  29. package/dist/adapters/svelte.js.map +1 -0
  30. package/dist/adapters/vue.cjs +155 -0
  31. package/dist/adapters/vue.cjs.map +1 -0
  32. package/dist/adapters/vue.d.cts +26 -0
  33. package/dist/adapters/vue.d.ts +26 -0
  34. package/dist/adapters/vue.js +46 -0
  35. package/dist/adapters/vue.js.map +1 -0
  36. package/dist/agent-runtime-BesGDZcB.d.ts +555 -0
  37. package/dist/agent-runtime-DZTJ3C-p.d.cts +555 -0
  38. package/dist/agentic-memory-BmRCvh0d.d.ts +517 -0
  39. package/dist/agentic-memory-DfuVZ-lY.d.cts +517 -0
  40. package/dist/capability-admission-B0BzqAm5.d.cts +102 -0
  41. package/dist/capability-admission-g0mn9hpq.d.ts +102 -0
  42. package/dist/{chunk-JR4IKCR2.js → chunk-2747WN4Y.js} +5 -5
  43. package/dist/{chunk-2ILL7HQI.js → chunk-3JR3EDB2.js} +17 -17
  44. package/dist/{chunk-2ILL7HQI.js.map → chunk-3JR3EDB2.js.map} +1 -1
  45. package/dist/{chunk-GDL26N2T.js → chunk-3KN7NJDR.js} +2 -2
  46. package/dist/{chunk-DJC4CHLQ.js → chunk-43BKLFZU.js} +9 -9
  47. package/dist/chunk-6XAIOL3X.js +2407 -0
  48. package/dist/chunk-6XAIOL3X.js.map +1 -0
  49. package/dist/{chunk-SCRFRCGR.js → chunk-BSQGE5PS.js} +1 -1
  50. package/dist/{chunk-Y3ZLRGHC.js → chunk-CZNV3VXM.js} +16 -16
  51. package/dist/chunk-DGUM43GV.js +11 -0
  52. package/dist/chunk-DGUM43GV.js.map +1 -0
  53. package/dist/{chunk-JIMUDQN3.js → chunk-FBUU43PM.js} +2 -2
  54. package/dist/chunk-H75VXTGT.js +219 -0
  55. package/dist/chunk-H75VXTGT.js.map +1 -0
  56. package/dist/{chunk-RIIOUTGM.js → chunk-HKK2JD7Z.js} +12 -9
  57. package/dist/chunk-HKK2JD7Z.js.map +1 -0
  58. package/dist/{chunk-D6BG7U6A.js → chunk-IXZBUWSP.js} +3 -3
  59. package/dist/chunk-PC3BTTBE.js +3217 -0
  60. package/dist/chunk-PC3BTTBE.js.map +1 -0
  61. package/dist/chunk-QFY4AFY4.js +879 -0
  62. package/dist/chunk-QFY4AFY4.js.map +1 -0
  63. package/dist/{chunk-DK554R7P.js → chunk-S6HXABGL.js} +2 -1
  64. package/dist/chunk-S6HXABGL.js.map +1 -0
  65. package/dist/{chunk-PKVBHGBM.js → chunk-SS2A464I.js} +7 -7
  66. package/dist/chunk-UT3MHJCW.js +49 -0
  67. package/dist/chunk-UT3MHJCW.js.map +1 -0
  68. package/dist/{chunk-G4M3NHRJ.js → chunk-V7CIJE4B.js} +3 -3
  69. package/dist/{chunk-TEW47IVR.js → chunk-VPEFSDME.js} +2 -2
  70. package/dist/chunk-VTHLCFN4.js +368 -0
  71. package/dist/chunk-VTHLCFN4.js.map +1 -0
  72. package/dist/{chunk-SWTLEQL6.js → chunk-WQIA3GFB.js} +2 -2
  73. package/dist/chunk-WQIA3GFB.js.map +1 -0
  74. package/dist/{chunk-I3IHOHCJ.js → chunk-XKXWK2KP.js} +108 -64
  75. package/dist/chunk-XKXWK2KP.js.map +1 -0
  76. package/dist/{chunk-COHO25CZ.js → chunk-YDSIVHRR.js} +553 -7
  77. package/dist/chunk-YDSIVHRR.js.map +1 -0
  78. package/dist/chunk-YXMZ2N6J.js +1884 -0
  79. package/dist/chunk-YXMZ2N6J.js.map +1 -0
  80. package/dist/composition/index.cjs +102 -57
  81. package/dist/composition/index.cjs.map +1 -1
  82. package/dist/composition/index.d.cts +4 -4
  83. package/dist/composition/index.d.ts +4 -4
  84. package/dist/composition/index.js +6 -5
  85. package/dist/core/index.cjs +102 -57
  86. package/dist/core/index.cjs.map +1 -1
  87. package/dist/core/index.d.cts +2 -2
  88. package/dist/core/index.d.ts +2 -2
  89. package/dist/core/index.js +5 -4
  90. package/dist/cqrs/index.cjs.map +1 -1
  91. package/dist/cqrs/index.d.cts +4 -4
  92. package/dist/cqrs/index.d.ts +4 -4
  93. package/dist/cqrs/index.js +3 -2
  94. package/dist/cqrs/index.js.map +1 -1
  95. package/dist/cqrs/messaging.cjs +312 -0
  96. package/dist/cqrs/messaging.cjs.map +1 -0
  97. package/dist/cqrs/messaging.d.cts +57 -0
  98. package/dist/cqrs/messaging.d.ts +57 -0
  99. package/dist/cqrs/messaging.js +274 -0
  100. package/dist/cqrs/messaging.js.map +1 -0
  101. package/dist/cqrs/work-queue.cjs +329 -0
  102. package/dist/cqrs/work-queue.cjs.map +1 -0
  103. package/dist/cqrs/work-queue.d.cts +90 -0
  104. package/dist/cqrs/work-queue.d.ts +90 -0
  105. package/dist/cqrs/work-queue.js +292 -0
  106. package/dist/cqrs/work-queue.js.map +1 -0
  107. package/dist/data/index.cjs +19 -0
  108. package/dist/data/index.cjs.map +1 -0
  109. package/dist/data/index.d.cts +36 -0
  110. package/dist/data/index.d.ts +36 -0
  111. package/dist/data/index.js +1 -0
  112. package/dist/data/index.js.map +1 -0
  113. package/dist/data-structures/index.cjs +105 -57
  114. package/dist/data-structures/index.cjs.map +1 -1
  115. package/dist/data-structures/index.d.cts +8 -8
  116. package/dist/data-structures/index.d.ts +8 -8
  117. package/dist/data-structures/index.js +7 -6
  118. package/dist/{describe-BZb7AS2y.d.ts → describe-BpyJuWkw.d.ts} +1 -1
  119. package/dist/{describe-Ciu8SUnN.d.cts → describe-DYMw_l1C.d.cts} +1 -1
  120. package/dist/executors/work-queue.cjs +342 -0
  121. package/dist/executors/work-queue.cjs.map +1 -0
  122. package/dist/executors/work-queue.d.cts +90 -0
  123. package/dist/executors/work-queue.d.ts +90 -0
  124. package/dist/executors/work-queue.js +306 -0
  125. package/dist/executors/work-queue.js.map +1 -0
  126. package/dist/graph/index.cjs +112 -58
  127. package/dist/graph/index.cjs.map +1 -1
  128. package/dist/graph/index.d.cts +9 -9
  129. package/dist/graph/index.d.ts +9 -9
  130. package/dist/graph/index.js +18 -17
  131. package/dist/{graph-DfdF9zy4.d.ts → graph-D-1-SQeC.d.ts} +3 -3
  132. package/dist/{graph-s23RbbFO.d.cts → graph-DCEWh4T2.d.cts} +3 -3
  133. package/dist/{index-CAEmLCYF.d.cts → index-72VZC0-E.d.cts} +2 -2
  134. package/dist/{index-SnzZu3x7.d.ts → index-Bmxeu0nK.d.ts} +2 -2
  135. package/dist/index.cjs +112 -58
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.d.cts +11 -10
  138. package/dist/index.d.ts +11 -10
  139. package/dist/index.js +118 -113
  140. package/dist/inspection/boundary.cjs +98 -0
  141. package/dist/inspection/boundary.cjs.map +1 -0
  142. package/dist/inspection/boundary.d.cts +61 -0
  143. package/dist/inspection/boundary.d.ts +61 -0
  144. package/dist/inspection/boundary.js +75 -0
  145. package/dist/inspection/boundary.js.map +1 -0
  146. package/dist/{messages-BZqrGGm1.d.ts → messages-CAzUPPJM.d.cts} +10 -5
  147. package/dist/{messages-BZqrGGm1.d.cts → messages-CAzUPPJM.d.ts} +10 -5
  148. package/dist/messaging/index.cjs +744 -613
  149. package/dist/messaging/index.cjs.map +1 -1
  150. package/dist/messaging/index.d.cts +216 -160
  151. package/dist/messaging/index.d.ts +216 -160
  152. package/dist/messaging/index.js +19 -749
  153. package/dist/messaging/index.js.map +1 -1
  154. package/dist/operators/index.cjs +102 -57
  155. package/dist/operators/index.cjs.map +1 -1
  156. package/dist/operators/index.d.cts +6 -6
  157. package/dist/operators/index.d.ts +6 -6
  158. package/dist/operators/index.js +8 -7
  159. package/dist/orchestration/index.cjs +3333 -59
  160. package/dist/orchestration/index.cjs.map +1 -1
  161. package/dist/orchestration/index.d.cts +7 -4
  162. package/dist/orchestration/index.d.ts +7 -4
  163. package/dist/orchestration/index.js +49 -8
  164. package/dist/orchestration/index.js.map +1 -1
  165. package/dist/orchestration/messaging.cjs +314 -0
  166. package/dist/orchestration/messaging.cjs.map +1 -0
  167. package/dist/orchestration/messaging.d.cts +59 -0
  168. package/dist/orchestration/messaging.d.ts +59 -0
  169. package/dist/orchestration/messaging.js +276 -0
  170. package/dist/orchestration/messaging.js.map +1 -0
  171. package/dist/orchestration/work-queue.cjs +262 -0
  172. package/dist/orchestration/work-queue.cjs.map +1 -0
  173. package/dist/orchestration/work-queue.d.cts +85 -0
  174. package/dist/orchestration/work-queue.d.ts +85 -0
  175. package/dist/orchestration/work-queue.js +226 -0
  176. package/dist/orchestration/work-queue.js.map +1 -0
  177. package/dist/patterns/event-flow.cjs +447 -0
  178. package/dist/patterns/event-flow.cjs.map +1 -0
  179. package/dist/patterns/event-flow.d.cts +115 -0
  180. package/dist/patterns/event-flow.d.ts +115 -0
  181. package/dist/patterns/event-flow.js +14 -0
  182. package/dist/patterns/event-flow.js.map +1 -0
  183. package/dist/patterns/index.cjs +423 -18
  184. package/dist/patterns/index.cjs.map +1 -1
  185. package/dist/patterns/index.d.cts +8 -5
  186. package/dist/patterns/index.d.ts +8 -5
  187. package/dist/patterns/index.js +13 -4
  188. package/dist/{reactive-collection-Cb1II1Fi.d.ts → reactive-collection-BAmfrGjd.d.ts} +9 -9
  189. package/dist/{reactive-collection-BxBqtIOE.d.cts → reactive-collection-DNV0-gFi.d.cts} +9 -9
  190. package/dist/{reactive-collection-storage-D-KmjE0J.d.cts → reactive-collection-storage-BNEldDyi.d.cts} +5 -5
  191. package/dist/{reactive-collection-storage-BNiEc-Gd.d.ts → reactive-collection-storage-YZsAQsWK.d.ts} +5 -5
  192. package/dist/{reactive-map-D-g3dv8I.d.cts → reactive-map-DRD1LJ2H.d.cts} +6 -6
  193. package/dist/{reactive-map-BcB4KsQR.d.ts → reactive-map-EsDiCmJk.d.ts} +6 -6
  194. package/dist/render/index.d.cts +3 -3
  195. package/dist/render/index.d.ts +3 -3
  196. package/dist/render/index.js +1 -0
  197. package/dist/{semantic-memory-graph-BYoIlP35.d.cts → semantic-memory-graph-DKuNzuWw.d.cts} +2 -2
  198. package/dist/{semantic-memory-graph-CxyXLms3.d.ts → semantic-memory-graph-uwbwJdhe.d.ts} +2 -2
  199. package/dist/solutions/index.cjs +4478 -2
  200. package/dist/solutions/index.cjs.map +1 -1
  201. package/dist/solutions/index.d.cts +13 -519
  202. package/dist/solutions/index.d.ts +13 -519
  203. package/dist/solutions/index.js +90 -6
  204. package/dist/solutions/reactive-layout/browser/index.cjs +449 -0
  205. package/dist/solutions/reactive-layout/browser/index.cjs.map +1 -0
  206. package/dist/solutions/reactive-layout/browser/index.d.cts +44 -0
  207. package/dist/solutions/reactive-layout/browser/index.d.ts +44 -0
  208. package/dist/solutions/reactive-layout/browser/index.js +69 -0
  209. package/dist/solutions/reactive-layout/browser/index.js.map +1 -0
  210. package/dist/solutions/reactive-layout/index.cjs +4266 -0
  211. package/dist/solutions/reactive-layout/index.cjs.map +1 -0
  212. package/dist/solutions/reactive-layout/index.d.cts +581 -0
  213. package/dist/solutions/reactive-layout/index.d.ts +581 -0
  214. package/dist/solutions/reactive-layout/index.js +86 -0
  215. package/dist/solutions/reactive-layout/index.js.map +1 -0
  216. package/dist/solutions/reactive-layout/node-canvas/index.cjs +545 -0
  217. package/dist/solutions/reactive-layout/node-canvas/index.cjs.map +1 -0
  218. package/dist/solutions/reactive-layout/node-canvas/index.d.cts +54 -0
  219. package/dist/solutions/reactive-layout/node-canvas/index.d.ts +54 -0
  220. package/dist/solutions/reactive-layout/node-canvas/index.js +131 -0
  221. package/dist/solutions/reactive-layout/node-canvas/index.js.map +1 -0
  222. package/dist/solutions/reactive-layout/react-native/index.cjs +494 -0
  223. package/dist/solutions/reactive-layout/react-native/index.cjs.map +1 -0
  224. package/dist/solutions/reactive-layout/react-native/index.d.cts +51 -0
  225. package/dist/solutions/reactive-layout/react-native/index.d.ts +51 -0
  226. package/dist/solutions/reactive-layout/react-native/index.js +77 -0
  227. package/dist/solutions/reactive-layout/react-native/index.js.map +1 -0
  228. package/dist/solutions/reactive-layout/skia/index.cjs +547 -0
  229. package/dist/solutions/reactive-layout/skia/index.cjs.map +1 -0
  230. package/dist/solutions/reactive-layout/skia/index.d.cts +64 -0
  231. package/dist/solutions/reactive-layout/skia/index.d.ts +64 -0
  232. package/dist/solutions/reactive-layout/skia/index.js +70 -0
  233. package/dist/solutions/reactive-layout/skia/index.js.map +1 -0
  234. package/dist/solutions/work-item/actions.cjs +2164 -0
  235. package/dist/solutions/work-item/actions.cjs.map +1 -0
  236. package/dist/solutions/work-item/actions.d.cts +201 -0
  237. package/dist/solutions/work-item/actions.d.ts +201 -0
  238. package/dist/solutions/work-item/actions.js +1454 -0
  239. package/dist/solutions/work-item/actions.js.map +1 -0
  240. package/dist/solutions/work-item/scheduling.cjs +2454 -0
  241. package/dist/solutions/work-item/scheduling.cjs.map +1 -0
  242. package/dist/solutions/work-item/scheduling.d.cts +433 -0
  243. package/dist/solutions/work-item/scheduling.d.ts +433 -0
  244. package/dist/solutions/work-item/scheduling.js +32 -0
  245. package/dist/solutions/work-item/scheduling.js.map +1 -0
  246. package/dist/solutions/work-item/work-queue.cjs +306 -0
  247. package/dist/solutions/work-item/work-queue.cjs.map +1 -0
  248. package/dist/solutions/work-item/work-queue.d.cts +71 -0
  249. package/dist/solutions/work-item/work-queue.d.ts +71 -0
  250. package/dist/solutions/work-item/work-queue.js +270 -0
  251. package/dist/solutions/work-item/work-queue.js.map +1 -0
  252. package/dist/sources/browser.cjs +169 -57
  253. package/dist/sources/browser.cjs.map +1 -1
  254. package/dist/sources/browser.d.cts +33 -6
  255. package/dist/sources/browser.d.ts +33 -6
  256. package/dist/sources/browser.js +73 -6
  257. package/dist/sources/browser.js.map +1 -1
  258. package/dist/sources/index.cjs +102 -57
  259. package/dist/sources/index.cjs.map +1 -1
  260. package/dist/sources/index.d.cts +5 -5
  261. package/dist/sources/index.d.ts +5 -5
  262. package/dist/sources/index.js +6 -5
  263. package/dist/sources/node.cjs.map +1 -1
  264. package/dist/sources/node.d.cts +4 -4
  265. package/dist/sources/node.d.ts +4 -4
  266. package/dist/sources/node.js +2 -1
  267. package/dist/sources/node.js.map +1 -1
  268. package/dist/storage/browser.js +1 -0
  269. package/dist/storage/browser.js.map +1 -1
  270. package/dist/storage/index.d.cts +5 -5
  271. package/dist/storage/index.d.ts +5 -5
  272. package/dist/storage/index.js +5 -4
  273. package/dist/storage/node.js +1 -0
  274. package/dist/storage/node.js.map +1 -1
  275. package/dist/store-C-joM4gh.d.ts +123 -0
  276. package/dist/store-CNJwmT-h.d.cts +123 -0
  277. package/dist/testing/index.cjs +1 -0
  278. package/dist/testing/index.cjs.map +1 -1
  279. package/dist/testing/index.d.cts +1 -1
  280. package/dist/testing/index.d.ts +1 -1
  281. package/dist/testing/index.js +3 -2
  282. package/dist/{types-h12mNYbq.d.ts → types-BsJvElYZ.d.ts} +31 -31
  283. package/dist/{types-bNMSWKqF.d.cts → types-CcPIn7sy.d.cts} +31 -31
  284. package/dist/work-item-runtime-C3M79vE9.d.ts +228 -0
  285. package/dist/work-item-runtime-qaVgsL0T.d.cts +228 -0
  286. package/dist/work-queue/index.cjs +1132 -0
  287. package/dist/work-queue/index.cjs.map +1 -0
  288. package/dist/work-queue/index.d.cts +369 -0
  289. package/dist/work-queue/index.d.ts +369 -0
  290. package/dist/work-queue/index.js +1078 -0
  291. package/dist/work-queue/index.js.map +1 -0
  292. package/package.json +266 -2
  293. package/dist/chunk-COHO25CZ.js.map +0 -1
  294. package/dist/chunk-DK554R7P.js.map +0 -1
  295. package/dist/chunk-I3IHOHCJ.js.map +0 -1
  296. package/dist/chunk-RIIOUTGM.js.map +0 -1
  297. package/dist/chunk-SWTLEQL6.js.map +0 -1
  298. /package/dist/{chunk-JR4IKCR2.js.map → chunk-2747WN4Y.js.map} +0 -0
  299. /package/dist/{chunk-GDL26N2T.js.map → chunk-3KN7NJDR.js.map} +0 -0
  300. /package/dist/{chunk-DJC4CHLQ.js.map → chunk-43BKLFZU.js.map} +0 -0
  301. /package/dist/{chunk-SCRFRCGR.js.map → chunk-BSQGE5PS.js.map} +0 -0
  302. /package/dist/{chunk-Y3ZLRGHC.js.map → chunk-CZNV3VXM.js.map} +0 -0
  303. /package/dist/{chunk-JIMUDQN3.js.map → chunk-FBUU43PM.js.map} +0 -0
  304. /package/dist/{chunk-D6BG7U6A.js.map → chunk-IXZBUWSP.js.map} +0 -0
  305. /package/dist/{chunk-PKVBHGBM.js.map → chunk-SS2A464I.js.map} +0 -0
  306. /package/dist/{chunk-G4M3NHRJ.js.map → chunk-V7CIJE4B.js.map} +0 -0
  307. /package/dist/{chunk-TEW47IVR.js.map → chunk-VPEFSDME.js.map} +0 -0
@@ -0,0 +1,1454 @@
1
+ import {
2
+ validateAcceptanceCriteria,
3
+ validateVerificationPlan
4
+ } from "../../chunk-6XAIOL3X.js";
5
+ import {
6
+ workItemDomainActionAdmissionProjector
7
+ } from "../../chunk-PC3BTTBE.js";
8
+ import {
9
+ depBatch
10
+ } from "../../chunk-WQIA3GFB.js";
11
+ import "../../chunk-S6HXABGL.js";
12
+ import "../../chunk-DGUM43GV.js";
13
+
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
44
+ };
45
+ }
46
+ function workItemDomainActionProposalIntake(proposalId, workItemId, actionKind, opts = {}) {
47
+ 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
61
+ };
62
+ }
63
+ function workItemDomainActionApplyPolicy(policyId, opts = {}) {
64
+ 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
71
+ };
72
+ }
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],
78
+ (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);
86
+ },
87
+ {
88
+ name: `${name}/runtime`,
89
+ factory: "workItemDomainActionProposalIntakeProjector",
90
+ partial: true,
91
+ completeWhenDepsComplete: false,
92
+ errorWhenDepsError: false
93
+ }
94
+ );
95
+ 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
+ };
125
+ }
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];
129
+ const runtime = graph.node(
130
+ deps,
131
+ (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
+ };
143
+ for (const raw of depBatch(ctx, 0) ?? []) {
144
+ const proposal = raw;
145
+ if (state.proposals.has(proposal.proposalId)) {
146
+ emitApplicationIssue(
147
+ ctx,
148
+ state,
149
+ `duplicate-proposal:${proposal.proposalId}`,
150
+ "duplicate-suppressed",
151
+ `Duplicate WorkItem domain action proposal '${proposal.proposalId}' suppressed`,
152
+ proposal.workItemId,
153
+ proposal.sourceRefs
154
+ );
155
+ continue;
156
+ }
157
+ state.proposals.set(proposal.proposalId, proposal);
158
+ }
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
+ }
169
+ for (const raw of depBatch(ctx, 1) ?? []) {
170
+ const admission = raw;
171
+ if (state.admissions.has(admission.admissionId)) {
172
+ emitApplicationIssue(
173
+ ctx,
174
+ state,
175
+ `duplicate-admission:${admission.admissionId}`,
176
+ "duplicate-suppressed",
177
+ `Duplicate WorkItem domain action admission '${admission.admissionId}' suppressed`,
178
+ admission.workItemId,
179
+ admissionRefs(admission)
180
+ );
181
+ continue;
182
+ }
183
+ state.admissions.set(admission.admissionId, admission);
184
+ }
185
+ for (const admission of state.admissions.values()) applyAdmission(ctx, state, admission);
186
+ ctx.state.set(state);
187
+ },
188
+ {
189
+ name: `${name}/runtime`,
190
+ factory: "workItemDomainActionApplicationProjector",
191
+ partial: true,
192
+ completeWhenDepsComplete: false,
193
+ errorWhenDepsError: false
194
+ }
195
+ );
196
+ 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(
205
+ graph,
206
+ runtime,
207
+ `${name}/applications`,
208
+ "workItemDomainActionApplications",
209
+ (fact) => fact.kind === "application" ? fact.value : void 0
210
+ ),
211
+ status: project(
212
+ graph,
213
+ runtime,
214
+ `${name}/status`,
215
+ "workItemDomainActionStatus",
216
+ (fact) => fact.kind === "status" ? fact.value : void 0
217
+ ),
218
+ issues: project(
219
+ graph,
220
+ runtime,
221
+ `${name}/issues`,
222
+ "workItemDomainActionIssues",
223
+ (fact) => fact.kind === "issue" ? fact.value : void 0
224
+ ),
225
+ audit: project(
226
+ graph,
227
+ runtime,
228
+ `${name}/audit`,
229
+ "workItemDomainActionAudit",
230
+ (fact) => fact.kind === "audit" ? fact.value : void 0
231
+ )
232
+ };
233
+ }
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
347
+ }
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
+ };
379
+ }
380
+ function evaluateCapabilityGuardProposal(ctx, state, proposal, decidedAtMs) {
381
+ if (state.emittedProposalDecisions.has(proposal.proposalId)) return;
382
+ const policy = selectCapabilityGuardPolicy(state, proposal);
383
+ if (typeof policy === "string") {
384
+ emitCapabilityGuardIssue(
385
+ ctx,
386
+ 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
+ })
392
+ );
393
+ return;
394
+ }
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);
402
+ }
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(
412
+ ctx,
413
+ 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
+ }
430
+ );
431
+ return;
432
+ }
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`,
442
+ 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),
447
+ 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
+ )
454
+ }
455
+ };
456
+ state.emittedProposalDecisions.add(proposal.proposalId);
457
+ emitCapabilityGuard(ctx, "decision", decision);
458
+ emitCapabilityGuardStatus(ctx, state, {
459
+ state: outcome === "admit" ? "admitted" : "rejected",
460
+ workItemId: proposal.workItemId,
461
+ 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
+ });
470
+ }
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;
480
+ }
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
+ );
490
+ }
491
+ return void 0;
492
+ }
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
+ );
500
+ }
501
+ return void 0;
502
+ }
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
+ );
519
+ }
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;
564
+ }
565
+ return void 0;
566
+ }
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
+ ]);
621
+ }
622
+ function capabilityBoundaryRefId(capability) {
623
+ return `${capability.kind}:${capability.id}`;
624
+ }
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",
637
+ subjectId: status.workItemId,
638
+ message: status.message,
639
+ sourceRefs: status.sourceRefs,
640
+ metadata: {
641
+ statusId: statusFact.statusId,
642
+ state: status.state,
643
+ proposalId: status.proposalId,
644
+ policyId: status.policyId,
645
+ ...status.metadata ?? {}
646
+ }
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
+ });
665
+ }
666
+ function emitCapabilityGuard(ctx, kind, value) {
667
+ ctx.down([["DATA", { kind, value }]]);
668
+ }
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
+ });
701
+ }
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;
722
+ }
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
+ );
739
+ }
740
+ function applyAdmission(ctx, state, admission) {
741
+ if (state.appliedAdmissions.has(admission.admissionId)) return;
742
+ const proposal = state.proposals.get(admission.proposalId);
743
+ if (proposal === void 0) {
744
+ emitApplicationIssue(
745
+ ctx,
746
+ state,
747
+ `missing-proposal:${admission.admissionId}:${admission.proposalId}`,
748
+ "dangling-ref",
749
+ `Admission '${admission.admissionId}' cannot apply without proposal '${admission.proposalId}'`,
750
+ admission.workItemId,
751
+ admissionRefs(admission)
752
+ );
753
+ return;
754
+ }
755
+ if (admission.state !== "admitted") {
756
+ state.appliedAdmissions.add(admission.admissionId);
757
+ emitApplication(ctx, state, admission, proposal, admission.state, []);
758
+ return;
759
+ }
760
+ const mismatch = admissionProposalMismatch(admission, proposal);
761
+ if (mismatch !== void 0) {
762
+ state.appliedAdmissions.add(admission.admissionId);
763
+ emitApplicationIssue(
764
+ ctx,
765
+ state,
766
+ `admission-proposal-mismatch:${admission.admissionId}:${mismatch.field}`,
767
+ "dangling-ref",
768
+ mismatch.message,
769
+ admission.workItemId,
770
+ admissionRefs(admission, proposal),
771
+ {
772
+ field: mismatch.field,
773
+ admissionValue: mismatch.admissionValue,
774
+ proposalValue: mismatch.proposalValue
775
+ }
776
+ );
777
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
778
+ code: "dangling-ref",
779
+ message: mismatch.message
780
+ });
781
+ return;
782
+ }
783
+ const workItem = state.workItems.get(admission.workItemId);
784
+ if (workItem === void 0) {
785
+ emitApplicationIssue(
786
+ ctx,
787
+ state,
788
+ `missing-work-item:${admission.admissionId}:${admission.workItemId}`,
789
+ "dangling-ref",
790
+ `Admission '${admission.admissionId}' references unknown WorkItem '${admission.workItemId}'`,
791
+ admission.workItemId,
792
+ admissionRefs(admission, proposal)
793
+ );
794
+ return;
795
+ }
796
+ const metadataConflict = conflictingApplicationMetadata(proposal, admission);
797
+ if (metadataConflict !== void 0) {
798
+ state.appliedAdmissions.add(admission.admissionId);
799
+ emitApplicationIssue(
800
+ ctx,
801
+ state,
802
+ `metadata-conflict:${admission.admissionId}:${metadataConflict.field}`,
803
+ metadataConflict.code,
804
+ metadataConflict.message,
805
+ admission.workItemId,
806
+ admissionRefs(admission, proposal),
807
+ {
808
+ field: metadataConflict.field,
809
+ admissionValue: metadataConflict.admissionValue,
810
+ proposalValue: metadataConflict.proposalValue
811
+ }
812
+ );
813
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
814
+ code: metadataConflict.code,
815
+ message: metadataConflict.message
816
+ });
817
+ return;
818
+ }
819
+ const stale = staleRevision(proposal, admission, workItem);
820
+ if (stale !== void 0) {
821
+ state.appliedAdmissions.add(admission.admissionId);
822
+ emitApplicationIssue(
823
+ ctx,
824
+ state,
825
+ `stale:${admission.admissionId}:${stale.kind}:${stale.expected}:${stale.current}`,
826
+ stale.kind,
827
+ `Admission '${admission.admissionId}' targets stale WorkItem revision`,
828
+ admission.workItemId,
829
+ admissionRefs(admission, proposal),
830
+ { expected: stale.expected, current: stale.current }
831
+ );
832
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
833
+ code: stale.kind,
834
+ message: "Stale WorkItem revision"
835
+ });
836
+ return;
837
+ }
838
+ const policyResult = selectApplyPolicy(state, proposal, admission);
839
+ if (typeof policyResult === "string") {
840
+ emitApplicationIssue(
841
+ ctx,
842
+ state,
843
+ `policy:${admission.admissionId}:${policyResult}`,
844
+ policyResult,
845
+ applyPolicyMessage(policyResult, proposal, admission),
846
+ admission.workItemId,
847
+ admissionRefs(admission, proposal)
848
+ );
849
+ return;
850
+ }
851
+ const output = lowerAction(ctx, state, workItem, proposal, admission, policyResult);
852
+ if (output === void 0) {
853
+ state.appliedAdmissions.add(admission.admissionId);
854
+ emitApplication(ctx, state, admission, proposal, "rejected", [], {
855
+ code: "invalid-action",
856
+ message: "WorkItem domain action application rejected; see emitted issues",
857
+ policyId: policyResult.policyId
858
+ });
859
+ return;
860
+ }
861
+ const duplicateFactId = firstDuplicateFactId(state, output.facts);
862
+ if (duplicateFactId !== void 0) {
863
+ state.appliedAdmissions.add(admission.admissionId);
864
+ emitApplicationIssue(
865
+ ctx,
866
+ state,
867
+ `duplicate-authoring-fact:${admission.admissionId}:${duplicateFactId}`,
868
+ "duplicate-suppressed",
869
+ `WorkItem domain action application '${admission.admissionId}' would duplicate authoring fact '${duplicateFactId}'`,
870
+ admission.workItemId,
871
+ admissionRefs(admission, proposal, policyResult),
872
+ { eventId: duplicateFactId }
873
+ );
874
+ emitApplication(ctx, state, admission, proposal, "duplicate", [], {
875
+ code: "duplicate-suppressed",
876
+ message: "Duplicate WorkItem authoring fact suppressed atomically",
877
+ policyId: policyResult.policyId
878
+ });
879
+ return;
880
+ }
881
+ state.appliedAdmissions.add(admission.admissionId);
882
+ for (const fact of output.facts) claimFactId(state, fact.eventId);
883
+ for (const fact of output.facts) emitApplicationFact(ctx, "authoring-fact", fact);
884
+ emitApplication(ctx, state, admission, proposal, output.state, output.facts, {
885
+ code: output.code,
886
+ message: output.message,
887
+ policyId: policyResult.policyId
888
+ });
889
+ }
890
+ function lowerAction(ctx, state, workItem, proposal, admission, policy) {
891
+ if (!policyAllowsAction(policy, proposal.actionKind)) {
892
+ emitApplicationIssue(
893
+ ctx,
894
+ state,
895
+ `policy-action:${admission.admissionId}:${policy.policyId}:${proposal.actionKind}`,
896
+ "policy-mismatch",
897
+ `Apply policy '${policy.policyId}' does not allow actionKind '${proposal.actionKind}'`,
898
+ proposal.workItemId,
899
+ admissionRefs(admission, proposal, policy)
900
+ );
901
+ return { state: "policy-rejected", facts: [], code: "policy-mismatch" };
902
+ }
903
+ if (proposal.actionKind === "patch") {
904
+ const lowered = lowerPatchAction(ctx, state, workItem, proposal, admission, policy);
905
+ if (lowered === void 0) return void 0;
906
+ return { state: "applied", facts: lowered };
907
+ }
908
+ if (proposal.actionKind === "mark-verified" || proposal.actionKind === "require-review") {
909
+ return {
910
+ state: "proposal-only",
911
+ facts: [],
912
+ code: "domain-fact-unimplemented",
913
+ message: `Action '${proposal.actionKind}' recorded as visible application status only; no WorkItem domain mutation fact was emitted`
914
+ };
915
+ }
916
+ if (proposal.actionKind === "spawn-proposed" || proposal.actionKind === "spawn-child") {
917
+ return lowerSpawnAction(ctx, state, proposal, admission, policy);
918
+ }
919
+ emitApplicationIssue(
920
+ ctx,
921
+ state,
922
+ `unsupported-action:${admission.admissionId}:${proposal.actionKind}`,
923
+ "unsupported-effect-kind",
924
+ `Unsupported WorkItem domain actionKind '${proposal.actionKind}'`,
925
+ proposal.workItemId,
926
+ admissionRefs(admission, proposal, policy)
927
+ );
928
+ return { state: "rejected", facts: [], code: "unsupported-effect-kind" };
929
+ }
930
+ function lowerPatchAction(ctx, state, workItem, proposal, admission, policy) {
931
+ const payload = normalizePatchPayload(proposal.payload);
932
+ if (typeof payload === "string") {
933
+ emitApplicationIssue(
934
+ ctx,
935
+ state,
936
+ `invalid-patch:${admission.admissionId}`,
937
+ "invalid-patch",
938
+ payload,
939
+ proposal.workItemId,
940
+ admissionRefs(admission, proposal, policy)
941
+ );
942
+ return void 0;
943
+ }
944
+ const splitPayload = splitDedicatedPatchFields(payload, workItem);
945
+ const facts = [];
946
+ if (splitPayload.patch !== void 0) {
947
+ const invalid = invalidPatchKeys(splitPayload.patch, policy);
948
+ if (invalid.length > 0) {
949
+ emitApplicationIssue(
950
+ ctx,
951
+ state,
952
+ `invalid-patch-fields:${admission.admissionId}:${invalid.join(",")}`,
953
+ "invalid-patch",
954
+ `Patch action uses unsupported fields: ${invalid.join(", ")}`,
955
+ proposal.workItemId,
956
+ admissionRefs(admission, proposal, policy),
957
+ { invalidFields: invalid }
958
+ );
959
+ return void 0;
960
+ }
961
+ facts.push({
962
+ kind: "work-item-patched",
963
+ eventId: splitPayload.eventId ?? `${admission.admissionId}:work-item-patched`,
964
+ workItemId: workItem.workItemId,
965
+ patch: splitPayload.patch,
966
+ executionRelevantFields: splitPayload.executionRelevantFields ?? policy.patch?.executionRelevantFields,
967
+ authorId: splitPayload.authorId,
968
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
969
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
970
+ });
971
+ }
972
+ if (splitPayload.acceptanceCriteria !== void 0) {
973
+ if (!allowsAcceptanceCriteria(policy)) {
974
+ emitApplicationIssue(
975
+ ctx,
976
+ state,
977
+ `ac-policy:${admission.admissionId}`,
978
+ "policy-mismatch",
979
+ `Apply policy '${policy.policyId}' does not allow acceptance criteria changes`,
980
+ proposal.workItemId,
981
+ admissionRefs(admission, proposal, policy)
982
+ );
983
+ return void 0;
984
+ }
985
+ const issues = validateAcceptanceCriteria(splitPayload.acceptanceCriteria, {
986
+ workItemId: workItem.workItemId
987
+ });
988
+ if (issues.length > 0) {
989
+ for (const item of issues) emitApplicationFact(ctx, "issue", item);
990
+ emitApplicationStatus(ctx, state, {
991
+ state: "rejected",
992
+ code: issues[0]?.code,
993
+ message: issues[0]?.message,
994
+ workItemId: workItem.workItemId,
995
+ proposalId: proposal.proposalId,
996
+ admissionId: admission.admissionId,
997
+ actionKind: proposal.actionKind,
998
+ sourceRefs: admissionRefs(admission, proposal, policy)
999
+ });
1000
+ return void 0;
1001
+ }
1002
+ facts.push({
1003
+ kind: "acceptance-criteria-changed",
1004
+ eventId: `${admission.admissionId}:acceptance-criteria-changed`,
1005
+ workItemId: workItem.workItemId,
1006
+ acceptanceCriteria: splitPayload.acceptanceCriteria,
1007
+ authorId: splitPayload.authorId,
1008
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1009
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
1010
+ });
1011
+ }
1012
+ if (splitPayload.verificationPlan !== void 0) {
1013
+ if (!allowsVerificationPlan(policy)) {
1014
+ emitApplicationIssue(
1015
+ ctx,
1016
+ state,
1017
+ `plan-policy:${admission.admissionId}`,
1018
+ "policy-mismatch",
1019
+ `Apply policy '${policy.policyId}' does not allow verification plan changes`,
1020
+ proposal.workItemId,
1021
+ admissionRefs(admission, proposal, policy)
1022
+ );
1023
+ return void 0;
1024
+ }
1025
+ const issues = validateVerificationPlan(
1026
+ splitPayload.verificationPlan,
1027
+ splitPayload.acceptanceCriteria ?? workItem.acceptanceCriteria ?? [],
1028
+ { workItemId: workItem.workItemId }
1029
+ );
1030
+ if (issues.length > 0) {
1031
+ for (const item of issues) emitApplicationFact(ctx, "issue", item);
1032
+ emitApplicationStatus(ctx, state, {
1033
+ state: "rejected",
1034
+ code: issues[0]?.code,
1035
+ message: issues[0]?.message,
1036
+ workItemId: workItem.workItemId,
1037
+ proposalId: proposal.proposalId,
1038
+ admissionId: admission.admissionId,
1039
+ actionKind: proposal.actionKind,
1040
+ sourceRefs: admissionRefs(admission, proposal, policy)
1041
+ });
1042
+ return void 0;
1043
+ }
1044
+ facts.push({
1045
+ kind: "verification-plan-changed",
1046
+ eventId: `${admission.admissionId}:verification-plan-changed`,
1047
+ workItemId: workItem.workItemId,
1048
+ verificationPlan: splitPayload.verificationPlan,
1049
+ authorId: splitPayload.authorId,
1050
+ sourceRefs: actionSourceRefs(admission, proposal, policy),
1051
+ metadata: { ...splitPayload.metadata ?? {}, actionKind: proposal.actionKind }
1052
+ });
1053
+ }
1054
+ if (facts.length === 0) {
1055
+ emitApplicationIssue(
1056
+ ctx,
1057
+ state,
1058
+ `empty-patch:${admission.admissionId}`,
1059
+ "invalid-patch",
1060
+ "Patch action payload did not contain patch, acceptanceCriteria, or verificationPlan",
1061
+ proposal.workItemId,
1062
+ admissionRefs(admission, proposal, policy)
1063
+ );
1064
+ return void 0;
1065
+ }
1066
+ return facts;
1067
+ }
1068
+ function lowerSpawnAction(ctx, state, proposal, admission, policy) {
1069
+ if (policy.spawn?.create !== true) {
1070
+ return {
1071
+ state: "proposal-only",
1072
+ facts: [],
1073
+ message: "Spawn action remains proposal/admission only without explicit create policy"
1074
+ };
1075
+ }
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"
1093
+ };
1094
+ }
1095
+ function normalizePatchPayload(payload) {
1096
+ if (!isRecord(payload)) return "Patch action payload must be an object";
1097
+ if ("patch" in payload || "acceptanceCriteria" in payload || "verificationPlan" in payload || "executionRelevantFields" in payload) {
1098
+ if ("patch" in payload && payload.patch !== void 0 && !isRecord(payload.patch))
1099
+ return "Patch action payload.patch must be an object";
1100
+ if ("acceptanceCriteria" in payload && payload.acceptanceCriteria !== void 0 && !Array.isArray(payload.acceptanceCriteria))
1101
+ return "Patch action payload.acceptanceCriteria must be an array";
1102
+ if ("verificationPlan" in payload && payload.verificationPlan !== void 0 && !isRecord(payload.verificationPlan))
1103
+ return "Patch action payload.verificationPlan must be an object";
1104
+ const inlinePatch = inlinePatchFields(payload);
1105
+ const explicitPatch = isRecord(payload.patch) ? payload.patch : void 0;
1106
+ const patch = explicitPatch === void 0 ? inlinePatch : { ...inlinePatch, ...explicitPatch };
1107
+ return {
1108
+ ...payload,
1109
+ patch: Object.keys(patch).length === 0 ? void 0 : patch
1110
+ };
1111
+ }
1112
+ return { patch: payload };
1113
+ }
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;
1121
+ }
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
+ };
1142
+ }
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));
1146
+ }
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;
1151
+ }
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;
1156
+ }
1157
+ function selectApplyPolicy(state, proposal, admission) {
1158
+ const explicitId = explicitApplyPolicyId(proposal, admission);
1159
+ 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)
1163
+ );
1164
+ if (matching.length === 0) return "missing-policy";
1165
+ if (matching.length > 1) return "policy-mismatch";
1166
+ return matching[0];
1167
+ }
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
+ };
1193
+ return void 0;
1194
+ }
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"
1208
+ );
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
+ }
1257
+ function applyPolicyMessage(code, proposal, admission) {
1258
+ 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
+ });
1305
+ }
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);
1315
+ }
1316
+ function emitApplicationStatus(ctx, state, status) {
1317
+ state.statusSeq += 1;
1318
+ const statusFact = {
1319
+ kind: "work-item-domain-action-status",
1320
+ statusId: `work-item-domain-action-application-status:${state.statusSeq}`,
1321
+ ...status
1322
+ };
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) {
1331
+ 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,
1338
+ subjectId: status.workItemId,
1339
+ message: status.message,
1340
+ issueCode: status.code,
1341
+ sourceRefs: status.sourceRefs,
1342
+ metadata: {
1343
+ statusId: status.statusId,
1344
+ state: status.state,
1345
+ proposalId: status.proposalId,
1346
+ admissionId: status.admissionId,
1347
+ actionKind: status.actionKind,
1348
+ ...status.metadata ?? {}
1349
+ }
1350
+ };
1351
+ }
1352
+ function emitIntake(ctx, kind, value) {
1353
+ ctx.down([["DATA", { kind, value }]]);
1354
+ }
1355
+ function emitApplicationFact(ctx, kind, value) {
1356
+ ctx.down([["DATA", { kind, value }]]);
1357
+ }
1358
+ function project(graph, runtime, name, factory, select) {
1359
+ return graph.node(
1360
+ [runtime],
1361
+ (ctx) => {
1362
+ for (const raw of depBatch(ctx, 0) ?? []) {
1363
+ const selected = select(raw);
1364
+ if (selected !== void 0) ctx.down([["DATA", selected]]);
1365
+ }
1366
+ },
1367
+ { name, factory, partial: true, completeWhenDepsComplete: false, errorWhenDepsError: false }
1368
+ );
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
+ 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
1409
+ };
1410
+ }
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);
1419
+ }
1420
+ return out;
1421
+ }
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"
1426
+ );
1427
+ }
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 };
1438
+ }
1439
+ function recordString(value, key) {
1440
+ return isRecord(value) && typeof value[key] === "string" ? value[key] : void 0;
1441
+ }
1442
+ function isRecord(value) {
1443
+ return value !== null && typeof value === "object";
1444
+ }
1445
+ export {
1446
+ workItemDomainActionAdmissionProjector,
1447
+ workItemDomainActionApplicationProjector,
1448
+ workItemDomainActionApplyPolicy,
1449
+ workItemDomainActionCapabilityGuardProjector,
1450
+ workItemDomainActionProposal,
1451
+ workItemDomainActionProposalIntake,
1452
+ workItemDomainActionProposalIntakeProjector
1453
+ };
1454
+ //# sourceMappingURL=actions.js.map