@shipfox/api-workflows 11.0.0 → 12.0.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 +100 -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 +21 -21
  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,10 +1,18 @@
1
- import {createWorkflowModelSnapshot, type WorkflowModel} from '@shipfox/api-definitions-dto';
1
+ import {
2
+ createWorkflowModelSnapshot,
3
+ WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS,
4
+ type WorkflowModel,
5
+ } from '@shipfox/api-definitions-dto';
2
6
  import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';
3
7
  import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';
4
8
  import type {SecretsInterModuleClient} from '@shipfox/api-secrets-dto/inter-module';
5
- import {analyzeContextKeyAccess, type ResolvedFieldSegment} from '@shipfox/expression';
9
+ import {
10
+ analyzeContextKeyAccess,
11
+ type ResolvedFieldSegment,
12
+ type WorkflowExpression,
13
+ } from '@shipfox/expression';
6
14
  import {logger} from '@shipfox/node-opentelemetry';
7
- import {eq} from 'drizzle-orm';
15
+ import {eq, sql} from 'drizzle-orm';
8
16
  import type {AgentDefaultsResolver} from '#core/agent-defaults.js';
9
17
  import {
10
18
  createAgentToolMaterializationSnapshot,
@@ -16,15 +24,22 @@ import type {
16
24
  WorkflowSourceSnapshot,
17
25
  } from '#core/entities/workflow-run.js';
18
26
  import {InterpolationUnresolvableError} from '#core/errors.js';
27
+ import {resolveWorkflowRunTriggerReference} from '#core/resolve-trigger-reference.js';
28
+ import {assembleCreationContext} from '#core/step-config/assemble-run-context.js';
19
29
  import type {MaterializedWorkflowJob} from '#core/step-config/materialize-workflow-model.js';
20
30
  import type {WorkflowStepTemplateDiagnostic} from '#core/step-config/resolve-step-config.js';
31
+ import {resolveWorkflowRunName} from '#core/step-config/resolve-workflow-run-name.js';
21
32
  import {
22
33
  deriveInitialJobExecutionPlan,
23
34
  materializeWorkflowRunJobs,
24
35
  } from '#core/workflow-run-creation.js';
25
- import {recordWorkflowRunCreated} from '#metrics/instance.js';
26
- import {db} from '../db.js';
36
+ import {
37
+ recordWorkflowDisplayNameResolutionDegraded,
38
+ recordWorkflowRunCreated,
39
+ } from '#metrics/instance.js';
40
+ import {db, type Tx} from '../db.js';
27
41
  import {workflowRunAttempts} from '../schema/workflow-run-attempts.js';
42
+ import {workflowRunCounters} from '../schema/workflow-run-counters.js';
28
43
  import {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';
29
44
  import {type MaterializedRunGraphJob, persistMaterializedRunGraph} from './run-graph.js';
30
45
 
@@ -44,6 +59,7 @@ export interface CreateWorkflowRunParams {
44
59
  name?: string | undefined;
45
60
  model: WorkflowModel;
46
61
  triggerPayload: TriggerPayload;
62
+ triggerConnectionId?: string | undefined;
47
63
  inputs?: Record<string, unknown> | undefined;
48
64
  sourceSnapshot?: WorkflowSourceSnapshot | null | undefined;
49
65
  triggerIdempotencyKey?: string | undefined;
@@ -54,6 +70,14 @@ export interface CreateWorkflowRunParams {
54
70
  }
55
71
 
56
72
  export async function createWorkflowRun(params: CreateWorkflowRunParams): Promise<WorkflowRun> {
73
+ const triggerReference = await resolveWorkflowRunTriggerReference({
74
+ workspaceId: params.workspaceId,
75
+ triggerConnectionId: params.triggerConnectionId,
76
+ triggerPayload: params.triggerPayload,
77
+ integrations: params.integrations,
78
+ projects: params.projects,
79
+ });
80
+ const staticName = params.name ?? params.model.name;
57
81
  const agentToolContext =
58
82
  params.integrations === undefined
59
83
  ? undefined
@@ -69,19 +93,42 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
69
93
  context: agentToolContext,
70
94
  });
71
95
  const result = await db().transaction(async (tx) => {
96
+ // Serialize idempotent trigger resolution separately from per-definition number
97
+ // allocation so a replay never consumes a number, including when two deliveries
98
+ // race before either run is visible.
99
+ if (params.triggerIdempotencyKey) {
100
+ await tx.execute(
101
+ sql`select pg_advisory_xact_lock(hashtext(${params.triggerIdempotencyKey}))`,
102
+ );
103
+ const existing = await tx
104
+ .select()
105
+ .from(workflowRuns)
106
+ .where(eq(workflowRuns.triggerIdempotencyKey, params.triggerIdempotencyKey))
107
+ .limit(1);
108
+ const existingRow = existing[0];
109
+ if (existingRow) return {run: toWorkflowRun(existingRow), created: false};
110
+ }
111
+
112
+ // Keep allocation on the existing transaction so a trigger burst cannot pin
113
+ // every pool connection and then wait for a second connection per run.
114
+ const number = await allocateWorkflowRunNumber(tx, params.definitionId);
115
+
72
116
  const insertResult = await tx
73
117
  .insert(workflowRuns)
74
118
  .values({
75
119
  workspaceId: params.workspaceId,
76
120
  projectId: params.projectId,
77
121
  definitionId: params.definitionId,
78
- name: params.name ?? params.model.name,
122
+ number,
123
+ name: null,
124
+ workflowName: staticName,
79
125
  status: 'pending',
80
126
  currentAttempt: 1,
81
127
  triggerProvider: params.triggerPayload.provider ?? null,
82
128
  triggerSource: params.triggerPayload.source,
83
129
  triggerEvent: params.triggerPayload.event,
84
130
  triggerPayload: params.triggerPayload,
131
+ triggerReference,
85
132
  inputs: params.inputs ?? null,
86
133
  sourceSnapshot: params.sourceSnapshot ?? null,
87
134
  triggerIdempotencyKey: params.triggerIdempotencyKey ?? null,
@@ -109,7 +156,38 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
109
156
  return {run: toWorkflowRun(existingRow), created: false};
110
157
  }
111
158
 
112
- const run = toWorkflowRun(runRow);
159
+ // Resolving run-creation templates and predicates here gives them a stable variable snapshot
160
+ // and interpolation access to the inserted run id. Run-name resolution is display-only and
161
+ // persists only a resolved override. If resolution fails, the transaction rolls back the run,
162
+ // jobs, steps, and outbox event together. Listening steps are resolved later when a job
163
+ // execution is created.
164
+ const provisionalRun = toWorkflowRun(runRow);
165
+ const oneShotJobs = params.model.jobs.filter((job) => job.mode !== 'listening');
166
+ const vars = await loadReferencedVariables({
167
+ model: params.model,
168
+ jobs: oneShotJobs,
169
+ workspaceId: params.workspaceId,
170
+ projectId: params.projectId,
171
+ definitionId: params.definitionId,
172
+ secrets: params.secrets,
173
+ });
174
+ const runNameResolution = resolveWorkflowRunName({
175
+ runName: params.model.runName,
176
+ context: assembleCreationContext({
177
+ run: provisionalRun,
178
+ triggerPayload: params.triggerPayload,
179
+ inputs: params.inputs ?? null,
180
+ vars,
181
+ }).values,
182
+ });
183
+ const [resolvedRunRow] = await tx
184
+ .update(workflowRuns)
185
+ .set({name: runNameResolution.value, updatedAt: new Date()})
186
+ .where(eq(workflowRuns.id, provisionalRun.id))
187
+ .returning();
188
+ if (!resolvedRunRow)
189
+ throw new Error(`Workflow run missing after name resolution: ${runRow.id}`);
190
+ const run = toWorkflowRun(resolvedRunRow);
113
191
  const [attemptRow] = await tx
114
192
  .insert(workflowRunAttempts)
115
193
  .values({
@@ -117,23 +195,12 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
117
195
  attempt: 1,
118
196
  status: 'pending',
119
197
  model: createWorkflowModelSnapshot(params.model),
198
+ vars,
120
199
  agentToolMaterialization,
121
200
  })
122
201
  .returning();
123
202
  if (!attemptRow) throw new Error('Insert returned no rows');
124
203
 
125
- // Resolving one-shot templates here gives interpolation access to the inserted run id.
126
- // If resolution fails, the transaction rolls back the run, jobs, steps, and outbox event together.
127
- // Listening steps are resolved later when a job execution is created.
128
- const oneShotJobs = params.model.jobs.filter((job) => job.mode !== 'listening');
129
- const vars = await loadReferencedVariables({
130
- model: params.model,
131
- jobs: oneShotJobs,
132
- workspaceId: params.workspaceId,
133
- projectId: params.projectId,
134
- definitionId: params.definitionId,
135
- secrets: params.secrets,
136
- });
137
204
  const materializedJobs = await materializeWorkflowRunJobs({
138
205
  run,
139
206
  model: params.model,
@@ -171,15 +238,49 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
171
238
  ),
172
239
  });
173
240
 
174
- return {run, created: true};
241
+ return {
242
+ run,
243
+ created: true,
244
+ nameDegradation: runNameResolution.degradation,
245
+ };
175
246
  });
176
247
 
177
- if (result.created)
248
+ if (result.created && result.nameDegradation !== undefined) {
249
+ recordWorkflowDisplayNameResolutionDegraded('workflow.run_name', result.nameDegradation.cause);
250
+ logger().warn(
251
+ {
252
+ workflowRunId: result.run.id,
253
+ definitionId: result.run.definitionId,
254
+ field: 'workflow.run_name',
255
+ cause: result.nameDegradation.cause,
256
+ ...(result.nameDegradation.expression === undefined
257
+ ? {}
258
+ : {expression: result.nameDegradation.expression.slice(0, 256)}),
259
+ },
260
+ 'Workflow run name resolution degraded to the static workflow name',
261
+ );
262
+ }
263
+
264
+ if (result.created) {
178
265
  recordWorkflowRunCreated(result.run.triggerPayload.provider ?? result.run.triggerSource);
266
+ }
179
267
 
180
268
  return result.run;
181
269
  }
182
270
 
271
+ async function allocateWorkflowRunNumber(tx: Tx, definitionId: string): Promise<number> {
272
+ const [counterRow] = await tx
273
+ .insert(workflowRunCounters)
274
+ .values({definitionId, nextNumber: 2})
275
+ .onConflictDoUpdate({
276
+ target: workflowRunCounters.definitionId,
277
+ set: {nextNumber: sql`${workflowRunCounters.nextNumber} + 1`},
278
+ })
279
+ .returning({number: sql<number>`${workflowRunCounters.nextNumber} - 1`});
280
+ if (!counterRow) throw new Error('Run counter allocation returned no rows');
281
+ return counterRow.number;
282
+ }
283
+
183
284
  export async function loadReferencedVariables(params: {
184
285
  readonly model: WorkflowModel;
185
286
  readonly jobs?: readonly WorkflowModelJob[] | undefined;
@@ -192,15 +293,22 @@ export async function loadReferencedVariables(params: {
192
293
  const keys = [...new Set(references.map((reference) => reference.key))].sort();
193
294
  if (keys.length === 0) return undefined;
194
295
 
195
- if (!params.secrets) throw new Error('Secrets client is not configured.');
296
+ const requiresSecrets = (reference: ReferencedVariable) =>
297
+ reference.field !== 'job.execution_name' && reference.field !== 'workflow.run_name';
298
+ const requiredReferences = references.filter(requiresSecrets);
299
+ const requiredKeys = new Set(requiredReferences.map((reference) => reference.key));
300
+ if (!params.secrets) {
301
+ if (requiredKeys.size === 0) return undefined;
302
+ throw new Error('Secrets client is not configured.');
303
+ }
196
304
  const {values: vars} = await params.secrets.getVariablesByNamespace({
197
305
  workspaceId: params.workspaceId,
198
306
  projectId: params.projectId,
199
307
  namespace: '',
200
308
  });
201
- const missingKey = keys.find((key) => !(key in vars));
309
+ const missingKey = [...requiredKeys].find((key) => !(key in vars));
202
310
  if (missingKey !== undefined) {
203
- const reference = references.find((candidate) => candidate.key === missingKey);
311
+ const reference = requiredReferences.find((candidate) => candidate.key === missingKey);
204
312
  throw new InterpolationUnresolvableError(params.definitionId, {
205
313
  field: reference?.field ?? 'env',
206
314
  source: reference?.source ?? `vars.${missingKey}`,
@@ -208,7 +316,12 @@ export async function loadReferencedVariables(params: {
208
316
  });
209
317
  }
210
318
 
211
- return vars;
319
+ const referencedVars: Record<string, string> = {};
320
+ for (const key of keys) {
321
+ const value = vars[key];
322
+ if (value !== undefined) referencedVars[key] = value;
323
+ }
324
+ return referencedVars;
212
325
  }
213
326
 
214
327
  function materializeRunGraphJobs(params: {
@@ -221,7 +334,7 @@ function materializeRunGraphJobs(params: {
221
334
  job: {
222
335
  key: job.key,
223
336
  mode: job.mode,
224
- name: workflowTemplateSource(job.name),
337
+ name: job.name ?? null,
225
338
  status: 'pending' as const,
226
339
  checkoutPersistCredentials: job.checkout.persistCredentials,
227
340
  checkoutPermissionsContents: job.checkout.permissions.contents,
@@ -242,7 +355,7 @@ function materializeRunGraphJobs(params: {
242
355
  createExecution: (jobRow) => {
243
356
  if (jobRow.mode === 'listening') return undefined;
244
357
 
245
- const fallbackName = `${jobRow.key} #1`;
358
+ const fallbackName = jobRow.name ?? jobRow.key;
246
359
  const modelJob = params.params.model.jobs[jobIndex];
247
360
  if (!modelJob) return undefined;
248
361
  const executionPlan = deriveInitialJobExecutionPlan({
@@ -259,7 +372,9 @@ function materializeRunGraphJobs(params: {
259
372
 
260
373
  return {
261
374
  sequence: 1,
262
- name: executionPlan.name,
375
+ // Persist only the resolved override. The core entity supplies the
376
+ // static job name/key when this is null.
377
+ name: executionPlan.nameOverride,
263
378
  runner: [...executionPlan.runner],
264
379
  status: 'pending' as const,
265
380
  evaluationTrace:
@@ -288,12 +403,28 @@ function referencedVariables(
288
403
  ): readonly ReferencedVariable[] {
289
404
  const references: ReferencedVariable[] = [];
290
405
 
406
+ for (const job of model.jobs) {
407
+ collectPredicateVariableReferences(job.if, references);
408
+ collectPredicateVariableReferences(job.success, references);
409
+
410
+ for (const trigger of [...(job.listening?.on ?? []), ...(job.listening?.until ?? [])]) {
411
+ collectPredicateVariableReferences(trigger.filter, references);
412
+ }
413
+
414
+ for (const step of job.steps) {
415
+ collectPredicateVariableReferences(step.if, references);
416
+ collectPredicateVariableReferences(step.gate?.success, references);
417
+ }
418
+ }
419
+
420
+ collectFieldVariableReferences(model.runName, references, {field: 'workflow.run_name'});
421
+
291
422
  if (jobs.length > 0) {
292
423
  collectTemplateVariableReferences(model.templates?.env, references);
293
424
  }
294
425
 
295
426
  for (const job of jobs) {
296
- collectFieldVariableReferences(job.name, references, {field: 'job.name'});
427
+ collectFieldVariableReferences(job.executionName, references, {field: 'job.execution_name'});
297
428
  for (const template of job.runnerTemplates ?? []) {
298
429
  collectFieldVariableReferences(template, references, {field: 'job.runner'});
299
430
  }
@@ -302,15 +433,22 @@ function referencedVariables(
302
433
 
303
434
  for (const step of job.steps) {
304
435
  collectFieldVariableReferences(step.templates?.name, references, {field: 'step.name'});
436
+ collectFieldVariableReferences(step.templates?.workingDirectory, references, {
437
+ field: 'step.working_directory',
438
+ });
305
439
  if (step.kind === 'run') {
306
440
  collectFieldVariableReferences(step.templates?.command, references, {field: 'run'});
307
441
  collectTemplateVariableReferences(step.templates?.env, references);
308
- } else {
442
+ } else if (step.kind === 'agent') {
309
443
  collectFieldVariableReferences(step.templates?.prompt, references, {field: 'agent.prompt'});
310
444
  collectFieldVariableReferences(step.templates?.model, references, {field: 'agent.model'});
311
445
  collectFieldVariableReferences(step.templates?.provider, references, {
312
446
  field: 'agent.provider',
313
447
  });
448
+ } else if (step.kind === 'checkout') {
449
+ for (const [key, field] of WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS) {
450
+ collectFieldVariableReferences(step.checkout.templates?.[key], references, {field});
451
+ }
314
452
  }
315
453
  }
316
454
  }
@@ -318,6 +456,23 @@ function referencedVariables(
318
456
  return references;
319
457
  }
320
458
 
459
+ function collectPredicateVariableReferences(
460
+ expression: WorkflowExpression | string | undefined,
461
+ references: ReferencedVariable[],
462
+ ): void {
463
+ if (expression === undefined) return;
464
+
465
+ const keyAccess = analyzeContextKeyAccess(expression);
466
+ for (const reference of keyAccess.references) {
467
+ if (reference.root !== 'vars') continue;
468
+ references.push({
469
+ key: reference.key,
470
+ field: 'env',
471
+ source: typeof expression === 'string' ? expression : expression.source,
472
+ });
473
+ }
474
+ }
475
+
321
476
  function collectTemplateVariableReferences(
322
477
  templates: Readonly<Record<string, readonly ResolvedFieldSegment[]>> | undefined,
323
478
  references: ReferencedVariable[],
@@ -357,16 +512,6 @@ function collectFieldVariableReferences(
357
512
  }
358
513
  }
359
514
 
360
- function workflowTemplateSource(template: MaterializedWorkflowJob['name']): string | null {
361
- if (template === undefined) return null;
362
-
363
- return template
364
- .map((segment) =>
365
- segment.kind === 'literal' ? segment.value : `$${'{{'} ${segment.expression.source} ${'}}'}`,
366
- )
367
- .join('');
368
- }
369
-
370
515
  function logTemplateDiagnostics(params: {
371
516
  readonly workflowRunId: string;
372
517
  readonly diagnostics: readonly (WorkflowStepTemplateDiagnostic & {
@@ -42,6 +42,7 @@ describe('workflow run queries', () => {
42
42
  describe('createRerunWorkflowRun', () => {
43
43
  function rerunModel() {
44
44
  return buildModel({
45
+ runName: `Run ${template('inputs.env')}`,
45
46
  jobs: {
46
47
  build: {steps: [{run: 'echo build'}]},
47
48
  test: {needs: 'build', steps: [{run: 'echo test'}]},
@@ -112,6 +113,10 @@ describe('workflow run queries', () => {
112
113
 
113
114
  expect(rerun).toMatchObject({
114
115
  id: source.id,
116
+ number: source.number,
117
+ name: 'Run staging',
118
+ workflowName: 'Test Workflow',
119
+ nameOverride: 'Run staging',
115
120
  inputs: {env: 'staging'},
116
121
  sourceSnapshot: {content: 'name: Original\njobs: {}\n', format: 'yaml'},
117
122
  });
@@ -198,7 +203,7 @@ describe('workflow run queries', () => {
198
203
  expect(rerunAttempt?.agentToolMaterialization).toEqual(snapshot);
199
204
  });
200
205
 
201
- test('reruns preserve each source job checkout policy', async () => {
206
+ test('reruns re-materialize each job checkout policy from the model', async () => {
202
207
  const source = await createWorkflowRun({
203
208
  workspaceId,
204
209
  projectId,
@@ -222,6 +227,12 @@ describe('workflow run queries', () => {
222
227
  },
223
228
  });
224
229
  const sourceJobs = await getJobsByWorkflowRunId(source.id);
230
+ const sourceJob = sourceJobs[0];
231
+ if (!sourceJob) throw new Error('Missing source job');
232
+ await db()
233
+ .update(jobs)
234
+ .set({checkoutPersistCredentials: true, checkoutPermissionsContents: 'read'})
235
+ .where(eq(jobs.id, sourceJob.id));
225
236
  await markJob(sourceJobs, 'build', 'failed');
226
237
  await updateWorkflowRunStatus({
227
238
  workflowRunId: source.id,
@@ -411,7 +422,7 @@ describe('workflow run queries', () => {
411
422
  model: buildModel({
412
423
  jobs: {
413
424
  deploy: {
414
- name: `Deploy ${template('inputs.environment')}`,
425
+ executionName: `Deploy ${template('inputs.environment')}`,
415
426
  steps: [{run: 'echo deploy'}],
416
427
  },
417
428
  },
@@ -451,6 +462,54 @@ describe('workflow run queries', () => {
451
462
  expect(rerunExecution?.name).toBe('Deploy prod (attempt 1)');
452
463
  });
453
464
 
465
+ test('reruns preserve a null name override instead of copying the fallback', async () => {
466
+ const source = await createWorkflowRun({
467
+ workspaceId,
468
+ projectId,
469
+ definitionId,
470
+ model: buildModel({
471
+ jobs: {
472
+ deploy: {name: 'Deploy', steps: [{run: 'echo deploy'}]},
473
+ },
474
+ }),
475
+ triggerPayload: {
476
+ source: 'manual',
477
+ event: 'fire',
478
+ subscriptionId: crypto.randomUUID(),
479
+ userId: crypto.randomUUID(),
480
+ },
481
+ });
482
+ const [sourceJob] = await getJobsByWorkflowRunId(source.id);
483
+ if (!sourceJob) throw new Error('Missing deploy job');
484
+ await markJob([sourceJob], 'deploy', 'failed');
485
+ const [sourceExecution] = await getJobExecutionsByJobId(sourceJob.id);
486
+ if (!sourceExecution) throw new Error('Missing deploy execution');
487
+ expect(sourceExecution.nameOverride).toBeNull();
488
+ expect(sourceExecution.name).toBe('Deploy');
489
+ await updateWorkflowRunStatus({
490
+ workflowRunId: source.id,
491
+ status: 'failed',
492
+ expectedVersion: 1,
493
+ });
494
+
495
+ const rerun = await createRerunWorkflowRun({
496
+ workflowRunId: source.id,
497
+ mode: 'all',
498
+ actorUserId: crypto.randomUUID(),
499
+ });
500
+
501
+ const [rerunJob] = await getJobsByWorkflowRunId(rerun.id);
502
+ if (!rerunJob) throw new Error('Missing rerun deploy job');
503
+ const [rerunExecution] = await getJobExecutionsByJobId(rerunJob.id);
504
+ expect(rerunExecution?.nameOverride).toBeNull();
505
+ expect(rerunExecution?.name).toBe('Deploy');
506
+ const [storedRerunExecution] = await db()
507
+ .select({name: jobExecutions.name})
508
+ .from(jobExecutions)
509
+ .where(eq(jobExecutions.jobId, rerunJob.id));
510
+ expect(storedRerunExecution?.name).toBeNull();
511
+ });
512
+
454
513
  test('writes one run-attempt-created outbox event for the rerun', async () => {
455
514
  const source = await createTerminalSourceRun();
456
515
 
@@ -77,6 +77,7 @@ export async function createRerunWorkflowRun(
77
77
  rerunMode: params.mode,
78
78
  rerunByUserId: params.actorUserId,
79
79
  model: sourceAttemptRow.model,
80
+ vars: sourceAttemptRow.vars,
80
81
  agentToolMaterialization: sourceAttemptRow.agentToolMaterialization,
81
82
  })
82
83
  .returning();
@@ -192,6 +193,9 @@ function materializeRerunGraphJobs(params: {
192
193
 
193
194
  return params.sourceJobs.map((sourceJob) => {
194
195
  const carriedOver = params.mode === 'failed' && sourceJob.status === 'succeeded';
196
+ const modelJob = sourceModelJobByKey.get(sourceJob.key);
197
+ const modelCheckout = modelJob?.checkout;
198
+ const resolvedModelCheckout = modelCheckout === false ? undefined : modelCheckout;
195
199
 
196
200
  return {
197
201
  job: {
@@ -201,8 +205,10 @@ function materializeRerunGraphJobs(params: {
201
205
  status: carriedOver ? ('succeeded' as const) : ('pending' as const),
202
206
  statusReason: null,
203
207
  carriedOver,
204
- checkoutPersistCredentials: sourceJob.checkoutPersistCredentials,
205
- checkoutPermissionsContents: sourceJob.checkoutPermissionsContents,
208
+ checkoutPersistCredentials:
209
+ resolvedModelCheckout?.persistCredentials ?? sourceJob.checkoutPersistCredentials,
210
+ checkoutPermissionsContents:
211
+ resolvedModelCheckout?.permissions?.contents ?? sourceJob.checkoutPermissionsContents,
206
212
  success: sourceJob.success,
207
213
  executionTimeoutMs: sourceJob.executionTimeoutMs,
208
214
  listeningTimeoutMs: sourceJob.listeningTimeoutMs,
@@ -224,8 +230,8 @@ function materializeRerunGraphJobs(params: {
224
230
  if (job.mode === 'listening') return undefined;
225
231
 
226
232
  const sourceExecution = params.sourceJobExecutionByJobId.get(sourceJob.id);
227
- const modelJob = sourceModelJobByKey.get(job.key);
228
- const executionName = sourceExecution?.name ?? `${job.key} #1`;
233
+ const nameOverride = sourceExecution?.name ?? null;
234
+ const executionName = nameOverride ?? job.name ?? job.key;
229
235
  const runner =
230
236
  carriedOver || modelJob === undefined
231
237
  ? (sourceExecution?.runner ?? job.runner ?? null)
@@ -234,13 +240,17 @@ function materializeRerunGraphJobs(params: {
234
240
  modelJob,
235
241
  jobId: job.id,
236
242
  sequence: 1,
243
+ nameOverride,
237
244
  executionName,
245
+ jobName: job.name,
238
246
  status: 'pending',
239
247
  });
240
248
 
241
249
  return {
242
250
  sequence: 1,
243
- name: executionName,
251
+ // Reruns preserve the authored/resolved override, never the
252
+ // effective fallback exposed by the core entity.
253
+ name: nameOverride,
244
254
  runner: runner ? [...runner] : null,
245
255
  status: carriedOver ? ('succeeded' as const) : ('pending' as const),
246
256
  statusReason: null,
@@ -64,6 +64,7 @@ export async function getWorkflowContextForJob(
64
64
  workflowRunAttemptId: string;
65
65
  workspaceId: string;
66
66
  projectId: string;
67
+ vars: Record<string, string> | null;
67
68
  }> {
68
69
  const rows = await tx
69
70
  .select({
@@ -72,6 +73,7 @@ export async function getWorkflowContextForJob(
72
73
  workflowRunAttemptId: workflowRunAttempts.id,
73
74
  workspaceId: workflowRuns.workspaceId,
74
75
  projectId: workflowRuns.projectId,
76
+ vars: workflowRunAttempts.vars,
75
77
  })
76
78
  .from(jobs)
77
79
  .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))
@@ -379,8 +379,8 @@ export interface RewindStepsToPendingParams {
379
379
  // Restart-only: rewind every step at or after `fromPosition` back to pending,
380
380
  // clearing its result and bumping both `version` and `current_attempt` so the next
381
381
  // dispatch opens a fresh attempt. This DELIBERATELY bypasses the never-downgrade
382
- // guard used everywhere else it is the one place that resurrects terminal steps
383
- // so it must only be called from the durable-restart path, never the ordinary
382
+ // guard used everywhere else. It is the one place that resurrects terminal steps,
383
+ // so it must only be called from the durable-restart path, never the ordinary
384
384
  // report path. It must run in the same transaction as the failed-attempt write.
385
385
  export async function rewindStepsToPending(
386
386
  params: RewindStepsToPendingParams,
@@ -405,7 +405,7 @@ export async function rewindStepsToPending(
405
405
  }
406
406
 
407
407
  // Count a single step's own attempts. Used to bound the restart cap on the
408
- // gating step's actual executions `steps.current_attempt` can't be used for
408
+ // gating step's actual executions: `steps.current_attempt` can't be used for
409
409
  // the cap because a rewind also bumps it for downstream steps swept into the
410
410
  // rewind range (which would inflate a later gate's cap in a multi-gate job).
411
411
  export async function countStepAttempts(stepId: string, tx: Tx): Promise<number> {
@@ -47,6 +47,10 @@ export type {
47
47
  WorkflowRunAggregates,
48
48
  WorkflowRunCursor,
49
49
  WorkflowRunFilters,
50
+ WorkflowRunJobStatusCount,
51
+ WorkflowRunJobSummary,
52
+ WorkflowRunJobSummaryTarget,
53
+ WorkflowRunJobsSummary,
50
54
  } from './workflow-runs/queries.js';
51
55
  export {
52
56
  buildWorkflowRunListConditions,
@@ -59,6 +63,7 @@ export {
59
63
  getWorkflowRunById,
60
64
  getWorkflowRunDetail,
61
65
  listRunAttempts,
66
+ listWorkflowRunJobSummaries,
62
67
  listWorkflowRuns,
63
68
  listWorkflowRunsByProject,
64
69
  } from './workflow-runs/queries.js';
@@ -74,8 +79,10 @@ export {
74
79
  createRerunWorkflowRun,
75
80
  createWorkflowRun,
76
81
  failWorkflowRunAsTimedOut,
82
+ loadReferencedVariables,
77
83
  updateWorkflowRunStatus,
78
84
  } from './workflow-runs/runs.js';
85
+ export {getWorkflowContextForJob} from './workflow-runs/shared.js';
79
86
  export type {
80
87
  ApplyStepResultParams,
81
88
  BulkUpdateStepStatusesParams,
@@ -10,6 +10,13 @@ const runCreatedCount = meter.createCounter<{provider: string}>('workflows_run_c
10
10
  description: 'Workflow runs created by bounded trigger provider',
11
11
  });
12
12
 
13
+ const displayNameResolutionDegradedCount = meter.createCounter<{
14
+ field: 'workflow.run_name' | 'job.execution_name';
15
+ cause: 'missing_value' | 'evaluation_error' | 'empty_value' | 'sanitization';
16
+ }>('workflows_display_name_resolution_degraded', {
17
+ description: 'Display-name resolution degradations by field and bounded cause',
18
+ });
19
+
13
20
  const runStatusChangedCount = meter.createCounter<{status: WorkflowRunStatus}>(
14
21
  'workflows_run_status_changed',
15
22
  {description: 'Workflow run status transitions by resulting status'},
@@ -97,6 +104,13 @@ export function recordWorkflowRunCreated(provider: string): void {
97
104
  runCreatedCount.add(1, {provider});
98
105
  }
99
106
 
107
+ export function recordWorkflowDisplayNameResolutionDegraded(
108
+ field: 'workflow.run_name' | 'job.execution_name',
109
+ cause: 'missing_value' | 'evaluation_error' | 'empty_value' | 'sanitization',
110
+ ): void {
111
+ displayNameResolutionDegradedCount.add(1, {field, cause});
112
+ }
113
+
100
114
  export function recordWorkflowRunStatusChanged(status: WorkflowRunStatus): void {
101
115
  runStatusChangedCount.add(1, {status});
102
116
  }