@intentius/chant 0.124.27 → 0.124.29

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 (681) hide show
  1. package/README.md +1 -1
  2. package/dist/__golden__/wave-loop/fan-out-gated.json +8 -0
  3. package/dist/__golden__/wave-loop/fan-out-no-members.json +4 -0
  4. package/dist/__golden__/wave-loop/fan-out-only.json +6 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  6. package/dist/__golden__/wave-loop/op-cost-member.json +3 -0
  7. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  8. package/dist/__golden__/wave-loop/op-held-on.json +2 -0
  9. package/dist/__golden__/wave-loop/op-hooks-held.json +2 -0
  10. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  11. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  12. package/dist/__golden__/wave-loop/op-hooks-share.json +3 -0
  13. package/dist/__golden__/wave-loop/op-per-run.json +7 -0
  14. package/dist/__golden__/wave-loop/op-pr-review.json +7 -0
  15. package/dist/__golden__/wave-loop/op-sealed.json +3 -0
  16. package/dist/__golden__/wave-loop/op-spend.json +3 -0
  17. package/dist/__golden__/wave-loop/op-wave-commands.json +7 -0
  18. package/dist/__golden__/wave-loop/op-wide-waiting.json +4 -0
  19. package/dist/build-params.d.ts +34 -1
  20. package/dist/build-params.d.ts.map +1 -1
  21. package/dist/build-params.js +31 -1
  22. package/dist/change-set-graph.d.ts +63 -0
  23. package/dist/change-set-graph.d.ts.map +1 -0
  24. package/dist/change-set-graph.js +130 -0
  25. package/dist/change-set.d.ts +62 -3
  26. package/dist/change-set.d.ts.map +1 -1
  27. package/dist/change-set.js +36 -4
  28. package/dist/chant-version.d.ts +9 -0
  29. package/dist/chant-version.d.ts.map +1 -0
  30. package/dist/chant-version.js +16 -0
  31. package/dist/cli/build-params-cli.d.ts +7 -1
  32. package/dist/cli/build-params-cli.d.ts.map +1 -1
  33. package/dist/cli/build-params-cli.js +17 -8
  34. package/dist/cli/commands/build.d.ts +8 -0
  35. package/dist/cli/commands/build.d.ts.map +1 -1
  36. package/dist/cli/commands/build.js +15 -11
  37. package/dist/cli/commands/check-lexicon-docs.d.ts.map +1 -1
  38. package/dist/cli/commands/check-lexicon-docs.js +30 -2
  39. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  40. package/dist/cli/commands/check-lexicon.js +13 -2
  41. package/dist/cli/commands/init-lexicon/templates/docs.d.ts +4 -1
  42. package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -1
  43. package/dist/cli/commands/init-lexicon/templates/docs.js +6 -6
  44. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  45. package/dist/cli/commands/init-lexicon.js +17 -8
  46. package/dist/cli/handlers/approve.d.ts.map +1 -1
  47. package/dist/cli/handlers/approve.js +64 -4
  48. package/dist/cli/handlers/build.d.ts.map +1 -1
  49. package/dist/cli/handlers/build.js +43 -4
  50. package/dist/cli/handlers/change-set.d.ts +10 -0
  51. package/dist/cli/handlers/change-set.d.ts.map +1 -1
  52. package/dist/cli/handlers/change-set.js +51 -1
  53. package/dist/cli/handlers/fan-out.d.ts +10 -1
  54. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  55. package/dist/cli/handlers/fan-out.js +54 -6
  56. package/dist/cli/handlers/lifecycle-gc.d.ts +19 -0
  57. package/dist/cli/handlers/lifecycle-gc.d.ts.map +1 -0
  58. package/dist/cli/handlers/lifecycle-gc.js +143 -0
  59. package/dist/cli/handlers/pr.d.ts +16 -2
  60. package/dist/cli/handlers/pr.d.ts.map +1 -1
  61. package/dist/cli/handlers/pr.js +269 -37
  62. package/dist/cli/handlers/promote.d.ts +7 -0
  63. package/dist/cli/handlers/promote.d.ts.map +1 -1
  64. package/dist/cli/handlers/promote.js +440 -28
  65. package/dist/cli/handlers/release.d.ts +91 -0
  66. package/dist/cli/handlers/release.d.ts.map +1 -0
  67. package/dist/cli/handlers/release.js +589 -0
  68. package/dist/cli/handlers/run.d.ts +38 -2
  69. package/dist/cli/handlers/run.d.ts.map +1 -1
  70. package/dist/cli/handlers/run.js +234 -16
  71. package/dist/cli/main.d.ts.map +1 -1
  72. package/dist/cli/main.js +143 -17
  73. package/dist/cli/mcp/workspace-tools.js +1 -1
  74. package/dist/cli/parse-args.d.ts.map +1 -1
  75. package/dist/cli/parse-args.js +73 -5
  76. package/dist/cli/registry.d.ts +43 -5
  77. package/dist/cli/registry.d.ts.map +1 -1
  78. package/dist/cli/run-events.d.ts +30 -0
  79. package/dist/cli/run-events.d.ts.map +1 -0
  80. package/dist/cli/run-events.js +49 -0
  81. package/dist/cli/version.d.ts +3 -5
  82. package/dist/cli/version.d.ts.map +1 -1
  83. package/dist/cli/version.js +3 -13
  84. package/dist/codegen/docs-in-site.d.ts +71 -0
  85. package/dist/codegen/docs-in-site.d.ts.map +1 -0
  86. package/dist/codegen/docs-in-site.js +177 -0
  87. package/dist/codegen/docs-types.d.ts +14 -1
  88. package/dist/codegen/docs-types.d.ts.map +1 -1
  89. package/dist/codegen/docs.d.ts +18 -1
  90. package/dist/codegen/docs.d.ts.map +1 -1
  91. package/dist/codegen/docs.js +40 -7
  92. package/dist/codegen/rehype-base-url.mjs +15 -9
  93. package/dist/components/auto-release.d.ts +6 -1
  94. package/dist/components/auto-release.d.ts.map +1 -1
  95. package/dist/components/auto-release.js +3 -0
  96. package/dist/components/capability.d.ts +9 -0
  97. package/dist/components/capability.d.ts.map +1 -1
  98. package/dist/components/cli-support.d.ts +6 -0
  99. package/dist/components/cli-support.d.ts.map +1 -1
  100. package/dist/components/cli-support.js +10 -9
  101. package/dist/components/driver.d.ts +50 -9
  102. package/dist/components/driver.d.ts.map +1 -1
  103. package/dist/components/driver.js +116 -54
  104. package/dist/components/fan-out-inputs.d.ts +69 -0
  105. package/dist/components/fan-out-inputs.d.ts.map +1 -0
  106. package/dist/components/fan-out-inputs.js +169 -0
  107. package/dist/components/fan-out-record.d.ts +13 -0
  108. package/dist/components/fan-out-record.d.ts.map +1 -1
  109. package/dist/components/fan-out-record.js +16 -0
  110. package/dist/components/fan-out-run.d.ts +7 -0
  111. package/dist/components/fan-out-run.d.ts.map +1 -1
  112. package/dist/components/fan-out-run.js +85 -26
  113. package/dist/components/fan-out.d.ts +4 -0
  114. package/dist/components/fan-out.d.ts.map +1 -1
  115. package/dist/components/pr-pipeline.d.ts +25 -0
  116. package/dist/components/pr-pipeline.d.ts.map +1 -1
  117. package/dist/components/pr-pipeline.js +22 -4
  118. package/dist/components/pr-run.d.ts +11 -0
  119. package/dist/components/pr-run.d.ts.map +1 -1
  120. package/dist/components/pr-run.js +20 -1
  121. package/dist/components/promote-order.d.ts +38 -0
  122. package/dist/components/promote-order.d.ts.map +1 -0
  123. package/dist/components/promote-order.js +62 -0
  124. package/dist/components/promote.d.ts +38 -2
  125. package/dist/components/promote.d.ts.map +1 -1
  126. package/dist/components/promote.js +77 -2
  127. package/dist/components/release-compile.d.ts +142 -0
  128. package/dist/components/release-compile.d.ts.map +1 -0
  129. package/dist/components/release-compile.js +382 -0
  130. package/dist/components/release-gate.d.ts +135 -0
  131. package/dist/components/release-gate.d.ts.map +1 -0
  132. package/dist/components/release-gate.js +288 -0
  133. package/dist/components/release-promote.d.ts +96 -0
  134. package/dist/components/release-promote.d.ts.map +1 -0
  135. package/dist/components/release-promote.js +204 -0
  136. package/dist/components/run-progress.d.ts +7 -0
  137. package/dist/components/run-progress.d.ts.map +1 -1
  138. package/dist/components/wave-plan.d.ts +8 -1
  139. package/dist/components/wave-plan.d.ts.map +1 -1
  140. package/dist/components/wave-plan.js +11 -3
  141. package/dist/config.d.ts +45 -0
  142. package/dist/config.d.ts.map +1 -1
  143. package/dist/config.js +3 -0
  144. package/dist/flag-params.d.ts +54 -0
  145. package/dist/flag-params.d.ts.map +1 -0
  146. package/dist/flag-params.js +130 -0
  147. package/dist/index.d.ts +1 -0
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +2 -0
  150. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +120 -0
  151. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -0
  152. package/dist/lifecycle/__fixtures__/publish-fakes.js +304 -0
  153. package/dist/lifecycle/change-set-store.d.ts +68 -0
  154. package/dist/lifecycle/change-set-store.d.ts.map +1 -0
  155. package/dist/lifecycle/change-set-store.js +97 -0
  156. package/dist/lifecycle/commit-sha.d.ts +13 -0
  157. package/dist/lifecycle/commit-sha.d.ts.map +1 -0
  158. package/dist/lifecycle/commit-sha.js +21 -0
  159. package/dist/lifecycle/delivery-metrics.d.ts +139 -0
  160. package/dist/lifecycle/delivery-metrics.d.ts.map +1 -0
  161. package/dist/lifecycle/delivery-metrics.js +145 -0
  162. package/dist/lifecycle/deploy-outcome.d.ts +81 -0
  163. package/dist/lifecycle/deploy-outcome.d.ts.map +1 -0
  164. package/dist/lifecycle/deploy-outcome.js +101 -0
  165. package/dist/lifecycle/gate-change-set.d.ts +78 -0
  166. package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
  167. package/dist/lifecycle/gate-change-set.js +138 -0
  168. package/dist/lifecycle/gate-ledger.d.ts +51 -4
  169. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  170. package/dist/lifecycle/gate-ledger.js +18 -0
  171. package/dist/lifecycle/git.d.ts +30 -1
  172. package/dist/lifecycle/git.d.ts.map +1 -1
  173. package/dist/lifecycle/git.js +31 -5
  174. package/dist/lifecycle/index.d.ts +4 -0
  175. package/dist/lifecycle/index.d.ts.map +1 -1
  176. package/dist/lifecycle/index.js +4 -0
  177. package/dist/lifecycle/mixed-environment.d.ts +95 -0
  178. package/dist/lifecycle/mixed-environment.d.ts.map +1 -0
  179. package/dist/lifecycle/mixed-environment.js +154 -0
  180. package/dist/lifecycle/publish-attachments.d.ts +79 -0
  181. package/dist/lifecycle/publish-attachments.d.ts.map +1 -0
  182. package/dist/lifecycle/publish-attachments.js +179 -0
  183. package/dist/lifecycle/publish-credentials.d.ts +37 -0
  184. package/dist/lifecycle/publish-credentials.d.ts.map +1 -0
  185. package/dist/lifecycle/publish-credentials.js +69 -0
  186. package/dist/lifecycle/publish-declaration.d.ts +97 -0
  187. package/dist/lifecycle/publish-declaration.d.ts.map +1 -0
  188. package/dist/lifecycle/publish-declaration.js +83 -0
  189. package/dist/lifecycle/publish-forge.d.ts +53 -0
  190. package/dist/lifecycle/publish-forge.d.ts.map +1 -0
  191. package/dist/lifecycle/publish-forge.js +298 -0
  192. package/dist/lifecycle/publish-npm.d.ts +61 -0
  193. package/dist/lifecycle/publish-npm.d.ts.map +1 -0
  194. package/dist/lifecycle/publish-npm.js +242 -0
  195. package/dist/lifecycle/publish-oci.d.ts +64 -0
  196. package/dist/lifecycle/publish-oci.d.ts.map +1 -0
  197. package/dist/lifecycle/publish-oci.js +383 -0
  198. package/dist/lifecycle/publish-record.d.ts +66 -0
  199. package/dist/lifecycle/publish-record.d.ts.map +1 -0
  200. package/dist/lifecycle/publish-record.js +84 -0
  201. package/dist/lifecycle/publish-targets.d.ts +45 -0
  202. package/dist/lifecycle/publish-targets.d.ts.map +1 -0
  203. package/dist/lifecycle/publish-targets.js +85 -0
  204. package/dist/lifecycle/release-cut.d.ts +154 -0
  205. package/dist/lifecycle/release-cut.d.ts.map +1 -0
  206. package/dist/lifecycle/release-cut.js +366 -0
  207. package/dist/lifecycle/release-join.d.ts +95 -0
  208. package/dist/lifecycle/release-join.d.ts.map +1 -0
  209. package/dist/lifecycle/release-join.js +139 -0
  210. package/dist/lifecycle/release-ledger.d.ts +54 -0
  211. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  212. package/dist/lifecycle/release-ledger.js +53 -20
  213. package/dist/lifecycle/release-publish.d.ts +312 -0
  214. package/dist/lifecycle/release-publish.d.ts.map +1 -0
  215. package/dist/lifecycle/release-publish.js +335 -0
  216. package/dist/lifecycle/release-revocation.d.ts +80 -0
  217. package/dist/lifecycle/release-revocation.d.ts.map +1 -0
  218. package/dist/lifecycle/release-revocation.js +123 -0
  219. package/dist/lifecycle/release-store.d.ts +200 -0
  220. package/dist/lifecycle/release-store.d.ts.map +1 -0
  221. package/dist/lifecycle/release-store.js +320 -0
  222. package/dist/lifecycle/release-verify.d.ts +61 -0
  223. package/dist/lifecycle/release-verify.d.ts.map +1 -0
  224. package/dist/lifecycle/release-verify.js +92 -0
  225. package/dist/lifecycle/release-workstation.d.ts +91 -0
  226. package/dist/lifecycle/release-workstation.d.ts.map +1 -0
  227. package/dist/lifecycle/release-workstation.js +180 -0
  228. package/dist/lifecycle/retention-policy.d.ts +45 -0
  229. package/dist/lifecycle/retention-policy.d.ts.map +1 -0
  230. package/dist/lifecycle/retention-policy.js +43 -0
  231. package/dist/lifecycle/retention.d.ts +185 -0
  232. package/dist/lifecycle/retention.d.ts.map +1 -0
  233. package/dist/lifecycle/retention.js +400 -0
  234. package/dist/lifecycle/run-ledger.d.ts +4 -0
  235. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  236. package/dist/lifecycle/run-ledger.js +2 -0
  237. package/dist/op/activities/change-coverage.d.ts.map +1 -1
  238. package/dist/op/activities/change-coverage.js +4 -2
  239. package/dist/op/activities/source-release.d.ts.map +1 -1
  240. package/dist/op/activities/source-release.js +7 -3
  241. package/dist/op/activities/source-rollback.d.ts.map +1 -1
  242. package/dist/op/activities/source-rollback.js +7 -3
  243. package/dist/op/gate-name.d.ts +11 -2
  244. package/dist/op/gate-name.d.ts.map +1 -1
  245. package/dist/op/gate-name.js +12 -3
  246. package/dist/op/gate-run-locator.d.ts +22 -0
  247. package/dist/op/gate-run-locator.d.ts.map +1 -1
  248. package/dist/op/gate-run-locator.js +31 -0
  249. package/dist/op/gate.d.ts +27 -3
  250. package/dist/op/gate.d.ts.map +1 -1
  251. package/dist/op/gate.js +57 -3
  252. package/dist/op/local-executor.d.ts +36 -1
  253. package/dist/op/local-executor.d.ts.map +1 -1
  254. package/dist/op/local-executor.js +158 -52
  255. package/dist/op/op-waves-run.d.ts.map +1 -1
  256. package/dist/op/op-waves-run.js +4 -0
  257. package/dist/op/run-live.d.ts +2 -0
  258. package/dist/op/run-live.d.ts.map +1 -1
  259. package/dist/op/run-live.js +1 -1
  260. package/dist/op/runtime.d.ts +46 -0
  261. package/dist/op/runtime.d.ts.map +1 -1
  262. package/dist/op/runtimes/local.d.ts.map +1 -1
  263. package/dist/op/runtimes/local.js +8 -0
  264. package/dist/plan-summary.d.ts.map +1 -1
  265. package/dist/plan-summary.js +8 -2
  266. package/dist/point-decision.d.ts +2 -0
  267. package/dist/point-decision.d.ts.map +1 -1
  268. package/dist/point-decision.js +9 -2
  269. package/dist/pr-loop.d.ts +7 -0
  270. package/dist/pr-loop.d.ts.map +1 -1
  271. package/dist/pr-loop.js +23 -4
  272. package/dist/pr-report-url.d.ts +82 -0
  273. package/dist/pr-report-url.d.ts.map +1 -0
  274. package/dist/pr-report-url.js +174 -0
  275. package/dist/provenance.d.ts +2 -2
  276. package/dist/provenance.d.ts.map +1 -1
  277. package/dist/run-event-store.d.ts +104 -0
  278. package/dist/run-event-store.d.ts.map +1 -0
  279. package/dist/run-event-store.js +251 -0
  280. package/dist/run-event-stream.d.ts +133 -0
  281. package/dist/run-event-stream.d.ts.map +1 -0
  282. package/dist/run-event-stream.js +242 -0
  283. package/dist/run-event.d.ts +285 -0
  284. package/dist/run-event.d.ts.map +1 -0
  285. package/dist/run-event.js +209 -0
  286. package/dist/wave-runtime.mjs +262 -226
  287. package/dist/workspace/__fixtures__/flag-workspace.d.ts +31 -0
  288. package/dist/workspace/__fixtures__/flag-workspace.d.ts.map +1 -0
  289. package/dist/workspace/__fixtures__/flag-workspace.js +114 -0
  290. package/dist/workspace/__fixtures__/run-event-check.d.ts +19 -0
  291. package/dist/workspace/__fixtures__/run-event-check.d.ts.map +1 -0
  292. package/dist/workspace/__fixtures__/run-event-check.js +59 -0
  293. package/dist/workspace/change-set-show.d.ts +56 -0
  294. package/dist/workspace/change-set-show.d.ts.map +1 -0
  295. package/dist/workspace/change-set-show.js +54 -0
  296. package/dist/workspace/change-set-show.schema.json +102 -0
  297. package/dist/workspace/change-set.schema.json +32 -1
  298. package/dist/workspace/changes-cli.d.ts.map +1 -1
  299. package/dist/workspace/changes-cli.js +10 -1
  300. package/dist/workspace/changes.d.ts +37 -0
  301. package/dist/workspace/changes.d.ts.map +1 -1
  302. package/dist/workspace/changes.js +49 -2
  303. package/dist/workspace/changes.schema.json +135 -0
  304. package/dist/workspace/check.schema.json +4 -2
  305. package/dist/workspace/checks/records.d.ts +9 -1
  306. package/dist/workspace/checks/records.d.ts.map +1 -1
  307. package/dist/workspace/checks/records.js +35 -1
  308. package/dist/workspace/checks.d.ts +1 -0
  309. package/dist/workspace/checks.d.ts.map +1 -1
  310. package/dist/workspace/checks.js +2 -1
  311. package/dist/workspace/ci-green-cli.d.ts +19 -4
  312. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  313. package/dist/workspace/ci-green-cli.js +75 -12
  314. package/dist/workspace/ci-green-forge.d.ts +20 -3
  315. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  316. package/dist/workspace/ci-green-forge.js +6 -4
  317. package/dist/workspace/ci-green-workflow.d.ts +11 -0
  318. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  319. package/dist/workspace/ci-green-workflow.js +6 -0
  320. package/dist/workspace/ci-green.d.ts +281 -13
  321. package/dist/workspace/ci-green.d.ts.map +1 -1
  322. package/dist/workspace/ci-green.js +456 -38
  323. package/dist/workspace/ci-last-green.schema.json +32 -2
  324. package/dist/workspace/ci-list.schema.json +525 -0
  325. package/dist/workspace/commit-links.d.ts +85 -0
  326. package/dist/workspace/commit-links.d.ts.map +1 -0
  327. package/dist/workspace/commit-links.js +163 -0
  328. package/dist/workspace/declaration.d.ts +35 -0
  329. package/dist/workspace/declaration.d.ts.map +1 -1
  330. package/dist/workspace/declaration.js +27 -1
  331. package/dist/workspace/declaration.schema.json +76 -0
  332. package/dist/workspace/declared-kinds.d.ts +16 -0
  333. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  334. package/dist/workspace/declared-kinds.js +25 -0
  335. package/dist/workspace/delivery-metrics.d.ts +91 -0
  336. package/dist/workspace/delivery-metrics.d.ts.map +1 -0
  337. package/dist/workspace/delivery-metrics.js +217 -0
  338. package/dist/workspace/delivery-metrics.schema.json +519 -0
  339. package/dist/workspace/flags-read.d.ts +37 -0
  340. package/dist/workspace/flags-read.d.ts.map +1 -0
  341. package/dist/workspace/flags-read.js +103 -0
  342. package/dist/workspace/flags.d.ts +100 -0
  343. package/dist/workspace/flags.d.ts.map +1 -0
  344. package/dist/workspace/flags.js +98 -0
  345. package/dist/workspace/graph-cli.js +1 -1
  346. package/dist/workspace/identity-gate-rule.d.ts +37 -0
  347. package/dist/workspace/identity-gate-rule.d.ts.map +1 -1
  348. package/dist/workspace/identity-gate-rule.js +72 -7
  349. package/dist/workspace/identity.d.ts +12 -0
  350. package/dist/workspace/identity.d.ts.map +1 -1
  351. package/dist/workspace/identity.js +13 -1
  352. package/dist/workspace/intent-cli.d.ts +11 -2
  353. package/dist/workspace/intent-cli.d.ts.map +1 -1
  354. package/dist/workspace/intent-cli.js +54 -5
  355. package/dist/workspace/intent-trace.d.ts +219 -0
  356. package/dist/workspace/intent-trace.d.ts.map +1 -0
  357. package/dist/workspace/intent-trace.js +314 -0
  358. package/dist/workspace/intent.d.ts +36 -7
  359. package/dist/workspace/intent.d.ts.map +1 -1
  360. package/dist/workspace/intent.js +192 -22
  361. package/dist/workspace/intent.schema.json +702 -6
  362. package/dist/workspace/ls.d.ts +4 -0
  363. package/dist/workspace/ls.d.ts.map +1 -1
  364. package/dist/workspace/ls.js +2 -0
  365. package/dist/workspace/ls.schema.json +3 -1
  366. package/dist/workspace/member-pipeline.d.ts +6 -0
  367. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  368. package/dist/workspace/member-pipeline.js +6 -0
  369. package/dist/workspace/overlap.d.ts +146 -0
  370. package/dist/workspace/overlap.d.ts.map +1 -0
  371. package/dist/workspace/overlap.js +276 -0
  372. package/dist/workspace/promotion-order.d.ts +41 -0
  373. package/dist/workspace/promotion-order.d.ts.map +1 -0
  374. package/dist/workspace/promotion-order.js +95 -0
  375. package/dist/workspace/reason-codes.d.ts +4 -0
  376. package/dist/workspace/reason-codes.d.ts.map +1 -1
  377. package/dist/workspace/reason-codes.js +7 -1
  378. package/dist/workspace/records.d.ts +15 -2
  379. package/dist/workspace/records.d.ts.map +1 -1
  380. package/dist/workspace/records.js +32 -0
  381. package/dist/workspace/records.schema.json +21 -2
  382. package/dist/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  383. package/dist/workspace/reference-kinds/flag/flag.schema.json +53 -0
  384. package/dist/workspace/releases.d.ts +81 -0
  385. package/dist/workspace/releases.d.ts.map +1 -0
  386. package/dist/workspace/releases.js +103 -0
  387. package/dist/workspace/releases.schema.json +513 -0
  388. package/dist/workspace/run-event.schema.json +295 -0
  389. package/dist/workspace/status-gates.d.ts +34 -1
  390. package/dist/workspace/status-gates.d.ts.map +1 -1
  391. package/dist/workspace/status-gates.js +31 -2
  392. package/dist/workspace/status-stewards.d.ts +4 -0
  393. package/dist/workspace/status-stewards.d.ts.map +1 -1
  394. package/dist/workspace/status-stewards.js +2 -0
  395. package/dist/workspace/status.d.ts +117 -0
  396. package/dist/workspace/status.d.ts.map +1 -1
  397. package/dist/workspace/status.js +218 -4
  398. package/dist/workspace/status.schema.json +268 -2
  399. package/dist/workspace/trust/ci-tag-statement.d.ts +102 -0
  400. package/dist/workspace/trust/ci-tag-statement.d.ts.map +1 -0
  401. package/dist/workspace/trust/ci-tag-statement.js +123 -0
  402. package/dist/workspace/trust/op-run-statement.d.ts +91 -0
  403. package/dist/workspace/trust/op-run-statement.d.ts.map +1 -0
  404. package/dist/workspace/trust/op-run-statement.js +143 -0
  405. package/dist/workspace/trust/rotation.d.ts +18 -2
  406. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  407. package/dist/workspace/trust/rotation.js +65 -16
  408. package/dist/workspace/trust/seal.d.ts +11 -0
  409. package/dist/workspace/trust/seal.d.ts.map +1 -1
  410. package/dist/workspace/trust/seal.js +9 -0
  411. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  412. package/dist/workspace/trust/ssh-commit.js +10 -10
  413. package/dist/workspace/wip.d.ts.map +1 -1
  414. package/dist/workspace/wip.js +11 -3
  415. package/package.json +1 -1
  416. package/src/__golden__/wave-loop/fan-out-gated.json +8 -0
  417. package/src/__golden__/wave-loop/fan-out-no-members.json +4 -0
  418. package/src/__golden__/wave-loop/fan-out-only.json +6 -0
  419. package/src/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  420. package/src/__golden__/wave-loop/op-cost-member.json +3 -0
  421. package/src/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  422. package/src/__golden__/wave-loop/op-held-on.json +2 -0
  423. package/src/__golden__/wave-loop/op-hooks-held.json +2 -0
  424. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  425. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  426. package/src/__golden__/wave-loop/op-hooks-share.json +3 -0
  427. package/src/__golden__/wave-loop/op-per-run.json +7 -0
  428. package/src/__golden__/wave-loop/op-pr-review.json +7 -0
  429. package/src/__golden__/wave-loop/op-sealed.json +3 -0
  430. package/src/__golden__/wave-loop/op-spend.json +3 -0
  431. package/src/__golden__/wave-loop/op-wave-commands.json +7 -0
  432. package/src/__golden__/wave-loop/op-wide-waiting.json +4 -0
  433. package/src/build-params.test.ts +46 -0
  434. package/src/build-params.ts +55 -1
  435. package/src/change-set-graph.test.ts +72 -0
  436. package/src/change-set-graph.ts +141 -0
  437. package/src/change-set.ts +87 -6
  438. package/src/chant-version.ts +16 -0
  439. package/src/cli/build-params-cli.ts +22 -9
  440. package/src/cli/commands/build.ts +25 -11
  441. package/src/cli/commands/check-lexicon-docs.test.ts +51 -0
  442. package/src/cli/commands/check-lexicon-docs.ts +39 -2
  443. package/src/cli/commands/check-lexicon.ts +14 -2
  444. package/src/cli/commands/init-lexicon/templates/docs.ts +7 -6
  445. package/src/cli/commands/init-lexicon.test.ts +25 -0
  446. package/src/cli/commands/init-lexicon.ts +18 -8
  447. package/src/cli/handlers/approve-release.test.ts +84 -0
  448. package/src/cli/handlers/approve-revoked.test.ts +155 -0
  449. package/src/cli/handlers/approve.ts +65 -2
  450. package/src/cli/handlers/build.test.ts +67 -0
  451. package/src/cli/handlers/build.ts +46 -4
  452. package/src/cli/handlers/change-set.ts +49 -1
  453. package/src/cli/handlers/fan-out.test.ts +228 -1
  454. package/src/cli/handlers/fan-out.ts +53 -6
  455. package/src/cli/handlers/intent-trace.e2e.test.ts +201 -0
  456. package/src/cli/handlers/lifecycle-gc.test.ts +126 -0
  457. package/src/cli/handlers/lifecycle-gc.ts +146 -0
  458. package/src/cli/handlers/operator.test.ts +37 -0
  459. package/src/cli/handlers/pr.test.ts +341 -0
  460. package/src/cli/handlers/pr.ts +292 -47
  461. package/src/cli/handlers/promote.test.ts +669 -7
  462. package/src/cli/handlers/promote.ts +464 -29
  463. package/src/cli/handlers/release-implicit.e2e.test.ts +161 -0
  464. package/src/cli/handlers/release-join.e2e.test.ts +185 -0
  465. package/src/cli/handlers/release-publish-targets.e2e.test.ts +295 -0
  466. package/src/cli/handlers/release-verify.e2e.test.ts +117 -0
  467. package/src/cli/handlers/release-workstation-ci.e2e.test.ts +135 -0
  468. package/src/cli/handlers/release.e2e.test.ts +199 -0
  469. package/src/cli/handlers/release.ts +593 -0
  470. package/src/cli/handlers/run-auto-release.test.ts +80 -0
  471. package/src/cli/handlers/run-events-cmd.test.ts +92 -0
  472. package/src/cli/handlers/run-release.test.ts +55 -0
  473. package/src/cli/handlers/run.test.ts +30 -0
  474. package/src/cli/handlers/run.ts +243 -18
  475. package/src/cli/main.test.ts +8 -0
  476. package/src/cli/main.ts +143 -17
  477. package/src/cli/mcp/never-over-mcp.test.ts +2 -0
  478. package/src/cli/mcp/workspace-tools.ts +1 -1
  479. package/src/cli/parse-args.ts +56 -5
  480. package/src/cli/registry.ts +43 -5
  481. package/src/cli/run-events.ts +57 -0
  482. package/src/cli/version.ts +3 -13
  483. package/src/codegen/docs-in-site.test.ts +166 -0
  484. package/src/codegen/docs-in-site.ts +182 -0
  485. package/src/codegen/docs-site/AgentPrompt.astro +26 -1
  486. package/src/codegen/docs-types.ts +14 -1
  487. package/src/codegen/docs.ts +60 -7
  488. package/src/codegen/rehype-base-url.d.mts +3 -1
  489. package/src/codegen/rehype-base-url.mjs +15 -9
  490. package/src/codegen/rehype-base-url.test.ts +34 -0
  491. package/src/components/auto-release.test.ts +30 -0
  492. package/src/components/auto-release.ts +9 -1
  493. package/src/components/capability.ts +9 -0
  494. package/src/components/cli-support.test.ts +82 -0
  495. package/src/components/cli-support.ts +16 -9
  496. package/src/components/driver.test.ts +24 -0
  497. package/src/components/driver.ts +165 -56
  498. package/src/components/fan-out-inputs.test.ts +85 -0
  499. package/src/components/fan-out-inputs.ts +192 -0
  500. package/src/components/fan-out-record.test.ts +10 -0
  501. package/src/components/fan-out-record.ts +19 -0
  502. package/src/components/fan-out-run.ts +104 -35
  503. package/src/components/fan-out.ts +4 -0
  504. package/src/components/pr-pipeline.ts +35 -4
  505. package/src/components/pr-run.ts +30 -1
  506. package/src/components/promote-order.test.ts +90 -0
  507. package/src/components/promote-order.ts +75 -0
  508. package/src/components/promote.test.ts +10 -1
  509. package/src/components/promote.ts +94 -3
  510. package/src/components/release-compile.test.ts +147 -0
  511. package/src/components/release-compile.ts +459 -0
  512. package/src/components/release-gate.test.ts +215 -0
  513. package/src/components/release-gate.ts +355 -0
  514. package/src/components/release-promote.test.ts +159 -0
  515. package/src/components/release-promote.ts +232 -0
  516. package/src/components/run-progress.ts +7 -0
  517. package/src/components/wave-plan.ts +16 -3
  518. package/src/config.ts +15 -1
  519. package/src/flag-params.test.ts +144 -0
  520. package/src/flag-params.ts +134 -0
  521. package/src/index.ts +2 -0
  522. package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
  523. package/src/lifecycle/change-set-store.test.ts +217 -0
  524. package/src/lifecycle/change-set-store.ts +113 -0
  525. package/src/lifecycle/commit-sha.ts +23 -0
  526. package/src/lifecycle/delivery-metrics.ts +263 -0
  527. package/src/lifecycle/deploy-outcome.ts +147 -0
  528. package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
  529. package/src/lifecycle/gate-change-set.ts +164 -0
  530. package/src/lifecycle/gate-ledger.test.ts +33 -0
  531. package/src/lifecycle/gate-ledger.ts +68 -3
  532. package/src/lifecycle/git.ts +61 -8
  533. package/src/lifecycle/index.ts +4 -0
  534. package/src/lifecycle/mixed-environment.test.ts +97 -0
  535. package/src/lifecycle/mixed-environment.ts +204 -0
  536. package/src/lifecycle/publish-attachments.ts +196 -0
  537. package/src/lifecycle/publish-credentials.ts +84 -0
  538. package/src/lifecycle/publish-declaration.ts +95 -0
  539. package/src/lifecycle/publish-forge.ts +325 -0
  540. package/src/lifecycle/publish-npm.ts +259 -0
  541. package/src/lifecycle/publish-oci.ts +396 -0
  542. package/src/lifecycle/publish-record.ts +113 -0
  543. package/src/lifecycle/publish-resume.test.ts +168 -0
  544. package/src/lifecycle/publish-targets.test.ts +494 -0
  545. package/src/lifecycle/publish-targets.ts +100 -0
  546. package/src/lifecycle/release-cut-signed.test.ts +180 -0
  547. package/src/lifecycle/release-cut.test.ts +483 -0
  548. package/src/lifecycle/release-cut.ts +503 -0
  549. package/src/lifecycle/release-flag.test.ts +112 -0
  550. package/src/lifecycle/release-join.test.ts +68 -0
  551. package/src/lifecycle/release-join.ts +182 -0
  552. package/src/lifecycle/release-ledger.test.ts +14 -0
  553. package/src/lifecycle/release-ledger.ts +85 -17
  554. package/src/lifecycle/release-publish.test.ts +225 -0
  555. package/src/lifecycle/release-publish.ts +568 -0
  556. package/src/lifecycle/release-revocation.ts +147 -0
  557. package/src/lifecycle/release-store.ts +434 -0
  558. package/src/lifecycle/release-verify.test.ts +110 -0
  559. package/src/lifecycle/release-verify.ts +120 -0
  560. package/src/lifecycle/release-workstation.test.ts +204 -0
  561. package/src/lifecycle/release-workstation.ts +216 -0
  562. package/src/lifecycle/retention-growth.e2e.test.ts +279 -0
  563. package/src/lifecycle/retention-policy.ts +63 -0
  564. package/src/lifecycle/retention.test.ts +363 -0
  565. package/src/lifecycle/retention.ts +508 -0
  566. package/src/lifecycle/run-ledger.test.ts +10 -0
  567. package/src/lifecycle/run-ledger.ts +6 -0
  568. package/src/op/activities/change-coverage.ts +4 -1
  569. package/src/op/activities/source-release.ts +8 -3
  570. package/src/op/activities/source-rollback.ts +8 -4
  571. package/src/op/commit-run-gate-deploy-join.test.ts +117 -0
  572. package/src/op/gate-name.ts +13 -3
  573. package/src/op/gate-release.test.ts +126 -0
  574. package/src/op/gate-run-locator.test.ts +110 -0
  575. package/src/op/gate-run-locator.ts +35 -0
  576. package/src/op/gate.ts +88 -6
  577. package/src/op/local-executor.ts +207 -52
  578. package/src/op/op-waves-run.ts +4 -0
  579. package/src/op/run-events.test.ts +166 -0
  580. package/src/op/run-live.ts +1 -1
  581. package/src/op/runtime.ts +39 -0
  582. package/src/op/runtimes/local.test.ts +16 -0
  583. package/src/op/runtimes/local.ts +9 -0
  584. package/src/plan-summary.test.ts +20 -0
  585. package/src/plan-summary.ts +8 -1
  586. package/src/point-decision.ts +12 -2
  587. package/src/pr-loop.ts +25 -4
  588. package/src/pr-report-url.test.ts +131 -0
  589. package/src/pr-report-url.ts +209 -0
  590. package/src/provenance.ts +2 -2
  591. package/src/run-event-store.test.ts +144 -0
  592. package/src/run-event-store.ts +273 -0
  593. package/src/run-event-stream.test.ts +175 -0
  594. package/src/run-event-stream.ts +309 -0
  595. package/src/run-event.test.ts +277 -0
  596. package/src/run-event.ts +471 -0
  597. package/src/wave-loop-golden.test.ts +9 -0
  598. package/src/workspace/__fixtures__/flag-workspace.ts +132 -0
  599. package/src/workspace/__fixtures__/older-records/change-set-984534ea9.json +100 -0
  600. package/src/workspace/__fixtures__/older-records/older-records.json +326 -0
  601. package/src/workspace/__fixtures__/run-event-check.ts +58 -0
  602. package/src/workspace/ancestry-index.test.ts +93 -0
  603. package/src/workspace/change-set-show.schema.json +102 -0
  604. package/src/workspace/change-set-show.ts +72 -0
  605. package/src/workspace/change-set.schema.json +32 -1
  606. package/src/workspace/changes-cli.ts +10 -1
  607. package/src/workspace/changes.schema.json +135 -0
  608. package/src/workspace/changes.test.ts +1 -1
  609. package/src/workspace/changes.ts +84 -2
  610. package/src/workspace/check.schema.json +4 -2
  611. package/src/workspace/checks/records.ts +35 -1
  612. package/src/workspace/checks.ts +2 -1
  613. package/src/workspace/ci-green-cli.ts +75 -13
  614. package/src/workspace/ci-green-forge.ts +24 -4
  615. package/src/workspace/ci-green-runs.test.ts +242 -0
  616. package/src/workspace/ci-green-signed.test.ts +302 -0
  617. package/src/workspace/ci-green-workflow.test.ts +16 -0
  618. package/src/workspace/ci-green-workflow.ts +12 -0
  619. package/src/workspace/ci-green.test.ts +131 -2
  620. package/src/workspace/ci-green.ts +635 -42
  621. package/src/workspace/ci-last-green.schema.json +32 -2
  622. package/src/workspace/ci-list.schema.json +525 -0
  623. package/src/workspace/commit-links.test.ts +279 -0
  624. package/src/workspace/commit-links.ts +183 -0
  625. package/src/workspace/declaration.schema.json +76 -0
  626. package/src/workspace/declaration.test.ts +28 -0
  627. package/src/workspace/declaration.ts +60 -2
  628. package/src/workspace/declared-kinds.ts +40 -1
  629. package/src/workspace/delivery-metrics.schema.json +519 -0
  630. package/src/workspace/delivery-metrics.test.ts +236 -0
  631. package/src/workspace/delivery-metrics.ts +286 -0
  632. package/src/workspace/flags-read.ts +121 -0
  633. package/src/workspace/flags.test.ts +141 -0
  634. package/src/workspace/flags.ts +157 -0
  635. package/src/workspace/graph-cli.ts +1 -1
  636. package/src/workspace/identity-gate-rule.ts +91 -7
  637. package/src/workspace/identity.ts +14 -1
  638. package/src/workspace/intent-cli.ts +46 -5
  639. package/src/workspace/intent-trace.test.ts +173 -0
  640. package/src/workspace/intent-trace.ts +484 -0
  641. package/src/workspace/intent.schema.json +702 -6
  642. package/src/workspace/intent.ts +196 -26
  643. package/src/workspace/ls.schema.json +3 -1
  644. package/src/workspace/ls.ts +6 -0
  645. package/src/workspace/member-pipeline.test.ts +17 -0
  646. package/src/workspace/member-pipeline.ts +9 -0
  647. package/src/workspace/older-records.test.ts +412 -0
  648. package/src/workspace/overlap.test.ts +165 -0
  649. package/src/workspace/overlap.ts +340 -0
  650. package/src/workspace/promotion-order.ts +97 -0
  651. package/src/workspace/read-contract.e2e.test.ts +5 -1
  652. package/src/workspace/reason-codes.test.ts +7 -1
  653. package/src/workspace/reason-codes.ts +7 -1
  654. package/src/workspace/record-assets.test.ts +2 -1
  655. package/src/workspace/records-contract.e2e.test.ts +2 -1
  656. package/src/workspace/records.schema.json +21 -2
  657. package/src/workspace/records.ts +36 -2
  658. package/src/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  659. package/src/workspace/reference-kinds/flag/flag.schema.json +53 -0
  660. package/src/workspace/releases.schema.json +513 -0
  661. package/src/workspace/releases.test.ts +108 -0
  662. package/src/workspace/releases.ts +133 -0
  663. package/src/workspace/run-event.schema.json +295 -0
  664. package/src/workspace/status-contract.test.ts +81 -1
  665. package/src/workspace/status-gates.ts +64 -1
  666. package/src/workspace/status-mixed.test.ts +152 -0
  667. package/src/workspace/status-revoked.test.ts +153 -0
  668. package/src/workspace/status-stewards.ts +6 -0
  669. package/src/workspace/status.schema.json +268 -2
  670. package/src/workspace/status.ts +334 -4
  671. package/src/workspace/trust/ci-tag-statement.ts +151 -0
  672. package/src/workspace/trust/op-run-statement.ts +148 -0
  673. package/src/workspace/trust/rotation.ts +61 -14
  674. package/src/workspace/trust/seal.ts +10 -0
  675. package/src/workspace/trust/ssh-commit.ts +10 -9
  676. package/src/workspace/wip.ts +11 -2
  677. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -14
  678. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +0 -16
  679. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +0 -8
  680. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +0 -15
  681. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +0 -10
@@ -52,6 +52,7 @@ import { gateName } from "../op/gate-name.js";
52
52
  import { GateNotRecordableError } from "../lifecycle/no-record.js";
53
53
  import { componentPlanDigest } from "./gate-plan.js";
54
54
  import { isPromotedArtifact } from "./auto-release.js";
55
+ import { gateEventsOf, joinRunEventSinks, progressSinkOf } from "../run-event-stream.js";
55
56
  function isGateStep(step) {
56
57
  return step.kind === "gate";
57
58
  }
@@ -185,6 +186,41 @@ export function resolveStepInput(input, phaseOutputs, componentOutputs) {
185
186
  };
186
187
  return walk(input);
187
188
  }
189
+ /**
190
+ * The components (or stacks) whose outputs `input` reads through
191
+ * cross-component wiring, `stackOutput()` or `@<component>.publish.*`, and
192
+ * which have no value for it in `componentOutputs`, sorted and each once
193
+ * (#4084). {@link resolveStepInput} turns each such reference into
194
+ * `undefined`; a plan uses this to say whose outputs it is waiting on.
195
+ */
196
+ export function unresolvedWiringSources(input, componentOutputs) {
197
+ const found = new Set();
198
+ const walk = (value) => {
199
+ if (typeof value === "string") {
200
+ if (PRIOR_STEP_REF.test(value))
201
+ return;
202
+ const ref = value.match(COMPONENT_ARTIFACT_REF);
203
+ if (ref && resolvePath(componentOutputs[ref[1]]?.publish, ref[2]) === undefined)
204
+ found.add(ref[1]);
205
+ return;
206
+ }
207
+ if (Array.isArray(value)) {
208
+ value.forEach(walk);
209
+ return;
210
+ }
211
+ if (value && typeof value === "object") {
212
+ if ("stackOutput" in value) {
213
+ const { stack, name } = value.stackOutput;
214
+ if (resolvePath(componentOutputs[stack], name) === undefined)
215
+ found.add(stack);
216
+ return;
217
+ }
218
+ Object.values(value).forEach(walk);
219
+ }
220
+ };
221
+ walk(input);
222
+ return [...found].sort();
223
+ }
188
224
  class StepFailure extends Error {
189
225
  constructor(records, executed) {
190
226
  super("step failed");
@@ -210,7 +246,7 @@ class GateStop extends Error {
210
246
  this.name = "GateStop";
211
247
  }
212
248
  }
213
- /** A result status as the progress stream spells it — the only difference is `fail` vs `failed`, which the two vocabularies have always disagreed on. */
249
+ /** A result status as the event stream spells it — the only difference is `fail` vs `failed`, which the two vocabularies have always disagreed on. */
214
250
  function progressStatus(status) {
215
251
  return status === "fail" ? "failed" : status;
216
252
  }
@@ -261,30 +297,44 @@ async function runCapabilityStep(step, phaseName, ctx, registry, phaseOutputs, c
261
297
  * gate is a read of the ledger rather than work, and starting activities a
262
298
  * pending gate is about to strand defeats the point of stopping at it.
263
299
  *
264
- * `onProgress`, when supplied, is called with a `phase-start` event before any
265
- * step runs, a `step` event around each capability invocation (`"running"`
266
- * then `"ok"`/`"failed"`), and a `phase-done` event once the phase settles —
267
- * purely additive observation, never consulted for control flow. Recursion
268
- * into a nested fan-out phase passes the same callback through, so a nested
269
- * phase's events use its own name. Left `undefined` by every caller that
270
- * doesn't opt into `--progress-json` (see ./run-progress.ts), in which case
271
- * every `onProgress?.(...)` call below is a no-op and behavior is unchanged.
300
+ * `emit`, when supplied, gets the phase's run events (#4041): `phase-start`
301
+ * before any step runs, a `step-start` and a `step-settle` around each gate
302
+ * and each capability invocation, the gate's `gate-resolved` or
303
+ * `gate-waiting`, a `skipped` settle with `skip: "not-run"` for each step a
304
+ * failure or a gate stopped, and `phase-settle` once the phase settles. It
305
+ * is observation only, never consulted for control flow. Recursion into a
306
+ * nested fan-out phase passes the same sink through, so a nested phase's
307
+ * events use its own name. `--progress-json` reads the same events through
308
+ * `progressOfRunEvent` (../run-event-stream.ts), which keeps the older
309
+ * stream's shape.
272
310
  */
273
- async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, onProgress) {
311
+ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit) {
312
+ /** Where a step of this phase sits, for its events. */
313
+ const stepAt = (entry, step) => ({
314
+ component: ctx.component,
315
+ phase: phaseDef.phase,
316
+ step,
317
+ index: phaseDef.steps.indexOf(entry),
318
+ });
274
319
  /** Decide this phase's gates against the ledger, in authored order, before any of its work starts. Throws `GateStop` at the first one nobody has approved. */
275
320
  const decideGates = async () => {
276
321
  const gateRecords = [];
277
322
  for (const gate of phaseDef.steps.filter(isGateStep)) {
278
323
  const start = Date.now();
279
324
  const base = { component: ctx.component, phase: phaseDef.phase, kind: `gate:${gateName(gate)}` };
325
+ const at = stepAt(gate, base.kind);
326
+ emit?.({ type: "step-start", ...at });
280
327
  let check;
281
328
  try {
282
329
  check = await evaluateGate(gates.port, {
283
- op: ctx.component,
330
+ op: gates.releaseGate?.op ?? ctx.component,
284
331
  gate: gateName(gate),
285
332
  // #2574: an approval counts only for this environment and this plan.
286
333
  environment: ctx.env,
287
334
  ...(gates.planDigest !== undefined ? { planDigest: gates.planDigest } : {}),
335
+ // #4045: and under a release, only for that release.
336
+ ...(gates.releaseGate ? { releaseDigest: gates.releaseGate.releaseDigest } : {}),
337
+ ...(gates.releaseGate?.verifyEmpty ? { verifyEmpty: gates.releaseGate.verifyEmpty } : {}),
288
338
  ...(gate.description ? { description: gate.description } : {}),
289
339
  ...(gate.timeout ? { timeout: gate.timeout } : {}),
290
340
  ...(gates.now ? { now: gates.now } : {}),
@@ -296,11 +346,18 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
296
346
  if (!(err instanceof GateNotRecordableError))
297
347
  throw err;
298
348
  gateRecords.push({ ...base, status: "fail", durationMs: Date.now() - start, error: err.message });
349
+ emit?.({ type: "step-settle", ...at, status: "failed", durationMs: Date.now() - start, error: err.message });
299
350
  for (const skipped of phaseDef.steps.filter((s) => !isGateStep(s))) {
300
351
  gateRecords.push(skippedRecord(skipped));
301
352
  }
302
353
  throw new StepFailure(gateRecords, []);
303
354
  }
355
+ for (const body of gateEventsOf(check, { ...at, op: gates.releaseGate?.op ?? ctx.component, gate: gateName(gate) }, {
356
+ durationMs: Date.now() - start,
357
+ ...(!check.satisfied && check.mismatch ? { message: "an approval stands for this gate, but for another environment or plan" } : {}),
358
+ })) {
359
+ emit?.(body);
360
+ }
304
361
  if (!check.satisfied) {
305
362
  gateRecords.push({ ...base, status: "skipped", durationMs: Date.now() - start });
306
363
  for (const skipped of phaseDef.steps.filter((s) => !isGateStep(s))) {
@@ -317,6 +374,8 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
317
374
  resolvedBy: check.resolution.resolvedBy,
318
375
  timestamp: check.resolution.timestamp,
319
376
  ...(check.resolution.url ? { url: check.resolution.url } : {}),
377
+ ...(gates.releaseGate ? { op: gates.releaseGate.op } : {}),
378
+ ...(check.via === "empty" ? { empty: true } : {}),
320
379
  },
321
380
  });
322
381
  }
@@ -326,7 +385,7 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
326
385
  const runEntry = async (entry) => {
327
386
  if (isPhaseStep(entry)) {
328
387
  try {
329
- const nested = await runPhase(entry, ctx, registry, phaseOutputs, componentOutputs, gates, onProgress);
388
+ const nested = await runPhase(entry, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
330
389
  return { ...nested, failed: false };
331
390
  }
332
391
  catch (err) {
@@ -348,14 +407,14 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
348
407
  throw err;
349
408
  }
350
409
  }
351
- onProgress?.({ type: "step", component: ctx.component, phase: phaseDef.phase, step: entry.kind, status: "running" });
410
+ const at = stepAt(entry, entry.kind);
411
+ emit?.({ type: "step-start", ...at });
352
412
  const { record, resolvedInput, output } = await runCapabilityStep(entry, phaseDef.phase, ctx, registry, phaseOutputs, componentOutputs);
353
- onProgress?.({
354
- type: "step",
355
- component: ctx.component,
356
- phase: phaseDef.phase,
357
- step: entry.kind,
413
+ emit?.({
414
+ type: "step-settle",
415
+ ...at,
358
416
  status: record.status === "ok" ? "ok" : "failed",
417
+ durationMs: record.durationMs,
359
418
  ...(record.error !== undefined ? { error: record.error } : {}),
360
419
  });
361
420
  if (record.status === "ok") {
@@ -372,13 +431,12 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
372
431
  failed: record.status === "fail",
373
432
  };
374
433
  };
375
- const skippedRecord = (entry) => ({
376
- component: ctx.component,
377
- phase: phaseDef.phase,
378
- kind: isPhaseStep(entry) ? entry.phase : entry.kind,
379
- status: "skipped",
380
- durationMs: 0,
381
- });
434
+ /** A step a failure or a gate stopped before it started: recorded, and settled `skipped` with `skip: "not-run"`. */
435
+ const skippedRecord = (entry) => {
436
+ const kind = isPhaseStep(entry) ? entry.phase : entry.kind;
437
+ emit?.({ type: "step-settle", ...stepAt(entry, kind), status: "skipped", skip: "not-run", durationMs: null });
438
+ return { component: ctx.component, phase: phaseDef.phase, kind, status: "skipped", durationMs: 0 };
439
+ };
382
440
  const runEntries = async () => {
383
441
  const gateRecords = await decideGates();
384
442
  if (phaseDef.parallel) {
@@ -412,18 +470,18 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
412
470
  }
413
471
  return { records, executed };
414
472
  };
415
- onProgress?.({ type: "phase-start", component: ctx.component, phase: phaseDef.phase });
473
+ emit?.({ type: "phase-start", component: ctx.component, phase: phaseDef.phase });
416
474
  try {
417
475
  const result = await runEntries();
418
- onProgress?.({ type: "phase-done", component: ctx.component, phase: phaseDef.phase, status: "ok" });
476
+ emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "ok" });
419
477
  return result;
420
478
  }
421
479
  catch (err) {
422
480
  if (err instanceof GateStop) {
423
- onProgress?.({ type: "phase-done", component: ctx.component, phase: phaseDef.phase, status: "gated" });
481
+ emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "gated" });
424
482
  }
425
483
  else if (err instanceof StepFailure) {
426
- onProgress?.({ type: "phase-done", component: ctx.component, phase: phaseDef.phase, status: "failed" });
484
+ emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "failed" });
427
485
  }
428
486
  throw err;
429
487
  }
@@ -492,16 +550,17 @@ async function rollbackExecuted(executed, ctx, registry) {
492
550
  * any) are recorded into `componentOutputs` under its own name so downstream
493
551
  * components can reference `@<name>.publish.*`.
494
552
  *
495
- * `onProgress`, when supplied, is forwarded to every `runPhase` call (both the
496
- * forward `deploy` phases and, on failure, the component's own authored
497
- * `rollback` phases) so a `--progress-json` consumer sees `phase-start`/
498
- * `step`/`phase-done` events for whichever phases actually ran. The saga
499
- * unwind step-by-step compensation (`rollbackExecuted` below) is not part of
500
- * the `RunProgressEvent` contract and stays silent — it isn't a `deploy`
501
- * phase, and its record statuses (`rolled-back`/`rollback-opted-out`) don't
502
- * map onto the `step` event's `running`/`ok`/`failed` shape.
553
+ * `onProgress` (the older `RunProgressEvent` stream) and `onRunEvent` (run
554
+ * events, #4041), when supplied, are forwarded to every `runPhase` call (both
555
+ * the forward `deploy` phases and, on failure, the component's own authored
556
+ * `rollback` phases), so a consumer sees the phase and step events of
557
+ * whichever phases actually ran. The saga unwind step-by-step compensation
558
+ * (`rollbackExecuted` below) stays silent: it isn't a `deploy` phase, and
559
+ * its record statuses (`rolled-back`/`rollback-opted-out`) are not step
560
+ * statuses either stream has.
503
561
  */
504
- export async function runComponentDeploy(component, ctx, registry, componentOutputs, onProgress, gateContext = { port: gitGateLedgerPort() }) {
562
+ export async function runComponentDeploy(component, ctx, registry, componentOutputs, onProgress, gateContext = { port: gitGateLedgerPort() }, onRunEvent) {
563
+ const emit = joinRunEventSinks(onRunEvent, progressSinkOf(onProgress));
505
564
  // Each component tracks its own release: a digest one component promoted never stamps another's deploy.
506
565
  if (ctx.release)
507
566
  ctx = { ...ctx, release: { ...ctx.release } };
@@ -515,18 +574,20 @@ export async function runComponentDeploy(component, ctx, registry, componentOutp
515
574
  ctx.release.version = release;
516
575
  const gates = {
517
576
  ...gateContext,
518
- planDigest: componentPlanDigest({
519
- environment: ctx.env,
520
- component,
521
- ...(ctx.vars ? { vars: ctx.vars } : {}),
522
- ...(release !== undefined ? { release } : {}),
523
- }),
577
+ // #4045: a release gate binds the release's change set, not this composition.
578
+ planDigest: gateContext.releaseGate?.planDigest ??
579
+ componentPlanDigest({
580
+ environment: ctx.env,
581
+ component,
582
+ ...(ctx.vars ? { vars: ctx.vars } : {}),
583
+ ...(release !== undefined ? { release } : {}),
584
+ }),
524
585
  };
525
586
  const records = [];
526
587
  const allExecuted = [];
527
588
  try {
528
589
  for (const phaseDef of component.deploy) {
529
- const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, onProgress);
590
+ const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
530
591
  records.push(...result.records);
531
592
  allExecuted.push(...result.executed);
532
593
  }
@@ -559,7 +620,7 @@ export async function runComponentDeploy(component, ctx, registry, componentOutp
559
620
  records.push(...(await rollbackExecuted(allExecuted, ctx, registry)));
560
621
  for (const phaseDef of [...(component.rollback ?? [])].reverse()) {
561
622
  try {
562
- const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, onProgress);
623
+ const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
563
624
  records.push(...result.records);
564
625
  }
565
626
  catch (compErr) {
@@ -688,29 +749,30 @@ export async function runInterpretDriver(components, registry, options) {
688
749
  const { order, waves } = resolveComponentGraph(components);
689
750
  const byName = new Map(components.map((c) => [c.name, c]));
690
751
  const componentOutputs = { ...(options.componentOutputs ?? {}) };
691
- const { onProgress } = options;
752
+ const emit = joinRunEventSinks(options.onRunEvent, progressSinkOf(options.onProgress));
692
753
  const gates = {
693
754
  port: options.gates ?? gitGateLedgerPort(),
694
755
  ...(options.now ? { now: options.now } : {}),
695
756
  ...(options.releases ? { releases: options.releases } : {}),
757
+ ...(options.releaseGate ? { releaseGate: options.releaseGate } : {}),
696
758
  };
697
- onProgress?.({ type: "run-start", waves });
759
+ emit?.({ type: "run-start", waves });
698
760
  const results = [];
699
761
  let failedComponent;
700
762
  let gated;
701
763
  waveLoop: for (const [waveIndex, wave] of waves.entries()) {
702
764
  const waveNum = waveIndex + 1;
703
- onProgress?.({ type: "wave-start", wave: waveNum, components: wave });
765
+ emit?.({ type: "wave-start", wave: waveNum, components: wave });
704
766
  const waveComponents = wave.map((name) => byName.get(name));
705
767
  const waveResults = await Promise.all(waveComponents.map(async (component) => {
706
- onProgress?.({ type: "component-start", wave: waveNum, component: component.name });
707
- const result = await runComponentDeploy(component, deployContext(options, component.name), registry, componentOutputs, onProgress, gates);
708
- onProgress?.({ type: "component-done", wave: waveNum, component: component.name, status: progressStatus(result.status) });
768
+ emit?.({ type: "component-start", wave: waveNum, component: component.name });
769
+ const result = await runComponentDeploy(component, deployContext(options, component.name), registry, componentOutputs, undefined, gates, emit);
770
+ emit?.({ type: "component-settle", wave: waveNum, component: component.name, status: progressStatus(result.status) });
709
771
  return result;
710
772
  }));
711
773
  results.push(...waveResults);
712
774
  const stopped = waveResults.find((r) => r.status !== "ok");
713
- onProgress?.({ type: "wave-done", wave: waveNum, status: progressStatus(stopped?.status ?? "ok") });
775
+ emit?.({ type: "wave-settle", wave: waveNum, status: progressStatus(stopped?.status ?? "ok") });
714
776
  if (stopped) {
715
777
  // A failure in the same wave outranks a gate: something is actually
716
778
  // broken, and reporting the run as "waiting on a human" would hide it.
@@ -724,7 +786,7 @@ export async function runInterpretDriver(components, registry, options) {
724
786
  }
725
787
  const status = failedComponent ? "fail" : gated ? "gated" : "ok";
726
788
  const ok = status === "ok";
727
- onProgress?.({ type: "run-done", status: progressStatus(status) });
789
+ emit?.({ type: "run-settle", status: progressStatus(status), durationMs: null });
728
790
  const result = {
729
791
  order, waves, results, ok, status, failedComponent, componentOutputs,
730
792
  ...(gated
@@ -0,0 +1,69 @@
1
+ /**
2
+ * What each component of a fan-out would apply, as one digest per component
3
+ * (#4081), and which of an earlier attempt's progress still holds against it.
4
+ *
5
+ * A fan-out's plan digest identifies the derivation: who runs, in what order,
6
+ * off which edges. Two different changes that touch the same components in
7
+ * the same shape derive the same plan, so the plan digest alone cannot say
8
+ * whether "cluster-a already applied" is about the change in front of us.
9
+ * The attempt record therefore keeps, for each component it applied, the
10
+ * input digest computed here, and a resumed attempt carries a component as
11
+ * `already-applied` only when that digest is the one the component has now.
12
+ *
13
+ * ## What a component's input digest covers
14
+ *
15
+ * - The environment. Progress against `local` says nothing about `prod`.
16
+ * - The composition: every phase and step as authored, `rollback` included.
17
+ * A `stackOutput` reference is hashed as the reference, not its value.
18
+ * - The bytes of every file a step input names. A string input that resolves,
19
+ * relative to the project root, to a file or directory inside the root is
20
+ * read and hashed, so `template: "dist/cluster-a.template.json"` covers the
21
+ * built template and a rebuild that changes it changes the digest. A
22
+ * directory is hashed by its files, skipping `.git`, `node_modules` and
23
+ * `.chant`, the last because the attempt record itself lives there.
24
+ * - The input digests of the components it depends on. A parameter filled
25
+ * from an upstream output gets its value from that upstream's apply, so a
26
+ * change upstream changes the digest of everything downstream of it, the
27
+ * same reach the fan-out's own walk has.
28
+ *
29
+ * Nothing decided during the run goes in: no run id, no time, no output an
30
+ * apply produced.
31
+ */
32
+ import type { DriverComponent } from "./driver.js";
33
+ export interface ComponentInputOptions {
34
+ /** The root step inputs' file paths are read relative to, the project the fan-out runs in. */
35
+ projectRoot: string;
36
+ /** The environment the fan-out applies to. */
37
+ env: string;
38
+ /** Environment config resolved ahead of the run, when the caller has any. */
39
+ vars?: Record<string, unknown>;
40
+ }
41
+ /**
42
+ * One input digest per component in `components`, keyed by name. Each folds
43
+ * in the digests of the components it depends on, so `components` should be
44
+ * the whole project: a dependency it does not contain is hashed by name only.
45
+ */
46
+ export declare function componentInputDigests(components: DriverComponent[], options: ComponentInputOptions): Record<string, string>;
47
+ /** What of an earlier attempt's progress holds against the inputs the components have now. */
48
+ export interface CarriedProgress {
49
+ /** Components the attempt applied whose input is the same now. These stay `already-applied`. */
50
+ carried: string[];
51
+ /** Components the attempt applied whose input moved since. These run again. */
52
+ changed: string[];
53
+ /**
54
+ * True when the record has no input digests at all, as one written before
55
+ * #4081 has. Nothing carries from such a record, since nothing in it says
56
+ * what was applied.
57
+ */
58
+ unrecorded: boolean;
59
+ }
60
+ /**
61
+ * Split an attempt's `completed` by whether each component's input is the
62
+ * same as now. A component the record holds no digest for counts as changed:
63
+ * a claim that it applied is only worth keeping for the input it applied.
64
+ */
65
+ export declare function progressThatCarries(attempt: {
66
+ completed: string[];
67
+ inputs?: Record<string, string>;
68
+ }, now: Record<string, string>): CarriedProgress;
69
+ //# sourceMappingURL=fan-out-inputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fan-out-inputs.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-inputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAyED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,EAAE,qBAAqB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+BxB;AAED,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC9B,gGAAgG;IAChG,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EACjE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,eAAe,CAUjB"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * What each component of a fan-out would apply, as one digest per component
3
+ * (#4081), and which of an earlier attempt's progress still holds against it.
4
+ *
5
+ * A fan-out's plan digest identifies the derivation: who runs, in what order,
6
+ * off which edges. Two different changes that touch the same components in
7
+ * the same shape derive the same plan, so the plan digest alone cannot say
8
+ * whether "cluster-a already applied" is about the change in front of us.
9
+ * The attempt record therefore keeps, for each component it applied, the
10
+ * input digest computed here, and a resumed attempt carries a component as
11
+ * `already-applied` only when that digest is the one the component has now.
12
+ *
13
+ * ## What a component's input digest covers
14
+ *
15
+ * - The environment. Progress against `local` says nothing about `prod`.
16
+ * - The composition: every phase and step as authored, `rollback` included.
17
+ * A `stackOutput` reference is hashed as the reference, not its value.
18
+ * - The bytes of every file a step input names. A string input that resolves,
19
+ * relative to the project root, to a file or directory inside the root is
20
+ * read and hashed, so `template: "dist/cluster-a.template.json"` covers the
21
+ * built template and a rebuild that changes it changes the digest. A
22
+ * directory is hashed by its files, skipping `.git`, `node_modules` and
23
+ * `.chant`, the last because the attempt record itself lives there.
24
+ * - The input digests of the components it depends on. A parameter filled
25
+ * from an upstream output gets its value from that upstream's apply, so a
26
+ * change upstream changes the digest of everything downstream of it, the
27
+ * same reach the fan-out's own walk has.
28
+ *
29
+ * Nothing decided during the run goes in: no run id, no time, no output an
30
+ * apply produced.
31
+ */
32
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
33
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
34
+ import { computePlanDigest } from "../lifecycle/plan-digest.js";
35
+ import { sha256Hex } from "../content-digest.js";
36
+ const SKIPPED_DIRS = new Set([".git", "node_modules", ".chant"]);
37
+ /** Inside `root`, and not `root` itself: a bare "." names the whole project, which is no one step's input. */
38
+ function insideRoot(root, path) {
39
+ const rel = relative(root, path);
40
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
41
+ }
42
+ /** Hash a file, or a directory by the relative path and bytes of each file under it. */
43
+ function hashPath(path) {
44
+ let stat;
45
+ try {
46
+ stat = statSync(path);
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ if (stat.isFile())
52
+ return `sha256:${sha256Hex(readFileSync(path))}`;
53
+ if (!stat.isDirectory())
54
+ return undefined;
55
+ const files = {};
56
+ const walk = (dir) => {
57
+ for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
58
+ if (SKIPPED_DIRS.has(entry.name))
59
+ continue;
60
+ const full = join(dir, entry.name);
61
+ if (entry.isDirectory())
62
+ walk(full);
63
+ else if (entry.isFile())
64
+ files[relative(path, full).split(sep).join("/")] = sha256Hex(readFileSync(full));
65
+ }
66
+ };
67
+ walk(path);
68
+ return computePlanDigest("component-input-dir", files);
69
+ }
70
+ /** Every file or directory a component's steps name, keyed by the string the step wrote. */
71
+ function referencedFiles(component, root) {
72
+ const out = {};
73
+ const visit = (value) => {
74
+ if (typeof value === "string") {
75
+ if (value === "" || value.includes("\n") || value in out)
76
+ return;
77
+ const path = resolve(root, value);
78
+ if (!insideRoot(root, path) || !existsSync(path))
79
+ return;
80
+ const digest = hashPath(path);
81
+ if (digest !== undefined)
82
+ out[value] = digest;
83
+ return;
84
+ }
85
+ if (Array.isArray(value))
86
+ value.forEach(visit);
87
+ else if (value && typeof value === "object")
88
+ Object.values(value).forEach(visit);
89
+ };
90
+ // Only a step's inputs name files. A phase name or a step's `kind` that
91
+ // happens to match a directory in the project is not one.
92
+ const visitPhases = (phases) => {
93
+ for (const phase of phases ?? []) {
94
+ for (const step of phase.steps) {
95
+ if (isPhase(step)) {
96
+ visitPhases([step]);
97
+ continue;
98
+ }
99
+ if (step.kind === "gate")
100
+ continue;
101
+ const { kind: _kind, ...inputs } = step;
102
+ visit(inputs);
103
+ }
104
+ visitPhases(phase.onFailure);
105
+ }
106
+ };
107
+ visitPhases(component.deploy);
108
+ visitPhases(component.rollback);
109
+ return out;
110
+ }
111
+ function isPhase(step) {
112
+ return typeof step.phase === "string" && Array.isArray(step.steps);
113
+ }
114
+ /**
115
+ * One input digest per component in `components`, keyed by name. Each folds
116
+ * in the digests of the components it depends on, so `components` should be
117
+ * the whole project: a dependency it does not contain is hashed by name only.
118
+ */
119
+ export function componentInputDigests(components, options) {
120
+ const root = resolve(options.projectRoot);
121
+ const byName = new Map(components.map((c) => [c.name, c]));
122
+ const digests = new Map();
123
+ const visiting = new Set();
124
+ const digestOf = (name) => {
125
+ const known = digests.get(name);
126
+ if (known !== undefined)
127
+ return known;
128
+ const component = byName.get(name);
129
+ // An unknown dependency or a cycle is refused by the fan-out's derivation
130
+ // before this runs; here it only has to not loop.
131
+ if (!component || visiting.has(name))
132
+ return null;
133
+ visiting.add(name);
134
+ const upstream = [...(component.dependsOn ?? [])].sort().map((dep) => ({ component: dep, digest: digestOf(dep) }));
135
+ visiting.delete(name);
136
+ const digest = computePlanDigest("component-input", {
137
+ environment: options.env,
138
+ component: name,
139
+ deploy: component.deploy,
140
+ rollback: component.rollback ?? null,
141
+ vars: options.vars ?? null,
142
+ files: referencedFiles(component, root),
143
+ upstream,
144
+ });
145
+ digests.set(name, digest);
146
+ return digest;
147
+ };
148
+ for (const c of components)
149
+ digestOf(c.name);
150
+ return Object.fromEntries([...digests.entries()].sort(([a], [b]) => a.localeCompare(b)));
151
+ }
152
+ /**
153
+ * Split an attempt's `completed` by whether each component's input is the
154
+ * same as now. A component the record holds no digest for counts as changed:
155
+ * a claim that it applied is only worth keeping for the input it applied.
156
+ */
157
+ export function progressThatCarries(attempt, now) {
158
+ const recorded = attempt.inputs;
159
+ const carried = [];
160
+ const changed = [];
161
+ for (const name of [...attempt.completed].sort()) {
162
+ const then = recorded?.[name];
163
+ if (then !== undefined && now[name] !== undefined && then === now[name])
164
+ carried.push(name);
165
+ else
166
+ changed.push(name);
167
+ }
168
+ return { carried, changed, unrecorded: recorded === undefined };
169
+ }
@@ -25,6 +25,14 @@
25
25
  * `carried` holds what a step asked to keep for its member (#3459). It rides
26
26
  * in the record rather than beside it because the record is the one file a
27
27
  * per-wave CI job hands to the next.
28
+ *
29
+ * `inputs` holds, for each component in `completed`, the input digest it
30
+ * applied (#4081, ./fan-out-inputs.ts). The plan digest only identifies the
31
+ * derivation, and two different changes with the same shape derive the same
32
+ * one, so the digest alone would carry "cluster-a already applied" into a
33
+ * change that never applied it. A resumed attempt carries a component only
34
+ * when its input digest is the same now. A record written before #4081 has
35
+ * no `inputs`, and none of its progress carries.
28
36
  */
29
37
  import { type WaveRecord } from "../wave-engine.js";
30
38
  import type { ChangeSetDocument } from "../change-set.js";
@@ -64,6 +72,11 @@ export interface FanOutAttempt {
64
72
  carried?: Record<string, unknown>;
65
73
  /** A pull request's apply only (#3464). */
66
74
  prApply?: PrApplyRecord;
75
+ /**
76
+ * The input digest each completed component applied (#4081), keyed by
77
+ * name. Absent on a record written before it, which then carries nothing.
78
+ */
79
+ inputs?: Record<string, string>;
67
80
  }
68
81
  /** Read an attempt record, or `undefined` when there is none yet. Throws on a file that is not JSON. */
69
82
  export declare function readFanOutAttempt(path: string): FanOutAttempt | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"fan-out-record.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oDAAoD;IACpD,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,qGAAqG;IACrG,SAAS,EAAE,iBAAiB,CAAC;IAC7B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,wCAAwC;IACxC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AA+BD,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAkBzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAE7E"}
1
+ {"version":3,"file":"fan-out-record.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oDAAoD;IACpD,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,qGAAqG;IACrG,SAAS,EAAE,iBAAiB,CAAC;IAC7B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,wCAAwC;IACxC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA+BD,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAwBzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAE7E"}
@@ -25,6 +25,14 @@
25
25
  * `carried` holds what a step asked to keep for its member (#3459). It rides
26
26
  * in the record rather than beside it because the record is the one file a
27
27
  * per-wave CI job hands to the next.
28
+ *
29
+ * `inputs` holds, for each component in `completed`, the input digest it
30
+ * applied (#4081, ./fan-out-inputs.ts). The plan digest only identifies the
31
+ * derivation, and two different changes with the same shape derive the same
32
+ * one, so the digest alone would carry "cluster-a already applied" into a
33
+ * change that never applied it. A resumed attempt carries a component only
34
+ * when its input digest is the same now. A record written before #4081 has
35
+ * no `inputs`, and none of its progress carries.
28
36
  */
29
37
  import { existsSync, readFileSync } from "node:fs";
30
38
  import { readWaveRecords, writeWaveRecordFile } from "../wave-engine.js";
@@ -71,6 +79,13 @@ export function readFanOutAttempt(path) {
71
79
  }
72
80
  const waves = readWaveRecords(parsed.waves);
73
81
  const prApply = readPrApplyRecord(parsed.prApply);
82
+ let inputs;
83
+ if (isRecord(parsed.inputs)) {
84
+ inputs = {};
85
+ for (const [name, value] of Object.entries(parsed.inputs))
86
+ if (typeof value === "string")
87
+ inputs[name] = value;
88
+ }
74
89
  return {
75
90
  digest: typeof parsed.digest === "string" ? parsed.digest : "",
76
91
  completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n) => typeof n === "string") : [],
@@ -79,6 +94,7 @@ export function readFanOutAttempt(path) {
79
94
  ...(waves.length > 0 ? { waves } : {}),
80
95
  ...(isRecord(parsed.carried) && Object.keys(parsed.carried).length > 0 ? { carried: parsed.carried } : {}),
81
96
  ...(prApply ? { prApply } : {}),
97
+ ...(inputs ? { inputs } : {}),
82
98
  };
83
99
  }
84
100
  /**