@intentius/chant 0.101.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (739) hide show
  1. package/dist/agents/checks.d.ts.map +1 -1
  2. package/dist/attrref.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +2 -0
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts.map +1 -1
  6. package/dist/audit/nginx.d.ts.map +1 -1
  7. package/dist/audit/prior-art.d.ts +48 -0
  8. package/dist/audit/prior-art.d.ts.map +1 -1
  9. package/dist/behaviour-kinds.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/change-set.d.ts +232 -0
  12. package/dist/change-set.d.ts.map +1 -0
  13. package/dist/cli/commands/audit.d.ts +7 -0
  14. package/dist/cli/commands/audit.d.ts.map +1 -1
  15. package/dist/cli/commands/build.d.ts.map +1 -1
  16. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  17. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  18. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  19. package/dist/cli/commands/import.d.ts +8 -0
  20. package/dist/cli/commands/import.d.ts.map +1 -1
  21. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  22. package/dist/cli/commands/init.d.ts +19 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/onboard.d.ts +9 -0
  25. package/dist/cli/commands/onboard.d.ts.map +1 -1
  26. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  27. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  28. package/dist/cli/handlers/build.d.ts.map +1 -1
  29. package/dist/cli/handlers/change-set.d.ts +11 -0
  30. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts +33 -0
  33. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +16 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/pr.d.ts +31 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -0
  40. package/dist/cli/handlers/run.d.ts.map +1 -1
  41. package/dist/cli/lsp/server.d.ts.map +1 -1
  42. package/dist/cli/main.d.ts.map +1 -1
  43. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  44. package/dist/cli/mcp/server.d.ts.map +1 -1
  45. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  46. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  47. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  48. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  49. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  50. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  51. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  52. package/dist/cli/mcp/workspace-tools.d.ts +4 -3
  53. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  54. package/dist/cli/registry.d.ts +74 -3
  55. package/dist/cli/registry.d.ts.map +1 -1
  56. package/dist/codegen/fetch.d.ts.map +1 -1
  57. package/dist/codegen/naming.d.ts.map +1 -1
  58. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  59. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  60. package/dist/codegen/registry.d.ts.map +1 -1
  61. package/dist/components/auto-release.d.ts +16 -0
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  64. package/dist/components/capability.d.ts +53 -0
  65. package/dist/components/capability.d.ts.map +1 -1
  66. package/dist/components/changed-files.d.ts +31 -0
  67. package/dist/components/changed-files.d.ts.map +1 -0
  68. package/dist/components/cli-support.d.ts +9 -1
  69. package/dist/components/cli-support.d.ts.map +1 -1
  70. package/dist/components/component.d.ts +24 -0
  71. package/dist/components/component.d.ts.map +1 -1
  72. package/dist/components/deploy-units.d.ts.map +1 -1
  73. package/dist/components/driver.d.ts +13 -0
  74. package/dist/components/driver.d.ts.map +1 -1
  75. package/dist/components/fan-out-output.d.ts +6 -0
  76. package/dist/components/fan-out-output.d.ts.map +1 -1
  77. package/dist/components/fan-out-record.d.ts +41 -0
  78. package/dist/components/fan-out-record.d.ts.map +1 -0
  79. package/dist/components/fan-out-run.d.ts +65 -0
  80. package/dist/components/fan-out-run.d.ts.map +1 -1
  81. package/dist/components/fan-out-support.d.ts +2 -0
  82. package/dist/components/fan-out-support.d.ts.map +1 -1
  83. package/dist/components/fan-out.d.ts +6 -0
  84. package/dist/components/fan-out.d.ts.map +1 -1
  85. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  86. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  87. package/dist/components/index.d.ts +1 -1
  88. package/dist/components/index.d.ts.map +1 -1
  89. package/dist/components/layers.d.ts +25 -0
  90. package/dist/components/layers.d.ts.map +1 -0
  91. package/dist/components/pr-pipeline.d.ts +61 -0
  92. package/dist/components/pr-pipeline.d.ts.map +1 -0
  93. package/dist/components/pr-run.d.ts +119 -0
  94. package/dist/components/pr-run.d.ts.map +1 -0
  95. package/dist/components/promote.d.ts.map +1 -1
  96. package/dist/components/starter-plugin.d.ts.map +1 -1
  97. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  98. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  99. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  100. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  101. package/dist/components/verbs/shell.d.ts.map +1 -1
  102. package/dist/components/verbs/sign.d.ts.map +1 -1
  103. package/dist/components/verbs/verify.d.ts.map +1 -1
  104. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  105. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  106. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  107. package/dist/components/wave-plan.d.ts +49 -0
  108. package/dist/components/wave-plan.d.ts.map +1 -0
  109. package/dist/composite.d.ts.map +1 -1
  110. package/dist/config.d.ts +19 -7
  111. package/dist/config.d.ts.map +1 -1
  112. package/dist/declarable.d.ts +16 -0
  113. package/dist/declarable.d.ts.map +1 -1
  114. package/dist/discovery/cache.d.ts.map +1 -1
  115. package/dist/discovery/fold-import.d.ts +15 -5
  116. package/dist/discovery/fold-import.d.ts.map +1 -1
  117. package/dist/discovery/param-deps.d.ts +16 -0
  118. package/dist/discovery/param-deps.d.ts.map +1 -1
  119. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  120. package/dist/discovery/specifier-resolve.d.ts +37 -0
  121. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  122. package/dist/errors.d.ts.map +1 -1
  123. package/dist/fold/fold.d.ts +3 -1
  124. package/dist/fold/fold.d.ts.map +1 -1
  125. package/dist/gated-waves.d.ts +147 -0
  126. package/dist/gated-waves.d.ts.map +1 -0
  127. package/dist/graph-detail.d.ts.map +1 -1
  128. package/dist/graph-ir.d.ts.map +1 -1
  129. package/dist/graph-layout.d.ts.map +1 -1
  130. package/dist/import/base-parser.d.ts.map +1 -1
  131. package/dist/import/embedded.d.ts +7 -0
  132. package/dist/import/embedded.d.ts.map +1 -1
  133. package/dist/import/parser-options.d.ts +14 -0
  134. package/dist/import/parser-options.d.ts.map +1 -0
  135. package/dist/import/parser.d.ts +17 -0
  136. package/dist/import/parser.d.ts.map +1 -1
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/kubectl-context.d.ts.map +1 -1
  140. package/dist/lexicon-output.d.ts.map +1 -1
  141. package/dist/lexicon-schema.d.ts +3 -3
  142. package/dist/lexicon.d.ts +103 -3
  143. package/dist/lexicon.d.ts.map +1 -1
  144. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  145. package/dist/lifecycle/gate-ledger.d.ts +22 -0
  146. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  147. package/dist/lifecycle/git.d.ts +46 -1
  148. package/dist/lifecycle/git.d.ts.map +1 -1
  149. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  150. package/dist/lifecycle/observe.d.ts.map +1 -1
  151. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  153. package/dist/lifecycle/scenario.d.ts.map +1 -1
  154. package/dist/lifecycle/status.d.ts.map +1 -1
  155. package/dist/lifecycle/work-lease.d.ts +61 -2
  156. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  157. package/dist/lint/config.d.ts +8 -8
  158. package/dist/lint/engine.d.ts +6 -0
  159. package/dist/lint/engine.d.ts.map +1 -1
  160. package/dist/lint/post-synth.d.ts +18 -0
  161. package/dist/lint/post-synth.d.ts.map +1 -1
  162. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  163. package/dist/op/activities/activity-contracts.d.ts +137 -11
  164. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  165. package/dist/op/activities/apply.d.ts +79 -9
  166. package/dist/op/activities/apply.d.ts.map +1 -1
  167. package/dist/op/activities/change-set.d.ts +62 -0
  168. package/dist/op/activities/change-set.d.ts.map +1 -0
  169. package/dist/op/activities/decide.d.ts +2 -0
  170. package/dist/op/activities/decide.d.ts.map +1 -1
  171. package/dist/op/activities/factory.d.ts +137 -0
  172. package/dist/op/activities/factory.d.ts.map +1 -0
  173. package/dist/op/activities/index.d.ts +5 -1
  174. package/dist/op/activities/index.d.ts.map +1 -1
  175. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  176. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  177. package/dist/op/activity-contract.d.ts +1 -1
  178. package/dist/op/activity-contract.d.ts.map +1 -1
  179. package/dist/op/activity-failure.d.ts.map +1 -1
  180. package/dist/op/activity-profiles.d.ts.map +1 -1
  181. package/dist/op/builders.d.ts +11 -0
  182. package/dist/op/builders.d.ts.map +1 -1
  183. package/dist/op/composites/apply-op.d.ts +12 -5
  184. package/dist/op/composites/apply-op.d.ts.map +1 -1
  185. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  186. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  187. package/dist/op/decide-backend.d.ts +5 -1
  188. package/dist/op/decide-backend.d.ts.map +1 -1
  189. package/dist/op/decide-read-inputs.d.ts +4 -2
  190. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  191. package/dist/op/emulator-lifecycle.d.ts +21 -2
  192. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  193. package/dist/op/factory.d.ts +83 -0
  194. package/dist/op/factory.d.ts.map +1 -0
  195. package/dist/op/gate-approval.d.ts +5 -1
  196. package/dist/op/gate-approval.d.ts.map +1 -1
  197. package/dist/op/gate-wait.d.ts.map +1 -1
  198. package/dist/op/gate.d.ts +19 -3
  199. package/dist/op/gate.d.ts.map +1 -1
  200. package/dist/op/index.d.ts +6 -1
  201. package/dist/op/index.d.ts.map +1 -1
  202. package/dist/op/local-executor.d.ts +6 -0
  203. package/dist/op/local-executor.d.ts.map +1 -1
  204. package/dist/op/op-ir.d.ts +2 -0
  205. package/dist/op/op-ir.d.ts.map +1 -1
  206. package/dist/op/op-verb-class.d.ts.map +1 -1
  207. package/dist/op/operator.d.ts.map +1 -1
  208. package/dist/op/run-context.d.ts +39 -0
  209. package/dist/op/run-context.d.ts.map +1 -0
  210. package/dist/op/run-live.d.ts.map +1 -1
  211. package/dist/op/runtimes/local.d.ts.map +1 -1
  212. package/dist/op/source-archive.d.ts.map +1 -1
  213. package/dist/op/steward-beside.d.ts.map +1 -1
  214. package/dist/op/steward-points.d.ts.map +1 -1
  215. package/dist/op/steward.d.ts.map +1 -1
  216. package/dist/op/types.d.ts +16 -3
  217. package/dist/op/types.d.ts.map +1 -1
  218. package/dist/op/work-lease-run.d.ts +24 -4
  219. package/dist/op/work-lease-run.d.ts.map +1 -1
  220. package/dist/plan-summary.d.ts +207 -0
  221. package/dist/plan-summary.d.ts.map +1 -0
  222. package/dist/pr-forge.d.ts +105 -0
  223. package/dist/pr-forge.d.ts.map +1 -0
  224. package/dist/pr-loop.d.ts +178 -0
  225. package/dist/pr-loop.d.ts.map +1 -0
  226. package/dist/project-root.d.ts.map +1 -1
  227. package/dist/provenance.d.ts +21 -0
  228. package/dist/provenance.d.ts.map +1 -1
  229. package/dist/pseudo-parameter.d.ts.map +1 -1
  230. package/dist/reconcile.d.ts.map +1 -1
  231. package/dist/secret-materialization.d.ts.map +1 -1
  232. package/dist/telemetry-attribution.d.ts +31 -0
  233. package/dist/telemetry-attribution.d.ts.map +1 -1
  234. package/dist/terraform/emit-source.d.ts.map +1 -1
  235. package/dist/terraform/hcl2json.d.ts +45 -0
  236. package/dist/terraform/hcl2json.d.ts.map +1 -0
  237. package/dist/terraform/parse.d.ts +4 -40
  238. package/dist/terraform/parse.d.ts.map +1 -1
  239. package/dist/testing.d.ts.map +1 -1
  240. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  241. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  242. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  243. package/dist/workspace/agent-cli.d.ts +5 -0
  244. package/dist/workspace/agent-cli.d.ts.map +1 -1
  245. package/dist/workspace/box-cli.d.ts +12 -0
  246. package/dist/workspace/box-cli.d.ts.map +1 -0
  247. package/dist/workspace/box-factory.d.ts +97 -0
  248. package/dist/workspace/box-factory.d.ts.map +1 -0
  249. package/dist/workspace/box-listing.d.ts +85 -0
  250. package/dist/workspace/box-listing.d.ts.map +1 -0
  251. package/dist/workspace/box-publish.d.ts +147 -0
  252. package/dist/workspace/box-publish.d.ts.map +1 -0
  253. package/dist/workspace/broker-protocol.d.ts +190 -0
  254. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  255. package/dist/workspace/changes.d.ts.map +1 -1
  256. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  257. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  258. package/dist/workspace/checks.d.ts +5 -0
  259. package/dist/workspace/checks.d.ts.map +1 -1
  260. package/dist/workspace/compose-graph.d.ts +10 -0
  261. package/dist/workspace/compose-graph.d.ts.map +1 -1
  262. package/dist/workspace/composites.d.ts +2 -2
  263. package/dist/workspace/composites.d.ts.map +1 -1
  264. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  265. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  266. package/dist/workspace/conformance/broker.d.ts +202 -0
  267. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  268. package/dist/workspace/conformance/index.d.ts +68 -6
  269. package/dist/workspace/conformance/index.d.ts.map +1 -1
  270. package/dist/workspace/conformance/vitest.d.ts +19 -3
  271. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  272. package/dist/workspace/conformance/writer.d.ts +462 -0
  273. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  274. package/dist/workspace/decide.d.ts +126 -12
  275. package/dist/workspace/decide.d.ts.map +1 -1
  276. package/dist/workspace/decision-points.schema.json +11 -4
  277. package/dist/workspace/declaration.d.ts +156 -4
  278. package/dist/workspace/declaration.d.ts.map +1 -1
  279. package/dist/workspace/declaration.schema.json +383 -5
  280. package/dist/workspace/environments.d.ts +36 -10
  281. package/dist/workspace/environments.d.ts.map +1 -1
  282. package/dist/workspace/factory-rules.d.ts +180 -0
  283. package/dist/workspace/factory-rules.d.ts.map +1 -0
  284. package/dist/workspace/generated-files.d.ts.map +1 -1
  285. package/dist/workspace/graph-cache.d.ts.map +1 -1
  286. package/dist/workspace/graph-cli.d.ts +2 -0
  287. package/dist/workspace/graph-cli.d.ts.map +1 -1
  288. package/dist/workspace/identity.d.ts +111 -0
  289. package/dist/workspace/identity.d.ts.map +1 -0
  290. package/dist/workspace/init.d.ts +21 -0
  291. package/dist/workspace/init.d.ts.map +1 -1
  292. package/dist/workspace/intent-cli.d.ts +7 -4
  293. package/dist/workspace/intent-cli.d.ts.map +1 -1
  294. package/dist/workspace/intent-record.d.ts +36 -2
  295. package/dist/workspace/intent-record.d.ts.map +1 -1
  296. package/dist/workspace/intent.d.ts +249 -8
  297. package/dist/workspace/intent.d.ts.map +1 -1
  298. package/dist/workspace/json-edit.d.ts +24 -0
  299. package/dist/workspace/json-edit.d.ts.map +1 -0
  300. package/dist/workspace/jsonc.d.ts +11 -0
  301. package/dist/workspace/jsonc.d.ts.map +1 -1
  302. package/dist/workspace/kinds.d.ts +66 -4
  303. package/dist/workspace/kinds.d.ts.map +1 -1
  304. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  305. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  306. package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
  307. package/dist/workspace/lineage-lock.d.ts +2 -2
  308. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  309. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  310. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  311. package/dist/workspace/links.d.ts.map +1 -1
  312. package/dist/workspace/point-answer.schema.json +42 -2
  313. package/dist/workspace/points-cli.d.ts +10 -3
  314. package/dist/workspace/points-cli.d.ts.map +1 -1
  315. package/dist/workspace/points.d.ts +66 -5
  316. package/dist/workspace/points.d.ts.map +1 -1
  317. package/dist/workspace/principal-classes.d.ts +114 -0
  318. package/dist/workspace/principal-classes.d.ts.map +1 -0
  319. package/dist/workspace/reason-codes.d.ts +53 -4
  320. package/dist/workspace/reason-codes.d.ts.map +1 -1
  321. package/dist/workspace/record-assets.d.ts.map +1 -1
  322. package/dist/workspace/record-sessions.d.ts +5 -7
  323. package/dist/workspace/record-sessions.d.ts.map +1 -1
  324. package/dist/workspace/records-checkout.d.ts +54 -0
  325. package/dist/workspace/records-checkout.d.ts.map +1 -0
  326. package/dist/workspace/records-cli.d.ts +34 -1
  327. package/dist/workspace/records-cli.d.ts.map +1 -1
  328. package/dist/workspace/records-close.d.ts +7 -3
  329. package/dist/workspace/records-close.d.ts.map +1 -1
  330. package/dist/workspace/records-since.d.ts.map +1 -1
  331. package/dist/workspace/records-write.d.ts +68 -7
  332. package/dist/workspace/records-write.d.ts.map +1 -1
  333. package/dist/workspace/records.d.ts +43 -9
  334. package/dist/workspace/records.d.ts.map +1 -1
  335. package/dist/workspace/runs-cli.d.ts +296 -0
  336. package/dist/workspace/runs-cli.d.ts.map +1 -0
  337. package/dist/workspace/runs.d.ts +544 -0
  338. package/dist/workspace/runs.d.ts.map +1 -0
  339. package/dist/workspace/session-kinds.d.ts +1 -1
  340. package/dist/workspace/session-kinds.d.ts.map +1 -1
  341. package/dist/workspace/source-block.d.ts +1 -1
  342. package/dist/workspace/source-block.d.ts.map +1 -1
  343. package/dist/workspace/squash.d.ts +80 -0
  344. package/dist/workspace/squash.d.ts.map +1 -0
  345. package/dist/workspace/status-gates.d.ts +17 -3
  346. package/dist/workspace/status-gates.d.ts.map +1 -1
  347. package/dist/workspace/status.d.ts +64 -0
  348. package/dist/workspace/status.d.ts.map +1 -1
  349. package/dist/workspace/symbols.d.ts +63 -0
  350. package/dist/workspace/symbols.d.ts.map +1 -0
  351. package/dist/workspace/trailer-joins.d.ts +46 -0
  352. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  353. package/dist/workspace/trailers.d.ts +89 -0
  354. package/dist/workspace/trailers.d.ts.map +1 -0
  355. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  356. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  357. package/dist/workspace/trust/run-commits.d.ts +46 -0
  358. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  359. package/dist/workspace/trust/run-statement.d.ts +128 -0
  360. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  361. package/dist/workspace/trust/seal.d.ts +38 -0
  362. package/dist/workspace/trust/seal.d.ts.map +1 -1
  363. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  364. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  365. package/dist/workspace/trust/verify.d.ts +16 -2
  366. package/dist/workspace/trust/verify.d.ts.map +1 -1
  367. package/dist/workspace/wip-cli.d.ts +21 -0
  368. package/dist/workspace/wip-cli.d.ts.map +1 -0
  369. package/dist/workspace/wip.d.ts +268 -0
  370. package/dist/workspace/wip.d.ts.map +1 -0
  371. package/dist/workspace/work-cli.d.ts +39 -3
  372. package/dist/workspace/work-cli.d.ts.map +1 -1
  373. package/dist/workspace/work-evidence.d.ts +1 -1
  374. package/dist/workspace/work-evidence.d.ts.map +1 -1
  375. package/dist/workspace/work-size.d.ts +55 -0
  376. package/dist/workspace/work-size.d.ts.map +1 -0
  377. package/dist/workspace/work.d.ts +26 -1
  378. package/dist/workspace/work.d.ts.map +1 -1
  379. package/dist/workspace/workspace-kinds.schema.json +122 -0
  380. package/dist/workspace/workspace-principals.schema.json +60 -0
  381. package/dist/workspace/write-lock-cli.d.ts +60 -0
  382. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  383. package/dist/workspace/write-lock.d.ts +152 -0
  384. package/dist/workspace/write-lock.d.ts.map +1 -0
  385. package/dist/workspace/write-scope.d.ts +83 -19
  386. package/dist/workspace/write-scope.d.ts.map +1 -1
  387. package/dist/yaml.d.ts +21 -39
  388. package/dist/yaml.d.ts.map +1 -1
  389. package/package.json +7 -2
  390. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  391. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  392. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  393. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  394. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  395. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  396. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  397. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  398. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  399. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  400. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  401. package/src/audit/core.test.ts +15 -0
  402. package/src/audit/core.ts +8 -2
  403. package/src/audit/discover.test.ts +11 -0
  404. package/src/audit/discover.ts +7 -2
  405. package/src/audit/prior-art.ts +15 -0
  406. package/src/change-set-bundle.test.ts +57 -0
  407. package/src/change-set.test.ts +215 -0
  408. package/src/change-set.ts +445 -0
  409. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  410. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  411. package/src/cli/commands/audit.ts +29 -2
  412. package/src/cli/commands/build.test.ts +19 -0
  413. package/src/cli/commands/build.ts +3 -2
  414. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  415. package/src/cli/commands/carve-emit.ts +5 -19
  416. package/src/cli/commands/check-lexicon.test.ts +62 -1
  417. package/src/cli/commands/check-lexicon.ts +36 -6
  418. package/src/cli/commands/import-live.test.ts +18 -0
  419. package/src/cli/commands/import-parser-options.test.ts +133 -0
  420. package/src/cli/commands/import.ts +21 -3
  421. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  422. package/src/cli/commands/init.test.ts +8 -1
  423. package/src/cli/commands/init.ts +23 -8
  424. package/src/cli/commands/lint.test.ts +37 -0
  425. package/src/cli/commands/onboard.test.ts +53 -3
  426. package/src/cli/commands/onboard.ts +52 -4
  427. package/src/cli/commands/pinned-upgrade.ts +73 -33
  428. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  429. package/src/cli/handlers/build.ts +13 -1
  430. package/src/cli/handlers/change-set.test.ts +56 -0
  431. package/src/cli/handlers/change-set.ts +44 -0
  432. package/src/cli/handlers/components.ts +2 -2
  433. package/src/cli/handlers/dev.ts +8 -6
  434. package/src/cli/handlers/fan-out.test.ts +221 -2
  435. package/src/cli/handlers/fan-out.ts +165 -75
  436. package/src/cli/handlers/graph.ts +3 -0
  437. package/src/cli/handlers/lifecycle.test.ts +67 -0
  438. package/src/cli/handlers/lifecycle.ts +6 -5
  439. package/src/cli/handlers/misc.ts +2 -0
  440. package/src/cli/handlers/operator.test.ts +21 -0
  441. package/src/cli/handlers/operator.ts +121 -6
  442. package/src/cli/handlers/pr.ts +373 -0
  443. package/src/cli/handlers/run.test.ts +111 -0
  444. package/src/cli/handlers/run.ts +86 -24
  445. package/src/cli/handlers/scenario.ts +2 -2
  446. package/src/cli/main.test.ts +21 -0
  447. package/src/cli/main.ts +246 -30
  448. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  449. package/src/cli/mcp/op-tools.ts +24 -2
  450. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  451. package/src/cli/mcp/workspace-tools.ts +62 -7
  452. package/src/cli/registry.ts +74 -3
  453. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  454. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  455. package/src/codegen/pinned-upgrade.test.ts +104 -0
  456. package/src/codegen/pinned-upgrade.ts +250 -56
  457. package/src/codegen/testdata/postgres-tags.json +242 -0
  458. package/src/components/auto-release.ts +1 -1
  459. package/src/components/capability.ts +55 -0
  460. package/src/components/changed-files.ts +66 -0
  461. package/src/components/cli-support.ts +28 -5
  462. package/src/components/component.schema.json +17 -0
  463. package/src/components/component.ts +25 -0
  464. package/src/components/deploy-units.ts +3 -0
  465. package/src/components/driver.test.ts +52 -0
  466. package/src/components/driver.ts +31 -13
  467. package/src/components/fan-out-output.ts +42 -1
  468. package/src/components/fan-out-record.ts +69 -0
  469. package/src/components/fan-out-run.test.ts +17 -0
  470. package/src/components/fan-out-run.ts +304 -1
  471. package/src/components/fan-out-support.ts +3 -0
  472. package/src/components/fan-out-waves.test.ts +375 -0
  473. package/src/components/fan-out.ts +18 -17
  474. package/src/components/gated-wave-pipeline.ts +82 -0
  475. package/src/components/index.ts +1 -0
  476. package/src/components/layers.ts +30 -0
  477. package/src/components/pr-pipeline.ts +91 -0
  478. package/src/components/pr-run.test.ts +205 -0
  479. package/src/components/pr-run.ts +280 -0
  480. package/src/components/promote.ts +5 -0
  481. package/src/components/verbs/shell.test.ts +11 -0
  482. package/src/components/verbs/shell.ts +7 -3
  483. package/src/components/wave-plan.ts +124 -0
  484. package/src/config.test.ts +21 -0
  485. package/src/config.ts +15 -0
  486. package/src/declarable.test.ts +21 -0
  487. package/src/declarable.ts +19 -0
  488. package/src/discovery/fold-composite.test.ts +41 -5
  489. package/src/discovery/fold-import.test.ts +129 -0
  490. package/src/discovery/fold-import.ts +643 -131
  491. package/src/discovery/fold-package-composite.test.ts +264 -0
  492. package/src/discovery/fold-specifiers.test.ts +191 -0
  493. package/src/discovery/param-deps.test.ts +66 -1
  494. package/src/discovery/param-deps.ts +45 -0
  495. package/src/discovery/sandbox/bundle.ts +1 -1
  496. package/src/discovery/specifier-resolve.ts +344 -0
  497. package/src/fold/fold.test.ts +39 -1
  498. package/src/fold/fold.ts +83 -9
  499. package/src/fold-provenance.test.ts +140 -0
  500. package/src/gated-waves-bundle.test.ts +62 -0
  501. package/src/gated-waves.test.ts +118 -0
  502. package/src/gated-waves.ts +240 -0
  503. package/src/graph-ir.test.ts +83 -0
  504. package/src/graph-ir.ts +29 -0
  505. package/src/import/embedded.test.ts +20 -0
  506. package/src/import/embedded.ts +13 -0
  507. package/src/import/parser-options.ts +46 -0
  508. package/src/import/parser.ts +20 -0
  509. package/src/index.ts +1 -0
  510. package/src/lexicon.ts +106 -3
  511. package/src/lifecycle/gate-ledger.ts +23 -0
  512. package/src/lifecycle/git.ts +102 -16
  513. package/src/lifecycle/observe.test.ts +18 -0
  514. package/src/lifecycle/observe.ts +6 -4
  515. package/src/lifecycle/snapshot.ts +2 -2
  516. package/src/lifecycle/work-lease.test.ts +1 -1
  517. package/src/lifecycle/work-lease.ts +93 -2
  518. package/src/lint/engine.test.ts +55 -0
  519. package/src/lint/engine.ts +30 -4
  520. package/src/lint/output-docs.test.ts +59 -56
  521. package/src/lint/post-synth.test.ts +19 -0
  522. package/src/lint/post-synth.ts +19 -1
  523. package/src/meta/declared-imports.test.ts +1 -1
  524. package/src/op/activities/activity-contracts.ts +84 -0
  525. package/src/op/activities/apply.test.ts +189 -5
  526. package/src/op/activities/apply.ts +230 -8
  527. package/src/op/activities/change-set.ts +114 -0
  528. package/src/op/activities/decide.ts +3 -0
  529. package/src/op/activities/factory.ts +675 -0
  530. package/src/op/activities/index.ts +9 -0
  531. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  532. package/src/op/activities/lexicon-upgrade.ts +154 -51
  533. package/src/op/activity-contract.test.ts +21 -1
  534. package/src/op/activity-contract.ts +19 -9
  535. package/src/op/builders.ts +23 -0
  536. package/src/op/composites/apply-op.ts +12 -5
  537. package/src/op/composites/composites.test.ts +30 -3
  538. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  539. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  540. package/src/op/decide-backend.ts +5 -1
  541. package/src/op/decide-read-inputs.ts +33 -5
  542. package/src/op/emulator-lifecycle.test.ts +23 -0
  543. package/src/op/emulator-lifecycle.ts +52 -14
  544. package/src/op/factory.e2e.test.ts +232 -0
  545. package/src/op/factory.ts +118 -0
  546. package/src/op/gate-approval.test.ts +74 -0
  547. package/src/op/gate-approval.ts +5 -1
  548. package/src/op/gate.ts +31 -5
  549. package/src/op/index.ts +11 -1
  550. package/src/op/local-executor.test.ts +15 -0
  551. package/src/op/local-executor.ts +40 -12
  552. package/src/op/local-output.ts +1 -1
  553. package/src/op/op-ir.test.ts +9 -0
  554. package/src/op/op-ir.ts +4 -0
  555. package/src/op/op-verb-class.ts +3 -0
  556. package/src/op/operator.ts +4 -0
  557. package/src/op/run-context.test.ts +141 -0
  558. package/src/op/run-context.ts +51 -0
  559. package/src/op/runtimes/local.test.ts +14 -0
  560. package/src/op/runtimes/local.ts +2 -0
  561. package/src/op/steward-beside.ts +2 -0
  562. package/src/op/types.ts +16 -3
  563. package/src/op/work-lease-run.test.ts +47 -0
  564. package/src/op/work-lease-run.ts +76 -11
  565. package/src/plan-summary.test.ts +263 -0
  566. package/src/plan-summary.ts +845 -0
  567. package/src/pr-forge.test.ts +237 -0
  568. package/src/pr-forge.ts +332 -0
  569. package/src/pr-loop-bundle.test.ts +46 -0
  570. package/src/pr-loop.test.ts +171 -0
  571. package/src/pr-loop.ts +324 -0
  572. package/src/provenance.ts +35 -0
  573. package/src/telemetry-attribution.test.ts +23 -1
  574. package/src/telemetry-attribution.ts +51 -0
  575. package/src/terraform/hcl2json.test.ts +21 -0
  576. package/src/terraform/hcl2json.ts +81 -0
  577. package/src/terraform/parse.ts +11 -74
  578. package/src/workspace/agent-cli.ts +7 -3
  579. package/src/workspace/agent.schema.json +22 -0
  580. package/src/workspace/app-kind.test.ts +196 -0
  581. package/src/workspace/box-cli.ts +113 -0
  582. package/src/workspace/box-factory.test.ts +323 -0
  583. package/src/workspace/box-factory.ts +136 -0
  584. package/src/workspace/box-listing-write.schema.json +204 -0
  585. package/src/workspace/box-listing.test.ts +234 -0
  586. package/src/workspace/box-listing.ts +324 -0
  587. package/src/workspace/box-publish.schema.json +498 -0
  588. package/src/workspace/box-publish.test.ts +204 -0
  589. package/src/workspace/box-publish.ts +420 -0
  590. package/src/workspace/box-ship.test.ts +96 -0
  591. package/src/workspace/broker-protocol.schema.json +186 -0
  592. package/src/workspace/broker-protocol.test.ts +122 -0
  593. package/src/workspace/broker-protocol.ts +317 -0
  594. package/src/workspace/builder-tiers.test.ts +146 -0
  595. package/src/workspace/change-set.schema.json +460 -0
  596. package/src/workspace/changes.schema.json +12 -20
  597. package/src/workspace/changes.ts +4 -1
  598. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  599. package/src/workspace/checks/boxes.test.ts +5 -0
  600. package/src/workspace/checks.ts +39 -8
  601. package/src/workspace/component-environments.test.ts +105 -0
  602. package/src/workspace/compose-graph.ts +7 -0
  603. package/src/workspace/composites.schema.json +23 -4
  604. package/src/workspace/composites.test.ts +8 -8
  605. package/src/workspace/composites.ts +13 -2
  606. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  607. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  608. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
  609. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
  610. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  611. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  612. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
  613. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  614. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  615. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
  616. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
  617. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  618. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  619. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
  620. package/src/workspace/conformance/broker.test.ts +122 -0
  621. package/src/workspace/conformance/broker.ts +792 -0
  622. package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
  623. package/src/workspace/conformance/index.mjs +51 -3
  624. package/src/workspace/conformance/index.ts +107 -15
  625. package/src/workspace/conformance/vitest.ts +76 -2
  626. package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
  627. package/src/workspace/conformance/writer.test.ts +186 -0
  628. package/src/workspace/conformance/writer.ts +1191 -0
  629. package/src/workspace/decide.test.ts +208 -4
  630. package/src/workspace/decide.ts +433 -73
  631. package/src/workspace/decision-points.schema.json +11 -4
  632. package/src/workspace/declaration.schema.json +383 -5
  633. package/src/workspace/declaration.ts +315 -10
  634. package/src/workspace/environments.ts +66 -14
  635. package/src/workspace/factory-rules.test.ts +62 -0
  636. package/src/workspace/factory-rules.ts +218 -0
  637. package/src/workspace/graph-cli.ts +6 -3
  638. package/src/workspace/graph.schema.json +314 -0
  639. package/src/workspace/identity.test.ts +219 -0
  640. package/src/workspace/identity.ts +186 -0
  641. package/src/workspace/init.ts +82 -2
  642. package/src/workspace/intent-cli.ts +84 -13
  643. package/src/workspace/intent-patch-id.test.ts +162 -0
  644. package/src/workspace/intent-record.schema.json +336 -1
  645. package/src/workspace/intent-record.ts +96 -16
  646. package/src/workspace/intent-reviews.test.ts +76 -0
  647. package/src/workspace/intent-squash.test.ts +213 -0
  648. package/src/workspace/intent-why.test.ts +274 -0
  649. package/src/workspace/intent.schema.json +950 -9
  650. package/src/workspace/intent.test.ts +11 -2
  651. package/src/workspace/intent.ts +722 -65
  652. package/src/workspace/json-edit.test.ts +121 -0
  653. package/src/workspace/json-edit.ts +142 -0
  654. package/src/workspace/jsonc.ts +20 -0
  655. package/src/workspace/kinds.ts +201 -39
  656. package/src/workspace/lexicon-symbols.test.ts +148 -0
  657. package/src/workspace/lexicon-symbols.ts +125 -0
  658. package/src/workspace/lineage-upgrade.test.ts +63 -0
  659. package/src/workspace/lineage-upgrade.ts +146 -5
  660. package/src/workspace/plan-summary.schema.json +155 -0
  661. package/src/workspace/point-answer.schema.json +42 -2
  662. package/src/workspace/points-cli.ts +42 -16
  663. package/src/workspace/points-write.schema.json +163 -4
  664. package/src/workspace/points.schema.json +157 -2
  665. package/src/workspace/points.test.ts +13 -1
  666. package/src/workspace/points.ts +118 -12
  667. package/src/workspace/pr-report.schema.json +95 -0
  668. package/src/workspace/principal-classes.test.ts +175 -0
  669. package/src/workspace/principal-classes.ts +307 -0
  670. package/src/workspace/profiles.test.ts +159 -0
  671. package/src/workspace/read-contract.test.ts +2 -2
  672. package/src/workspace/reason-codes.test.ts +23 -3
  673. package/src/workspace/reason-codes.ts +61 -4
  674. package/src/workspace/record-sessions.ts +9 -8
  675. package/src/workspace/records-amend.schema.json +80 -0
  676. package/src/workspace/records-checkout.ts +106 -0
  677. package/src/workspace/records-cli.ts +123 -17
  678. package/src/workspace/records-close.schema.json +79 -0
  679. package/src/workspace/records-close.ts +31 -7
  680. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  681. package/src/workspace/records-concurrent.test.ts +145 -0
  682. package/src/workspace/records-formats.test.ts +46 -10
  683. package/src/workspace/records-new.schema.json +9 -0
  684. package/src/workspace/records-review.schema.json +80 -0
  685. package/src/workspace/records-sessions-write.test.ts +69 -0
  686. package/src/workspace/records-sessions.test.ts +22 -0
  687. package/src/workspace/records-uncommitted.test.ts +171 -0
  688. package/src/workspace/records-write.ts +219 -30
  689. package/src/workspace/records.schema.json +88 -1
  690. package/src/workspace/records.ts +76 -8
  691. package/src/workspace/reference-kinds/app/package.json +10 -0
  692. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  693. package/src/workspace/run-statement.schema.json +622 -0
  694. package/src/workspace/runs-cli.ts +710 -0
  695. package/src/workspace/runs-statement.test.ts +239 -0
  696. package/src/workspace/runs-write.schema.json +994 -0
  697. package/src/workspace/runs.schema.json +1257 -0
  698. package/src/workspace/runs.test.ts +281 -0
  699. package/src/workspace/runs.ts +970 -0
  700. package/src/workspace/session-kinds.ts +3 -3
  701. package/src/workspace/squash.ts +198 -0
  702. package/src/workspace/status-contract.test.ts +10 -2
  703. package/src/workspace/status-gates.ts +25 -9
  704. package/src/workspace/status.schema.json +252 -4
  705. package/src/workspace/status.ts +110 -1
  706. package/src/workspace/symbols.ts +191 -0
  707. package/src/workspace/trailer-joins.test.ts +171 -0
  708. package/src/workspace/trailer-joins.ts +82 -0
  709. package/src/workspace/trailers.ts +148 -0
  710. package/src/workspace/trust/run-commits.ts +115 -0
  711. package/src/workspace/trust/run-statement.ts +226 -0
  712. package/src/workspace/trust/seal.ts +58 -1
  713. package/src/workspace/trust/verify-cli.ts +6 -5
  714. package/src/workspace/trust/verify.ts +39 -6
  715. package/src/workspace/wip-cli.ts +97 -0
  716. package/src/workspace/wip-write.schema.json +504 -0
  717. package/src/workspace/wip.schema.json +334 -0
  718. package/src/workspace/wip.test.ts +294 -0
  719. package/src/workspace/wip.ts +753 -0
  720. package/src/workspace/work-cli.e2e.test.ts +28 -1
  721. package/src/workspace/work-cli.ts +136 -8
  722. package/src/workspace/work-evidence.schema.json +5 -0
  723. package/src/workspace/work-history.schema.json +73 -1
  724. package/src/workspace/work-history.test.ts +48 -5
  725. package/src/workspace/work-kind-fields.test.ts +154 -0
  726. package/src/workspace/work-lease.schema.json +14 -1
  727. package/src/workspace/work-size.test.ts +77 -0
  728. package/src/workspace/work-size.ts +93 -0
  729. package/src/workspace/work.ts +82 -0
  730. package/src/workspace/workspace-kinds.schema.json +122 -0
  731. package/src/workspace/workspace-principals.schema.json +60 -0
  732. package/src/workspace/write-lock-cli.ts +131 -0
  733. package/src/workspace/write-lock.schema.json +172 -0
  734. package/src/workspace/write-lock.test.ts +189 -0
  735. package/src/workspace/write-lock.ts +474 -0
  736. package/src/workspace/write-scope.test.ts +144 -3
  737. package/src/workspace/write-scope.ts +192 -45
  738. package/src/yaml.test.ts +111 -1
  739. package/src/yaml.ts +141 -549
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
12
12
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
13
+ import { readFileSync } from "node:fs";
13
14
  import { join } from "node:path";
14
15
  import { tmpdir } from "node:os";
15
16
  import type { Component } from "../../components/component";
@@ -75,6 +76,12 @@ const ESTATE = [
75
76
 
76
77
  let ran: string[] = [];
77
78
  let failing: string[] = [];
79
+ /** What each component's step was handed, after wiring resolved. */
80
+ let inputs: Record<string, Record<string, unknown>> = {};
81
+ /** Stack outputs a component's step returns, as cfn-deploy's `outputs` does. */
82
+ let stepOutputs: Record<string, Record<string, unknown>> = {};
83
+ /** Called as a component's step starts, before it applies. */
84
+ let onStart: (component: string) => void = () => {};
78
85
 
79
86
  function makeArgs(overrides: Partial<ParsedArgs>): ParsedArgs {
80
87
  return {
@@ -101,6 +108,9 @@ beforeEach(() => {
101
108
  vi.clearAllMocks();
102
109
  ran = [];
103
110
  failing = [];
111
+ inputs = {};
112
+ stepOutputs = {};
113
+ onStart = () => {};
104
114
  gateLedger = memoryGateLedgerPort();
105
115
  stderrLines = [];
106
116
  stdoutLines = [];
@@ -129,10 +139,12 @@ beforeEach(() => {
129
139
  const registry = new CapabilityRegistry();
130
140
  registry.register({
131
141
  kind: "cfn-deploy",
132
- async run(runCtx: { component: string }) {
142
+ async run(runCtx: { component: string }, input: Record<string, unknown>) {
143
+ onStart(runCtx.component);
133
144
  ran.push(runCtx.component);
145
+ inputs[runCtx.component] = input;
134
146
  if (failing.includes(runCtx.component)) throw new Error(`${runCtx.component} failed`);
135
- return { ok: true };
147
+ return { ok: true, ...(stepOutputs[runCtx.component] ? { outputs: stepOutputs[runCtx.component] } : {}) };
136
148
  },
137
149
  } as never);
138
150
  return Promise.resolve(registry);
@@ -326,6 +338,76 @@ describe("proof: the re-run prints already-applied for what it skips, and finish
326
338
  });
327
339
  });
328
340
 
341
+ describe("proof: killed mid-fan-out, a re-run finishes without hand repair", () => {
342
+ test("the record keeps what applied before the kill, and the repeated command runs only the rest", async () => {
343
+ const dir = await mkdtemp(join(tmpdir(), "fan-out-"));
344
+ try {
345
+ const resume = join(dir, "attempt.json");
346
+ // The process dies as app-one starts. Whatever the record says at that
347
+ // instant is all a killed process leaves behind, so that is what the
348
+ // second run is handed.
349
+ let atKill: string | undefined;
350
+ onStart = (name) => {
351
+ if (name === "app-one") atKill = readFileSync(resume, "utf8");
352
+ };
353
+ await runComponentsFanOut(ctx({ base: "main", env: "test", resume }));
354
+ expect(atKill).toBeDefined();
355
+ expect(JSON.parse(atKill!).completed).toEqual(["cluster-a", "cluster-b", "net"]);
356
+
357
+ await writeFile(resume, atKill!);
358
+ ran = [];
359
+ onStart = () => {};
360
+ stderrLines = [];
361
+ expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
362
+ expect([...ran].sort()).toEqual(["app-one", "app-three", "app-two"]);
363
+ expect(stderr()).toMatch(/net +already-applied/);
364
+ expect(stderr()).toContain("fan-out completed: 3 applied, 0 failed, 0 blocked");
365
+ } finally {
366
+ await rm(dir, { recursive: true, force: true });
367
+ }
368
+ });
369
+
370
+ test("a component left to run reads a completed dependency's outputs from the record", async () => {
371
+ const wired: Component = {
372
+ name: "cluster-a",
373
+ dependsOn: ["net"],
374
+ deploy: [
375
+ {
376
+ phase: "Apply",
377
+ steps: [{ kind: "cfn-deploy", stack: "cluster-a-stack", inputs: { topic: { stackOutput: { stack: "net", name: "TopicArn" } } } }],
378
+ },
379
+ ],
380
+ };
381
+ const estate = ESTATE.map((c) => (c.name === "cluster-a" ? wired : c));
382
+ discoverComponentsMock.mockResolvedValue({
383
+ components: new Map(estate.map((c) => [c.name, { component: c, exportName: c.name, filePath: `${c.name}.component.ts` }])),
384
+ sourceFiles: [],
385
+ errors: [],
386
+ });
387
+ stepOutputs = { net: { TopicArn: "arn:aws:sns:us-east-1:000000000000:net" } };
388
+
389
+ const dir = await mkdtemp(join(tmpdir(), "fan-out-"));
390
+ try {
391
+ const resume = join(dir, "attempt.json");
392
+ failing = ["cluster-a"];
393
+ expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(1);
394
+ expect(JSON.parse(await readFile(resume, "utf8")).outputs.net).toEqual(stepOutputs.net);
395
+
396
+ // net does not run again, and nobody passes --seed-outputs.
397
+ ran = [];
398
+ failing = [];
399
+ inputs = {};
400
+ expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
401
+ expect(ran).not.toContain("net");
402
+ expect(inputs["cluster-a"]).toEqual(
403
+ expect.objectContaining({ inputs: { topic: "arn:aws:sns:us-east-1:000000000000:net" } }),
404
+ );
405
+ } finally {
406
+ await rm(dir, { recursive: true, force: true });
407
+ }
408
+ });
409
+ });
410
+
329
411
  describe("proof: one approval covers the set, and the printed digest is what approves it", () => {
330
412
  test("an unapproved gate stops the whole fan-out before anything runs", async () => {
331
413
  const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release" }));
@@ -392,3 +474,140 @@ describe("proof: one approval covers the set, and the printed digest is what app
392
474
  expect(ran).toEqual([]);
393
475
  });
394
476
  });
477
+
478
+ describe("gated waves (#3049): one gate per wave, bound to the wave's set digest", () => {
479
+ /** What each root's plan would write. Change one to change a root. */
480
+ let versions: Record<string, string> = {};
481
+
482
+ beforeEach(() => {
483
+ versions = {};
484
+ buildCapabilityRegistryMock.mockImplementation(() => {
485
+ const registry = new CapabilityRegistry();
486
+ registry.register({
487
+ kind: "cfn-deploy",
488
+ async plan(_ctx: unknown, input: { stack: string }) {
489
+ const v = versions[input.stack] ?? "v1";
490
+ return { member: input.stack, planDigest: "jcs1-sha256:" + (v === "v1" ? "1" : "2").repeat(64) };
491
+ },
492
+ async run(runCtx: { component: string }) {
493
+ ran.push(runCtx.component);
494
+ return { ok: true };
495
+ },
496
+ } as never);
497
+ return Promise.resolve(registry);
498
+ });
499
+ });
500
+
501
+ test("wave 1 stops at its own gate, and the record names its digest", async () => {
502
+ const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
503
+ try {
504
+ const record = join(dir, "fan-out.json");
505
+ const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
506
+ expect(exit).toBe(3);
507
+ expect(ran).toEqual([]);
508
+ const pending = gateLedger.appended[0];
509
+ expect(pending.gate).toBe("release-wave-1");
510
+ expect(stderr()).toContain(`approve : chant approve fan-out release-wave-1 --plan ${pending.planDigest}`);
511
+ const saved = JSON.parse(readFileSync(record, "utf8"));
512
+ expect(saved.waves).toMatchObject([{ wave: 1, gate: "release-wave-1", status: "gated", digest: pending.planDigest }]);
513
+ } finally {
514
+ await rm(dir, { recursive: true, force: true });
515
+ }
516
+ });
517
+
518
+ test("approve wave 1, change a root, re-run: it stops naming both digests and applies nothing", async () => {
519
+ const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
520
+ try {
521
+ const record = join(dir, "fan-out.json");
522
+ const run = () => runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
523
+ await run();
524
+ const approved = gateLedger.appended[0].planDigest!;
525
+ gateLedger = memoryGateLedgerPort({
526
+ pending: [gateLedger.appended[0]],
527
+ resolutions: [
528
+ {
529
+ version: 1,
530
+ kind: "resolution",
531
+ op: "fan-out",
532
+ gate: "release-wave-1",
533
+ resolvedBy: "operator",
534
+ timestamp: new Date(Date.parse(gateLedger.appended[0].timestamp) + 1000).toISOString(),
535
+ planDigest: approved,
536
+ },
537
+ ],
538
+ });
539
+
540
+ versions["net-stack"] = "v2";
541
+ stderrLines = [];
542
+ expect(await run()).toBe(3);
543
+ expect(ran).toEqual([]);
544
+ const planned = gateLedger.appended[0].planDigest!;
545
+ expect(planned).not.toBe(approved);
546
+ expect(stderr()).toContain(`approved: ${approved}; planned now: ${planned}`);
547
+ expect(stderr()).toContain("nothing in it was applied");
548
+ const saved = JSON.parse(readFileSync(record, "utf8"));
549
+ expect(saved.waves[0]).toMatchObject({ status: "gated", approved, digest: planned });
550
+ } finally {
551
+ await rm(dir, { recursive: true, force: true });
552
+ }
553
+ });
554
+
555
+ test("an approved wave applies, the run stops at the next wave, and the record carries both", async () => {
556
+ const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
557
+ try {
558
+ const record = join(dir, "fan-out.json");
559
+ const run = () => runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
560
+ await run();
561
+ const first = gateLedger.appended[0];
562
+ gateLedger = memoryGateLedgerPort({
563
+ pending: [first],
564
+ resolutions: [
565
+ {
566
+ version: 1,
567
+ kind: "resolution",
568
+ op: "fan-out",
569
+ gate: "release-wave-1",
570
+ resolvedBy: "operator",
571
+ timestamp: new Date(Date.parse(first.timestamp) + 1000).toISOString(),
572
+ planDigest: first.planDigest,
573
+ },
574
+ ],
575
+ });
576
+ expect(await run()).toBe(3);
577
+ expect(ran).toEqual(["net"]);
578
+ const saved = JSON.parse(readFileSync(record, "utf8"));
579
+ expect(saved.completed).toEqual(["net"]);
580
+ expect(saved.waves.map((w: { wave: number; status: string }) => [w.wave, w.status])).toEqual([
581
+ [1, "applied"],
582
+ [2, "gated"],
583
+ ]);
584
+
585
+ // The same command again: wave 1 is not applied a second time.
586
+ ran = [];
587
+ expect(await run()).toBe(3);
588
+ expect(ran).toEqual([]);
589
+ } finally {
590
+ await rm(dir, { recursive: true, force: true });
591
+ }
592
+ });
593
+
594
+ test("--canary puts a component in wave 1, and the dry run names each wave's gate", async () => {
595
+ const exit = await runComponentsFanOut(ctx({ base: "main", dryRun: true, waveGate: "release", canary: ["cluster-b"] }));
596
+ expect(exit).toBe(0);
597
+ expect(stderr()).toContain("wave 1: cluster-b (gate release-wave-1)");
598
+ expect(stderr()).toContain("wave 2: app-three, net (gate release-wave-2)");
599
+ });
600
+
601
+ test("--wave 2 refuses while wave 1 has not applied", async () => {
602
+ const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", wave: 2 }));
603
+ expect(exit).toBe(1);
604
+ expect(stderr()).toContain("wave 2 cannot run yet: wave 1 has not applied (net)");
605
+ });
606
+
607
+ test("--gate and --wave-gate together are refused, and --wave needs --wave-gate", async () => {
608
+ expect(await runComponentsFanOut(ctx({ base: "main", gate: "release", waveGate: "release" }))).toBe(1);
609
+ expect(stderr()).toContain("--gate and --wave-gate both name a gate");
610
+ expect(await runComponentsFanOut(ctx({ base: "main", wave: 1 }))).toBe(1);
611
+ expect(stderr()).toContain("--wave runs one wave");
612
+ });
613
+ });
@@ -33,19 +33,28 @@
33
33
  * `--resume` carries the earlier attempt's progress, `remainingFanOut` narrows
34
34
  * the plan before the gate is decided, and the digest is carried rather than
35
35
  * recomputed, so the approval still stands.
36
+ *
37
+ * `--wave-gate <name>` (#3049) swaps the one gate for one per wave: the same
38
+ * repeated command stops at each wave's gate in turn, each planned after the
39
+ * wave before it applied, and `chant approve fan-out <name>-wave-<n>` answers
40
+ * it. `--wave <n>` runs one wave, for a CI job per wave.
36
41
  */
37
42
 
38
43
  import { resolve, dirname } from "node:path";
39
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
44
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
40
45
  import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
41
46
  import { samePlanDigest } from "../../lifecycle/plan-digest";
42
47
  import { affectedStacks } from "../../lifecycle/affected";
48
+ import { changedFilesBetween, lexiconChangedUnits } from "../../components/changed-files";
43
49
  import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
44
- import { runFanOut } from "../../components/fan-out-run";
50
+ import { EarlierWaveNotAppliedError, runFanOut } from "../../components/fan-out-run";
51
+ import { readFanOutAttempt, writeFanOutAttempt, type FanOutAttempt } from "../../components/fan-out-record";
52
+ import { describeChangedWave, withWaveRecord, type WaveRecord } from "../../gated-waves";
45
53
  import { renderFanOutHuman, renderFanOutJson, renderFanOutPlan } from "../../components/fan-out-output";
46
54
  import { ndjsonProgressSink } from "../../components/run-progress";
47
55
  import { summaryLedgerPrefix, writeGatedRunSummary } from "../../op/gate-summary";
48
56
  import { approveCommand } from "../../op/gate";
57
+ import { getHeadCommit } from "../../lifecycle/git";
49
58
  import { remainingFanOut, type ChangedUnits, type FanOutProgress } from "../../components/fan-out";
50
59
  import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
51
60
  import { formatError, formatInfo, formatWarning } from "../format";
@@ -54,37 +63,6 @@ import { resolveBuildRoot } from "./lifecycle";
54
63
  import { GATED_EXIT_CODE, recordAutoReleasesForRun } from "./run";
55
64
  import type { CommandContext } from "../registry";
56
65
 
57
-
58
-
59
- /**
60
- * What an attempt left behind, and what the next one reads (`--resume`).
61
- *
62
- * The digest is stored alongside the progress because progress is only
63
- * meaningful for the plan it was made against. A fan-out derived from different
64
- * source is a different fan-out, and carrying "cluster-a already applied" into
65
- * it would be a claim about work nobody did.
66
- */
67
- interface FanOutAttempt {
68
- digest: string;
69
- completed: string[];
70
- failed: string[];
71
- }
72
-
73
- function readAttempt(path: string): FanOutAttempt | undefined {
74
- if (!existsSync(path)) return undefined;
75
- const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial<FanOutAttempt>;
76
- return {
77
- digest: typeof parsed.digest === "string" ? parsed.digest : "",
78
- completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n): n is string => typeof n === "string") : [],
79
- failed: Array.isArray(parsed.failed) ? parsed.failed.filter((n): n is string => typeof n === "string") : [],
80
- };
81
- }
82
-
83
- function writeAttempt(path: string, attempt: FanOutAttempt): void {
84
- mkdirSync(dirname(path), { recursive: true });
85
- writeFileSync(path, JSON.stringify(attempt, null, 2) + "\n");
86
- }
87
-
88
66
  /**
89
67
  * The stack-level change signal, from whichever end the invocation supplied.
90
68
  *
@@ -100,13 +78,20 @@ function writeAttempt(path: string, attempt: FanOutAttempt): void {
100
78
  * consumes a changed export is affected at stack granularity in the same way a
101
79
  * changed component is at component granularity.
102
80
  */
103
- async function resolveChangedUnits(
81
+ export async function resolveChangedUnits(
104
82
  ctx: CommandContext,
105
83
  config: ChantConfig,
84
+ opts: {
85
+ /** Measure from this commit instead of `--base` (a pull request's merge base, #3183). */
86
+ base?: string;
87
+ /** Build both refs for `lifecycle affected` only when the project declares `stacks`. */
88
+ stacksOnly?: boolean;
89
+ } = {},
106
90
  ): Promise<{ units: ChangedUnits } | { error: string; hint?: string }> {
107
91
  const { args } = ctx;
92
+ const base = opts.base ?? args.base;
108
93
  const fromFile = args.fromAffected;
109
- if (args.base && fromFile) {
94
+ if (base && fromFile) {
110
95
  return {
111
96
  error: "--base and --from-affected both name a change signal",
112
97
  hint: "Pass --base <ref> to derive it here, or --from-affected <file> to read one `chant lifecycle affected --json` already wrote.",
@@ -136,7 +121,7 @@ async function resolveChangedUnits(
136
121
  };
137
122
  }
138
123
 
139
- if (!args.base) {
124
+ if (!base) {
140
125
  return {
141
126
  error: "A change signal is required: chant components fan-out --base <ref> [--head <ref>]",
142
127
  hint: "Or pass --from-affected <file> with the JSON `chant lifecycle affected --base <ref> --json` wrote.",
@@ -144,23 +129,37 @@ async function resolveChangedUnits(
144
129
  }
145
130
 
146
131
  try {
147
- const result = await affectedStacks({
148
- // Components are discovered from the current directory, the convention
149
- // every component command follows. In a multi-stack project the diff
150
- // reads the same root, because `stacks[].src` is written relative to it.
151
- projectPath: config.stacks?.length ? resolve(".") : resolveBuildRoot(args, config),
152
- serializers: ctx.plugins.map((p) => p.serializer),
153
- baseRef: args.base,
154
- headRef: args.head,
155
- includeDependents: args.includeDependents,
156
- // A project that declares its stacks gets an answer keyed by stack name,
157
- // which is the name a component's deploy step uses. Without this the diff
158
- // answers by lexicon partition and the join below claims none of it.
159
- ...(config.stacks ? { stacks: config.stacks } : {}),
160
- });
132
+ // A unit that is not chant source, such as a Terraform root, never shows
133
+ // in the artifact diff below; the lexicon that owns it answers from the
134
+ // changed paths (#3183).
135
+ const projectRoot = resolve(".");
136
+ const lexiconUnits = ctx.plugins.some((p) => p.changedUnits)
137
+ ? await lexiconChangedUnits(ctx.plugins, {
138
+ projectRoot,
139
+ config: config as Record<string, unknown>,
140
+ changedFiles: await changedFilesBetween(projectRoot, base, args.head ?? "HEAD"),
141
+ })
142
+ : [];
143
+ const result =
144
+ opts.stacksOnly && !config.stacks?.length
145
+ ? { changed: [], dependents: [], indeterminate: [] }
146
+ : await affectedStacks({
147
+ // Components are discovered from the current directory, the convention
148
+ // every component command follows. In a multi-stack project the diff
149
+ // reads the same root, because `stacks[].src` is written relative to it.
150
+ projectPath: config.stacks?.length ? resolve(".") : resolveBuildRoot(args, config),
151
+ serializers: ctx.plugins.map((p) => p.serializer),
152
+ baseRef: base,
153
+ headRef: args.head,
154
+ includeDependents: args.includeDependents,
155
+ // A project that declares its stacks gets an answer keyed by stack name,
156
+ // which is the name a component's deploy step uses. Without this the diff
157
+ // answers by lexicon partition and the join below claims none of it.
158
+ ...(config.stacks ? { stacks: config.stacks } : {}),
159
+ });
161
160
  return {
162
161
  units: {
163
- changed: [...new Set([...result.changed, ...result.dependents])].sort(),
162
+ changed: [...new Set([...result.changed, ...result.dependents, ...lexiconUnits])].sort(),
164
163
  indeterminate: result.indeterminate,
165
164
  },
166
165
  };
@@ -190,6 +189,21 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
190
189
  return 1;
191
190
  }
192
191
 
192
+ // The two gate modes (#3049). `--gate` approves the whole set once, as
193
+ // #2417 decided; `--wave-gate` approves each wave once the waves before it
194
+ // applied. They answer different questions, so one run takes one of them.
195
+ if (args.gate && args.waveGate) {
196
+ console.error(formatError({
197
+ message: "--gate and --wave-gate both name a gate",
198
+ hint: "Pass --gate <name> for one approval over the whole set, or --wave-gate <name> for one per wave.",
199
+ }));
200
+ return 1;
201
+ }
202
+ if (args.wave !== undefined && !args.waveGate) {
203
+ console.error(formatError({ message: "--wave runs one wave of a gated-wave fan-out, so it needs --wave-gate <name>" }));
204
+ return 1;
205
+ }
206
+
193
207
  const signal = await resolveChangedUnits(ctx, config);
194
208
  if ("error" in signal) {
195
209
  console.error(formatError({ message: signal.error, ...(signal.hint ? { hint: signal.hint } : {}) }));
@@ -204,6 +218,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
204
218
  sandbox: args.sandbox,
205
219
  buildParams: paramsResolution.provenance,
206
220
  config,
221
+ ...(args.canary?.length ? { canary: args.canary } : {}),
207
222
  });
208
223
  } catch (err) {
209
224
  // A cycle or an unknown `dependsOn` refuses here, over the whole graph and
@@ -226,6 +241,9 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
226
241
  }
227
242
 
228
243
  const gate = args.gate ? { op: FAN_OUT_GATE_OP, gate: args.gate } : undefined;
244
+ const waveGate = args.waveGate
245
+ ? { op: FAN_OUT_GATE_OP, gate: args.waveGate, ...(args.wave !== undefined ? { only: args.wave } : {}) }
246
+ : undefined;
229
247
 
230
248
  // `--resume`: what an earlier attempt at this same plan finished. Read before
231
249
  // the dry-run branch so a plan-only invocation shows what is actually left
@@ -234,11 +252,13 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
234
252
  // approval survives the resume rather than being re-asked for.
235
253
  const resumePath = args.resume ? resolve(args.resume) : undefined;
236
254
  let priorCompleted: string[] = [];
255
+ let priorOutputs: Record<string, Record<string, unknown>> = {};
256
+ let priorWaves: WaveRecord[] = [];
237
257
  let progress: FanOutProgress | undefined;
238
258
  if (resumePath) {
239
259
  let attempt: FanOutAttempt | undefined;
240
260
  try {
241
- attempt = readAttempt(resumePath);
261
+ attempt = readFanOutAttempt(resumePath);
242
262
  } catch (err) {
243
263
  console.error(formatError({ message: `--resume: could not read "${args.resume}": ${err instanceof Error ? err.message : String(err)}` }));
244
264
  return 1;
@@ -255,16 +275,22 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
255
275
  // exists to retry them — the operator repeated the command precisely
256
276
  // because the thing that failed is now expected to work.
257
277
  priorCompleted = attempt.completed;
278
+ priorOutputs = Object.fromEntries(
279
+ Object.entries(attempt.outputs).filter(([name]) => attempt.completed.includes(name)),
280
+ );
258
281
  progress = { completed: attempt.completed };
282
+ priorWaves = attempt.waves ?? [];
259
283
  }
260
284
  }
261
285
 
262
286
  if (args.dryRun) {
263
287
  // `remainingFanOut` carries the digest rather than minting a new one, so
264
288
  // the digest printed here is the same string that approves the real run.
265
- const plan = progress ? remainingFanOut(derived.plan, derived.components, progress) : derived.plan;
289
+ // A gated-wave fan-out keeps the derivation's wave numbers, since they
290
+ // name the gates, so its plan is printed whole.
291
+ const plan = progress && !waveGate ? remainingFanOut(derived.plan, derived.components, progress) : derived.plan;
266
292
  if (args.json) renderFanOutJson(plan);
267
- else renderFanOutPlan(plan, { ...(gate ? { gate } : {}) });
293
+ else renderFanOutPlan(plan, { ...(gate ? { gate } : {}), ...(waveGate ? { waveGate } : {}) });
268
294
  return 0;
269
295
  }
270
296
 
@@ -279,13 +305,72 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
279
305
  }
280
306
 
281
307
  const registry = await fanOutRegistry(projectPath, config);
282
- const result = await runFanOut(derived.plan, derived.components, registry, {
283
- env: args.env ?? "local",
284
- componentOutputs: seededOutputs,
285
- ...(gate ? { gate } : {}),
286
- ...(progress ? { progress } : {}),
287
- ...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
288
- });
308
+ // #3061: the commit this run deploys, for the workloads' vcs.ref.head.revision.
309
+ const revision = await getHeadCommit().catch(() => undefined);
310
+
311
+ // The record is rewritten as each component settles, not only once the run
312
+ // returns. A fan-out killed in its third wave (a cancelled CI job, a lost
313
+ // runner, ctrl-c) then still knows that the first two applied, and the
314
+ // repeated command picks up from there instead of redoing them.
315
+ const completedSoFar = new Set(priorCompleted);
316
+ const failedSoFar: string[] = [];
317
+ const outputsSoFar = { ...priorOutputs };
318
+ let wavesSoFar = priorWaves;
319
+ const recordAttempt = (): void => {
320
+ if (!resumePath) return;
321
+ const attempt: FanOutAttempt = {
322
+ digest: derived.plan.digest,
323
+ completed: [...completedSoFar].sort(),
324
+ failed: [...failedSoFar].sort(),
325
+ outputs: outputsSoFar,
326
+ ...(wavesSoFar.length > 0 ? { waves: wavesSoFar } : {}),
327
+ };
328
+ writeFanOutAttempt(resumePath, attempt);
329
+ };
330
+
331
+ let result;
332
+ try {
333
+ result = await runFanOut(derived.plan, derived.components, registry, {
334
+ env: args.env ?? "local",
335
+ releaseIdentity: () => (revision ? { revision } : {}),
336
+ // A completed component's recorded outputs win over a `--seed-outputs`
337
+ // entry for the same name, as a fresh apply's outputs merge over a seed in
338
+ // the driver: the record holds what this fan-out itself applied.
339
+ componentOutputs: { ...seededOutputs, ...priorOutputs },
340
+ ...(gate ? { gate } : {}),
341
+ ...(waveGate ? { waveGate } : {}),
342
+ ...(waveGate
343
+ ? {
344
+ onWaveSettled: (record: WaveRecord) => {
345
+ wavesSoFar = withWaveRecord(wavesSoFar, record);
346
+ recordAttempt();
347
+ },
348
+ }
349
+ : {}),
350
+ ...(progress ? { progress } : {}),
351
+ ...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
352
+ ...(resumePath
353
+ ? {
354
+ onComponentSettled: (settled, outputs) => {
355
+ if (settled.status === "ok") {
356
+ completedSoFar.add(settled.component);
357
+ if (outputs) outputsSoFar[settled.component] = outputs;
358
+ } else if (settled.status === "fail") {
359
+ failedSoFar.push(settled.component);
360
+ }
361
+ recordAttempt();
362
+ },
363
+ }
364
+ : {}),
365
+ });
366
+ } catch (err) {
367
+ // `--wave <n>` reached before an earlier wave applied: nothing ran.
368
+ if (err instanceof EarlierWaveNotAppliedError) {
369
+ console.error(formatError({ message: err.message }));
370
+ return 1;
371
+ }
372
+ throw err;
373
+ }
289
374
 
290
375
  if (args.dumpOutputs) {
291
376
  const dumpPath = resolve(args.dumpOutputs);
@@ -293,25 +378,28 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
293
378
  writeFileSync(dumpPath, JSON.stringify(result.componentOutputs, null, 2));
294
379
  }
295
380
 
296
- // Written even on a failure and even on a gate: the next attempt needs to
297
- // know what this one got through, and a gated attempt got through nothing,
298
- // which is itself worth recording against this plan's digest.
299
- if (resumePath) {
300
- writeAttempt(resumePath, {
301
- digest: result.plan.digest,
302
- completed: [...new Set([...priorCompleted, ...result.completed])].sort(),
303
- failed: result.failed,
304
- });
305
- }
381
+ // Written again at the end, even on a failure and even on a gate: a gated
382
+ // attempt got through nothing, which is itself worth recording against this
383
+ // plan's digest.
384
+ recordAttempt();
306
385
 
307
386
  if (args.json) renderFanOutJson(result);
308
- else renderFanOutHuman(result, { ...(gate ? { gate } : {}) });
387
+ else renderFanOutHuman(result, { ...(gate ? { gate } : {}), ...(waveGate ? { waveGate } : {}) });
388
+
389
+ // A wave whose set moved after its approval stops with both digests named
390
+ // (#3049), the #2300 refusal on a set. Printed on stderr even under --json,
391
+ // since it is the line a CI log reader is looking for.
392
+ for (const wave of result.waves ?? []) {
393
+ if (wave.status === "gated" && wave.approved) console.error(formatWarning({ message: describeChangedWave(wave) }));
394
+ }
309
395
 
310
396
  // The same durable trace `chant run --components` leaves (#597), for the
311
397
  // components this fan-out actually applied. A partial fan-out records the
312
398
  // branches that finished and nothing else, which is the whole reason the
313
399
  // runner reports `completed` separately from `failed`.
314
- if (result.status !== "gated") {
400
+ // A gated-wave run can stop at a later wave's gate after earlier waves
401
+ // applied, and those applies are recorded like any other.
402
+ if (result.status !== "gated" || result.completed.length > 0) {
315
403
  await recordAutoReleasesForRun(
316
404
  result.results,
317
405
  args.env ?? "local",
@@ -320,7 +408,9 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
320
408
  );
321
409
  }
322
410
 
323
- if (result.status === "gated" && result.gate) {
411
+ // A failed root outranks a gate in the status, but a gated-wave run that
412
+ // stopped at a wave's gate still prints how to approve it.
413
+ if (result.gate && (result.status === "gated" || waveGate)) {
324
414
  const pending = result.gate;
325
415
  // The pending fact's own plan: the fan-out's digest for the gate over the
326
416
  // set, or a component's plan and environment for a gate inside one (#2574).
@@ -337,7 +427,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
337
427
  ...(await summaryLedgerPrefix()),
338
428
  ...(pending.environment ? { environment: pending.environment } : {}),
339
429
  });
340
- return GATED_EXIT_CODE;
430
+ return result.status === "gated" ? GATED_EXIT_CODE : 1;
341
431
  }
342
432
 
343
433
  return result.status === "ok" ? 0 : 1;
@@ -637,6 +637,9 @@ async function runComponentGraphView(
637
637
  // `chant workspace graph --composites` labels a component without
638
638
  // importing its source.
639
639
  ...(graph.archetypes?.[name] ? { archetype: graph.archetypes[name] } : {}),
640
+ // The environments the component declares (#3153), where each release goes, so
641
+ // `chant workspace graph --composites` lists them without importing its source.
642
+ ...(graph.environments?.[name] ? { environments: graph.environments[name] } : {}),
640
643
  },
641
644
  // Deep-link the node to its `*.component.ts` (behold's inspect panel).
642
645
  ...(graph.files?.[name] ? { sourceLoc: { file: graph.files[name] } } : {}),