@intentius/chant 0.124.46 → 0.124.48

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 (633) hide show
  1. package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  2. package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  3. package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  4. package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  6. package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  7. package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
  8. package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
  9. package/dist/__golden__/wave-loop/op-denied.json +16 -0
  10. package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  11. package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  12. package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
  13. package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
  14. package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
  15. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  16. package/dist/__golden__/wave-loop/op-held-on.json +16 -0
  17. package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  18. package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  19. package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  20. package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  21. package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
  22. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  23. package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
  24. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  25. package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
  26. package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
  27. package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  28. package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  29. package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
  30. package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  31. package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  32. package/dist/__golden__/wave-loop/op-overridden.json +16 -0
  33. package/dist/__golden__/wave-loop/op-per-run.json +20 -0
  34. package/dist/__golden__/wave-loop/op-point.json +13 -0
  35. package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
  36. package/dist/__golden__/wave-loop/op-sealed.json +10 -0
  37. package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
  38. package/dist/__golden__/wave-loop/op-spend.json +10 -0
  39. package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
  40. package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
  41. package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
  42. package/dist/__golden__/wave-loop/op-wide.json +39 -0
  43. package/dist/action-pins.d.ts +61 -0
  44. package/dist/action-pins.d.ts.map +1 -0
  45. package/dist/action-pins.js +77 -0
  46. package/dist/cli/commands/carve.d.ts +3 -0
  47. package/dist/cli/commands/carve.d.ts.map +1 -1
  48. package/dist/cli/commands/carve.js +36 -7
  49. package/dist/cli/commands/import-report.d.ts +26 -0
  50. package/dist/cli/commands/import-report.d.ts.map +1 -0
  51. package/dist/cli/commands/import-report.js +65 -0
  52. package/dist/cli/commands/import.d.ts +11 -1
  53. package/dist/cli/commands/import.d.ts.map +1 -1
  54. package/dist/cli/commands/import.js +22 -3
  55. package/dist/cli/commands/migrate.d.ts +13 -1
  56. package/dist/cli/commands/migrate.d.ts.map +1 -1
  57. package/dist/cli/commands/migrate.js +134 -10
  58. package/dist/cli/handlers/approve.d.ts.map +1 -1
  59. package/dist/cli/handlers/approve.js +21 -2
  60. package/dist/cli/handlers/build.d.ts.map +1 -1
  61. package/dist/cli/handlers/build.js +6 -1
  62. package/dist/cli/handlers/ledger.d.ts +3 -0
  63. package/dist/cli/handlers/ledger.d.ts.map +1 -0
  64. package/dist/cli/handlers/ledger.js +55 -0
  65. package/dist/cli/handlers/migrate.d.ts.map +1 -1
  66. package/dist/cli/handlers/migrate.js +18 -11
  67. package/dist/cli/handlers/misc.d.ts.map +1 -1
  68. package/dist/cli/handlers/misc.js +12 -1
  69. package/dist/cli/handlers/pr-env.js +2 -2
  70. package/dist/cli/handlers/pr.d.ts +15 -1
  71. package/dist/cli/handlers/pr.d.ts.map +1 -1
  72. package/dist/cli/handlers/pr.js +143 -39
  73. package/dist/cli/handlers/query.d.ts +7 -2
  74. package/dist/cli/handlers/query.d.ts.map +1 -1
  75. package/dist/cli/handlers/query.js +16 -4
  76. package/dist/cli/handlers/release.d.ts.map +1 -1
  77. package/dist/cli/handlers/release.js +6 -3
  78. package/dist/cli/handlers/search.d.ts +2 -4
  79. package/dist/cli/handlers/search.d.ts.map +1 -1
  80. package/dist/cli/handlers/search.js +13 -39
  81. package/dist/cli/main.d.ts.map +1 -1
  82. package/dist/cli/main.js +65 -14
  83. package/dist/cli/parse-args.d.ts.map +1 -1
  84. package/dist/cli/parse-args.js +36 -2
  85. package/dist/cli/registry.d.ts +14 -4
  86. package/dist/cli/registry.d.ts.map +1 -1
  87. package/dist/components/builders.d.ts +5 -1
  88. package/dist/components/builders.d.ts.map +1 -1
  89. package/dist/components/builders.js +5 -0
  90. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  91. package/dist/components/capability-plugin-loader.js +16 -1
  92. package/dist/components/capability-plugin.d.ts +14 -0
  93. package/dist/components/capability-plugin.d.ts.map +1 -1
  94. package/dist/components/pr-hooks.d.ts +21 -1
  95. package/dist/components/pr-hooks.d.ts.map +1 -1
  96. package/dist/components/pr-hooks.js +72 -4
  97. package/dist/components/pr-pipeline.d.ts +45 -10
  98. package/dist/components/pr-pipeline.d.ts.map +1 -1
  99. package/dist/components/pr-pipeline.js +47 -14
  100. package/dist/components/pr-policy.d.ts +36 -0
  101. package/dist/components/pr-policy.d.ts.map +1 -1
  102. package/dist/components/pr-policy.js +36 -0
  103. package/dist/components/starter-plugin.d.ts +1 -0
  104. package/dist/components/starter-plugin.d.ts.map +1 -1
  105. package/dist/components/starter-plugin.js +5 -1
  106. package/dist/components/verbs/index.d.ts +2 -0
  107. package/dist/components/verbs/index.d.ts.map +1 -1
  108. package/dist/components/verbs/index.js +2 -0
  109. package/dist/components/verbs/publish-artifact.d.ts +65 -0
  110. package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
  111. package/dist/components/verbs/publish-artifact.js +74 -0
  112. package/dist/components/verbs/publish-image.d.ts +129 -0
  113. package/dist/components/verbs/publish-image.d.ts.map +1 -0
  114. package/dist/components/verbs/publish-image.js +145 -0
  115. package/dist/config-environments.d.ts +20 -0
  116. package/dist/config-environments.d.ts.map +1 -1
  117. package/dist/config-environments.js +12 -0
  118. package/dist/config.d.ts +9 -1
  119. package/dist/config.d.ts.map +1 -1
  120. package/dist/config.js +6 -2
  121. package/dist/gate-decision.d.ts +11 -2
  122. package/dist/gate-decision.d.ts.map +1 -1
  123. package/dist/gate-decision.js +15 -3
  124. package/dist/graph-ir.d.ts +25 -0
  125. package/dist/graph-ir.d.ts.map +1 -1
  126. package/dist/graph-walk.d.ts +66 -0
  127. package/dist/graph-walk.d.ts.map +1 -0
  128. package/dist/graph-walk.js +70 -0
  129. package/dist/import/parser.d.ts +19 -0
  130. package/dist/import/parser.d.ts.map +1 -1
  131. package/dist/lexicon.d.ts +71 -6
  132. package/dist/lexicon.d.ts.map +1 -1
  133. package/dist/lifecycle/gate-ledger.d.ts +11 -0
  134. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  135. package/dist/lifecycle/git.d.ts +2 -5
  136. package/dist/lifecycle/git.d.ts.map +1 -1
  137. package/dist/lifecycle/ledger-read.d.ts +65 -0
  138. package/dist/lifecycle/ledger-read.d.ts.map +1 -0
  139. package/dist/lifecycle/ledger-read.js +160 -0
  140. package/dist/lifecycle/release-workstation.d.ts +7 -0
  141. package/dist/lifecycle/release-workstation.d.ts.map +1 -1
  142. package/dist/lifecycle/release-workstation.js +25 -0
  143. package/dist/lifecycle/run-ledger.d.ts +4 -3
  144. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  145. package/dist/lifecycle/run-ledger.js +1 -0
  146. package/dist/lint/discover.js +3 -1
  147. package/dist/lint/post-synth.d.ts +127 -1
  148. package/dist/lint/post-synth.d.ts.map +1 -1
  149. package/dist/lint/post-synth.js +84 -2
  150. package/dist/lint/rules/op/index.d.ts +1 -0
  151. package/dist/lint/rules/op/index.d.ts.map +1 -1
  152. package/dist/lint/rules/op/index.js +2 -0
  153. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
  154. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
  155. package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
  156. package/dist/op/activities/activity-contracts.d.ts +5 -2
  157. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  158. package/dist/op/activities/activity-contracts.js +5 -2
  159. package/dist/op/activities/index.d.ts +2 -2
  160. package/dist/op/activities/index.d.ts.map +1 -1
  161. package/dist/op/activities/index.js +1 -1
  162. package/dist/op/activities/review-agent.d.ts +90 -4
  163. package/dist/op/activities/review-agent.d.ts.map +1 -1
  164. package/dist/op/activities/review-agent.js +217 -19
  165. package/dist/op/activities/work-evidence.d.ts +8 -1
  166. package/dist/op/activities/work-evidence.d.ts.map +1 -1
  167. package/dist/op/activities/work-evidence.js +1 -0
  168. package/dist/op/builders.d.ts +9 -5
  169. package/dist/op/builders.d.ts.map +1 -1
  170. package/dist/op/builders.js +9 -5
  171. package/dist/op/composites/apply-op.d.ts +29 -2
  172. package/dist/op/composites/apply-op.d.ts.map +1 -1
  173. package/dist/op/composites/apply-op.js +20 -1
  174. package/dist/op/gate-approval.d.ts +11 -5
  175. package/dist/op/gate-approval.d.ts.map +1 -1
  176. package/dist/op/gate-approval.js +11 -6
  177. package/dist/op/gate-quorum.d.ts +100 -3
  178. package/dist/op/gate-quorum.d.ts.map +1 -1
  179. package/dist/op/gate-quorum.js +108 -6
  180. package/dist/op/gate-review.d.ts +9 -0
  181. package/dist/op/gate-review.d.ts.map +1 -1
  182. package/dist/op/gate-review.js +13 -0
  183. package/dist/op/gate.d.ts +44 -3
  184. package/dist/op/gate.d.ts.map +1 -1
  185. package/dist/op/gate.js +25 -4
  186. package/dist/op/index.d.ts +3 -3
  187. package/dist/op/index.d.ts.map +1 -1
  188. package/dist/op/index.js +1 -1
  189. package/dist/op/local-executor.d.ts +38 -3
  190. package/dist/op/local-executor.d.ts.map +1 -1
  191. package/dist/op/local-executor.js +48 -6
  192. package/dist/op/op-waves-run.d.ts +26 -1
  193. package/dist/op/op-waves-run.d.ts.map +1 -1
  194. package/dist/op/op-waves-run.js +259 -13
  195. package/dist/op/op-waves.d.ts +72 -5
  196. package/dist/op/op-waves.d.ts.map +1 -1
  197. package/dist/op/op-waves.js +110 -15
  198. package/dist/op/runtime.d.ts +11 -0
  199. package/dist/op/runtime.d.ts.map +1 -1
  200. package/dist/op/schedule-overdue.d.ts +16 -0
  201. package/dist/op/schedule-overdue.d.ts.map +1 -1
  202. package/dist/op/schedule-overdue.js +36 -0
  203. package/dist/op/stage-hooks.d.ts +9 -2
  204. package/dist/op/stage-hooks.d.ts.map +1 -1
  205. package/dist/op/stage-hooks.js +7 -5
  206. package/dist/op/workspace-run-env.d.ts +22 -0
  207. package/dist/op/workspace-run-env.d.ts.map +1 -0
  208. package/dist/op/workspace-run-env.js +21 -0
  209. package/dist/pr-forge.d.ts +24 -0
  210. package/dist/pr-forge.d.ts.map +1 -1
  211. package/dist/pr-forge.js +47 -0
  212. package/dist/pr-post.d.ts +42 -0
  213. package/dist/pr-post.d.ts.map +1 -1
  214. package/dist/pr-post.js +67 -1
  215. package/dist/read-filter.d.ts +65 -0
  216. package/dist/read-filter.d.ts.map +1 -0
  217. package/dist/read-filter.js +179 -0
  218. package/dist/run-event.d.ts +1 -1
  219. package/dist/run-event.d.ts.map +1 -1
  220. package/dist/terraform/carve.d.ts +24 -3
  221. package/dist/terraform/carve.d.ts.map +1 -1
  222. package/dist/terraform/carve.js +32 -14
  223. package/dist/terraform/cuts.d.ts +97 -0
  224. package/dist/terraform/cuts.d.ts.map +1 -0
  225. package/dist/terraform/cuts.js +138 -0
  226. package/dist/terraform/folds.d.ts +26 -0
  227. package/dist/terraform/folds.d.ts.map +1 -0
  228. package/dist/terraform/folds.js +38 -0
  229. package/dist/terraform/graph.d.ts.map +1 -1
  230. package/dist/terraform/graph.js +10 -0
  231. package/dist/terraform/reach.d.ts +140 -0
  232. package/dist/terraform/reach.d.ts.map +1 -0
  233. package/dist/terraform/reach.js +170 -0
  234. package/dist/terraform/score.d.ts +14 -0
  235. package/dist/terraform/score.d.ts.map +1 -1
  236. package/dist/terraform/score.js +14 -31
  237. package/dist/terraform/state.d.ts.map +1 -1
  238. package/dist/terraform/state.js +4 -2
  239. package/dist/terraform/types.d.ts +8 -0
  240. package/dist/terraform/types.d.ts.map +1 -1
  241. package/dist/wave-blocked.d.ts +10 -1
  242. package/dist/wave-blocked.d.ts.map +1 -1
  243. package/dist/wave-blocked.js +31 -3
  244. package/dist/wave-runtime.mjs +263 -254
  245. package/dist/workspace/check.schema.json +11 -2
  246. package/dist/workspace/checks/ci-branch.d.ts +44 -0
  247. package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
  248. package/dist/workspace/checks/ci-branch.js +133 -0
  249. package/dist/workspace/checks/links.d.ts +3 -0
  250. package/dist/workspace/checks/links.d.ts.map +1 -1
  251. package/dist/workspace/checks/links.js +12 -1
  252. package/dist/workspace/checks/org.d.ts +48 -0
  253. package/dist/workspace/checks/org.d.ts.map +1 -0
  254. package/dist/workspace/checks/org.js +156 -0
  255. package/dist/workspace/checks.d.ts +11 -1
  256. package/dist/workspace/checks.d.ts.map +1 -1
  257. package/dist/workspace/checks.js +59 -7
  258. package/dist/workspace/ci-branches.d.ts +16 -0
  259. package/dist/workspace/ci-branches.d.ts.map +1 -1
  260. package/dist/workspace/ci-branches.js +27 -0
  261. package/dist/workspace/ci-green-cli.js +7 -7
  262. package/dist/workspace/ci-green-workflow.d.ts +1 -1
  263. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  264. package/dist/workspace/ci-green-workflow.js +13 -8
  265. package/dist/workspace/ci-green.d.ts +14 -0
  266. package/dist/workspace/ci-green.d.ts.map +1 -1
  267. package/dist/workspace/ci-green.js +44 -11
  268. package/dist/workspace/ci-run.d.ts +9 -1
  269. package/dist/workspace/ci-run.d.ts.map +1 -1
  270. package/dist/workspace/ci-run.js +67 -6
  271. package/dist/workspace/ci-serve.d.ts +9 -0
  272. package/dist/workspace/ci-serve.d.ts.map +1 -1
  273. package/dist/workspace/ci-serve.js +114 -76
  274. package/dist/workspace/compose-graph.d.ts +14 -0
  275. package/dist/workspace/compose-graph.d.ts.map +1 -1
  276. package/dist/workspace/composites.d.ts +4 -1
  277. package/dist/workspace/composites.d.ts.map +1 -1
  278. package/dist/workspace/composites.js +5 -2
  279. package/dist/workspace/composites.schema.json +22 -0
  280. package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  281. package/dist/workspace/cross-root-lint.d.ts +56 -0
  282. package/dist/workspace/cross-root-lint.d.ts.map +1 -0
  283. package/dist/workspace/cross-root-lint.js +111 -0
  284. package/dist/workspace/dbt-models-reader.d.ts +44 -0
  285. package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
  286. package/dist/workspace/dbt-models-reader.js +356 -0
  287. package/dist/workspace/dbt-project-common.d.ts +40 -0
  288. package/dist/workspace/dbt-project-common.d.ts.map +1 -0
  289. package/dist/workspace/dbt-project-common.js +106 -0
  290. package/dist/workspace/dbt-project-reader.d.ts +4 -3
  291. package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
  292. package/dist/workspace/dbt-project-reader.js +14 -108
  293. package/dist/workspace/decision-rank.d.ts +26 -0
  294. package/dist/workspace/decision-rank.d.ts.map +1 -0
  295. package/dist/workspace/decision-rank.js +16 -0
  296. package/dist/workspace/declaration.d.ts +43 -2
  297. package/dist/workspace/declaration.d.ts.map +1 -1
  298. package/dist/workspace/declaration.js +45 -11
  299. package/dist/workspace/declaration.schema.json +133 -24
  300. package/dist/workspace/environments.d.ts +26 -2
  301. package/dist/workspace/environments.d.ts.map +1 -1
  302. package/dist/workspace/environments.js +26 -2
  303. package/dist/workspace/flyway-dir.d.ts +39 -0
  304. package/dist/workspace/flyway-dir.d.ts.map +1 -0
  305. package/dist/workspace/flyway-dir.js +104 -0
  306. package/dist/workspace/flyway-layout.d.ts +96 -0
  307. package/dist/workspace/flyway-layout.d.ts.map +1 -0
  308. package/dist/workspace/flyway-layout.js +308 -0
  309. package/dist/workspace/graph-cli.d.ts.map +1 -1
  310. package/dist/workspace/graph-cli.js +26 -8
  311. package/dist/workspace/graph.schema.json +34 -0
  312. package/dist/workspace/intent.d.ts +2 -3
  313. package/dist/workspace/intent.d.ts.map +1 -1
  314. package/dist/workspace/intent.js +5 -9
  315. package/dist/workspace/kind-link-readers.d.ts +59 -2
  316. package/dist/workspace/kind-link-readers.d.ts.map +1 -1
  317. package/dist/workspace/kind-link-readers.js +17 -1
  318. package/dist/workspace/kinds.d.ts +66 -2
  319. package/dist/workspace/kinds.d.ts.map +1 -1
  320. package/dist/workspace/kinds.js +98 -4
  321. package/dist/workspace/ledger.schema.json +158 -0
  322. package/dist/workspace/lexicon-outputs.d.ts +20 -1
  323. package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
  324. package/dist/workspace/lexicon-outputs.js +102 -10
  325. package/dist/workspace/lineage-check.d.ts +3 -0
  326. package/dist/workspace/lineage-check.d.ts.map +1 -1
  327. package/dist/workspace/lineage-check.js +23 -4
  328. package/dist/workspace/links.d.ts +8 -1
  329. package/dist/workspace/links.d.ts.map +1 -1
  330. package/dist/workspace/links.js +25 -1
  331. package/dist/workspace/ls.d.ts +8 -0
  332. package/dist/workspace/ls.d.ts.map +1 -1
  333. package/dist/workspace/ls.js +7 -1
  334. package/dist/workspace/ls.schema.json +7 -0
  335. package/dist/workspace/member-commands.d.ts.map +1 -1
  336. package/dist/workspace/member-commands.js +54 -5
  337. package/dist/workspace/migrate-links.d.ts +45 -0
  338. package/dist/workspace/migrate-links.d.ts.map +1 -0
  339. package/dist/workspace/migrate-links.js +100 -0
  340. package/dist/workspace/migration-dirs.d.ts +74 -0
  341. package/dist/workspace/migration-dirs.d.ts.map +1 -0
  342. package/dist/workspace/migration-dirs.js +254 -0
  343. package/dist/workspace/reason-codes.d.ts +8 -0
  344. package/dist/workspace/reason-codes.d.ts.map +1 -1
  345. package/dist/workspace/reason-codes.js +11 -0
  346. package/dist/workspace/records-cli.d.ts +11 -0
  347. package/dist/workspace/records-cli.d.ts.map +1 -1
  348. package/dist/workspace/records-cli.js +57 -5
  349. package/dist/workspace/records.schema.json +5 -0
  350. package/dist/workspace/release-candidates.d.ts +2 -0
  351. package/dist/workspace/release-candidates.d.ts.map +1 -1
  352. package/dist/workspace/release-candidates.js +5 -2
  353. package/dist/workspace/release-train.d.ts +53 -0
  354. package/dist/workspace/release-train.d.ts.map +1 -0
  355. package/dist/workspace/release-train.js +134 -0
  356. package/dist/workspace/release-workflow.d.ts.map +1 -1
  357. package/dist/workspace/release-workflow.js +4 -3
  358. package/dist/workspace/repo-ref.d.ts +45 -0
  359. package/dist/workspace/repo-ref.d.ts.map +1 -0
  360. package/dist/workspace/repo-ref.js +114 -0
  361. package/dist/workspace/run-event.schema.json +2 -2
  362. package/dist/workspace/runs-cli.d.ts +9 -0
  363. package/dist/workspace/runs-cli.d.ts.map +1 -1
  364. package/dist/workspace/runs-cli.js +48 -3
  365. package/dist/workspace/runs.schema.json +7 -0
  366. package/dist/workspace/search-contract.d.ts +1 -1
  367. package/dist/workspace/search-contract.d.ts.map +1 -1
  368. package/dist/workspace/status-decisions.d.ts +37 -0
  369. package/dist/workspace/status-decisions.d.ts.map +1 -0
  370. package/dist/workspace/status-decisions.js +147 -0
  371. package/dist/workspace/status-gates.d.ts +9 -0
  372. package/dist/workspace/status-gates.d.ts.map +1 -1
  373. package/dist/workspace/status.d.ts +4 -0
  374. package/dist/workspace/status.d.ts.map +1 -1
  375. package/dist/workspace/status.js +14 -2
  376. package/dist/workspace/status.schema.json +6 -0
  377. package/dist/workspace/work-cli.d.ts.map +1 -1
  378. package/dist/workspace/work-cli.js +5 -3
  379. package/dist/workspace/work-evidence-ops.d.ts +83 -0
  380. package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
  381. package/dist/workspace/work-evidence-ops.js +169 -0
  382. package/dist/workspace/work-evidence.d.ts +12 -2
  383. package/dist/workspace/work-evidence.d.ts.map +1 -1
  384. package/dist/workspace/work-evidence.js +21 -3
  385. package/dist/workspace/work-evidence.schema.json +49 -2
  386. package/dist/workspace/workspace-gates.d.ts +110 -0
  387. package/dist/workspace/workspace-gates.d.ts.map +1 -0
  388. package/dist/workspace/workspace-gates.js +140 -0
  389. package/dist/workspace/workspace-kinds.schema.json +58 -3
  390. package/dist/workspace/workspace-ledger.d.ts +76 -0
  391. package/dist/workspace/workspace-ledger.d.ts.map +1 -0
  392. package/dist/workspace/workspace-ledger.js +91 -0
  393. package/dist/workspace/workspace-run.d.ts +112 -0
  394. package/dist/workspace/workspace-run.d.ts.map +1 -0
  395. package/dist/workspace/workspace-run.js +432 -0
  396. package/package.json +1 -1
  397. package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  398. package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  399. package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  400. package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  401. package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  402. package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  403. package/src/__golden__/wave-loop/op-cost-member.json +13 -0
  404. package/src/__golden__/wave-loop/op-denied-source.json +16 -0
  405. package/src/__golden__/wave-loop/op-denied.json +16 -0
  406. package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  407. package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  408. package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
  409. package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
  410. package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
  411. package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  412. package/src/__golden__/wave-loop/op-held-on.json +16 -0
  413. package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  414. package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  415. package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  416. package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  417. package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
  418. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  419. package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
  420. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  421. package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
  422. package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
  423. package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  424. package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  425. package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
  426. package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  427. package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  428. package/src/__golden__/wave-loop/op-overridden.json +16 -0
  429. package/src/__golden__/wave-loop/op-per-run.json +20 -0
  430. package/src/__golden__/wave-loop/op-point.json +13 -0
  431. package/src/__golden__/wave-loop/op-pr-review.json +10 -0
  432. package/src/__golden__/wave-loop/op-sealed.json +10 -0
  433. package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
  434. package/src/__golden__/wave-loop/op-spend.json +10 -0
  435. package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
  436. package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
  437. package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
  438. package/src/__golden__/wave-loop/op-wide.json +39 -0
  439. package/src/action-pins.test.ts +78 -0
  440. package/src/action-pins.ts +92 -0
  441. package/src/cli/commands/carve-score-once.test.ts +99 -0
  442. package/src/cli/commands/carve.ts +37 -6
  443. package/src/cli/commands/check-lexicon.test.ts +2 -2
  444. package/src/cli/commands/import-report.ts +71 -0
  445. package/src/cli/commands/import.ts +33 -3
  446. package/src/cli/commands/migrate-dialect.test.ts +145 -0
  447. package/src/cli/commands/migrate.ts +132 -11
  448. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
  449. package/src/cli/handlers/approve.ts +23 -2
  450. package/src/cli/handlers/build.ts +7 -1
  451. package/src/cli/handlers/ledger.ts +54 -0
  452. package/src/cli/handlers/migrate.ts +21 -12
  453. package/src/cli/handlers/misc.ts +10 -1
  454. package/src/cli/handlers/pr-env.ts +2 -2
  455. package/src/cli/handlers/pr.ts +138 -36
  456. package/src/cli/handlers/query.ts +16 -4
  457. package/src/cli/handlers/release.ts +6 -3
  458. package/src/cli/handlers/search.ts +13 -34
  459. package/src/cli/main.test.ts +15 -0
  460. package/src/cli/main.ts +65 -14
  461. package/src/cli/parse-args.ts +27 -2
  462. package/src/cli/registry.ts +14 -4
  463. package/src/components/builders.ts +8 -0
  464. package/src/components/capability-plugin-loader.ts +13 -1
  465. package/src/components/capability-plugin.ts +16 -0
  466. package/src/components/pr-hooks.test.ts +73 -5
  467. package/src/components/pr-hooks.ts +95 -5
  468. package/src/components/pr-pipeline.ts +64 -16
  469. package/src/components/pr-policy.test.ts +64 -1
  470. package/src/components/pr-policy.ts +53 -0
  471. package/src/components/registry.test.ts +1 -1
  472. package/src/components/starter-plugin.ts +6 -0
  473. package/src/components/verbs/index.ts +2 -0
  474. package/src/components/verbs/publish-artifact.test.ts +60 -0
  475. package/src/components/verbs/publish-artifact.ts +122 -0
  476. package/src/components/verbs/publish-image.test.ts +101 -0
  477. package/src/components/verbs/publish-image.ts +265 -0
  478. package/src/config-environments.ts +28 -1
  479. package/src/config.ts +8 -1
  480. package/src/gate-decision-bundle.test.ts +1 -0
  481. package/src/gate-decision-identity.test.ts +9 -0
  482. package/src/gate-decision.ts +26 -3
  483. package/src/graph-ir.ts +27 -0
  484. package/src/graph-walk.test.ts +44 -0
  485. package/src/graph-walk.ts +102 -0
  486. package/src/import/parser.ts +20 -0
  487. package/src/lexicon.ts +74 -6
  488. package/src/lifecycle/gate-ledger.ts +8 -0
  489. package/src/lifecycle/git.ts +2 -2
  490. package/src/lifecycle/ledger-read.test.ts +107 -0
  491. package/src/lifecycle/ledger-read.ts +195 -0
  492. package/src/lifecycle/release-workstation.ts +24 -0
  493. package/src/lifecycle/run-ledger.ts +5 -2
  494. package/src/lint/cross-root.test.ts +122 -0
  495. package/src/lint/discover.ts +3 -1
  496. package/src/lint/post-synth.ts +212 -2
  497. package/src/lint/rules/op/index.ts +2 -0
  498. package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
  499. package/src/op/activities/activity-contracts.ts +5 -2
  500. package/src/op/activities/index.ts +2 -2
  501. package/src/op/activities/review-agent.test.ts +221 -4
  502. package/src/op/activities/review-agent.ts +265 -22
  503. package/src/op/activities/work-evidence.ts +9 -1
  504. package/src/op/builders.ts +9 -5
  505. package/src/op/composites/apply-op.test.ts +108 -0
  506. package/src/op/composites/apply-op.ts +37 -2
  507. package/src/op/gate-approval.test.ts +6 -1
  508. package/src/op/gate-approval.ts +12 -6
  509. package/src/op/gate-quorum-at-base.test.ts +211 -0
  510. package/src/op/gate-quorum.ts +156 -8
  511. package/src/op/gate-review.ts +14 -0
  512. package/src/op/gate.ts +67 -8
  513. package/src/op/index.ts +3 -2
  514. package/src/op/local-executor.ts +69 -9
  515. package/src/op/op-waves-depends-on.test.ts +81 -0
  516. package/src/op/op-waves-hook-targets.test.ts +4 -2
  517. package/src/op/op-waves-quorum-product.test.ts +158 -0
  518. package/src/op/op-waves-run.ts +288 -14
  519. package/src/op/op-waves.ts +143 -14
  520. package/src/op/runtime.ts +8 -0
  521. package/src/op/schedule-overdue.ts +33 -0
  522. package/src/op/stage-hooks.ts +13 -5
  523. package/src/op/workspace-run-env.ts +29 -0
  524. package/src/pr-forge-bundle.test.ts +2 -2
  525. package/src/pr-forge.test.ts +47 -0
  526. package/src/pr-forge.ts +68 -0
  527. package/src/pr-post-open.e2e.test.ts +36 -0
  528. package/src/pr-post.test.ts +102 -3
  529. package/src/pr-post.ts +89 -1
  530. package/src/read-filter.test.ts +54 -0
  531. package/src/read-filter.ts +193 -0
  532. package/src/run-event.ts +1 -1
  533. package/src/stage-hooks-bundle.test.ts +1 -0
  534. package/src/terraform/carve.ts +52 -15
  535. package/src/terraform/cuts.test.ts +173 -0
  536. package/src/terraform/cuts.ts +188 -0
  537. package/src/terraform/folds.ts +44 -0
  538. package/src/terraform/graph.ts +9 -0
  539. package/src/terraform/radius.test.ts +90 -0
  540. package/src/terraform/reach.test.ts +146 -0
  541. package/src/terraform/reach.ts +247 -0
  542. package/src/terraform/score.ts +27 -29
  543. package/src/terraform/state.ts +3 -1
  544. package/src/terraform/types.ts +8 -0
  545. package/src/wave-blocked.ts +28 -3
  546. package/src/wave-loop-golden.test.ts +4 -3
  547. package/src/workspace/behold-kinds.test.ts +1 -1
  548. package/src/workspace/check-contract.test.ts +7 -6
  549. package/src/workspace/check.schema.json +11 -2
  550. package/src/workspace/checks/ci-branch.test.ts +128 -0
  551. package/src/workspace/checks/ci-branch.ts +141 -0
  552. package/src/workspace/checks/links.ts +12 -1
  553. package/src/workspace/checks/org.ts +169 -0
  554. package/src/workspace/checks.ts +64 -7
  555. package/src/workspace/ci-branches.ts +31 -0
  556. package/src/workspace/ci-green-branches.test.ts +153 -0
  557. package/src/workspace/ci-green-cli.ts +7 -7
  558. package/src/workspace/ci-green-workflow.test.ts +4 -3
  559. package/src/workspace/ci-green-workflow.ts +13 -9
  560. package/src/workspace/ci-green.ts +49 -12
  561. package/src/workspace/ci-run.test.ts +72 -1
  562. package/src/workspace/ci-run.ts +68 -8
  563. package/src/workspace/ci-serve.test.ts +95 -0
  564. package/src/workspace/ci-serve.ts +106 -65
  565. package/src/workspace/component-environments.test.ts +25 -2
  566. package/src/workspace/compose-graph.ts +9 -2
  567. package/src/workspace/composites.schema.json +22 -0
  568. package/src/workspace/composites.test.ts +39 -8
  569. package/src/workspace/composites.ts +6 -2
  570. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  571. package/src/workspace/cross-root-lint.test.ts +90 -0
  572. package/src/workspace/cross-root-lint.ts +126 -0
  573. package/src/workspace/dbt-kind.test.ts +3 -2
  574. package/src/workspace/dbt-models-reader.ts +362 -0
  575. package/src/workspace/dbt-models.test.ts +248 -0
  576. package/src/workspace/dbt-project-common.ts +113 -0
  577. package/src/workspace/dbt-project-reader.ts +29 -112
  578. package/src/workspace/decision-rank.ts +40 -0
  579. package/src/workspace/declaration.schema.json +133 -24
  580. package/src/workspace/declaration.ts +84 -15
  581. package/src/workspace/environments.ts +40 -4
  582. package/src/workspace/flyway-dir.ts +113 -0
  583. package/src/workspace/flyway-layout.ts +337 -0
  584. package/src/workspace/graph-cli.ts +25 -10
  585. package/src/workspace/graph-contract.test.ts +4 -2
  586. package/src/workspace/graph.schema.json +34 -0
  587. package/src/workspace/identity.test.ts +14 -2
  588. package/src/workspace/intent.ts +6 -14
  589. package/src/workspace/kind-link-readers.ts +68 -3
  590. package/src/workspace/kinds.test.ts +12 -7
  591. package/src/workspace/kinds.ts +132 -7
  592. package/src/workspace/ledger.schema.json +158 -0
  593. package/src/workspace/lexicon-outputs.ts +132 -13
  594. package/src/workspace/lineage-check.ts +30 -7
  595. package/src/workspace/links.ts +24 -1
  596. package/src/workspace/ls-contract.test.ts +1 -1
  597. package/src/workspace/ls.schema.json +7 -0
  598. package/src/workspace/ls.ts +10 -1
  599. package/src/workspace/member-commands.ts +60 -2
  600. package/src/workspace/member-file-schema.test.ts +124 -0
  601. package/src/workspace/migrate-links.test.ts +99 -0
  602. package/src/workspace/migrate-links.ts +108 -0
  603. package/src/workspace/migration-dirs.test.ts +272 -0
  604. package/src/workspace/migration-dirs.ts +267 -0
  605. package/src/workspace/org-scope.test.ts +238 -0
  606. package/src/workspace/reason-codes.test.ts +6 -1
  607. package/src/workspace/reason-codes.ts +11 -0
  608. package/src/workspace/records-cli.ts +58 -5
  609. package/src/workspace/records.schema.json +5 -0
  610. package/src/workspace/release-candidates.ts +7 -2
  611. package/src/workspace/release-train.ts +157 -0
  612. package/src/workspace/release-workflow.ts +4 -3
  613. package/src/workspace/repo-ref.ts +113 -0
  614. package/src/workspace/run-event.schema.json +2 -2
  615. package/src/workspace/runs-cli.ts +48 -4
  616. package/src/workspace/runs.schema.json +7 -0
  617. package/src/workspace/status-contract.test.ts +46 -1
  618. package/src/workspace/status-decisions.test.ts +100 -0
  619. package/src/workspace/status-decisions.ts +151 -0
  620. package/src/workspace/status-gates.ts +9 -0
  621. package/src/workspace/status.schema.json +6 -0
  622. package/src/workspace/status.ts +17 -3
  623. package/src/workspace/where-filters.test.ts +39 -0
  624. package/src/workspace/work-cli.ts +5 -3
  625. package/src/workspace/work-evidence-ops.test.ts +176 -0
  626. package/src/workspace/work-evidence-ops.ts +189 -0
  627. package/src/workspace/work-evidence.schema.json +49 -2
  628. package/src/workspace/work-evidence.ts +22 -3
  629. package/src/workspace/workspace-gates.ts +200 -0
  630. package/src/workspace/workspace-kinds.schema.json +58 -3
  631. package/src/workspace/workspace-ledger.ts +130 -0
  632. package/src/workspace/workspace-run.test.ts +322 -0
  633. package/src/workspace/workspace-run.ts +461 -0
@@ -63,6 +63,16 @@ import {
63
63
  type WaveStep,
64
64
  } from "../wave-engine";
65
65
  import type { ReviewApproval } from "../gate-decision";
66
+ import {
67
+ blockedMembers,
68
+ blockedWords,
69
+ earlierWaveOutcomes,
70
+ passesThrough,
71
+ readWaveOutcomeFile,
72
+ waveOutcomeFileName,
73
+ writeWaveOutcomeFile,
74
+ type WaveMemberOutcome,
75
+ } from "../wave-blocked";
66
76
  import { approveCommand, evaluateGate, gitGateLedgerPort, type GateCheck, type GateDigestMismatch, type GateLedgerPort } from "./gate";
67
77
  import type { GateAnswerRef, PendingGateRecord } from "../lifecycle/gate-ledger";
68
78
  import type { GatePointAsker } from "../point-decision";
@@ -75,8 +85,8 @@ import type { TrustPolicy } from "../workspace/trust/policy";
75
85
  import type { GateSigners } from "../lifecycle/gate-seal";
76
86
  import { ciRunIdFromEnv } from "./gate-run-locator";
77
87
  import {
78
- quorumProblems, quorumRuleLine, quorumRulesFor, quorumWaiting, ruleNeedsProof, samePrincipal, trustQuorumJudge,
79
- type GateQuorumRule, type GateQuorumRuleProgress,
88
+ changeInvolvement, quorumProblems, quorumRuleLine, quorumRulesFor, quorumWaiting, recordedReviewApprovals, ruleNeedsProof, samePrincipal, trustQuorumJudge,
89
+ type GateQuorumJudge, type GateQuorumRule, type GateQuorumRuleProgress, type QuorumJudgement,
80
90
  } from "./gate-quorum";
81
91
  import {
82
92
  OP_WAVE_DEFAULT_APPLY,
@@ -89,6 +99,7 @@ import {
89
99
  opWaveGateName,
90
100
  opWaveHooksAt,
91
101
  opWaveHookRuns,
102
+ opWaveOutcomeDir,
92
103
  opWavePointAt,
93
104
  opWavePointProblems,
94
105
  opWaveRecordPath,
@@ -103,7 +114,10 @@ import {
103
114
  type OpWaveHookMoment,
104
115
  type OpWavePoint,
105
116
  type OpWaveRun,
117
+ type OpWavesInvolved,
106
118
  type OpWavesSpec,
119
+ OP_LEDGER_NAME,
120
+ opWavesInvolvedProblems,
107
121
  } from "./op-waves";
108
122
  import {
109
123
  OP_WAVE_PENDING_RESERVED,
@@ -242,6 +256,10 @@ export interface OpWaveDecision {
242
256
  review?: { pr?: number; head?: string; approvers?: string[]; url?: string; reason?: string };
243
257
  /** The approval rules at base the wave's targets take (#4290). Absent when it takes none. */
244
258
  quorum?: GateQuorumRule[];
259
+ /** The op whose ledger holds the product's own reviews, read at base (#4333). */
260
+ reviewLedger?: string;
261
+ /** Who else counts as involved in the change, read at base (#4333). */
262
+ involved?: OpWavesInvolved;
245
263
  /** Where each of those rules stands (#4290), while the wave waits. */
246
264
  quorumProgress?: GateQuorumRuleProgress[];
247
265
  /** The command that approves this digest, when waiting. */
@@ -489,6 +507,10 @@ export interface OpWaveBaseRules {
489
507
  quorum?: GateQuorumRule[];
490
508
  /** Set when the rules at base cannot be read: the wave fails rather than wait on fewer approvers than they ask. */
491
509
  quorumRefused?: string;
510
+ /** `approvals.reviewLedger` at base (#4333): the op whose ledger holds a product's own reviews. */
511
+ reviewLedger?: string;
512
+ /** `approvals.involved` at base (#4333). */
513
+ involved?: OpWavesInvolved;
492
514
  }
493
515
 
494
516
  const noHooks = (): Record<OpWaveHookMoment, OpWaveHook[]> =>
@@ -541,12 +563,24 @@ export function readOpWavePolicy(
541
563
  }
542
564
 
543
565
  /** The approval rules at base (#4290), or why they cannot be read. A spec at base with none has none. */
544
- function quorumAtBase(spec: OpWavesSpec, where: string): Pick<OpWaveBaseRules, "quorum" | "quorumRefused"> {
545
- const raw = (spec as { approvals?: { quorum?: unknown } }).approvals?.quorum;
566
+ function quorumAtBase(spec: OpWavesSpec, where: string): Pick<OpWaveBaseRules, "quorum" | "quorumRefused" | "reviewLedger" | "involved"> {
567
+ const a = (spec as { approvals?: { quorum?: unknown; reviewLedger?: unknown; involved?: unknown } }).approvals;
568
+ const raw = a?.quorum;
569
+ // #4333: where a product's reviews are, and who counts as involved, read at base with the rules.
570
+ const extra: Pick<OpWaveBaseRules, "reviewLedger" | "involved"> = {};
571
+ if (a?.reviewLedger !== undefined) {
572
+ if (typeof a.reviewLedger !== "string" || !OP_LEDGER_NAME.test(a.reviewLedger)) return { quorumRefused: `the approval rules in ${where} cannot be read (approvals.reviewLedger must name an op)` };
573
+ extra.reviewLedger = a.reviewLedger;
574
+ }
575
+ if (a?.involved !== undefined) {
576
+ const bad = opWavesInvolvedProblems(a.involved);
577
+ if (bad.length > 0) return { quorumRefused: `the approval rules in ${where} cannot be read (${bad.join("; ")})` };
578
+ extra.involved = structuredClone(a.involved as OpWavesInvolved);
579
+ }
546
580
  if (raw === undefined) return {};
547
581
  const problems = Array.isArray(raw) ? quorumProblems(raw, "approvals.quorum", { notAuthor: true }) : ["`approvals.quorum` must be a list of rules"];
548
582
  if (problems.length > 0) return { quorumRefused: `the approval rules in ${where} cannot be read (${problems.join("; ")})` };
549
- return (raw as GateQuorumRule[]).length > 0 ? { quorum: raw as GateQuorumRule[] } : {};
583
+ return (raw as GateQuorumRule[]).length > 0 ? { quorum: raw as GateQuorumRule[], ...extra } : {};
550
584
  }
551
585
 
552
586
  /** The point wave `name` asks at base (#3836), or why it cannot be asked. */
@@ -607,6 +641,14 @@ export interface RunOpWaveOptions {
607
641
  signers?: (base: string) => GateSigners;
608
642
  /** How a gate with a `point` asks it (#3836). Default: `workspaceGatePointAsker` over `cwd`. A tool that bundles chant passes `chantGatePointAsker`. */
609
643
  points?: GatePointAsker;
644
+ /**
645
+ * Where the jobs' outcome files are (#4322), from `cwd`: the job reads the
646
+ * earlier waves' (a share job, its deciding job's) at any depth under it,
647
+ * and writes its own there. Default {@link opWaveOutcomeDir}.
648
+ */
649
+ outcomeDir?: string;
650
+ /** The commits after base up to the applied head, for `Requested-by:` trailers (#4333). Default: `git log`. */
651
+ commits?: (base: string, head: string) => { sha: string; message: string }[];
610
652
  }
611
653
 
612
654
  export interface RunOpWaveResult {
@@ -630,6 +672,12 @@ export interface RunOpWaveResult {
630
672
  failed: string[];
631
673
  /** Runs a share job refused because their plan moved since the decision. */
632
674
  moved: string[];
675
+ /**
676
+ * The runs a failure blocked (#4322), each with the run whose failure
677
+ * blocked it: a run of an earlier wave, or one listed before it in this
678
+ * wave. None of them was planned or applied.
679
+ */
680
+ blocked?: Record<string, string>;
633
681
  /** The hooks that ran (#3762). */
634
682
  hooks: OpWaveHookOutcome[];
635
683
  }
@@ -1150,12 +1198,55 @@ export async function runOpWave(options: RunOpWaveOptions): Promise<RunOpWaveRes
1150
1198
  const { spec } = options;
1151
1199
  assertOpWavesSpec(spec);
1152
1200
  const log = options.log ?? ((line: string) => console.error(line));
1153
- const last = spec.waves[spec.waves.length - 1]!;
1201
+ const cwd = options.cwd ?? process.cwd();
1202
+ const outcomeDir = options.outcomeDir ?? opWaveOutcomeDir(spec);
1203
+ const dir = isAbsolute(outcomeDir) ? outcomeDir : join(cwd, outcomeDir);
1204
+ // #4322: what the earlier jobs' outcome files say: an earlier wave that stopped stops this one, and a failure blocks its dependents.
1205
+ const before = opWaveBefore(options, dir);
1206
+ const blocked = before.blocked;
1207
+ if (before.stop) {
1208
+ log(before.stop.line);
1209
+ const stopped: RunOpWaveResult = { exitCode: before.stop.exitCode, applied: [], failed: [], moved: [], hooks: [], ...(blocked.size > 0 ? { blocked: Object.fromEntries(blocked) } : {}) };
1210
+ writeOpWaveOutcome(options, dir, stopped, before.stop.members);
1211
+ return stopped;
1212
+ }
1213
+ if (blocked.size > 0) log(`wave ${options.wave}: ${blockedWords(blocked)}, so not planned or applied`);
1214
+ const mine = jobRuns(options);
1215
+ if (mine.length > 0 && mine.every((t) => blocked.has(t))) {
1216
+ // Every run of this job is blocked: nothing to plan, decide or apply.
1217
+ const none: RunOpWaveResult = { exitCode: options.decide ? 0 : 1, applied: [], failed: [], moved: [], hooks: [], blocked: Object.fromEntries(blocked) };
1218
+ writeOpWaveOutcome(options, dir, none);
1219
+ return none;
1220
+ }
1221
+ let result: RunOpWaveResult;
1154
1222
  const applied: string[] = [];
1223
+ try {
1224
+ result = await runOpWaveLoop(options, log, applied, blocked);
1225
+ } catch (err) {
1226
+ writeOpWaveOutcome(options, dir, { exitCode: 1, applied, failed: [], moved: [], hooks: [], ...(blocked.size > 0 ? { blocked: Object.fromEntries(blocked) } : {}) });
1227
+ throw err;
1228
+ }
1229
+ const all = { ...Object.fromEntries(blocked), ...(result.blocked ?? {}) };
1230
+ if (Object.keys(all).length > 0) {
1231
+ result.blocked = all;
1232
+ // A deciding job applies nothing; its share jobs fail for the blocked runs of their slices.
1233
+ if (result.exitCode === 0 && !options.decide) {
1234
+ log(`wave ${options.wave}: the runs that could apply did; ${blockedWords(new Map(Object.entries(all)))}, so this job fails`);
1235
+ result.exitCode = 1;
1236
+ }
1237
+ }
1238
+ writeOpWaveOutcome(options, dir, result);
1239
+ return result;
1240
+ }
1241
+
1242
+ /** The wave engine's loop over this module's steps, from `options.wave` on, with the runs in `skip` left out of that wave. */
1243
+ async function runOpWaveLoop(options: RunOpWaveOptions, log: (line: string) => void, applied: string[], skip: ReadonlyMap<string, string>): Promise<RunOpWaveResult> {
1244
+ const { spec } = options;
1245
+ const last = spec.waves[spec.waves.length - 1]!;
1155
1246
  const rest: NonNullable<RunOpWaveResult["rest"]> = [];
1156
1247
  const result = await runWaveLoop<OpWavePlanned, OpWaveDecided, RunOpWaveResult>({
1157
1248
  first: options.wave,
1158
- plan: (at) => planOpWave(options, at),
1249
+ plan: (at) => planOpWave(options, at, at.k === options.wave ? skip : undefined),
1159
1250
  // A share job applies under the digest its deciding job recorded; it does not take the set digest again.
1160
1251
  digest: (_at, planned) => (planned.kind === "share" ? planned.decision.digest : opWaveSetDigest(spec, planned.members, planned.extras)),
1161
1252
  decide: (at, planned, digest) => (planned.kind === "share" ? shareUnmoved(planned) : decideOpWave(options, at, planned, digest)),
@@ -1183,6 +1274,116 @@ export async function runOpWave(options: RunOpWaveOptions): Promise<RunOpWaveRes
1183
1274
  return { ...result, applied, ...(rest.length > 0 ? { rest } : {}) };
1184
1275
  }
1185
1276
 
1277
+ /** What the earlier outcome files hold for a job (#4322): the runs they block, or why the job does not run at all. */
1278
+ interface OpWaveBefore {
1279
+ /** Each blocked run of this wave, with the run whose failure blocked it. */
1280
+ blocked: Map<string, string>;
1281
+ /** Set when the job runs nothing: its exit code, the log line, and the outcomes it writes. */
1282
+ stop?: { exitCode: number; line: string; members: Record<string, WaveMemberOutcome> };
1283
+ }
1284
+
1285
+ /**
1286
+ * Read the outcome files under `dir` for wave `k`'s job (#4322). A wave or
1287
+ * deciding job reads the earlier waves': with none at all (a pipeline
1288
+ * rendered before #4322, or a job run by hand) every earlier run counts as
1289
+ * applied, as `needs:` used to promise. An earlier run that waits at its gate
1290
+ * stops this wave (exit 3), and one that was refused, held, stood down or
1291
+ * moved, or whose share never reported, stops it too (exit 1): only a failure
1292
+ * lets the waves after it go on. Otherwise a run whose `dependsOn` names a
1293
+ * run that failed or was blocked is blocked, and so is one that depends on
1294
+ * it. A share job reads its deciding job's file instead: the runs it blocked
1295
+ * stay blocked, and a run that job failed on stops the share (exit 1), so a
1296
+ * decision record it left behind before failing applies nothing.
1297
+ */
1298
+ function opWaveBefore(options: RunOpWaveOptions, dir: string): OpWaveBefore {
1299
+ const { spec, wave: k } = options;
1300
+ const wave = spec.waves[k - 1];
1301
+ if (!wave) return { blocked: new Map() };
1302
+ if (options.share !== undefined || options.group !== undefined) {
1303
+ const decided = readWaveOutcomeFile([dir], waveOutcomeFileName(k));
1304
+ if (!decided) return { blocked: new Map() };
1305
+ const blocked = new Map<string, string>();
1306
+ const held: Array<[string, WaveMemberOutcome]> = [];
1307
+ for (const [target, o] of Object.entries(decided.members)) {
1308
+ if (o.status === "blocked") blocked.set(target, o.by ?? target);
1309
+ // A wave that waits or was refused says so in its decision record, which the share reads as before.
1310
+ else if (o.status !== "decided" && o.status !== "waiting" && o.status !== "refused") held.push([target, o]);
1311
+ }
1312
+ if (held.length === 0) return { blocked };
1313
+ const line = `${shareLabel(options)} of wave ${k} (${wave.name}) applies nothing: its deciding job did not decide ${held.map(([t, o]) => `${t} (${o.status})`).join(", ")}`;
1314
+ return { blocked, stop: { exitCode: 1, line, members: { ...decided.members } } };
1315
+ }
1316
+ if (k === 1) return { blocked: new Map() };
1317
+ const { members } = earlierWaveOutcomes([dir], k);
1318
+ if (members.size === 0) return { blocked: new Map() };
1319
+ const held = [...members].filter(([, o]) => !passesThrough(o) && o.status !== "failed" && o.status !== "blocked");
1320
+ if (held.length > 0) {
1321
+ const waiting = held.filter(([, o]) => o.status === "waiting");
1322
+ const shown = (waiting.length > 0 ? waiting : held).map(([t, o]) => `${t} (wave ${o.wave}${waiting.length > 0 ? "" : `, ${o.status}`})`).join(", ");
1323
+ const line = waiting.length > 0
1324
+ ? `Nothing in wave ${k} (${wave.name}) ran: ${shown} waits at its gate. Approve it and run that wave's job again, then this one.`
1325
+ : `Nothing in wave ${k} (${wave.name}) ran: ${shown} did not apply, and only a failure lets the waves after it go on.`;
1326
+ const status = waiting.length > 0 ? "waiting" : "not-applied";
1327
+ return { blocked: new Map(), stop: { exitCode: waiting.length > 0 ? 3 : 1, line, members: Object.fromEntries((wave.runs ?? []).map((r) => [r.target, { status }])) } };
1328
+ }
1329
+ const runs = wave.runs ?? [];
1330
+ const index = new Map(runs.map((r, i) => [r.target, i]));
1331
+ const ownBefore = (i: number, dep: string): boolean => (index.get(dep) ?? Infinity) < i;
1332
+ const upstreams = new Map(runs.map((r, i) => [r.target, (r.dependsOn ?? []).filter((d) => !ownBefore(i, d))]));
1333
+ const blocked = blockedMembers(runs.map((r) => r.target), upstreams, new Set([...upstreams.values()].flat()), members);
1334
+ // A run listed before this one in its own wave and blocked blocks it too, by the same failure.
1335
+ runs.forEach((run, i) => {
1336
+ if (blocked.has(run.target)) return;
1337
+ const dep = (run.dependsOn ?? []).filter((d) => ownBefore(i, d) && blocked.has(d)).sort()[0];
1338
+ if (dep !== undefined) blocked.set(run.target, blocked.get(dep)!);
1339
+ });
1340
+ return { blocked };
1341
+ }
1342
+
1343
+ /** The runs of wave `options.wave` this job holds (#4322): its slice for a share job, every run otherwise. Empty for a discovering wave. */
1344
+ function jobRuns(options: RunOpWaveOptions, runs?: readonly OpWaveRun[]): string[] {
1345
+ const wave = options.spec.waves[options.wave - 1];
1346
+ if (!wave) return [];
1347
+ const all = runs ?? (wave.discover ? [] : wave.runs);
1348
+ if (options.share === undefined && options.group === undefined) return all.map((r) => r.target);
1349
+ const group = options.group === undefined ? undefined : wave.jobs?.find((g) => g.name === options.group);
1350
+ if (options.group !== undefined && !group) return [];
1351
+ const shares = group ? (group.shares ?? 1) : (wave.shares ?? 1);
1352
+ return opWaveShare(group ? opWaveGroupRuns(group, all) : all, options.share ?? 1, shares).map((r) => r.target);
1353
+ }
1354
+
1355
+ /**
1356
+ * Write this job's outcome file (#4322): each of its runs' outcome, from how
1357
+ * the job ended. `members`, when given, is written as it is.
1358
+ */
1359
+ function writeOpWaveOutcome(options: RunOpWaveOptions, dir: string, result: RunOpWaveResult, members?: Record<string, WaveMemberOutcome>): void {
1360
+ const out: Record<string, WaveMemberOutcome> = { ...(members ?? {}) };
1361
+ if (!members) {
1362
+ const found = result.decision?.discovered !== undefined ? result.decision.members.map((m) => ({ target: m.member })) : undefined;
1363
+ const targets = new Set([...jobRuns(options, found), ...result.applied, ...result.failed, ...result.moved, ...Object.keys(result.blocked ?? {})]);
1364
+ const applied = new Set(result.applied);
1365
+ const failed = new Set(result.failed);
1366
+ const moved = new Set(result.moved);
1367
+ const otherwise: WaveMemberOutcome["status"] =
1368
+ result.exitCode === 0 ? (options.decide ? "decided" : "unchanged")
1369
+ : result.exitCode === 3 ? "waiting"
1370
+ : result.exitCode === 7 || result.exitCode === 8 ? "refused"
1371
+ : result.exitCode >= 4 && result.exitCode <= 6 ? "not-applied"
1372
+ : "failed";
1373
+ for (const t of targets) {
1374
+ const by = result.blocked?.[t];
1375
+ out[t] = by !== undefined ? { status: "blocked", by } : applied.has(t) ? { status: "applied" } : failed.has(t) ? { status: "failed" } : moved.has(t) ? { status: "not-applied" } : { status: otherwise };
1376
+ }
1377
+ }
1378
+ const part = { ...(options.group !== undefined ? { group: options.group } : {}), ...(options.share !== undefined ? { share: options.share } : {}) };
1379
+ try {
1380
+ mkdirSync(dir, { recursive: true });
1381
+ writeWaveOutcomeFile(dir, options.wave, part, out, options.now ?? new Date().toISOString());
1382
+ } catch (err) {
1383
+ (options.log ?? ((line: string) => console.error(line)))(`wave ${options.wave}: could not write its outcome file in ${dir}: ${err instanceof Error ? err.message : String(err)}`);
1384
+ }
1385
+ }
1386
+
1186
1387
  /** What a share or job group's job calls itself in the log: `share 2`, `job group "prod"`, `share 2 of job group "prod"`. */
1187
1388
  function shareLabel(options: Pick<RunOpWaveOptions, "share" | "group">): string {
1188
1389
  if (options.group === undefined) return `share ${options.share}`;
@@ -1240,7 +1441,7 @@ interface OpWaveDecided {
1240
1441
  * a hook fails or holds it on another gate, or a share's decision waits or
1241
1442
  * was refused.
1242
1443
  */
1243
- async function planOpWave(options: RunOpWaveOptions, { k, pass }: WaveAttempt<RunOpWaveResult>): Promise<WaveStep<OpWavePlanned, RunOpWaveResult>> {
1444
+ async function planOpWave(options: RunOpWaveOptions, { k, pass }: WaveAttempt<RunOpWaveResult>, skip?: ReadonlyMap<string, string>): Promise<WaveStep<OpWavePlanned, RunOpWaveResult>> {
1244
1445
  const { spec } = options;
1245
1446
  const cwd = options.cwd ?? process.cwd();
1246
1447
  const exec = options.exec ?? spawnExec;
@@ -1287,11 +1488,14 @@ async function planOpWave(options: RunOpWaveOptions, { k, pass }: WaveAttempt<Ru
1287
1488
  wave = { ...wave, runs: decision.members.map((m) => ({ target: m.member, ...(m.op !== spec.op ? { op: m.op } : {}) })) };
1288
1489
  ctx.wave = wave;
1289
1490
  }
1290
- const slice = opWaveShare(group ? opWaveGroupRuns(group, wave.runs) : wave.runs, options.share ?? 1, shares);
1291
- if (group && slice.length === 0) {
1491
+ const whole = opWaveShare(group ? opWaveGroupRuns(group, wave.runs) : wave.runs, options.share ?? 1, shares);
1492
+ if (group && whole.length === 0) {
1292
1493
  log(`${part} of wave ${k} (${wave.name}) holds none of the wave's runs; nothing to apply`);
1293
1494
  return { end: result };
1294
1495
  }
1496
+ // #4322: the runs its deciding job blocked are neither planned nor applied here.
1497
+ const slice = whole.filter((r) => !skip?.has(r.target));
1498
+ if (slice.length === 0) return { end: result };
1295
1499
  const before = await runBeforePlanHooks(ctx, decision.hooks, slice);
1296
1500
  if (before.failed) return { end: failed(ctx, `a hook before the plan failed, so nothing in ${part} of wave ${k} was planned or applied`) };
1297
1501
  if (before.waitingOn) return { end: await waitOnOther(ctx, decision, before.waitingOn) };
@@ -1347,6 +1551,11 @@ async function planOpWave(options: RunOpWaveOptions, { k, pass }: WaveAttempt<Ru
1347
1551
  ...(neverOverMcp ? { neverOverMcp: true as const } : {}),
1348
1552
  ...(rules.point ? { point: { ...rules.point } } : {}),
1349
1553
  };
1554
+ if (skip?.size && !wave.discover) {
1555
+ // #4322: a run a failure blocked is neither planned nor in the set digest.
1556
+ wave = { ...wave, runs: wave.runs.filter((r) => !skip.has(r.target)) };
1557
+ ctx.wave = wave;
1558
+ }
1350
1559
  const before = await runBeforePlanHooks(ctx, rules.hooks, wave.runs);
1351
1560
  if (before.failed) return { end: failed(ctx, `a hook before the plan failed, so nothing in wave ${k} was planned or applied`) };
1352
1561
  if (before.waitingOn) return { end: await decided(ctx, decision, recordPath, before.waitingOn) };
@@ -1423,7 +1632,11 @@ async function decideOpWave(
1423
1632
  decision.members = members;
1424
1633
  // #4290: the rules at base whose targets glob matches one of the wave's runs.
1425
1634
  const takes = planned.rules.quorum ? quorumRulesFor(planned.rules.quorum, members.map((m) => m.member)) : [];
1426
- if (takes.length > 0) decision.quorum = takes;
1635
+ if (takes.length > 0) {
1636
+ decision.quorum = takes;
1637
+ if (planned.rules.reviewLedger) decision.reviewLedger = planned.rules.reviewLedger;
1638
+ if (planned.rules.involved) decision.involved = planned.rules.involved;
1639
+ }
1427
1640
  if (extras) decision.extras = extras;
1428
1641
  if (pending) decision.pending = pending;
1429
1642
  const after = await runHooks(ctx, "after-plan", planned.rules.hooks["after-plan"], wave.runs, planned.planned, digest);
@@ -1741,6 +1954,16 @@ async function settleGate(options: RunOpWaveOptions, ctx: WaveContext, decision:
1741
1954
  decision.approve = approveCommand(spec.name, gate, undefined, digest, approval === "sealed");
1742
1955
  }
1743
1956
 
1957
+ /** The commits after `base` up to `head`, merge commits left out, for the `Requested-by:` trailers on them (#4333). */
1958
+ const gitCommitsBetween = (cwd: string) => (base: string, head: string): { sha: string; message: string }[] => {
1959
+ try {
1960
+ const out = execFileSync("git", ["log", "--no-merges", "--format=%H%x00%B%x01", `${base}..${head}`], { cwd, encoding: "utf-8" });
1961
+ return out.split("\x01").map((c) => c.replace(/^\n/, "")).filter((c) => c.includes("\x00")).map((c) => ({ sha: c.slice(0, c.indexOf("\x00")), message: c.slice(c.indexOf("\x00") + 1) }));
1962
+ } catch {
1963
+ return [];
1964
+ }
1965
+ };
1966
+
1744
1967
  /**
1745
1968
  * Decide a gate under approval rules (#4290): the rules at base the wave's
1746
1969
  * targets take, each met by distinct human approvers of the digest. Roles
@@ -1764,7 +1987,7 @@ async function settleQuorumGate(options: RunOpWaveOptions, ctx: WaveContext, dec
1764
1987
  // The merged pull request: its author for notAuthor, and its review under pr-review.
1765
1988
  let merged: MergedReview | null = null;
1766
1989
  let unknown: string | undefined;
1767
- const asks = approval === "pr-review" || rules.some((r) => r.notAuthor);
1990
+ const asks = approval === "pr-review" || rules.some((r) => r.notAuthor) || decision.involved !== undefined;
1768
1991
  const head = asks ? (options.head ?? execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8" }).trim()) : "";
1769
1992
  if (asks) {
1770
1993
  try {
@@ -1809,12 +2032,54 @@ async function settleQuorumGate(options: RunOpWaveOptions, ctx: WaveContext, dec
1809
2032
  }
1810
2033
  }
1811
2034
 
1812
- const judge = trustQuorumJudge({
2035
+ // #4333: reviews a product recorded itself, on the ledger the spec at base names. The ledger is
2036
+ // the lifecycle branch's, never the change's, and proves a reviewer only under `pr-review`.
2037
+ const principal = review.forgePrincipalFromEnv();
2038
+ let recorded: { head: string; approvers: string[] }[] = [];
2039
+ if (decision.reviewLedger && approval === "pr-review") {
2040
+ const lines = (await ledger.read(decision.reviewLedger)).resolutions.filter((r) => r.gate === gate && samePlanDigest(r.planDigest, digest));
2041
+ const read = recordedReviewApprovals(lines, principal);
2042
+ recorded = read.reviews.filter((x) => !(spent !== undefined && isApprovalSpent(spent, { gate, planDigest: digest, review: { head: x.head } })));
2043
+ const had = (await ledger.read(spec.name)).resolutions.filter((r) => r.gate === gate && samePlanDigest(r.planDigest, digest));
2044
+ for (const rec of read.records) {
2045
+ if (!rec.review || !recorded.some((x) => x.head === rec.review!.head) || had.some((r) => r.review?.head === rec.review!.head && samePrincipal(r.resolvedBy, rec.resolvedBy))) continue;
2046
+ await ledger.appendResolution?.({
2047
+ ...rec,
2048
+ op: spec.name,
2049
+ gate,
2050
+ timestamp: now,
2051
+ planDigest: digest,
2052
+ note: `approved by a review ${decision.reviewLedger} recorded for ${rec.review.head.slice(0, 12)}: ${rec.review.approvers.join(", ")}`,
2053
+ });
2054
+ }
2055
+ if (recorded.length > 0) log(`${label}: ${decision.reviewLedger} recorded a review of ${digest} by ${[...new Set(recorded.flatMap((x) => x.approvers))].join(", ")}`);
2056
+ }
2057
+
2058
+ // #4333: everyone involved in the change, from the commits after base and the agents' accounts at base.
2059
+ const involved = decision.involved || merged ? changeInvolvement({
2060
+ ...(merged ? { author: merged.author } : {}),
2061
+ commits: decision.involved ? (options.commits ?? gitCommitsBetween(cwd))(base, head) : [],
2062
+ ...(decision.involved?.agents ? { agents: decision.involved.agents.map(principal) } : {}),
2063
+ principal,
2064
+ }) : [];
2065
+ const said = new Set<string>();
2066
+ const sayExcluded = (j: QuorumJudgement): QuorumJudgement => {
2067
+ if (j.excluded !== undefined && !said.has(j.excluded)) {
2068
+ said.add(j.excluded);
2069
+ log(`${label}: ${j.excluded}`);
2070
+ }
2071
+ return j;
2072
+ };
2073
+ const judgeBase = trustQuorumJudge({
1813
2074
  signers: trust,
1814
2075
  roles: trust.roles,
1815
2076
  ...(merged ? { authors: [merged.author] } : {}),
2077
+ ...(involved.length > 0 ? { involved } : {}),
2078
+ ...(decision.involved?.exclude ? { excludeInvolved: true } : {}),
1816
2079
  ...(reviewed ? { review: reviewed } : {}),
2080
+ ...(recorded.length > 0 ? { recorded } : {}),
1817
2081
  });
2082
+ const judge: GateQuorumJudge = (r) => sayExcluded(judgeBase(r));
1818
2083
  const held = decision.heldBy?.length ? `, held by ${decision.heldBy.join(", ")}` : "";
1819
2084
  const check = await decideWaveGate(port, {
1820
2085
  op: spec.name,
@@ -2124,7 +2389,16 @@ async function applyStage(
2124
2389
  result.failed.push(...runs.map((r) => r.target));
2125
2390
  }
2126
2391
  } else {
2127
- for (const run of runs) {
2392
+ const order = new Map(runs.map((r, i) => [r.target, i]));
2393
+ for (const [i, run] of runs.entries()) {
2394
+ // #4322: a run listed before this one that failed, or was blocked, blocks it.
2395
+ const dep = (run.dependsOn ?? []).filter((d) => (order.get(d) ?? Infinity) < i && (result.failed.includes(d) || result.blocked?.[d] !== undefined)).sort()[0];
2396
+ if (dep !== undefined) {
2397
+ const by = result.blocked?.[dep] ?? dep;
2398
+ result.blocked = { ...result.blocked, [run.target]: by };
2399
+ log(`${run.target}: blocked by ${by}, so not applied`);
2400
+ continue;
2401
+ }
2128
2402
  const key = run.target.replace(/[^A-Za-z0-9._-]/g, "_");
2129
2403
  // Under runBy "apply" each run's apply runs its own apply-stage hooks, over a runs file of that run alone.
2130
2404
  const runsPath = byApply ? writeRunsFile(ctx, [run], planned, decision.digest, `.chant/op-waves/${spec.name}/wave-${k}/${key}.runs.json`) : opWaveRunsPath(spec, k);