@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,4 +1,5 @@
1
1
  import type {WorkflowEnvTemplates, WorkflowModel} from '@shipfox/api-definitions-dto';
2
+ import {WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS} from '@shipfox/api-definitions-dto';
2
3
  import {
3
4
  type AvailabilitySite,
4
5
  capTraceEntries,
@@ -14,6 +15,7 @@ import type {StepConfigDispatchPlan} from '#core/entities/step.js';
14
15
  import {resolveAgentStepConfig} from './agent.js';
15
16
  import {
16
17
  freezeStepField,
18
+ resolveStepField,
17
19
  type StepConfigField,
18
20
  type WorkflowStepEvaluationTraceEntry,
19
21
  type WorkflowStepTemplateDiagnostic,
@@ -25,6 +27,7 @@ type WorkflowModelJob = WorkflowModel['jobs'][number];
25
27
  type WorkflowModelStep = WorkflowModelJob['steps'][number];
26
28
  type WorkflowModelRunStep = Extract<WorkflowModelStep, {kind: 'run'}>;
27
29
  type WorkflowModelAgentStep = Extract<WorkflowModelStep, {kind: 'agent'}>;
30
+ type WorkflowModelCheckoutStep = Extract<WorkflowModelStep, {kind: 'checkout'}>;
28
31
 
29
32
  export type {StepConfigField, WorkflowStepTemplateDiagnostic};
30
33
 
@@ -62,6 +65,22 @@ interface BuiltStepConfig {
62
65
  readonly hasTemplates: boolean;
63
66
  }
64
67
 
68
+ interface WorkingDirectoryConfig {
69
+ readonly config: Record<string, unknown>;
70
+ readonly configPlan: Pick<StepConfigDispatchPlan, 'working_directory'> | undefined;
71
+ readonly diagnostics: readonly WorkflowStepTemplateDiagnostic[];
72
+ readonly trace: readonly WorkflowStepEvaluationTraceEntry[];
73
+ readonly hasTemplates: boolean;
74
+ }
75
+
76
+ interface CheckoutConfig {
77
+ readonly config: Record<string, unknown>;
78
+ readonly configPlan: Pick<StepConfigDispatchPlan, 'checkout'> | undefined;
79
+ readonly diagnostics: readonly WorkflowStepTemplateDiagnostic[];
80
+ readonly trace: readonly WorkflowStepEvaluationTraceEntry[];
81
+ readonly hasTemplates: boolean;
82
+ }
83
+
65
84
  export async function resolveStepConfig(
66
85
  params: ResolveStepConfigParams,
67
86
  ): Promise<ResolvedStepConfig> {
@@ -87,17 +106,34 @@ async function buildStepConfig(
87
106
  ): Promise<BuiltStepConfig> {
88
107
  const gate = gateConfigForStep(params.step);
89
108
  const outputs = outputsConfigForStep(params.step);
109
+ const workingDirectory = resolveWorkingDirectoryConfig(params);
90
110
  const runStep = runStepOrNull(params.step);
91
111
  const isRunStep = runStep !== null;
92
112
 
93
113
  if (isRunStep) {
94
114
  const run = resolveRunStepConfig({...params, step: runStep});
95
115
  return {
96
- config: {...run.config, ...gate, ...outputs},
97
- configPlan: run.configPlan,
98
- diagnostics: run.diagnostics,
99
- trace: run.trace,
100
- hasTemplates: run.hasTemplates,
116
+ config: {...workingDirectory.config, ...run.config, ...gate, ...outputs},
117
+ configPlan: mergeConfigPlans(run.configPlan, workingDirectory.configPlan),
118
+ diagnostics: [...workingDirectory.diagnostics, ...run.diagnostics],
119
+ trace: [...workingDirectory.trace, ...run.trace],
120
+ hasTemplates: run.hasTemplates || workingDirectory.hasTemplates,
121
+ };
122
+ }
123
+
124
+ const checkoutStep = checkoutStepOrNull(params.step);
125
+ if (checkoutStep !== null) {
126
+ const checkout = resolveCheckoutStepConfig({...params, step: checkoutStep});
127
+ return {
128
+ config: {
129
+ ...checkout.config,
130
+ ...gate,
131
+ ...outputs,
132
+ },
133
+ configPlan: checkout.configPlan === undefined ? null : checkout.configPlan,
134
+ diagnostics: checkout.diagnostics,
135
+ trace: checkout.trace,
136
+ hasTemplates: checkout.hasTemplates,
101
137
  };
102
138
  }
103
139
 
@@ -106,14 +142,81 @@ async function buildStepConfig(
106
142
 
107
143
  const agent = await resolveAgentStepConfig({...params, step: agentStep});
108
144
  return {
109
- config: {...agent.config, ...gate, ...outputs},
110
- configPlan: agent.configPlan,
111
- diagnostics: agent.diagnostics,
112
- trace: agent.trace,
113
- hasTemplates: agent.hasTemplates,
145
+ config: {...workingDirectory.config, ...agent.config, ...gate, ...outputs},
146
+ configPlan: mergeConfigPlans(agent.configPlan, workingDirectory.configPlan),
147
+ diagnostics: [...workingDirectory.diagnostics, ...agent.diagnostics],
148
+ trace: [...workingDirectory.trace, ...agent.trace],
149
+ hasTemplates: agent.hasTemplates || workingDirectory.hasTemplates,
150
+ };
151
+ }
152
+
153
+ function resolveWorkingDirectoryConfig(
154
+ params: Omit<BuildStepConfigParams, 'context'> & {readonly context: WorkflowEvaluationContext},
155
+ ): WorkingDirectoryConfig {
156
+ const value = params.step.workingDirectory;
157
+ const template = params.step.templates?.workingDirectory;
158
+ if (value === undefined) {
159
+ return {
160
+ config: {},
161
+ configPlan: undefined,
162
+ diagnostics: [],
163
+ trace: [],
164
+ hasTemplates: template !== undefined,
165
+ };
166
+ }
167
+
168
+ if (template === undefined || params.mode === 'authored') {
169
+ return {
170
+ config: {working_directory: value},
171
+ configPlan: undefined,
172
+ diagnostics: [],
173
+ trace: [],
174
+ hasTemplates: template !== undefined,
175
+ };
176
+ }
177
+
178
+ const resolved = resolveStepField({
179
+ field: 'step.working_directory',
180
+ template: {segments: template},
181
+ context: params.context,
182
+ definitionId: params.definitionId,
183
+ errorField: 'step.working_directory',
184
+ });
185
+ const trace = resolved.trace.map((entry) => ({
186
+ ...entry,
187
+ field: 'step.working_directory' as const,
188
+ }));
189
+ const diagnostics = resolved.diagnostics.map((diagnostic) => ({
190
+ ...diagnostic,
191
+ field: 'step.working_directory' as const,
192
+ }));
193
+ if (resolved.kind === 'residual') {
194
+ return {
195
+ config: {},
196
+ configPlan: {working_directory: resolved.field},
197
+ diagnostics,
198
+ trace,
199
+ hasTemplates: true,
200
+ };
201
+ }
202
+
203
+ return {
204
+ config: {working_directory: resolved.value},
205
+ configPlan: undefined,
206
+ diagnostics,
207
+ trace,
208
+ hasTemplates: true,
114
209
  };
115
210
  }
116
211
 
212
+ function mergeConfigPlans(
213
+ primary: StepConfigDispatchPlan | null,
214
+ secondary: Pick<StepConfigDispatchPlan, 'working_directory'> | undefined,
215
+ ): StepConfigDispatchPlan | null {
216
+ if (secondary === undefined) return primary;
217
+ return {...(primary ?? {}), ...secondary};
218
+ }
219
+
117
220
  function evaluationContext(params: {
118
221
  readonly context: WorkflowExpressionEvaluationContext;
119
222
  readonly site: AvailabilitySite;
@@ -131,6 +234,68 @@ function agentStepOrNull(step: WorkflowModelStep): WorkflowModelAgentStep | null
131
234
  return isAgentStep ? step : null;
132
235
  }
133
236
 
237
+ function checkoutStepOrNull(step: WorkflowModelStep): WorkflowModelCheckoutStep | null {
238
+ const isCheckoutStep = step.kind === 'checkout';
239
+ return isCheckoutStep ? step : null;
240
+ }
241
+
242
+ function resolveCheckoutStepConfig(
243
+ params: Omit<BuildStepConfigParams, 'context' | 'step'> & {
244
+ readonly context: WorkflowEvaluationContext;
245
+ readonly step: WorkflowModelCheckoutStep;
246
+ },
247
+ ): CheckoutConfig {
248
+ const checkout = params.step.checkout;
249
+ const config: Record<string, unknown> = {
250
+ fetch_depth: checkout.fetchDepth,
251
+ permissions: checkout.permissions,
252
+ persist_credentials: checkout.persistCredentials,
253
+ ...(checkout.force === undefined ? {} : {force: checkout.force}),
254
+ };
255
+ const checkoutConfig: Record<string, unknown> = config;
256
+ const checkoutPlan: NonNullable<StepConfigDispatchPlan['checkout']> = {};
257
+ const diagnostics: WorkflowStepTemplateDiagnostic[] = [];
258
+ const trace: WorkflowStepEvaluationTraceEntry[] = [];
259
+ let hasTemplates = false;
260
+
261
+ for (const [key, field] of WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS) {
262
+ const template = checkout.templates?.[key];
263
+ if (template !== undefined) hasTemplates = true;
264
+
265
+ const value = checkout[key];
266
+ if (value === undefined) continue;
267
+
268
+ if (template === undefined || params.mode === 'authored') {
269
+ checkoutConfig[key] = value;
270
+ continue;
271
+ }
272
+
273
+ const resolved = resolveStepField({
274
+ field,
275
+ template: {segments: template},
276
+ context: params.context,
277
+ definitionId: params.definitionId,
278
+ errorField: field,
279
+ });
280
+ trace.push(...resolved.trace.map((entry) => ({...entry, field})));
281
+ diagnostics.push(...resolved.diagnostics.map((diagnostic) => ({...diagnostic, field})));
282
+
283
+ if (resolved.kind === 'residual') {
284
+ checkoutPlan[key] = resolved.field;
285
+ } else {
286
+ checkoutConfig[key] = resolved.value;
287
+ }
288
+ }
289
+
290
+ return {
291
+ config: {checkout: config},
292
+ configPlan: Object.keys(checkoutPlan).length === 0 ? undefined : {checkout: checkoutPlan},
293
+ diagnostics,
294
+ trace,
295
+ hasTemplates,
296
+ };
297
+ }
298
+
134
299
  function gateConfigForStep(step: WorkflowModelStep): Record<string, unknown> {
135
300
  const hasGate = step.gate !== undefined;
136
301
  return hasGate ? {gate: stepGateConfig(step.gate)} : {};
@@ -0,0 +1,115 @@
1
+ import {workflowModel} from '#test/index.js';
2
+ import {resolveWorkflowRunName, sanitizeWorkflowDisplayText} from './resolve-workflow-run-name.js';
3
+
4
+ function template(source: string): string {
5
+ return `\${{ ${source} }}`;
6
+ }
7
+
8
+ describe('resolveWorkflowRunName', () => {
9
+ it('leaves an omitted run name unset', () => {
10
+ expect(
11
+ resolveWorkflowRunName({
12
+ runName: undefined,
13
+ context: {},
14
+ }),
15
+ ).toEqual({value: null, trace: []});
16
+ });
17
+
18
+ it('resolves a run name from trigger-event context', () => {
19
+ const model = workflowModel({runName: `Deploy ${template('event.environment')}`});
20
+
21
+ const result = resolveWorkflowRunName({
22
+ runName: model.runName,
23
+ context: {event: {environment: 'production'}},
24
+ });
25
+
26
+ expect(result).toMatchObject({
27
+ value: 'Deploy production',
28
+ trace: [
29
+ {
30
+ field: 'workflow.run_name',
31
+ expression: 'event.environment',
32
+ evaluatedAt: 'run-creation',
33
+ value: 'production',
34
+ },
35
+ ],
36
+ });
37
+ expect(result.degradation).toBeUndefined();
38
+ });
39
+
40
+ it('loads and resolves input values through the same creation context', () => {
41
+ const model = workflowModel({runName: `Deploy ${template('inputs.environment')}`});
42
+
43
+ const result = resolveWorkflowRunName({
44
+ runName: model.runName,
45
+ context: {inputs: {environment: 'staging'}},
46
+ });
47
+
48
+ expect(result.value).toBe('Deploy staging');
49
+ });
50
+
51
+ it.each([
52
+ [{event: {}}, 'missing_value'],
53
+ [{event: {environment: ''}}, 'empty_value'],
54
+ ] as const)('falls back without throwing for %s', (context, cause) => {
55
+ const model = workflowModel({runName: template('event.environment')});
56
+
57
+ const result = resolveWorkflowRunName({
58
+ runName: model.runName,
59
+ context,
60
+ });
61
+
62
+ expect(result).toMatchObject({value: null, degradation: {cause}});
63
+ });
64
+
65
+ it('sanitizes control and format characters without failing the run', () => {
66
+ const model = workflowModel({runName: template('event.environment')});
67
+
68
+ const result = resolveWorkflowRunName({
69
+ runName: model.runName,
70
+ context: {event: {environment: 'prod\u202e\nblue'}},
71
+ });
72
+
73
+ expect(result).toMatchObject({
74
+ value: 'prod blue',
75
+ degradation: {cause: 'sanitization'},
76
+ });
77
+ });
78
+
79
+ it('degrades when expression evaluation throws', () => {
80
+ const model = workflowModel({runName: template('1 / 0')});
81
+
82
+ const result = resolveWorkflowRunName({
83
+ runName: model.runName,
84
+ context: {},
85
+ });
86
+
87
+ expect(result).toMatchObject({
88
+ value: null,
89
+ degradation: {cause: 'evaluation_error', expression: '1 / 0'},
90
+ });
91
+ });
92
+
93
+ it('degrades when sanitization removes the complete resolved value', () => {
94
+ const model = workflowModel({runName: template('event.environment')});
95
+
96
+ const result = resolveWorkflowRunName({
97
+ runName: model.runName,
98
+ context: {event: {environment: '\u200b'}},
99
+ });
100
+
101
+ expect(result).toMatchObject({value: null, degradation: {cause: 'sanitization'}});
102
+ });
103
+ });
104
+
105
+ describe('sanitizeWorkflowDisplayText', () => {
106
+ it('trims and bounds display text', () => {
107
+ expect(sanitizeWorkflowDisplayText(` ${'a'.repeat(300)} `)).toBe('a'.repeat(255));
108
+ });
109
+
110
+ it('bounds by Unicode code point without splitting an emoji', () => {
111
+ const value = `${'a'.repeat(254)}😀`;
112
+
113
+ expect(sanitizeWorkflowDisplayText(value)).toBe(value);
114
+ });
115
+ });
@@ -0,0 +1,108 @@
1
+ import type {WorkflowModel} from '@shipfox/api-definitions-dto';
2
+ import {
3
+ capTraceEntries,
4
+ getWorkflowInterpolationFieldFailurePolicy,
5
+ type ResolvedFieldSegment,
6
+ resolveFieldAtSite,
7
+ type WorkflowExpressionEvaluationContext,
8
+ WorkflowTemplateResolutionError,
9
+ } from '@shipfox/expression';
10
+ import type {PersistedEvaluationTraceEntry} from '#core/entities/step.js';
11
+
12
+ const DISALLOWED_DISPLAY_CHARACTER_RE = /[\p{Cc}\p{Cf}]/gu;
13
+ const MAX_WORKFLOW_RUN_NAME_LENGTH = 255;
14
+
15
+ export type WorkflowRunNameResolutionCause =
16
+ | 'missing_value'
17
+ | 'evaluation_error'
18
+ | 'empty_value'
19
+ | 'sanitization';
20
+
21
+ export interface WorkflowRunNameDegradation {
22
+ readonly cause: WorkflowRunNameResolutionCause;
23
+ readonly expression?: string | undefined;
24
+ }
25
+
26
+ export interface ResolveWorkflowRunNameResult {
27
+ readonly value: string | null;
28
+ readonly trace: readonly PersistedEvaluationTraceEntry[];
29
+ readonly degradation?: WorkflowRunNameDegradation | undefined;
30
+ }
31
+
32
+ export function resolveWorkflowRunName(params: {
33
+ readonly runName: WorkflowModel['runName'];
34
+ readonly context: WorkflowExpressionEvaluationContext;
35
+ }): ResolveWorkflowRunNameResult {
36
+ if (params.runName === undefined) return {value: null, trace: []};
37
+
38
+ try {
39
+ const resolved = resolveFieldAtSite({
40
+ field: {segments: params.runName},
41
+ site: 'run-creation',
42
+ context: params.context,
43
+ failurePolicy: getWorkflowInterpolationFieldFailurePolicy('workflow.run_name'),
44
+ });
45
+ const trace = capTraceEntries(
46
+ resolved.trace.map((entry) => ({...entry, field: 'workflow.run_name'})),
47
+ );
48
+
49
+ if (resolved.kind !== 'frozen' || resolved.diagnostics.length > 0) {
50
+ return degraded(trace, {
51
+ cause: 'missing_value',
52
+ expression: resolved.diagnostics[0]?.expression ?? firstExpressionSource(params.runName),
53
+ });
54
+ }
55
+
56
+ if (resolved.value === '') {
57
+ return degraded(trace, {
58
+ cause: 'empty_value',
59
+ expression: firstExpressionSource(params.runName),
60
+ });
61
+ }
62
+
63
+ const sanitized = sanitizeWorkflowDisplayText(resolved.value);
64
+ if (sanitized === '') {
65
+ return degraded(trace, {
66
+ cause: 'sanitization',
67
+ expression: firstExpressionSource(params.runName),
68
+ });
69
+ }
70
+
71
+ return {
72
+ value: sanitized,
73
+ trace,
74
+ ...(sanitized === resolved.value
75
+ ? {}
76
+ : {
77
+ degradation: {
78
+ cause: 'sanitization' as const,
79
+ expression: firstExpressionSource(params.runName),
80
+ },
81
+ }),
82
+ };
83
+ } catch (error) {
84
+ return degraded([], {
85
+ cause: 'evaluation_error',
86
+ expression:
87
+ error instanceof WorkflowTemplateResolutionError
88
+ ? error.source
89
+ : firstExpressionSource(params.runName),
90
+ });
91
+ }
92
+ }
93
+
94
+ export function sanitizeWorkflowDisplayText(value: string): string {
95
+ const sanitized = value.replace(DISALLOWED_DISPLAY_CHARACTER_RE, ' ').trim();
96
+ return Array.from(sanitized).slice(0, MAX_WORKFLOW_RUN_NAME_LENGTH).join('');
97
+ }
98
+
99
+ function degraded(
100
+ trace: readonly PersistedEvaluationTraceEntry[],
101
+ degradation: WorkflowRunNameDegradation,
102
+ ): ResolveWorkflowRunNameResult {
103
+ return {value: null, trace, degradation};
104
+ }
105
+
106
+ function firstExpressionSource(template: readonly ResolvedFieldSegment[]): string | undefined {
107
+ return template.find((segment) => segment.kind === 'deferred')?.expression.source;
108
+ }
@@ -27,7 +27,7 @@ export interface StepReport {
27
27
  // Precomputed gate evaluation (the CEL engine runs in evaluate-gate.ts, never
28
28
  // here). `passed`/`failed` are clean evaluations; `uncheckable` means the gate
29
29
  // could not be evaluated (no exit code, or an evaluation error) and is treated
30
- // as a plain command failure never a restart.
30
+ // as a plain command failure. It is never a restart.
31
31
  export type GateOutcome =
32
32
  | {kind: 'no-gate'}
33
33
  | {kind: 'passed'; source: string; trace?: readonly PersistedEvaluationTraceEntry[]}
@@ -55,7 +55,7 @@ export interface DecideStepTransitionInput {
55
55
  // to DEFAULT_RESTART_ATTEMPT_CAP.
56
56
  maxAttempts?: number;
57
57
  // The gating step's own execution count (number of its attempts), used for the
58
- // cap. Defaults to `reportedAttempt` correct for a single-gate job, where the
58
+ // cap. Defaults to `reportedAttempt`: correct for a single-gate job, where the
59
59
  // two are equal; the service passes the real count so a downstream gate in a
60
60
  // multi-gate job isn't penalized for upstream-induced rewinds.
61
61
  gatingAttemptCount?: number;
@@ -144,6 +144,14 @@ describe('evaluateGate', () => {
144
144
  expect(evaluateGate(gate, {status: 'failed', exitCode: 0})).toMatchObject({kind: 'failed'});
145
145
  });
146
146
 
147
+ test('resolves vars from the run-creation snapshot', () => {
148
+ const gate = readStepGate(gateConfig('vars.ENABLED == "true"'));
149
+
150
+ expect(evaluateGate(gate, {status: 'succeeded', exitCode: 0}, {ENABLED: 'true'})).toMatchObject(
151
+ {kind: 'passed'},
152
+ );
153
+ });
154
+
147
155
  test('step.outputs gates on reported output values', () => {
148
156
  const gate = readStepGate(gateConfig('step.outputs.pass == true'));
149
157
 
@@ -69,7 +69,11 @@ export function readStepGate(config: Record<string, unknown>): StepGate | undefi
69
69
  * unless evaluation gets a budget outside the lock. The materializer only
70
70
  * persists CEL expressions, and this evaluator only needs the validated source.
71
71
  */
72
- export function evaluateGate(gate: StepGate | undefined, result: StepReport): GateOutcome {
72
+ export function evaluateGate(
73
+ gate: StepGate | undefined,
74
+ result: StepReport,
75
+ vars?: Record<string, string> | undefined,
76
+ ): GateOutcome {
73
77
  if (!gate?.success) return {kind: 'no-gate'};
74
78
  const source = gate.success.source;
75
79
 
@@ -81,6 +85,7 @@ export function evaluateGate(gate: StepGate | undefined, result: StepReport): Ga
81
85
  status: result.status,
82
86
  exitCode: result.exitCode,
83
87
  output: result.output,
88
+ vars,
84
89
  });
85
90
  const outcome = evaluatePlannedPredicateAtSite({
86
91
  expression: gate.success,
@@ -110,6 +115,7 @@ export function evaluateGateFeedback(params: {
110
115
  readonly gate: StepGate;
111
116
  readonly result: StepReport;
112
117
  readonly definitionId: string;
118
+ readonly vars?: Record<string, string> | undefined;
113
119
  }): string {
114
120
  const feedbackTemplate = params.gate.onFailure?.feedbackTemplate;
115
121
  if (feedbackTemplate === undefined) {
@@ -120,6 +126,7 @@ export function evaluateGateFeedback(params: {
120
126
  status: params.result.status,
121
127
  exitCode: params.result.exitCode ?? null,
122
128
  output: params.result.output,
129
+ vars: params.vars,
123
130
  });
124
131
  return completeStepField({
125
132
  field: 'step.feedback',
@@ -19,7 +19,7 @@ describe('deriveInitialJobExecutionPlan', () => {
19
19
  const model = buildModel({
20
20
  jobs: {
21
21
  deploy: {
22
- name: `Deploy ${template('inputs.environment')}`,
22
+ executionName: `Deploy ${template('inputs.environment')}`,
23
23
  runner: ['linux'],
24
24
  runnerTemplates: [template('inputs.runner')],
25
25
  steps: [{run: 'echo deploy'}],
@@ -47,10 +47,10 @@ describe('deriveInitialJobExecutionPlan', () => {
47
47
  {
48
48
  expression: 'inputs.environment',
49
49
  roots: ['inputs'],
50
- fillTarget: 'run-creation',
50
+ fillTarget: 'execution-creation',
51
51
  evaluatedAt: 'execution-creation',
52
52
  value: 'prod',
53
- field: 'job.name',
53
+ field: 'job.execution_name',
54
54
  },
55
55
  ],
56
56
  });
@@ -86,7 +86,7 @@ describe('deriveInitialJobExecutionPlan', () => {
86
86
  const model = buildModel({
87
87
  jobs: {
88
88
  deploy: {
89
- name: `Current ${template('execution.name')}`,
89
+ executionName: `Current ${template('execution.name')}`,
90
90
  steps: [{run: 'echo deploy'}],
91
91
  },
92
92
  },
@@ -136,10 +136,13 @@ function workflowRun(params: {inputs?: Record<string, unknown> | null} = {}): Wo
136
136
  const now = new Date('2026-01-01T00:00:00.000Z');
137
137
  return {
138
138
  id: 'run-1',
139
+ number: 1,
139
140
  workspaceId: 'workspace-1',
140
141
  projectId: 'project-1',
141
142
  definitionId: 'definition-1',
142
143
  name: 'Test workflow',
144
+ workflowName: 'Test workflow',
145
+ nameOverride: null,
143
146
  status: 'pending',
144
147
  currentAttempt: 1,
145
148
  triggerProvider: null,
@@ -55,6 +55,7 @@ export function deriveInitialJobExecutionPlan(params: {
55
55
  inputs?: Record<string, unknown> | null | undefined;
56
56
  vars?: Record<string, string> | undefined;
57
57
  }): {
58
+ nameOverride: string | null;
58
59
  name: string;
59
60
  runner: readonly string[];
60
61
  evaluationTrace: JobExecution['evaluationTrace'];
@@ -64,8 +65,9 @@ export function deriveInitialJobExecutionPlan(params: {
64
65
  triggerPayload: params.triggerPayload,
65
66
  inputs: params.inputs ?? null,
66
67
  vars: params.vars,
67
- jobId: params.jobId,
68
+ job: {id: params.jobId, key: params.job.key, name: params.job.name ?? null},
68
69
  sequence: params.sequence,
70
+ nameOverride: null,
69
71
  executionName: params.fallbackName,
70
72
  status: 'pending',
71
73
  triggerEvents: [],
@@ -73,8 +75,7 @@ export function deriveInitialJobExecutionPlan(params: {
73
75
  });
74
76
  const resolvedName = resolveJobExecutionName({
75
77
  definitionId: params.run.definitionId,
76
- job: params.job,
77
- fallbackName: params.fallbackName,
78
+ job: params.modelJob,
78
79
  context: nameContext.values,
79
80
  });
80
81
  const runnerContext = assembleExecutionCreationContext({
@@ -82,15 +83,17 @@ export function deriveInitialJobExecutionPlan(params: {
82
83
  triggerPayload: params.triggerPayload,
83
84
  inputs: params.inputs ?? null,
84
85
  vars: params.vars,
85
- jobId: params.jobId,
86
+ job: {id: params.jobId, key: params.job.key, name: params.job.name ?? null},
86
87
  sequence: params.sequence,
87
- executionName: resolvedName.value,
88
+ nameOverride: resolvedName.nameOverride,
89
+ executionName: resolvedName.nameOverride ?? params.fallbackName,
88
90
  status: 'pending',
89
91
  triggerEvents: [],
90
92
  priorExecutions: [],
91
93
  });
92
94
  return {
93
- name: resolvedName.value,
95
+ nameOverride: resolvedName.nameOverride,
96
+ name: resolvedName.nameOverride ?? params.fallbackName,
94
97
  runner: materializeJobRunner({
95
98
  job: params.modelJob,
96
99
  context: runnerContext,
@@ -105,7 +108,9 @@ export function deriveJobExecutionRunner(params: {
105
108
  modelJob: WorkflowModel['jobs'][number];
106
109
  jobId: string;
107
110
  sequence: number;
111
+ nameOverride: string | null;
108
112
  executionName: string;
113
+ jobName?: string | null | undefined;
109
114
  status: JobExecution['status'];
110
115
  triggerEvents?: readonly JobExecution['triggerEvents'][number][] | undefined;
111
116
  priorExecutions?: readonly JobExecution[] | undefined;
@@ -116,8 +121,9 @@ export function deriveJobExecutionRunner(params: {
116
121
  run: params.run,
117
122
  triggerPayload: params.run.triggerPayload,
118
123
  inputs: params.run.inputs,
119
- jobId: params.jobId,
124
+ job: {id: params.jobId, key: params.modelJob.key, name: params.jobName ?? null},
120
125
  sequence: params.sequence,
126
+ nameOverride: params.nameOverride,
121
127
  executionName: params.executionName,
122
128
  status: params.status,
123
129
  triggerEvents: params.triggerEvents ?? [],
package/src/db/db.ts CHANGED
@@ -7,11 +7,13 @@ import {workflowsOutbox} from './schema/outbox.js';
7
7
  import {stepAttempts} from './schema/step-attempts.js';
8
8
  import {steps} from './schema/steps.js';
9
9
  import {workflowRunAttempts} from './schema/workflow-run-attempts.js';
10
+ import {workflowRunCounters} from './schema/workflow-run-counters.js';
10
11
  import {workflowRuns} from './schema/workflow-runs.js';
11
12
 
12
13
  export const schema = {
13
14
  workflowRuns,
14
15
  workflowRunAttempts,
16
+ workflowRunCounters,
15
17
  jobs,
16
18
  jobExecutions,
17
19
  jobListenerEvents,
package/src/db/index.ts CHANGED
@@ -23,6 +23,7 @@ export {
23
23
  settleListenerJobExecution,
24
24
  } from './job-listeners.js';
25
25
  export {workflowsOutbox} from './schema/outbox.js';
26
+ export {workflowRunCounters} from './schema/workflow-run-counters.js';
26
27
  export type {
27
28
  BulkUpdateStepStatusesParams,
28
29
  CancelWorkflowRunParams,
@@ -40,6 +41,10 @@ export type {
40
41
  WorkflowJobExecutionDepthParams,
41
42
  WorkflowRunAggregates,
42
43
  WorkflowRunFilters,
44
+ WorkflowRunJobStatusCount,
45
+ WorkflowRunJobSummary,
46
+ WorkflowRunJobSummaryTarget,
47
+ WorkflowRunJobsSummary,
43
48
  } from './workflow-runs.js';
44
49
  export {
45
50
  bulkUpdateStepStatuses,
@@ -72,6 +77,7 @@ export {
72
77
  getWorkflowRunById,
73
78
  getWorkflowRunDetail,
74
79
  listRunAttempts,
80
+ listWorkflowRunJobSummaries,
75
81
  listWorkflowRuns,
76
82
  listWorkflowRunsByProject,
77
83
  recordJobExecutionQueuedAt,