@shipfox/api-workflows 11.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +107 -0
  3. package/README.md +75 -0
  4. package/dist/core/agent-defaults.d.ts +2 -1
  5. package/dist/core/agent-defaults.d.ts.map +1 -1
  6. package/dist/core/agent-defaults.js.map +1 -1
  7. package/dist/core/checkout.d.ts +7 -21
  8. package/dist/core/checkout.d.ts.map +1 -1
  9. package/dist/core/checkout.js +122 -41
  10. package/dist/core/checkout.js.map +1 -1
  11. package/dist/core/entities/job-execution.d.ts +8 -0
  12. package/dist/core/entities/job-execution.d.ts.map +1 -1
  13. package/dist/core/entities/job-execution.js +13 -1
  14. package/dist/core/entities/job-execution.js.map +1 -1
  15. package/dist/core/entities/job-listener-event.d.ts +2 -0
  16. package/dist/core/entities/job-listener-event.d.ts.map +1 -1
  17. package/dist/core/entities/job-listener-event.js.map +1 -1
  18. package/dist/core/entities/step.d.ts +13 -3
  19. package/dist/core/entities/step.d.ts.map +1 -1
  20. package/dist/core/entities/step.js +6 -0
  21. package/dist/core/entities/step.js.map +1 -1
  22. package/dist/core/entities/workflow-run-attempt.d.ts +1 -0
  23. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
  24. package/dist/core/entities/workflow-run-attempt.js.map +1 -1
  25. package/dist/core/entities/workflow-run.d.ts +17 -0
  26. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  27. package/dist/core/entities/workflow-run.js.map +1 -1
  28. package/dist/core/errors.d.ts +9 -2
  29. package/dist/core/errors.d.ts.map +1 -1
  30. package/dist/core/errors.js +10 -5
  31. package/dist/core/errors.js.map +1 -1
  32. package/dist/core/job-execution.d.ts.map +1 -1
  33. package/dist/core/job-execution.js +14 -8
  34. package/dist/core/job-execution.js.map +1 -1
  35. package/dist/core/job-transition/decide-job-activation.d.ts +1 -0
  36. package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -1
  37. package/dist/core/job-transition/decide-job-activation.js +1 -0
  38. package/dist/core/job-transition/decide-job-activation.js.map +1 -1
  39. package/dist/core/job-transition/derive-job-success.d.ts +1 -0
  40. package/dist/core/job-transition/derive-job-success.d.ts.map +1 -1
  41. package/dist/core/job-transition/derive-job-success.js +5 -8
  42. package/dist/core/job-transition/derive-job-success.js.map +1 -1
  43. package/dist/core/listener-execution-materialization.d.ts +6 -3
  44. package/dist/core/listener-execution-materialization.d.ts.map +1 -1
  45. package/dist/core/listener-execution-materialization.js +44 -6
  46. package/dist/core/listener-execution-materialization.js.map +1 -1
  47. package/dist/core/resolve-trigger-reference.d.ts +11 -0
  48. package/dist/core/resolve-trigger-reference.d.ts.map +1 -0
  49. package/dist/core/resolve-trigger-reference.js +39 -0
  50. package/dist/core/resolve-trigger-reference.js.map +1 -0
  51. package/dist/core/run-workflow.d.ts +1 -0
  52. package/dist/core/run-workflow.d.ts.map +1 -1
  53. package/dist/core/run-workflow.js +1 -0
  54. package/dist/core/run-workflow.js.map +1 -1
  55. package/dist/core/step-config/agent.d.ts +1 -2
  56. package/dist/core/step-config/agent.d.ts.map +1 -1
  57. package/dist/core/step-config/agent.js +22 -7
  58. package/dist/core/step-config/agent.js.map +1 -1
  59. package/dist/core/step-config/assemble-run-context.d.ts +19 -8
  60. package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
  61. package/dist/core/step-config/assemble-run-context.js +51 -19
  62. package/dist/core/step-config/assemble-run-context.js.map +1 -1
  63. package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -1
  64. package/dist/core/step-config/complete-step-dispatch-config.js +72 -4
  65. package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -1
  66. package/dist/core/step-config/index.d.ts +1 -0
  67. package/dist/core/step-config/index.d.ts.map +1 -1
  68. package/dist/core/step-config/index.js +1 -0
  69. package/dist/core/step-config/index.js.map +1 -1
  70. package/dist/core/step-config/materialize-job-execution-steps.d.ts +1 -1
  71. package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -1
  72. package/dist/core/step-config/materialize-job-execution-steps.js +49 -8
  73. package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -1
  74. package/dist/core/step-config/materialize-workflow-model.d.ts +3 -3
  75. package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
  76. package/dist/core/step-config/materialize-workflow-model.js +9 -5
  77. package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
  78. package/dist/core/step-config/resolve-job-execution-name.d.ts +3 -3
  79. package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -1
  80. package/dist/core/step-config/resolve-job-execution-name.js +24 -13
  81. package/dist/core/step-config/resolve-job-execution-name.js.map +1 -1
  82. package/dist/core/step-config/resolve-step-config.d.ts.map +1 -1
  83. package/dist/core/step-config/resolve-step-config.js +174 -9
  84. package/dist/core/step-config/resolve-step-config.js.map +1 -1
  85. package/dist/core/step-config/resolve-workflow-run-name.d.ts +19 -0
  86. package/dist/core/step-config/resolve-workflow-run-name.d.ts.map +1 -0
  87. package/dist/core/step-config/resolve-workflow-run-name.js +73 -0
  88. package/dist/core/step-config/resolve-workflow-run-name.js.map +1 -0
  89. package/dist/core/step-transition/decide-step-transition.js.map +1 -1
  90. package/dist/core/step-transition/evaluate-gate.d.ts +2 -1
  91. package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -1
  92. package/dist/core/step-transition/evaluate-gate.js +5 -3
  93. package/dist/core/step-transition/evaluate-gate.js.map +1 -1
  94. package/dist/core/workflow-run-creation.d.ts +3 -0
  95. package/dist/core/workflow-run-creation.d.ts.map +1 -1
  96. package/dist/core/workflow-run-creation.js +22 -7
  97. package/dist/core/workflow-run-creation.js.map +1 -1
  98. package/dist/db/db.d.ts +278 -10
  99. package/dist/db/db.d.ts.map +1 -1
  100. package/dist/db/db.js +2 -0
  101. package/dist/db/db.js.map +1 -1
  102. package/dist/db/index.d.ts +3 -2
  103. package/dist/db/index.d.ts.map +1 -1
  104. package/dist/db/index.js +2 -1
  105. package/dist/db/index.js.map +1 -1
  106. package/dist/db/job-listener-events.d.ts +2 -0
  107. package/dist/db/job-listener-events.d.ts.map +1 -1
  108. package/dist/db/job-listener-events.js +1 -0
  109. package/dist/db/job-listener-events.js.map +1 -1
  110. package/dist/db/job-listeners.d.ts +2 -0
  111. package/dist/db/job-listeners.d.ts.map +1 -1
  112. package/dist/db/job-listeners.js +81 -21
  113. package/dist/db/job-listeners.js.map +1 -1
  114. package/dist/db/schema/job-executions.d.ts +3 -3
  115. package/dist/db/schema/job-executions.d.ts.map +1 -1
  116. package/dist/db/schema/job-executions.js +8 -4
  117. package/dist/db/schema/job-executions.js.map +1 -1
  118. package/dist/db/schema/job-listener-events.d.ts +20 -0
  119. package/dist/db/schema/job-listener-events.d.ts.map +1 -1
  120. package/dist/db/schema/job-listener-events.js +2 -0
  121. package/dist/db/schema/job-listener-events.js.map +1 -1
  122. package/dist/db/schema/step-attempts.js +2 -2
  123. package/dist/db/schema/step-attempts.js.map +1 -1
  124. package/dist/db/schema/steps.d.ts +4 -2
  125. package/dist/db/schema/steps.d.ts.map +1 -1
  126. package/dist/db/schema/steps.js +1 -1
  127. package/dist/db/schema/steps.js.map +1 -1
  128. package/dist/db/schema/workflow-run-attempts.d.ts +21 -2
  129. package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -1
  130. package/dist/db/schema/workflow-run-attempts.js +2 -0
  131. package/dist/db/schema/workflow-run-attempts.js.map +1 -1
  132. package/dist/db/schema/workflow-run-counters.d.ts +43 -0
  133. package/dist/db/schema/workflow-run-counters.d.ts.map +1 -0
  134. package/dist/db/schema/workflow-run-counters.js +10 -0
  135. package/dist/db/schema/workflow-run-counters.js.map +1 -0
  136. package/dist/db/schema/workflow-runs.d.ts +54 -1
  137. package/dist/db/schema/workflow-runs.d.ts.map +1 -1
  138. package/dist/db/schema/workflow-runs.js +10 -2
  139. package/dist/db/schema/workflow-runs.js.map +1 -1
  140. package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
  141. package/dist/db/workflow-runs/job-executions.js +35 -14
  142. package/dist/db/workflow-runs/job-executions.js.map +1 -1
  143. package/dist/db/workflow-runs/jobs.d.ts +2 -0
  144. package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
  145. package/dist/db/workflow-runs/jobs.js +9 -5
  146. package/dist/db/workflow-runs/jobs.js.map +1 -1
  147. package/dist/db/workflow-runs/queries.d.ts +51 -0
  148. package/dist/db/workflow-runs/queries.d.ts.map +1 -1
  149. package/dist/db/workflow-runs/queries.js +82 -2
  150. package/dist/db/workflow-runs/queries.js.map +1 -1
  151. package/dist/db/workflow-runs/run-create.d.ts +1 -0
  152. package/dist/db/workflow-runs/run-create.d.ts.map +1 -1
  153. package/dist/db/workflow-runs/run-create.js +159 -32
  154. package/dist/db/workflow-runs/run-create.js.map +1 -1
  155. package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -1
  156. package/dist/db/workflow-runs/run-rerun.js +13 -5
  157. package/dist/db/workflow-runs/run-rerun.js.map +1 -1
  158. package/dist/db/workflow-runs/shared.d.ts +1 -0
  159. package/dist/db/workflow-runs/shared.d.ts.map +1 -1
  160. package/dist/db/workflow-runs/shared.js +2 -1
  161. package/dist/db/workflow-runs/shared.js.map +1 -1
  162. package/dist/db/workflow-runs/steps.js +3 -3
  163. package/dist/db/workflow-runs/steps.js.map +1 -1
  164. package/dist/db/workflow-runs.d.ts +4 -3
  165. package/dist/db/workflow-runs.d.ts.map +1 -1
  166. package/dist/db/workflow-runs.js +3 -2
  167. package/dist/db/workflow-runs.js.map +1 -1
  168. package/dist/metrics/instance.d.ts +1 -0
  169. package/dist/metrics/instance.d.ts.map +1 -1
  170. package/dist/metrics/instance.js +9 -0
  171. package/dist/metrics/instance.js.map +1 -1
  172. package/dist/presentation/dto/checkout-token.d.ts +1 -0
  173. package/dist/presentation/dto/checkout-token.d.ts.map +1 -1
  174. package/dist/presentation/dto/checkout-token.js +1 -0
  175. package/dist/presentation/dto/checkout-token.js.map +1 -1
  176. package/dist/presentation/dto/index.d.ts +1 -1
  177. package/dist/presentation/dto/index.d.ts.map +1 -1
  178. package/dist/presentation/dto/index.js +1 -1
  179. package/dist/presentation/dto/index.js.map +1 -1
  180. package/dist/presentation/dto/step.d.ts.map +1 -1
  181. package/dist/presentation/dto/step.js +2 -2
  182. package/dist/presentation/dto/step.js.map +1 -1
  183. package/dist/presentation/dto/workflow-run.d.ts +3 -1
  184. package/dist/presentation/dto/workflow-run.d.ts.map +1 -1
  185. package/dist/presentation/dto/workflow-run.js +34 -0
  186. package/dist/presentation/dto/workflow-run.js.map +1 -1
  187. package/dist/presentation/inter-module.d.ts.map +1 -1
  188. package/dist/presentation/inter-module.js +31 -3
  189. package/dist/presentation/inter-module.js.map +1 -1
  190. package/dist/presentation/routes/checkout-token.d.ts +1 -1
  191. package/dist/presentation/routes/checkout-token.d.ts.map +1 -1
  192. package/dist/presentation/routes/checkout-token.js +32 -20
  193. package/dist/presentation/routes/checkout-token.js.map +1 -1
  194. package/dist/presentation/routes/leased-step.d.ts +2 -0
  195. package/dist/presentation/routes/leased-step.d.ts.map +1 -1
  196. package/dist/presentation/routes/leased-step.js +2 -1
  197. package/dist/presentation/routes/leased-step.js.map +1 -1
  198. package/dist/presentation/routes/list-runs.d.ts.map +1 -1
  199. package/dist/presentation/routes/list-runs.js +9 -3
  200. package/dist/presentation/routes/list-runs.js.map +1 -1
  201. package/dist/presentation/routes/project-access.d.ts +1 -0
  202. package/dist/presentation/routes/project-access.d.ts.map +1 -1
  203. package/dist/presentation/routes/report-step.d.ts.map +1 -1
  204. package/dist/presentation/routes/report-step.js +9 -2
  205. package/dist/presentation/routes/report-step.js.map +1 -1
  206. package/dist/presentation/subscribers/on-job-steps-settled.js +1 -1
  207. package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -1
  208. package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -1
  209. package/dist/presentation/subscribers/on-runner-job-claimed.js +21 -0
  210. package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -1
  211. package/dist/temporal/activities/index.d.ts.map +1 -1
  212. package/dist/temporal/activities/index.js +2 -1
  213. package/dist/temporal/activities/index.js.map +1 -1
  214. package/dist/temporal/activities/orchestration-activities.d.ts +1 -0
  215. package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
  216. package/dist/temporal/activities/orchestration-activities.js.map +1 -1
  217. package/dist/temporal/constants.d.ts +1 -0
  218. package/dist/temporal/constants.d.ts.map +1 -1
  219. package/dist/temporal/constants.js +1 -0
  220. package/dist/temporal/constants.js.map +1 -1
  221. package/dist/temporal/index.d.ts +1 -1
  222. package/dist/temporal/index.d.ts.map +1 -1
  223. package/dist/temporal/index.js +1 -1
  224. package/dist/temporal/index.js.map +1 -1
  225. package/dist/temporal/workflows/index.bundle.js +82 -43
  226. package/dist/temporal/workflows/index.d.ts +1 -1
  227. package/dist/temporal/workflows/index.d.ts.map +1 -1
  228. package/dist/temporal/workflows/index.js +1 -1
  229. package/dist/temporal/workflows/index.js.map +1 -1
  230. package/dist/temporal/workflows/job-execution-orchestration.d.ts +5 -0
  231. package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -1
  232. package/dist/temporal/workflows/job-execution-orchestration.js +77 -43
  233. package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -1
  234. package/dist/temporal/workflows/test-env.d.ts +5 -1
  235. package/dist/temporal/workflows/test-env.d.ts.map +1 -1
  236. package/dist/temporal/workflows/test-env.js +32 -11
  237. package/dist/temporal/workflows/test-env.js.map +1 -1
  238. package/dist/tsconfig.test.tsbuildinfo +1 -1
  239. package/drizzle/0000_initial.sql +14 -2
  240. package/drizzle/0001_windy_sunfire.sql +1 -0
  241. package/drizzle/meta/0000_snapshot.json +93 -1
  242. package/drizzle/meta/0001_snapshot.json +1711 -0
  243. package/drizzle/meta/_journal.json +2 -2
  244. package/package.json +19 -19
  245. package/src/core/agent-defaults.ts +2 -1
  246. package/src/core/checkout.test.ts +378 -67
  247. package/src/core/checkout.ts +142 -59
  248. package/src/core/entities/job-execution.test.ts +21 -0
  249. package/src/core/entities/job-execution.ts +24 -0
  250. package/src/core/entities/job-listener-event.ts +3 -0
  251. package/src/core/entities/step.ts +15 -3
  252. package/src/core/entities/workflow-run-attempt.ts +1 -0
  253. package/src/core/entities/workflow-run.ts +16 -0
  254. package/src/core/errors.ts +21 -7
  255. package/src/core/job-execution.ts +27 -4
  256. package/src/core/job-transition/decide-job-activation.test.ts +4 -0
  257. package/src/core/job-transition/decide-job-activation.ts +2 -0
  258. package/src/core/job-transition/derive-job-success.test.ts +12 -0
  259. package/src/core/job-transition/derive-job-success.ts +6 -9
  260. package/src/core/listener-execution-materialization.test.ts +2 -0
  261. package/src/core/listener-execution-materialization.ts +57 -11
  262. package/src/core/resolve-trigger-reference.test.ts +160 -0
  263. package/src/core/resolve-trigger-reference.ts +53 -0
  264. package/src/core/run-workflow.ts +2 -0
  265. package/src/core/step-config/agent.ts +29 -12
  266. package/src/core/step-config/assemble-run-context.test.ts +149 -6
  267. package/src/core/step-config/assemble-run-context.ts +87 -25
  268. package/src/core/step-config/complete-step-dispatch-config.test.ts +125 -2
  269. package/src/core/step-config/complete-step-dispatch-config.ts +83 -1
  270. package/src/core/step-config/index.ts +7 -0
  271. package/src/core/step-config/materialize-job-execution-steps.test.ts +250 -1
  272. package/src/core/step-config/materialize-job-execution-steps.ts +57 -10
  273. package/src/core/step-config/materialize-workflow-model.test.ts +212 -4
  274. package/src/core/step-config/materialize-workflow-model.ts +33 -28
  275. package/src/core/step-config/resolve-job-execution-name.test.ts +37 -15
  276. package/src/core/step-config/resolve-job-execution-name.ts +30 -15
  277. package/src/core/step-config/resolve-step-config.ts +175 -10
  278. package/src/core/step-config/resolve-workflow-run-name.test.ts +115 -0
  279. package/src/core/step-config/resolve-workflow-run-name.ts +108 -0
  280. package/src/core/step-transition/decide-step-transition.ts +2 -2
  281. package/src/core/step-transition/evaluate-gate.test.ts +8 -0
  282. package/src/core/step-transition/evaluate-gate.ts +8 -1
  283. package/src/core/workflow-run-creation.test.ts +7 -4
  284. package/src/core/workflow-run-creation.ts +13 -7
  285. package/src/db/db.ts +2 -0
  286. package/src/db/index.ts +6 -0
  287. package/src/db/job-listener-events.test.ts +19 -0
  288. package/src/db/job-listener-events.ts +3 -0
  289. package/src/db/job-listeners.test.ts +187 -5
  290. package/src/db/job-listeners.ts +122 -30
  291. package/src/db/schema/job-executions.ts +12 -5
  292. package/src/db/schema/job-listener-events.ts +3 -0
  293. package/src/db/schema/step-attempts.ts +2 -2
  294. package/src/db/schema/steps.ts +2 -1
  295. package/src/db/schema/workflow-run-attempts.ts +2 -0
  296. package/src/db/schema/workflow-run-counters.ts +13 -0
  297. package/src/db/schema/workflow-runs.ts +11 -2
  298. package/src/db/workflow-runs/job-executions.ts +37 -15
  299. package/src/db/workflow-runs/jobs.ts +17 -4
  300. package/src/db/workflow-runs/queries.test.ts +206 -0
  301. package/src/db/workflow-runs/queries.ts +146 -2
  302. package/src/db/workflow-runs/run-create.test.ts +606 -8
  303. package/src/db/workflow-runs/run-create.ts +185 -40
  304. package/src/db/workflow-runs/run-rerun.test.ts +61 -2
  305. package/src/db/workflow-runs/run-rerun.ts +15 -5
  306. package/src/db/workflow-runs/shared.ts +2 -0
  307. package/src/db/workflow-runs/steps.ts +3 -3
  308. package/src/db/workflow-runs.ts +7 -0
  309. package/src/metrics/instance.ts +14 -0
  310. package/src/presentation/dto/checkout-token.test.ts +19 -9
  311. package/src/presentation/dto/checkout-token.ts +2 -1
  312. package/src/presentation/dto/index.ts +1 -1
  313. package/src/presentation/dto/job.test.ts +9 -0
  314. package/src/presentation/dto/step.test.ts +12 -0
  315. package/src/presentation/dto/step.ts +5 -2
  316. package/src/presentation/dto/workflow-run.ts +44 -2
  317. package/src/presentation/inter-module.test.ts +165 -0
  318. package/src/presentation/inter-module.ts +38 -4
  319. package/src/presentation/routes/checkout-token.test.ts +357 -142
  320. package/src/presentation/routes/checkout-token.ts +56 -26
  321. package/src/presentation/routes/get-run.test.ts +2 -0
  322. package/src/presentation/routes/get-step-secrets.test.ts +7 -2
  323. package/src/presentation/routes/leased-step.ts +9 -1
  324. package/src/presentation/routes/list-runs.test.ts +57 -0
  325. package/src/presentation/routes/list-runs.ts +8 -3
  326. package/src/presentation/routes/report-step.test.ts +25 -0
  327. package/src/presentation/routes/report-step.ts +10 -2
  328. package/src/presentation/subscribers/on-job-steps-settled.ts +1 -1
  329. package/src/presentation/subscribers/on-runner-job-claimed.test.ts +49 -0
  330. package/src/presentation/subscribers/on-runner-job-claimed.ts +22 -0
  331. package/src/temporal/activities/index.ts +1 -0
  332. package/src/temporal/activities/orchestration-activities.ts +1 -0
  333. package/src/temporal/constants.ts +1 -0
  334. package/src/temporal/index.ts +1 -0
  335. package/src/temporal/workflows/index.ts +1 -0
  336. package/src/temporal/workflows/job-execution-orchestration.test.ts +142 -6
  337. package/src/temporal/workflows/job-execution-orchestration.ts +99 -50
  338. package/src/temporal/workflows/run-orchestration.test.ts +1 -1
  339. package/src/temporal/workflows/test-env.ts +50 -13
  340. package/test/factories/project.ts +2 -0
  341. package/test/factories/workflow-model.ts +80 -26
  342. package/test/factories/workflow-run.ts +4 -1
  343. package/test/fixtures/agent-inter-module.ts +2 -1
  344. package/test/fixtures/job-with-steps.ts +1 -1
  345. package/tsconfig.build.tsbuildinfo +1 -1
  346. package/drizzle/0001_agent_tool_materialization.sql +0 -1
@@ -1,58 +1,51 @@
1
1
  import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';
2
2
  import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';
3
- import {getJobById, getWorkflowRunByAttemptId} from '#db/workflow-runs.js';
4
- import {
5
- CheckoutIntentUnresolvedError,
6
- JobNotFoundError,
7
- WorkflowRunNotFoundError,
8
- } from './errors.js';
3
+ import {checkoutTargetValidationIssues} from '@shipfox/workflow-document';
4
+ import {z} from 'zod';
5
+ import type {Step} from '#core/entities/step.js';
6
+ import type {WorkflowRunTriggerReference} from '#core/entities/workflow-run.js';
7
+ import {CheckoutConfigInvalidError, CheckoutIntentUnresolvedError} from './errors.js';
9
8
 
10
- export interface CheckoutIntent {
11
- workspaceId: string;
12
- connectionId: string;
13
- externalRepositoryId: string;
14
- persistCredentials: boolean;
15
- permissions: {contents: 'read' | 'write'};
16
- }
17
-
18
- /**
19
- * Resolves what to check out for a job, keyed off the authoritative `jobId`
20
- * (`workflowRunId`/`workflowRunAttemptId`/`workspaceId` in the lease claim are informational).
21
- * Chain: job attempt → run → project source metadata. Credential-free.
22
- */
23
- export async function resolveCheckoutIntent(
24
- jobId: string,
25
- projects: ProjectsModuleClient,
26
- ): Promise<CheckoutIntent> {
27
- const job = await getJobById(jobId);
28
- if (!job) throw new JobNotFoundError(jobId);
29
-
30
- const run = await getWorkflowRunByAttemptId(job.workflowRunAttemptId);
31
- if (!run) throw new WorkflowRunNotFoundError(job.workflowRunAttemptId);
9
+ const checkoutConfigSchema = z
10
+ .object({
11
+ project: z.string().uuid().optional(),
12
+ connection: z.string().min(1).optional(),
13
+ repository: z.string().min(1).optional(),
14
+ ref: z.string().min(1).optional(),
15
+ fetch_depth: z.number().int().nonnegative().optional(),
16
+ permissions: z.object({contents: z.enum(['read', 'write'])}).optional(),
17
+ persist_credentials: z.boolean().optional(),
18
+ })
19
+ .superRefine((checkout, context) => {
20
+ for (const validationIssue of checkoutTargetValidationIssues(checkout)) {
21
+ const message =
22
+ validationIssue.kind === 'project-with-connection'
23
+ ? 'Checkout project cannot be combined with a connection.'
24
+ : validationIssue.kind === 'project-with-repository'
25
+ ? 'Checkout project cannot be combined with a repository.'
26
+ : 'Checkout connection requires a repository.';
27
+ context.addIssue({
28
+ code: 'custom',
29
+ path: [validationIssue.path],
30
+ message,
31
+ });
32
+ }
33
+ });
32
34
 
33
- const {project} = await projects.getProjectById({projectId: run.projectId});
34
- if (project === null) throw new CheckoutIntentUnresolvedError(run.projectId);
35
+ type CheckoutConfig = z.infer<typeof checkoutConfigSchema>;
35
36
 
36
- return {
37
- workspaceId: project.workspaceId,
38
- connectionId: project.sourceConnectionId,
39
- externalRepositoryId: project.sourceExternalRepositoryId,
40
- persistCredentials: job.checkout.persistCredentials,
41
- permissions: job.checkout.permissions,
42
- };
43
- }
44
-
45
- /**
46
- * Resolves the job's checkout intent and exchanges it for a short-lived,
47
- * scoped checkout spec. Omitting `ref` lets the provider use the repository's
48
- * default branch while preserving the JSON-only inter-module boundary.
49
- */
50
- export async function createJobCheckoutSpec({
51
- jobId,
37
+ export async function createStepCheckoutSpec({
38
+ step,
39
+ workspaceId,
40
+ projectId,
41
+ triggerReference,
52
42
  integrations,
53
43
  projects,
54
44
  }: {
55
- jobId: string;
45
+ step: Step;
46
+ workspaceId: string;
47
+ projectId: string;
48
+ triggerReference?: WorkflowRunTriggerReference | null | undefined;
56
49
  integrations: IntegrationsModuleClient;
57
50
  projects: ProjectsModuleClient;
58
51
  }): Promise<{
@@ -62,29 +55,119 @@ export async function createJobCheckoutSpec({
62
55
  credentials?: {username: string; token: string; expiresAt: Date};
63
56
  gitAuthor?: {name: string; email: string};
64
57
  };
58
+ fetchDepth: number;
65
59
  persistCredentials: boolean;
66
60
  }> {
67
- const intent = await resolveCheckoutIntent(jobId, projects);
61
+ const checkout = parseCheckoutConfig(step);
62
+ const {project: defaultProject} = await projects.getProjectById({projectId});
63
+ if (defaultProject === null || defaultProject === undefined) {
64
+ throw new CheckoutIntentUnresolvedError({kind: 'project', value: projectId});
65
+ }
66
+
67
+ const target = await checkoutTarget({
68
+ checkout,
69
+ defaultProjectId: projectId,
70
+ defaultConnectionId: defaultProject.sourceConnectionId,
71
+ integrations,
72
+ workspaceId,
73
+ });
74
+ const resolvedTarget = await projects.resolveCheckoutTarget({
75
+ workspaceId,
76
+ defaults: {
77
+ connectionId: defaultProject.sourceConnectionId,
78
+ owner: defaultOwner(defaultProject.sourceRepositoryOwner, checkout.repository),
79
+ },
80
+ target,
81
+ });
82
+ const ref =
83
+ checkout.ref ??
84
+ (triggerReference?.project?.id === resolvedTarget.projectId
85
+ ? (triggerReference.commit ?? undefined)
86
+ : undefined);
68
87
  const response = await integrations.createCheckoutSpec({
69
- workspaceId: intent.workspaceId,
70
- connectionId: intent.connectionId,
71
- externalRepositoryId: intent.externalRepositoryId,
72
- permissions: intent.permissions,
88
+ workspaceId,
89
+ connectionId: resolvedTarget.connectionId,
90
+ externalRepositoryId: resolvedTarget.externalRepositoryId,
91
+ ...(ref === undefined ? {} : {ref}),
92
+ permissions: checkout.permissions ?? {contents: 'read'},
73
93
  });
74
- const {credentials, gitAuthor, ...checkout} = response;
94
+
75
95
  return {
76
96
  spec: {
77
- ...checkout,
78
- ...(credentials
97
+ repositoryUrl: response.repositoryUrl,
98
+ ref: response.ref,
99
+ ...(response.credentials
79
100
  ? {
80
101
  credentials: {
81
- ...credentials,
82
- expiresAt: new Date(credentials.expiresAt),
102
+ ...response.credentials,
103
+ expiresAt: new Date(response.credentials.expiresAt),
83
104
  },
84
105
  }
85
106
  : {}),
86
- ...(gitAuthor ? {gitAuthor} : {}),
107
+ ...(response.gitAuthor === undefined ? {} : {gitAuthor: response.gitAuthor}),
87
108
  },
88
- persistCredentials: intent.persistCredentials,
109
+ fetchDepth: checkout.fetch_depth ?? 1,
110
+ persistCredentials: checkout.persist_credentials ?? true,
89
111
  };
90
112
  }
113
+
114
+ function parseCheckoutConfig(step: Step): CheckoutConfig {
115
+ const result = checkoutConfigSchema.safeParse(step.config.checkout);
116
+ if (!result.success) {
117
+ throw new CheckoutConfigInvalidError(step.id);
118
+ }
119
+ return result.data;
120
+ }
121
+
122
+ async function checkoutTarget(params: {
123
+ checkout: CheckoutConfig;
124
+ defaultProjectId: string;
125
+ defaultConnectionId: string;
126
+ integrations: IntegrationsModuleClient;
127
+ workspaceId: string;
128
+ }) {
129
+ const {checkout} = params;
130
+ if (checkout.project !== undefined) return {project: checkout.project};
131
+ if (checkout.repository !== undefined) {
132
+ const connection =
133
+ checkout.connection === undefined
134
+ ? undefined
135
+ : await resolveConnectionId({
136
+ integrations: params.integrations,
137
+ workspaceId: params.workspaceId,
138
+ defaultConnectionId: params.defaultConnectionId,
139
+ slug: checkout.connection,
140
+ });
141
+ return {
142
+ ...(connection === undefined ? {} : {connection}),
143
+ repository: checkout.repository,
144
+ };
145
+ }
146
+ return {project: params.defaultProjectId};
147
+ }
148
+
149
+ async function resolveConnectionId(params: {
150
+ integrations: IntegrationsModuleClient;
151
+ workspaceId: string;
152
+ defaultConnectionId: string;
153
+ slug: string;
154
+ }): Promise<string> {
155
+ const connection = await params.integrations.resolveConnection({
156
+ workspaceId: params.workspaceId,
157
+ slug: params.slug,
158
+ });
159
+ if (connection === null) {
160
+ throw new CheckoutIntentUnresolvedError({kind: 'connection', value: params.slug});
161
+ }
162
+ return connection.id;
163
+ }
164
+
165
+ function defaultOwner(
166
+ projectOwner: string | null | undefined,
167
+ repository: string | undefined,
168
+ ): string {
169
+ if (projectOwner) return projectOwner;
170
+ const separator = repository?.indexOf('/') ?? -1;
171
+ if (separator > 0 && repository !== undefined) return repository.slice(0, separator);
172
+ return 'unknown';
173
+ }
@@ -0,0 +1,21 @@
1
+ import {normalizeWorkflowExecutionEvent} from './job-execution.js';
2
+
3
+ describe('normalizeWorkflowExecutionEvent', () => {
4
+ it('fills null reference fields for legacy persisted events', () => {
5
+ const legacyEvent = {
6
+ source: 'github',
7
+ event: 'push',
8
+ delivery_id: 'delivery-1',
9
+ received_at: '2026-07-20T12:00:00.000Z',
10
+ data: {ref: 'refs/heads/main'},
11
+ };
12
+
13
+ expect(normalizeWorkflowExecutionEvent(legacyEvent)).toEqual({
14
+ ...legacyEvent,
15
+ project: null,
16
+ repository: null,
17
+ ref: null,
18
+ commit: null,
19
+ });
20
+ });
21
+ });
@@ -1,5 +1,6 @@
1
1
  import type {JobStatus, JobStatusReason} from './job.js';
2
2
  import type {PersistedEvaluationTraceEntry} from './step.js';
3
+ import type {WorkflowRunTriggerReference} from './workflow-run.js';
3
4
 
4
5
  export type JobExecutionStatus = Exclude<JobStatus, 'skipped'>;
5
6
 
@@ -8,13 +9,36 @@ export interface WorkflowExecutionEvent {
8
9
  event: string;
9
10
  delivery_id: string;
10
11
  received_at: string;
12
+ project: WorkflowRunTriggerReference['project'];
13
+ repository: WorkflowRunTriggerReference['repository'];
14
+ ref: WorkflowRunTriggerReference['ref'];
15
+ commit: WorkflowRunTriggerReference['commit'];
11
16
  data: unknown;
12
17
  }
13
18
 
19
+ export function normalizeWorkflowExecutionEvent(
20
+ event: Omit<WorkflowExecutionEvent, 'project' | 'repository' | 'ref' | 'commit'> &
21
+ Partial<Pick<WorkflowExecutionEvent, 'project' | 'repository' | 'ref' | 'commit'>>,
22
+ ): WorkflowExecutionEvent {
23
+ return {
24
+ source: event.source,
25
+ event: event.event,
26
+ delivery_id: event.delivery_id,
27
+ received_at: event.received_at,
28
+ project: event.project ?? null,
29
+ repository: event.repository ?? null,
30
+ ref: event.ref ?? null,
31
+ commit: event.commit ?? null,
32
+ data: event.data,
33
+ };
34
+ }
35
+
14
36
  export interface JobExecution {
15
37
  id: string;
16
38
  jobId: string;
17
39
  sequence: number;
40
+ /** A dynamically resolved name; null means use the parent job's fallback. */
41
+ nameOverride: string | null;
18
42
  name: string;
19
43
  runner: string[] | null;
20
44
  status: JobExecutionStatus;
@@ -1,3 +1,5 @@
1
+ import type {WorkflowRunTriggerReference} from './workflow-run.js';
2
+
1
3
  export type JobListenerEventDisposition = 'fire' | 'resolve';
2
4
 
3
5
  export interface JobListenerEvent {
@@ -8,6 +10,7 @@ export interface JobListenerEvent {
8
10
  deliveryId: string;
9
11
  source: string;
10
12
  event: string;
13
+ triggerReference: WorkflowRunTriggerReference | null;
11
14
  payload: unknown;
12
15
  receivedAt: Date;
13
16
  consumedByExecutionId: string | null;
@@ -8,11 +8,15 @@ import type {
8
8
  ResolvedField,
9
9
  WorkflowExpression,
10
10
  } from '@shipfox/expression';
11
- import type {AgentThinking, Harness} from '@shipfox/workflow-document';
11
+ import type {Harness} from '@shipfox/workflow-document';
12
12
  import type {InterpolationUnresolvableField} from '../errors.js';
13
13
 
14
14
  export type StepStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';
15
15
 
16
+ export const STEP_TYPES = ['setup', 'run', 'agent', 'checkout'] as const;
17
+
18
+ export type StepType = (typeof STEP_TYPES)[number];
19
+
16
20
  export const STEP_STATUS_REASONS = [
17
21
  'default_gate_rejected',
18
22
  'condition_rejected',
@@ -61,14 +65,22 @@ export interface StepConfigEvaluationTraceEntry extends EvaluationTraceEntry {
61
65
  }
62
66
 
63
67
  export interface StepConfigDispatchPlan {
68
+ working_directory?: ResolvedField;
64
69
  run?: ResolvedField;
65
70
  env?: Readonly<Record<string, ResolvedField>>;
71
+ checkout?: {
72
+ project?: ResolvedField;
73
+ connection?: ResolvedField;
74
+ repository?: ResolvedField;
75
+ ref?: ResolvedField;
76
+ path?: ResolvedField;
77
+ };
66
78
  agent?: {
67
79
  prompt?: ResolvedField;
68
80
  model?: ResolvedField;
69
81
  provider?: ResolvedField;
70
82
  harness?: Harness;
71
- thinking?: AgentThinking;
83
+ thinking?: ResolvedField;
72
84
  tools?: readonly string[];
73
85
  integrations?: readonly MaterializedAgentIntegrationConfigDto[];
74
86
  mcpServers?: readonly AgentIntegrationMcpServerConfigDto[];
@@ -85,7 +97,7 @@ export interface Step {
85
97
  status: StepStatus;
86
98
  statusReason: StepStatusReason | null;
87
99
  evaluationTrace: readonly PersistedEvaluationTraceEntry[] | null;
88
- type: string;
100
+ type: StepType;
89
101
  config: Record<string, unknown>;
90
102
  condition: WorkflowExpression | null;
91
103
  configPlan: StepConfigDispatchPlan | null;
@@ -12,6 +12,7 @@ export interface WorkflowRunAttempt {
12
12
  rerunMode: RerunMode | null;
13
13
  rerunByUserId: string | null;
14
14
  model: WorkflowModel | null;
15
+ vars: Record<string, string> | null;
15
16
  agentToolMaterialization: AgentToolMaterializationSnapshot | null;
16
17
  version: number;
17
18
  createdAt: Date;
@@ -22,6 +22,14 @@ export function isWorkflowRunTerminal(
22
22
  return TERMINAL_WORKFLOW_RUN_STATUSES.has(status);
23
23
  }
24
24
 
25
+ export interface WorkflowRunTriggerReference {
26
+ project: {id: string} | null;
27
+ repository: string | null;
28
+ ref: string | null;
29
+ commit: string | null;
30
+ actor: string | null;
31
+ }
32
+
25
33
  export interface WorkflowSourceSnapshot {
26
34
  content: string;
27
35
  format: 'yaml';
@@ -57,13 +65,21 @@ export interface WorkflowRun {
57
65
  workspaceId: string;
58
66
  projectId: string;
59
67
  definitionId: string;
68
+ number: number;
69
+ /** Effective runtime name: the resolved override, or workflowName when absent. */
60
70
  name: string;
71
+ /** Static workflow-name snapshot preserved from the definition at creation. */
72
+ workflowName: string;
73
+ /** Nullable resolved override retained for rerun fidelity. */
74
+ nameOverride: string | null;
61
75
  status: WorkflowRunStatus;
62
76
  currentAttempt: number;
63
77
  triggerProvider: string | null;
64
78
  triggerSource: string;
65
79
  triggerEvent: string;
66
80
  triggerPayload: TriggerPayload;
81
+ /** Provider-neutral trigger facts captured at run creation, when available. */
82
+ triggerReference?: WorkflowRunTriggerReference | null | undefined;
67
83
  inputs: Record<string, unknown> | null;
68
84
  sourceSnapshot: WorkflowSourceSnapshot | null;
69
85
  triggerIdempotencyKey: string | null;
@@ -61,11 +61,19 @@ export type InterpolationUnresolvableField =
61
61
  | 'agent.prompt'
62
62
  | 'agent.model'
63
63
  | 'agent.provider'
64
+ | 'agent.thinking'
64
65
  | 'job.runner'
65
66
  | 'job.outputs'
66
- | 'job.name'
67
+ | 'job.execution_name'
68
+ | 'workflow.run_name'
67
69
  | 'step.name'
68
- | 'step.feedback';
70
+ | 'step.working_directory'
71
+ | 'step.feedback'
72
+ | 'checkout.project'
73
+ | 'checkout.connection'
74
+ | 'checkout.repository'
75
+ | 'checkout.ref'
76
+ | 'checkout.path';
69
77
 
70
78
  export class InterpolationUnresolvableError extends Error {
71
79
  readonly field: InterpolationUnresolvableField;
@@ -182,15 +190,21 @@ export class NoFailedJobsError extends Error {
182
190
  }
183
191
  }
184
192
 
185
- // The run's project (and therefore its source repository) cannot be resolved, so
186
- // there is nothing to check out.
193
+ // The checkout target cannot be resolved, so there is nothing to check out.
187
194
  export class CheckoutIntentUnresolvedError extends Error {
188
- constructor(projectId: string) {
189
- super(`Checkout intent unresolved: project ${projectId} not found`);
195
+ constructor(target: {kind: 'project' | 'connection'; value: string}) {
196
+ super(`Checkout intent unresolved: ${target.kind} ${target.value} not found`);
190
197
  this.name = 'CheckoutIntentUnresolvedError';
191
198
  }
192
199
  }
193
200
 
201
+ export class CheckoutConfigInvalidError extends Error {
202
+ constructor(readonly stepId: string) {
203
+ super(`Checkout config is invalid for step ${stepId}`);
204
+ this.name = 'CheckoutConfigInvalidError';
205
+ }
206
+ }
207
+
194
208
  export class StepNotFoundError extends Error {
195
209
  constructor(stepId: string, jobId: string) {
196
210
  super(`Step ${stepId} not found in job ${jobId}`);
@@ -207,7 +221,7 @@ export class StepNotRunningError extends Error {
207
221
 
208
222
  // A report whose attempt is ahead of the step's current attempt. The host
209
223
  // allocates attempt numbers, so a runner can never report one it was not
210
- // dispatched this is a protocol error, not an idempotent no-op.
224
+ // dispatched: this is a protocol error, not an idempotent no-op.
211
225
  export class StepAttemptAheadError extends Error {
212
226
  constructor(
213
227
  readonly stepId: string,
@@ -15,6 +15,7 @@ import {
15
15
  getLatestJobExecutionByJobId,
16
16
  getStepAttemptsByJobExecutionId,
17
17
  getStepsByJobExecutionIdForUpdate,
18
+ getWorkflowContextForJob,
18
19
  insertRunningStepAttempt,
19
20
  markStepRunning,
20
21
  markStepSkipped,
@@ -91,6 +92,7 @@ interface ResolvePendingStepParams {
91
92
  readonly jobExecution: JobExecution;
92
93
  readonly attempts: Awaited<ReturnType<typeof getStepAttemptsByJobExecutionId>>;
93
94
  readonly jobs: Awaited<ReturnType<typeof getDirectDependencyJobContexts>>;
95
+ readonly vars: Record<string, string> | undefined;
94
96
  readonly tx: Tx;
95
97
  readonly agent?: AgentInterModuleClient | undefined;
96
98
  }
@@ -130,8 +132,18 @@ async function nextStepForJobExecutionInTransaction(
130
132
 
131
133
  const attempts = await getStepAttemptsByJobExecutionId(jobExecutionId, tx);
132
134
  const jobs = await getDirectDependencyJobContexts(jobExecution.jobId, tx);
135
+ const workflowContext = await getWorkflowContextForJob(jobExecution.jobId, tx);
133
136
 
134
- return resolveNextPendingStep({jobExecutionId, steps, jobExecution, attempts, jobs, tx, agent});
137
+ return resolveNextPendingStep({
138
+ jobExecutionId,
139
+ steps,
140
+ jobExecution,
141
+ attempts,
142
+ jobs,
143
+ vars: workflowContext.vars ?? undefined,
144
+ tx,
145
+ agent,
146
+ });
135
147
  }
136
148
 
137
149
  async function resolveNextPendingStep({
@@ -140,6 +152,7 @@ async function resolveNextPendingStep({
140
152
  jobExecution,
141
153
  attempts,
142
154
  jobs,
155
+ vars,
143
156
  tx,
144
157
  agent,
145
158
  }: ResolvePendingStepParams): Promise<NextStep> {
@@ -167,6 +180,7 @@ async function resolveNextPendingStep({
167
180
  targetStepId: pending.id,
168
181
  jobExecution,
169
182
  jobs,
183
+ vars,
170
184
  });
171
185
  const condition = evaluateStepCondition({step: pending, context});
172
186
  if (condition.kind === 'run') {
@@ -454,11 +468,17 @@ async function recordStepResultInTransaction(
454
468
  };
455
469
  }
456
470
 
457
- // Evaluate the gate (if any) at the service boundary the only place the CEL
458
- // engine runs and pass the precomputed outcome into the pure decision.
471
+ // Evaluate the gate (if any) at the service boundary. This is the only place
472
+ // the CEL engine runs. Pass the precomputed outcome into the pure decision.
459
473
  const shouldEvaluateGate = outputCoercion.kind !== 'failed';
460
474
  const gate = shouldEvaluateGate ? readStepGate(target.config) : undefined;
461
- const gateOutcome = shouldEvaluateGate ? evaluateGate(gate, result) : {kind: 'no-gate' as const};
475
+ const vars =
476
+ gate === undefined
477
+ ? undefined
478
+ : ((await getWorkflowContextForJob(jobExecution.jobId, tx)).vars ?? undefined);
479
+ const gateOutcome = shouldEvaluateGate
480
+ ? evaluateGate(gate, result, vars)
481
+ : {kind: 'no-gate' as const};
462
482
  const hasRestartPolicy = gate?.onFailure?.restartFrom !== undefined;
463
483
  // The restart cap is bounded on the gating step's OWN attempts, not its
464
484
  // current_attempt (which a rewind inflates for downstream steps).
@@ -479,6 +499,7 @@ async function recordStepResultInTransaction(
479
499
  gate,
480
500
  result,
481
501
  definitionId: jobExecution.jobId,
502
+ vars,
482
503
  });
483
504
 
484
505
  return applyStepTransition(
@@ -548,6 +569,7 @@ function resolveRestartFeedback(params: {
548
569
  gate: ReturnType<typeof readStepGate>;
549
570
  result: ReportedStepResult;
550
571
  definitionId: string;
572
+ vars?: Record<string, string> | undefined;
551
573
  }): StepTransitionDecision {
552
574
  if (params.decision.kind !== 'restart-job-from-step') return params.decision;
553
575
  if (params.gate === undefined) return params.decision;
@@ -559,6 +581,7 @@ function resolveRestartFeedback(params: {
559
581
  gate: params.gate,
560
582
  result: params.result,
561
583
  definitionId: params.definitionId,
584
+ vars: params.vars,
562
585
  }),
563
586
  };
564
587
  } catch (error) {
@@ -113,10 +113,13 @@ function expression(source: string) {
113
113
  function workflowRun(): WorkflowRun {
114
114
  return {
115
115
  id: crypto.randomUUID(),
116
+ number: 1,
116
117
  workspaceId: crypto.randomUUID(),
117
118
  projectId: crypto.randomUUID(),
118
119
  definitionId: crypto.randomUUID(),
119
120
  name: 'Run',
121
+ workflowName: 'Run',
122
+ nameOverride: null,
120
123
  status: 'pending',
121
124
  currentAttempt: 1,
122
125
  triggerProvider: null,
@@ -179,6 +182,7 @@ export function jobExecution(params: Partial<JobExecution> = {}): JobExecution {
179
182
  id: crypto.randomUUID(),
180
183
  jobId: params.jobId ?? crypto.randomUUID(),
181
184
  sequence: params.sequence ?? 1,
185
+ nameOverride: params.nameOverride ?? params.name ?? 'build',
182
186
  name: params.name ?? 'build',
183
187
  runner: null,
184
188
  status: params.status ?? 'succeeded',
@@ -34,6 +34,7 @@ export interface DecideJobActivationInput {
34
34
  job: Job;
35
35
  condition?: WorkflowExpression | undefined;
36
36
  dependencies: readonly JobContextInput[];
37
+ vars?: Record<string, string> | undefined;
37
38
  }
38
39
 
39
40
  export function decideJobActivation(input: DecideJobActivationInput): JobActivationDecision {
@@ -52,6 +53,7 @@ export function decideJobActivation(input: DecideJobActivationInput): JobActivat
52
53
  run: input.run,
53
54
  triggerPayload: input.run.triggerPayload,
54
55
  inputs: input.run.inputs,
56
+ vars: input.vars,
55
57
  jobs: input.dependencies,
56
58
  });
57
59
  const outcome = evaluatePlannedPredicateAtSite({
@@ -52,6 +52,17 @@ describe('deriveJobSuccess', () => {
52
52
  expect(result).toMatchObject({status: 'succeeded', statusReason: null});
53
53
  });
54
54
 
55
+ test('resolves vars from the run-creation snapshot', () => {
56
+ const result = deriveJobSuccess({
57
+ success: 'vars.RELEASE == "yes"',
58
+ executions: [jobExecution({status: 'succeeded'})],
59
+ jobs: [],
60
+ vars: {RELEASE: 'yes'},
61
+ });
62
+
63
+ expect(result).toMatchObject({status: 'succeeded', statusReason: null});
64
+ });
65
+
55
66
  test('fails closed when the success expression throws at runtime', () => {
56
67
  const result = deriveJobSuccess({
57
68
  success: 'executions.all(e, 1 / 0 == 0)',
@@ -116,6 +127,7 @@ function jobExecution(params: Partial<JobExecution> = {}): JobExecution {
116
127
  id: crypto.randomUUID(),
117
128
  jobId: params.jobId ?? crypto.randomUUID(),
118
129
  sequence: params.sequence ?? 1,
130
+ nameOverride: params.nameOverride ?? params.name ?? 'build',
119
131
  name: params.name ?? 'build',
120
132
  runner: null,
121
133
  status: params.status ?? 'succeeded',
@@ -9,8 +9,7 @@ import type {JobStatusReason} from '../entities/job.js';
9
9
  import type {JobExecution} from '../entities/job-execution.js';
10
10
  import type {PersistedEvaluationTraceEntry} from '../entities/step.js';
11
11
  import {
12
- assembleExecutionsContext,
13
- assembleJobsContext,
12
+ assembleJobResolutionContext,
14
13
  type JobContextInput,
15
14
  } from '../step-config/assemble-run-context.js';
16
15
  import type {RuntimeCompletionStatus} from '../workflow-scheduling/runtime-dag.js';
@@ -25,27 +24,25 @@ export function deriveJobSuccess(params: {
25
24
  success: string | null;
26
25
  executions: readonly JobExecution[];
27
26
  jobs: readonly JobContextInput[];
27
+ vars?: Record<string, string> | undefined;
28
28
  }): DeriveJobSuccessResult {
29
29
  const expression = createWorkflowExpression({
30
30
  source: params.success ?? DEFAULT_JOB_SUCCESS,
31
31
  check: {mode: 'syntax'},
32
32
  });
33
- const context = {
34
- ...assembleExecutionsContext(params.executions),
35
- ...assembleJobsContext(params.jobs),
36
- };
33
+ const context = assembleJobResolutionContext(params);
37
34
  const outcome = evaluatePlannedPredicateAtSite({
38
35
  expression,
39
36
  field: 'job.success',
40
- site: 'job-resolution',
41
- context,
37
+ site: context.site,
38
+ context: context.values,
42
39
  });
43
40
  const trace = capTraceEntries([
44
41
  {
45
42
  ...predicateTraceEntry({
46
43
  expression: expression.source,
47
44
  route: outcome.route,
48
- site: 'job-resolution',
45
+ site: context.site,
49
46
  value: outcome.value,
50
47
  degraded: outcome.evaluationFailed,
51
48
  }),
@@ -21,7 +21,9 @@ describe('materializeListenerExecution', () => {
21
21
  model,
22
22
  run: {
23
23
  id: crypto.randomUUID(),
24
+ number: 1,
24
25
  name: 'Review run',
26
+ workflowName: 'Review run',
25
27
  definitionId: crypto.randomUUID(),
26
28
  projectId: crypto.randomUUID(),
27
29
  workspaceId: crypto.randomUUID(),