@intentius/chant 0.124.51 → 0.124.54

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 (593) hide show
  1. package/dist/audit/discover.d.ts.map +1 -1
  2. package/dist/audit/discover.js +3 -1
  3. package/dist/behaviour.d.ts +1 -1
  4. package/dist/behaviour.d.ts.map +1 -1
  5. package/dist/capabilities/templates.d.ts +65 -0
  6. package/dist/capabilities/templates.d.ts.map +1 -0
  7. package/dist/capabilities/templates.js +193 -0
  8. package/dist/capabilities/templates.json +145 -0
  9. package/dist/change-set-graph.d.ts +35 -3
  10. package/dist/change-set-graph.d.ts.map +1 -1
  11. package/dist/change-set-graph.js +60 -9
  12. package/dist/change-set.d.ts +65 -7
  13. package/dist/change-set.d.ts.map +1 -1
  14. package/dist/change-set.js +23 -12
  15. package/dist/ci-identity.d.ts +7 -2
  16. package/dist/ci-identity.d.ts.map +1 -1
  17. package/dist/ci-identity.js +4 -1
  18. package/dist/cli/commands/import-index.d.ts +52 -0
  19. package/dist/cli/commands/import-index.d.ts.map +1 -0
  20. package/dist/cli/commands/import-index.js +226 -0
  21. package/dist/cli/commands/lint.d.ts.map +1 -1
  22. package/dist/cli/commands/lint.js +4 -2
  23. package/dist/cli/handlers/components.d.ts.map +1 -1
  24. package/dist/cli/handlers/components.js +11 -2
  25. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  26. package/dist/cli/handlers/fan-out.js +16 -3
  27. package/dist/cli/handlers/graph.d.ts.map +1 -1
  28. package/dist/cli/handlers/graph.js +22 -4
  29. package/dist/cli/handlers/index-cloud.d.ts +14 -0
  30. package/dist/cli/handlers/index-cloud.d.ts.map +1 -0
  31. package/dist/cli/handlers/index-cloud.js +22 -0
  32. package/dist/cli/handlers/index-diff.d.ts +18 -0
  33. package/dist/cli/handlers/index-diff.d.ts.map +1 -0
  34. package/dist/cli/handlers/index-diff.js +142 -0
  35. package/dist/cli/handlers/lifecycle-drift.d.ts +25 -0
  36. package/dist/cli/handlers/lifecycle-drift.d.ts.map +1 -0
  37. package/dist/cli/handlers/lifecycle-drift.js +64 -0
  38. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  39. package/dist/cli/handlers/lifecycle.js +188 -28
  40. package/dist/cli/handlers/misc.d.ts +9 -0
  41. package/dist/cli/handlers/misc.d.ts.map +1 -1
  42. package/dist/cli/handlers/misc.js +77 -0
  43. package/dist/cli/handlers/pr.d.ts.map +1 -1
  44. package/dist/cli/handlers/pr.js +17 -3
  45. package/dist/cli/handlers/promote.d.ts.map +1 -1
  46. package/dist/cli/handlers/promote.js +89 -15
  47. package/dist/cli/handlers/query.d.ts.map +1 -1
  48. package/dist/cli/handlers/query.js +28 -4
  49. package/dist/cli/handlers/scenario.d.ts.map +1 -1
  50. package/dist/cli/handlers/scenario.js +8 -7
  51. package/dist/cli/handlers/search.d.ts +34 -4
  52. package/dist/cli/handlers/search.d.ts.map +1 -1
  53. package/dist/cli/handlers/search.js +216 -36
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/main.js +55 -1
  56. package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/lifecycle-tools.js +3 -2
  58. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  59. package/dist/cli/mcp/resource-handlers.js +4 -3
  60. package/dist/cli/mcp/workspace-tools.js +1 -1
  61. package/dist/cli/parse-args.d.ts.map +1 -1
  62. package/dist/cli/parse-args.js +55 -2
  63. package/dist/cli/registry.d.ts +19 -1
  64. package/dist/cli/registry.d.ts.map +1 -1
  65. package/dist/cloud-lister/aws.d.ts +35 -0
  66. package/dist/cloud-lister/aws.d.ts.map +1 -0
  67. package/dist/cloud-lister/aws.js +203 -0
  68. package/dist/cloud-lister/azure.d.ts +34 -0
  69. package/dist/cloud-lister/azure.d.ts.map +1 -0
  70. package/dist/cloud-lister/azure.js +129 -0
  71. package/dist/cloud-lister/common.d.ts +40 -0
  72. package/dist/cloud-lister/common.d.ts.map +1 -0
  73. package/dist/cloud-lister/common.js +83 -0
  74. package/dist/cloud-lister/credentials.d.ts +50 -0
  75. package/dist/cloud-lister/credentials.d.ts.map +1 -0
  76. package/dist/cloud-lister/credentials.js +86 -0
  77. package/dist/cloud-lister/fakes.d.ts +27 -0
  78. package/dist/cloud-lister/fakes.d.ts.map +1 -0
  79. package/dist/cloud-lister/fakes.js +50 -0
  80. package/dist/cloud-lister/gcp.d.ts +42 -0
  81. package/dist/cloud-lister/gcp.d.ts.map +1 -0
  82. package/dist/cloud-lister/gcp.js +143 -0
  83. package/dist/cloud-lister/guard.d.ts +49 -0
  84. package/dist/cloud-lister/guard.d.ts.map +1 -0
  85. package/dist/cloud-lister/guard.js +103 -0
  86. package/dist/cloud-lister/ids.d.ts +23 -0
  87. package/dist/cloud-lister/ids.d.ts.map +1 -0
  88. package/dist/cloud-lister/ids.js +42 -0
  89. package/dist/cloud-lister/index.d.ts +67 -0
  90. package/dist/cloud-lister/index.d.ts.map +1 -0
  91. package/dist/cloud-lister/index.js +102 -0
  92. package/dist/cloud-lister/kubernetes.d.ts +64 -0
  93. package/dist/cloud-lister/kubernetes.d.ts.map +1 -0
  94. package/dist/cloud-lister/kubernetes.js +276 -0
  95. package/dist/cloud-lister/markers.d.ts +31 -0
  96. package/dist/cloud-lister/markers.d.ts.map +1 -0
  97. package/dist/cloud-lister/markers.js +73 -0
  98. package/dist/cloud-lister/mask.d.ts +31 -0
  99. package/dist/cloud-lister/mask.d.ts.map +1 -0
  100. package/dist/cloud-lister/mask.js +74 -0
  101. package/dist/cloud-lister/sigv4.d.ts +29 -0
  102. package/dist/cloud-lister/sigv4.d.ts.map +1 -0
  103. package/dist/cloud-lister/sigv4.js +54 -0
  104. package/dist/cloud-lister/transport.d.ts +55 -0
  105. package/dist/cloud-lister/transport.d.ts.map +1 -0
  106. package/dist/cloud-lister/transport.js +86 -0
  107. package/dist/cloud-lister/types.d.ts +121 -0
  108. package/dist/cloud-lister/types.d.ts.map +1 -0
  109. package/dist/cloud-lister/types.js +24 -0
  110. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  111. package/dist/components/capability-plugin-loader.js +6 -0
  112. package/dist/components/capability-plugin.d.ts +9 -0
  113. package/dist/components/capability-plugin.d.ts.map +1 -1
  114. package/dist/components/capability.d.ts +224 -0
  115. package/dist/components/capability.d.ts.map +1 -1
  116. package/dist/components/cli-support.d.ts +21 -0
  117. package/dist/components/cli-support.d.ts.map +1 -1
  118. package/dist/components/cli-support.js +58 -14
  119. package/dist/components/covered-round.d.ts +173 -0
  120. package/dist/components/covered-round.d.ts.map +1 -0
  121. package/dist/components/covered-round.js +200 -0
  122. package/dist/components/declared-reads.d.ts +38 -0
  123. package/dist/components/declared-reads.d.ts.map +1 -0
  124. package/dist/components/declared-reads.js +131 -0
  125. package/dist/components/deploy-units.d.ts.map +1 -1
  126. package/dist/components/deploy-units.js +4 -0
  127. package/dist/components/driver.d.ts +42 -1
  128. package/dist/components/driver.d.ts.map +1 -1
  129. package/dist/components/driver.js +74 -3
  130. package/dist/components/fan-out-run.d.ts +23 -1
  131. package/dist/components/fan-out-run.d.ts.map +1 -1
  132. package/dist/components/fan-out-run.js +82 -14
  133. package/dist/components/fan-out-support.d.ts +6 -0
  134. package/dist/components/fan-out-support.d.ts.map +1 -1
  135. package/dist/components/fan-out-support.js +4 -1
  136. package/dist/components/fan-out.d.ts +28 -0
  137. package/dist/components/fan-out.d.ts.map +1 -1
  138. package/dist/components/groups.d.ts +229 -0
  139. package/dist/components/groups.d.ts.map +1 -0
  140. package/dist/components/groups.js +760 -0
  141. package/dist/components/index.d.ts +7 -2
  142. package/dist/components/index.d.ts.map +1 -1
  143. package/dist/components/index.js +5 -0
  144. package/dist/components/plan-shape-conformance.d.ts +48 -0
  145. package/dist/components/plan-shape-conformance.d.ts.map +1 -0
  146. package/dist/components/plan-shape-conformance.js +122 -0
  147. package/dist/components/pr-run.d.ts +62 -7
  148. package/dist/components/pr-run.d.ts.map +1 -1
  149. package/dist/components/pr-run.js +354 -53
  150. package/dist/components/promote-rounds.d.ts +9 -0
  151. package/dist/components/promote-rounds.d.ts.map +1 -1
  152. package/dist/components/promote-rounds.js +23 -2
  153. package/dist/components/promote.d.ts +17 -0
  154. package/dist/components/promote.d.ts.map +1 -1
  155. package/dist/components/promote.js +36 -6
  156. package/dist/components/release-gate.d.ts +23 -1
  157. package/dist/components/release-gate.d.ts.map +1 -1
  158. package/dist/components/release-gate.js +97 -33
  159. package/dist/components/run-groups.d.ts +58 -0
  160. package/dist/components/run-groups.d.ts.map +1 -0
  161. package/dist/components/run-groups.js +78 -0
  162. package/dist/components/starter-plugin.d.ts +1 -0
  163. package/dist/components/starter-plugin.d.ts.map +1 -1
  164. package/dist/components/starter-plugin.js +6 -1
  165. package/dist/components/verbs/index.d.ts +1 -0
  166. package/dist/components/verbs/index.d.ts.map +1 -1
  167. package/dist/components/verbs/index.js +1 -0
  168. package/dist/components/verbs/member-outputs.d.ts +187 -0
  169. package/dist/components/verbs/member-outputs.d.ts.map +1 -0
  170. package/dist/components/verbs/member-outputs.js +218 -0
  171. package/dist/components/wave-plan.d.ts +2 -0
  172. package/dist/components/wave-plan.d.ts.map +1 -1
  173. package/dist/components/wave-plan.js +4 -1
  174. package/dist/config.d.ts +60 -0
  175. package/dist/config.d.ts.map +1 -1
  176. package/dist/config.js +27 -0
  177. package/dist/deep-observation.d.ts +1 -13
  178. package/dist/deep-observation.d.ts.map +1 -1
  179. package/dist/deep-observation.js +5 -22
  180. package/dist/drift-record.d.ts +542 -0
  181. package/dist/drift-record.d.ts.map +1 -0
  182. package/dist/drift-record.js +886 -0
  183. package/dist/engine-facts.d.ts +144 -0
  184. package/dist/engine-facts.d.ts.map +1 -0
  185. package/dist/engine-facts.js +14 -0
  186. package/dist/graph-ir.d.ts +153 -2
  187. package/dist/graph-ir.d.ts.map +1 -1
  188. package/dist/graph-ir.js +224 -6
  189. package/dist/graph-refs.d.ts +145 -0
  190. package/dist/graph-refs.d.ts.map +1 -1
  191. package/dist/graph-refs.js +305 -0
  192. package/dist/graph-schema/fixtures/adopt.json +15 -0
  193. package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  194. package/dist/graph-schema/fixtures/index.json +68 -0
  195. package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  196. package/dist/graph-schema/fixtures.d.ts +23 -0
  197. package/dist/graph-schema/fixtures.d.ts.map +1 -0
  198. package/dist/graph-schema/fixtures.js +246 -0
  199. package/dist/graph-schema/generate.d.ts +15 -0
  200. package/dist/graph-schema/generate.d.ts.map +1 -0
  201. package/dist/graph-schema/generate.js +267 -0
  202. package/dist/graph-schema/graph.schema.json +1387 -0
  203. package/dist/health.schema.json +2 -1
  204. package/dist/identity.d.ts.map +1 -1
  205. package/dist/identity.js +2 -0
  206. package/dist/index.d.ts +1 -0
  207. package/dist/index.d.ts.map +1 -1
  208. package/dist/index.js +2 -0
  209. package/dist/instance-nodes.d.ts +159 -0
  210. package/dist/instance-nodes.d.ts.map +1 -0
  211. package/dist/instance-nodes.js +231 -0
  212. package/dist/lexicon.d.ts +72 -0
  213. package/dist/lexicon.d.ts.map +1 -1
  214. package/dist/lifecycle/adoption-file.d.ts +56 -0
  215. package/dist/lifecycle/adoption-file.d.ts.map +1 -0
  216. package/dist/lifecycle/adoption-file.js +123 -0
  217. package/dist/lifecycle/cloud-index.d.ts +186 -0
  218. package/dist/lifecycle/cloud-index.d.ts.map +1 -0
  219. package/dist/lifecycle/cloud-index.js +618 -0
  220. package/dist/lifecycle/derive-edges.d.ts +59 -0
  221. package/dist/lifecycle/derive-edges.d.ts.map +1 -0
  222. package/dist/lifecycle/derive-edges.js +126 -0
  223. package/dist/lifecycle/git.d.ts +10 -9
  224. package/dist/lifecycle/git.d.ts.map +1 -1
  225. package/dist/lifecycle/git.js +7 -1
  226. package/dist/lifecycle/identity-match.d.ts +133 -0
  227. package/dist/lifecycle/identity-match.d.ts.map +1 -0
  228. package/dist/lifecycle/identity-match.js +147 -0
  229. package/dist/lifecycle/index-diff.d.ts +224 -0
  230. package/dist/lifecycle/index-diff.d.ts.map +1 -0
  231. package/dist/lifecycle/index-diff.js +327 -0
  232. package/dist/lifecycle/index-document.d.ts +130 -0
  233. package/dist/lifecycle/index-document.d.ts.map +1 -0
  234. package/dist/lifecycle/index-document.js +189 -0
  235. package/dist/lifecycle/index-drift.d.ts +121 -0
  236. package/dist/lifecycle/index-drift.d.ts.map +1 -0
  237. package/dist/lifecycle/index-drift.js +178 -0
  238. package/dist/lifecycle/index-import.d.ts +168 -0
  239. package/dist/lifecycle/index-import.d.ts.map +1 -0
  240. package/dist/lifecycle/index-import.js +515 -0
  241. package/dist/lifecycle/index-join.d.ts +129 -0
  242. package/dist/lifecycle/index-join.d.ts.map +1 -0
  243. package/dist/lifecycle/index-join.js +248 -0
  244. package/dist/lifecycle/index.d.ts +4 -0
  245. package/dist/lifecycle/index.d.ts.map +1 -1
  246. package/dist/lifecycle/index.js +4 -0
  247. package/dist/lifecycle/observation-baseline.d.ts +61 -21
  248. package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
  249. package/dist/lifecycle/observation-baseline.js +144 -19
  250. package/dist/lifecycle/observe.d.ts.map +1 -1
  251. package/dist/lifecycle/observe.js +6 -1
  252. package/dist/lifecycle/query.d.ts +45 -4
  253. package/dist/lifecycle/query.d.ts.map +1 -1
  254. package/dist/lifecycle/query.js +89 -7
  255. package/dist/lifecycle/replay.d.ts +10 -3
  256. package/dist/lifecycle/replay.d.ts.map +1 -1
  257. package/dist/lifecycle/replay.js +10 -6
  258. package/dist/lifecycle/scenario.d.ts +4 -3
  259. package/dist/lifecycle/scenario.d.ts.map +1 -1
  260. package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
  261. package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
  262. package/dist/lifecycle/snapshot-store-fake.js +21 -0
  263. package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
  264. package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
  265. package/dist/lifecycle/snapshot-store-s3.js +254 -0
  266. package/dist/lifecycle/snapshot-store.d.ts +170 -0
  267. package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
  268. package/dist/lifecycle/snapshot-store.js +832 -0
  269. package/dist/lifecycle/snapshot.d.ts +11 -0
  270. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  271. package/dist/lifecycle/snapshot.js +18 -5
  272. package/dist/lifecycle/type-listing.d.ts +148 -0
  273. package/dist/lifecycle/type-listing.d.ts.map +1 -0
  274. package/dist/lifecycle/type-listing.js +166 -0
  275. package/dist/lint/component-checks.d.ts +15 -1
  276. package/dist/lint/component-checks.d.ts.map +1 -1
  277. package/dist/lint/component-checks.js +1 -0
  278. package/dist/lint/presets/relaxed.json +2 -1
  279. package/dist/lint/presets/strict.json +2 -1
  280. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
  281. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
  282. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
  283. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
  284. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
  285. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
  286. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
  287. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
  288. package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
  289. package/dist/lint/rules/comp/index.d.ts +2 -1
  290. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  291. package/dist/lint/rules/comp/index.js +4 -1
  292. package/dist/observation.d.ts +19 -2
  293. package/dist/observation.d.ts.map +1 -1
  294. package/dist/observation.js +18 -1
  295. package/dist/op/activities/activity-contracts.d.ts +1 -1
  296. package/dist/op/activities/activity-contracts.js +1 -1
  297. package/dist/op/activities/change-set.d.ts +6 -4
  298. package/dist/op/activities/change-set.d.ts.map +1 -1
  299. package/dist/op/activities/change-set.js +4 -2
  300. package/dist/op/activity-failure.d.ts +27 -0
  301. package/dist/op/activity-failure.d.ts.map +1 -1
  302. package/dist/op/activity-failure.js +31 -0
  303. package/dist/op/index.d.ts +2 -1
  304. package/dist/op/index.d.ts.map +1 -1
  305. package/dist/op/index.js +1 -1
  306. package/dist/op/local-executor.d.ts +5 -1
  307. package/dist/op/local-executor.d.ts.map +1 -1
  308. package/dist/op/local-executor.js +22 -8
  309. package/dist/pr-loop.d.ts +92 -3
  310. package/dist/pr-loop.d.ts.map +1 -1
  311. package/dist/pr-loop.js +62 -3
  312. package/dist/pulumi-urn.d.ts +101 -0
  313. package/dist/pulumi-urn.d.ts.map +1 -0
  314. package/dist/pulumi-urn.js +131 -0
  315. package/dist/release-floors.d.ts +23 -0
  316. package/dist/release-floors.d.ts.map +1 -0
  317. package/dist/release-floors.js +22 -0
  318. package/dist/sensitive-key.d.ts +23 -0
  319. package/dist/sensitive-key.d.ts.map +1 -0
  320. package/dist/sensitive-key.js +31 -0
  321. package/dist/wave-runtime.mjs +234 -234
  322. package/dist/workspace/adoption-report.d.ts +53 -0
  323. package/dist/workspace/adoption-report.d.ts.map +1 -0
  324. package/dist/workspace/adoption-report.js +76 -0
  325. package/dist/workspace/capabilities-contract.d.ts +7 -0
  326. package/dist/workspace/capabilities-contract.d.ts.map +1 -1
  327. package/dist/workspace/capabilities-contract.js +2 -1
  328. package/dist/workspace/capabilities.schema.json +98 -0
  329. package/dist/workspace/change-set.schema.json +42 -3
  330. package/dist/workspace/ci-cloud-identity.d.ts +13 -1
  331. package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
  332. package/dist/workspace/ci-cloud-identity.js +30 -1
  333. package/dist/workspace/compose-graph.d.ts +10 -1
  334. package/dist/workspace/compose-graph.d.ts.map +1 -1
  335. package/dist/workspace/compose-graph.js +6 -1
  336. package/dist/workspace/conformance/index.d.ts +1 -1
  337. package/dist/workspace/conformance/index.d.ts.map +1 -1
  338. package/dist/workspace/conformance/index.js +6 -1
  339. package/dist/workspace/drift-cli.d.ts +81 -0
  340. package/dist/workspace/drift-cli.d.ts.map +1 -0
  341. package/dist/workspace/drift-cli.js +317 -0
  342. package/dist/workspace/drift.schema.json +672 -0
  343. package/dist/workspace/graph-cli.d.ts +2 -0
  344. package/dist/workspace/graph-cli.d.ts.map +1 -1
  345. package/dist/workspace/graph-cli.js +3 -0
  346. package/dist/workspace/graph.schema.json +72 -0
  347. package/dist/workspace/init.d.ts +5 -1
  348. package/dist/workspace/init.d.ts.map +1 -1
  349. package/dist/workspace/init.js +55 -9
  350. package/dist/workspace/ledger.schema.json +1 -1
  351. package/dist/workspace/nested-graph.d.ts.map +1 -1
  352. package/dist/workspace/nested-graph.js +2 -0
  353. package/dist/workspace/pr-report.schema.json +76 -3
  354. package/dist/workspace/promote-waves.d.ts +112 -0
  355. package/dist/workspace/promote-waves.d.ts.map +1 -0
  356. package/dist/workspace/promote-waves.js +290 -0
  357. package/dist/workspace/promote.d.ts +84 -2
  358. package/dist/workspace/promote.d.ts.map +1 -1
  359. package/dist/workspace/promote.js +347 -61
  360. package/dist/workspace/reason-codes.d.ts +12 -0
  361. package/dist/workspace/reason-codes.d.ts.map +1 -1
  362. package/dist/workspace/reason-codes.js +14 -0
  363. package/dist/workspace/search-contract.d.ts +3 -3
  364. package/dist/workspace/search-contract.d.ts.map +1 -1
  365. package/dist/workspace/search-contract.js +2 -0
  366. package/dist/workspace/search.schema.json +103 -5
  367. package/package.json +14 -1
  368. package/src/__fixtures__/drift-record/README.md +58 -0
  369. package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
  370. package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
  371. package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
  372. package/src/__fixtures__/drift-record/component-status.json +91 -0
  373. package/src/__fixtures__/drift-record/deep-diff.json +259 -0
  374. package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
  375. package/src/__fixtures__/drift-record/live-diff.json +125 -0
  376. package/src/audit/discover.e2e.test.ts +14 -0
  377. package/src/audit/discover.ts +3 -1
  378. package/src/behaviour.ts +1 -1
  379. package/src/capabilities/templates.json +145 -0
  380. package/src/capabilities/templates.test.ts +212 -0
  381. package/src/capabilities/templates.ts +204 -0
  382. package/src/change-set-bundle.test.ts +83 -0
  383. package/src/change-set-graph.ts +80 -9
  384. package/src/change-set.test.ts +24 -0
  385. package/src/change-set.ts +77 -14
  386. package/src/ci-identity-targets.test.ts +23 -0
  387. package/src/ci-identity.ts +10 -4
  388. package/src/cli/commands/import-index.test.ts +117 -0
  389. package/src/cli/commands/import-index.ts +265 -0
  390. package/src/cli/commands/lint.ts +4 -2
  391. package/src/cli/handlers/components.test.ts +9 -0
  392. package/src/cli/handlers/components.ts +12 -2
  393. package/src/cli/handlers/fan-out.ts +17 -3
  394. package/src/cli/handlers/graph.test.ts +42 -0
  395. package/src/cli/handlers/graph.ts +26 -4
  396. package/src/cli/handlers/index-cloud.ts +32 -0
  397. package/src/cli/handlers/index-diff.test.ts +68 -0
  398. package/src/cli/handlers/index-diff.ts +146 -0
  399. package/src/cli/handlers/ledger-root-member.test.ts +161 -0
  400. package/src/cli/handlers/lifecycle-drift.ts +68 -0
  401. package/src/cli/handlers/lifecycle.test.ts +33 -11
  402. package/src/cli/handlers/lifecycle.ts +205 -30
  403. package/src/cli/handlers/misc.ts +73 -0
  404. package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
  405. package/src/cli/handlers/pr.ts +16 -3
  406. package/src/cli/handlers/promote.test.ts +64 -0
  407. package/src/cli/handlers/promote.ts +81 -6
  408. package/src/cli/handlers/query.ts +27 -4
  409. package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
  410. package/src/cli/handlers/run-groups-cli.test.ts +229 -0
  411. package/src/cli/handlers/scenario.test.ts +13 -0
  412. package/src/cli/handlers/scenario.ts +8 -7
  413. package/src/cli/handlers/search-index.test.ts +255 -0
  414. package/src/cli/handlers/search-json.test.ts +1 -1
  415. package/src/cli/handlers/search-ownership.test.ts +194 -0
  416. package/src/cli/handlers/search.ts +271 -38
  417. package/src/cli/main.test.ts +7 -0
  418. package/src/cli/main.ts +56 -1
  419. package/src/cli/mcp/lifecycle-tools.ts +3 -2
  420. package/src/cli/mcp/resource-handlers.ts +4 -3
  421. package/src/cli/mcp/workspace-tools.ts +1 -1
  422. package/src/cli/parse-args.ts +40 -2
  423. package/src/cli/registry.ts +19 -1
  424. package/src/cloud-lister/aws.test.ts +202 -0
  425. package/src/cloud-lister/aws.ts +226 -0
  426. package/src/cloud-lister/azure.test.ts +132 -0
  427. package/src/cloud-lister/azure.ts +142 -0
  428. package/src/cloud-lister/common.ts +115 -0
  429. package/src/cloud-lister/credentials.ts +110 -0
  430. package/src/cloud-lister/fakes.ts +66 -0
  431. package/src/cloud-lister/gcp.test.ts +121 -0
  432. package/src/cloud-lister/gcp.ts +159 -0
  433. package/src/cloud-lister/guard.test.ts +198 -0
  434. package/src/cloud-lister/guard.ts +111 -0
  435. package/src/cloud-lister/ids.ts +54 -0
  436. package/src/cloud-lister/index.ts +134 -0
  437. package/src/cloud-lister/kubernetes.test.ts +160 -0
  438. package/src/cloud-lister/kubernetes.ts +284 -0
  439. package/src/cloud-lister/markers.ts +74 -0
  440. package/src/cloud-lister/mask.ts +77 -0
  441. package/src/cloud-lister/shape.test.ts +81 -0
  442. package/src/cloud-lister/sigv4.ts +70 -0
  443. package/src/cloud-lister/transport.ts +118 -0
  444. package/src/cloud-lister/types.ts +135 -0
  445. package/src/components/capability-plugin-loader.ts +4 -0
  446. package/src/components/capability-plugin.ts +10 -0
  447. package/src/components/capability.ts +238 -0
  448. package/src/components/cli-support.ts +70 -14
  449. package/src/components/covered-round.test.ts +166 -0
  450. package/src/components/covered-round.ts +293 -0
  451. package/src/components/declared-reads.test.ts +103 -0
  452. package/src/components/declared-reads.ts +134 -0
  453. package/src/components/deploy-units.ts +4 -0
  454. package/src/components/driver.ts +101 -4
  455. package/src/components/fan-out-run.ts +95 -15
  456. package/src/components/fan-out-support.ts +10 -1
  457. package/src/components/fan-out.ts +30 -0
  458. package/src/components/groups.test.ts +320 -0
  459. package/src/components/groups.ts +880 -0
  460. package/src/components/index.ts +59 -0
  461. package/src/components/plan-shape-conformance.ts +130 -0
  462. package/src/components/pr-env-run-bundle.test.ts +2 -0
  463. package/src/components/pr-run.test.ts +728 -4
  464. package/src/components/pr-run.ts +395 -55
  465. package/src/components/promote-rounds.ts +25 -2
  466. package/src/components/promote.ts +55 -5
  467. package/src/components/registry.test.ts +1 -1
  468. package/src/components/release-gate.ts +115 -30
  469. package/src/components/release-groups.test.ts +362 -0
  470. package/src/components/run-groups.ts +113 -0
  471. package/src/components/starter-plugin.ts +6 -0
  472. package/src/components/verbs/index.ts +1 -0
  473. package/src/components/verbs/member-outputs.test.ts +205 -0
  474. package/src/components/verbs/member-outputs.ts +308 -0
  475. package/src/components/wave-plan.ts +5 -2
  476. package/src/config.ts +44 -0
  477. package/src/deep-observation.ts +5 -23
  478. package/src/drift-record.test.ts +596 -0
  479. package/src/drift-record.ts +1206 -0
  480. package/src/engine-facts.guard.test.ts +111 -0
  481. package/src/engine-facts.test.ts +178 -0
  482. package/src/engine-facts.ts +154 -0
  483. package/src/gated-waves-bundle.test.ts +2 -0
  484. package/src/graph-ir-live.test.ts +92 -0
  485. package/src/graph-ir.ts +317 -7
  486. package/src/graph-refs.ts +416 -0
  487. package/src/graph-schema/fixtures/adopt.json +15 -0
  488. package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  489. package/src/graph-schema/fixtures/index.json +68 -0
  490. package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  491. package/src/graph-schema/fixtures.ts +267 -0
  492. package/src/graph-schema/generate.ts +263 -0
  493. package/src/graph-schema/graph-schema.test.ts +153 -0
  494. package/src/graph-schema/graph.schema.json +1387 -0
  495. package/src/health.schema.json +2 -1
  496. package/src/identity.ts +2 -0
  497. package/src/index.ts +2 -0
  498. package/src/instance-nodes.ts +288 -0
  499. package/src/lexicon.ts +76 -0
  500. package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
  501. package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
  502. package/src/lifecycle/adoption-file.test.ts +100 -0
  503. package/src/lifecycle/adoption-file.ts +154 -0
  504. package/src/lifecycle/cloud-index.test.ts +517 -0
  505. package/src/lifecycle/cloud-index.ts +736 -0
  506. package/src/lifecycle/derive-edges.test.ts +193 -0
  507. package/src/lifecycle/derive-edges.ts +182 -0
  508. package/src/lifecycle/git.ts +10 -4
  509. package/src/lifecycle/identity-match.test.ts +308 -0
  510. package/src/lifecycle/identity-match.ts +257 -0
  511. package/src/lifecycle/index-diff.test.ts +198 -0
  512. package/src/lifecycle/index-diff.ts +476 -0
  513. package/src/lifecycle/index-document.test.ts +64 -0
  514. package/src/lifecycle/index-document.ts +299 -0
  515. package/src/lifecycle/index-drift.test.ts +191 -0
  516. package/src/lifecycle/index-drift.ts +304 -0
  517. package/src/lifecycle/index-import.test.ts +255 -0
  518. package/src/lifecycle/index-import.ts +634 -0
  519. package/src/lifecycle/index-join.test.ts +250 -0
  520. package/src/lifecycle/index-join.ts +304 -0
  521. package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
  522. package/src/lifecycle/index.ts +4 -0
  523. package/src/lifecycle/member-ledger.test.ts +25 -7
  524. package/src/lifecycle/observation-baseline.test.ts +72 -1
  525. package/src/lifecycle/observation-baseline.ts +190 -27
  526. package/src/lifecycle/observe.ts +6 -1
  527. package/src/lifecycle/query.test.ts +69 -1
  528. package/src/lifecycle/query.ts +103 -10
  529. package/src/lifecycle/replay.test.ts +9 -5
  530. package/src/lifecycle/replay.ts +9 -5
  531. package/src/lifecycle/scenario.ts +4 -3
  532. package/src/lifecycle/snapshot-store-fake.ts +29 -0
  533. package/src/lifecycle/snapshot-store-s3.ts +316 -0
  534. package/src/lifecycle/snapshot-store.test.ts +385 -0
  535. package/src/lifecycle/snapshot-store.ts +981 -0
  536. package/src/lifecycle/snapshot.test.ts +13 -0
  537. package/src/lifecycle/snapshot.ts +23 -6
  538. package/src/lifecycle/type-listing.test.ts +166 -0
  539. package/src/lifecycle/type-listing.ts +309 -0
  540. package/src/lint/component-checks.ts +17 -1
  541. package/src/lint/config.test.ts +3 -0
  542. package/src/lint/presets/relaxed.json +2 -1
  543. package/src/lint/presets/strict.json +2 -1
  544. package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
  545. package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
  546. package/src/lint/rules/comp/comp.test.ts +2 -1
  547. package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
  548. package/src/lint/rules/comp/comp008.test.ts +77 -0
  549. package/src/lint/rules/comp/index.ts +4 -1
  550. package/src/observation-edges.test.ts +33 -0
  551. package/src/observation.ts +36 -1
  552. package/src/op/activities/activity-contracts.ts +1 -1
  553. package/src/op/activities/change-set.ts +8 -5
  554. package/src/op/activity-failure.ts +36 -0
  555. package/src/op/index.ts +2 -1
  556. package/src/op/local-executor.test.ts +80 -0
  557. package/src/op/local-executor.ts +27 -9
  558. package/src/pr-loop-bundle.test.ts +5 -2
  559. package/src/pr-loop.test.ts +57 -1
  560. package/src/pr-loop.ts +154 -6
  561. package/src/pulumi-urn.ts +151 -0
  562. package/src/release-floors.ts +22 -0
  563. package/src/sensitive-key.ts +34 -0
  564. package/src/workspace/adoption-report.test.ts +61 -0
  565. package/src/workspace/adoption-report.ts +103 -0
  566. package/src/workspace/capabilities-contract.test.ts +4 -0
  567. package/src/workspace/capabilities-contract.ts +9 -1
  568. package/src/workspace/capabilities.schema.json +98 -0
  569. package/src/workspace/change-set.schema.json +42 -3
  570. package/src/workspace/ci-cloud-identity.ts +31 -1
  571. package/src/workspace/compose-graph.test.ts +12 -0
  572. package/src/workspace/compose-graph.ts +12 -1
  573. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  574. package/src/workspace/conformance/index.ts +6 -1
  575. package/src/workspace/drift-cli.test.ts +65 -0
  576. package/src/workspace/drift-cli.ts +365 -0
  577. package/src/workspace/drift.schema.json +672 -0
  578. package/src/workspace/graph-cli.ts +5 -0
  579. package/src/workspace/graph.schema.json +72 -0
  580. package/src/workspace/init.test.ts +38 -1
  581. package/src/workspace/init.ts +50 -8
  582. package/src/workspace/intent-gaps.test.ts +18 -2
  583. package/src/workspace/ledger.schema.json +1 -1
  584. package/src/workspace/nested-graph.ts +1 -0
  585. package/src/workspace/pr-report.schema.json +76 -3
  586. package/src/workspace/promote-waves.test.ts +296 -0
  587. package/src/workspace/promote-waves.ts +340 -0
  588. package/src/workspace/promote.test.ts +158 -4
  589. package/src/workspace/promote.ts +398 -57
  590. package/src/workspace/reason-codes.test.ts +4 -1
  591. package/src/workspace/reason-codes.ts +14 -0
  592. package/src/workspace/search-contract.ts +2 -0
  593. package/src/workspace/search.schema.json +103 -5
@@ -18,6 +18,9 @@ const readReleaseLedgerMock = vi.fn();
18
18
  const pushLifecycleMock = vi.fn();
19
19
  const resolveTargetsMock = vi.fn();
20
20
  const ran: string[] = [];
21
+ /** #4516: the reads the fake `import-apply` declares, and the order its steps ran in. */
22
+ let importReads: Array<{ reader: string; upstream: string; output: string; at: string }> = [];
23
+ const importApplied: Array<{ component: string; input: unknown }> = [];
21
24
  const stepInputs: Array<{ kind: string; input: unknown }> = [];
22
25
  let releaseFixture: { release: import("../../lifecycle/release-store").Release; label: string | null } | null = null;
23
26
  let storedTemplate: string | null = null;
@@ -64,6 +67,15 @@ vi.mock("../../components/fan-out-support", () => ({
64
67
  if (ctx.component === failApplyFor) throw applyError ?? new Error("apply failed");
65
68
  return {};
66
69
  });
70
+ // #4516: a stack step whose template imports another component's export, found by `declaredReads`.
71
+ registry.register({
72
+ kind: "import-apply",
73
+ declaredReads: (_ctx: unknown, members: ReadonlyArray<{ component: string }>) => importReads.filter((r) => members.some((m) => m.component === r.reader)),
74
+ async run(ctx: DeployContext, input: unknown) {
75
+ importApplied.push({ component: ctx.component, input });
76
+ return { outputs: { VpcId: `${ctx.component}-vpc` } };
77
+ },
78
+ } as never);
67
79
  // #4045: a planner whose member is provisional.
68
80
  registry.register({
69
81
  kind: "plan-provisional",
@@ -226,6 +238,8 @@ beforeEach(() => {
226
238
  removedTemplates.length = 0;
227
239
  ran.length = 0;
228
240
  stepInputs.length = 0;
241
+ importReads = [];
242
+ importApplied.length = 0;
229
243
  writtenTemplates.length = 0;
230
244
  releaseFixture = null;
231
245
  storedTemplate = null;
@@ -429,6 +443,56 @@ describe("chant components promote", () => {
429
443
  });
430
444
  });
431
445
 
446
+ describe("chant components promote orders an importer after its exporter (#4516)", () => {
447
+ /** A component that publishes its image and applies one stack. */
448
+ const stackComponent = (name: string): DriverComponent => ({
449
+ name,
450
+ deploy: [
451
+ { phase: "Build", steps: [{ kind: "docker-build", context: ".", into: "api.tar" }] },
452
+ { phase: "Publish", steps: [{ kind: "publish-image", from: "archive:api.tar" }] },
453
+ { phase: "Apply", steps: [{ kind: "import-apply", stack: name }] },
454
+ ],
455
+ });
456
+ // Discovered importer first, so only the read can put network ahead of it.
457
+ const app = stackComponent("app");
458
+ const network = stackComponent("network");
459
+ const read = { reader: "app", upstream: "network", output: "VpcId", at: "/imports/Net-VpcId" };
460
+
461
+ beforeEach(() => {
462
+ readReleaseLedgerMock.mockResolvedValue({ records: [{ ...staging, component: "app" }, { ...staging, component: "network" }], malformed: 0 });
463
+ resolveTargetsMock.mockResolvedValue({ success: true, targets: [app, network] });
464
+ });
465
+
466
+ test("a template's Fn::ImportValue of another promoted component's export deploys the exporter first and hands the importer its output", async () => {
467
+ importReads = [read];
468
+ expect(await runComponentsPromote(ctx({}))).toBe(0);
469
+ expect(importApplied.map((a) => a.component)).toEqual(["network", "app"]);
470
+ expect(importApplied[1]!.input).toMatchObject({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
471
+ expect(appendReleaseRecordMock).toHaveBeenCalledTimes(2);
472
+ });
473
+
474
+ test("with no declared read the two deploy as one wave and the importer gets no imports", async () => {
475
+ expect(await runComponentsPromote(ctx({}))).toBe(0);
476
+ expect(importApplied.map((a) => a.component).sort()).toEqual(["app", "network"]);
477
+ expect((importApplied.find((a) => a.component === "app")!.input as Record<string, unknown>).imports).toBeUndefined();
478
+ });
479
+
480
+ test("a read of a component this promote does not deploy is left out: the importer deploys alone", async () => {
481
+ importReads = [read];
482
+ resolveTargetsMock.mockResolvedValue({ success: true, targets: [app] });
483
+ expect(await runComponentsPromote(ctx({ component: "app" }))).toBe(0);
484
+ expect(importApplied.map((a) => a.component)).toEqual(["app"]);
485
+ expect((importApplied[0]!.input as Record<string, unknown>).imports).toBeUndefined();
486
+ });
487
+
488
+ test("--dry-run with a declared read still deploys nothing", async () => {
489
+ importReads = [read];
490
+ expect(await runComponentsPromote(ctx({ dryRun: true, json: true }))).toBe(0);
491
+ expect(importApplied).toEqual([]);
492
+ expect(appendReleaseRecordMock).not.toHaveBeenCalled();
493
+ });
494
+ });
495
+
432
496
  describe("chant components promote --release (#4026)", () => {
433
497
  const prodTemplate = `{"env":"prod"}\n`;
434
498
  const withTemplate: DriverComponent = {
@@ -39,6 +39,7 @@ import {
39
39
  } from "../../lifecycle/release-ledger";
40
40
  import { isComponentList, resolveComponentTargets } from "../../components/cli-support";
41
41
  import { applyConfigDefaults } from "../../components/config-defaults";
42
+ import { withDeclaredReads } from "../../components/declared-reads";
42
43
  import { fanOutRegistry } from "../../components/fan-out-support";
43
44
  import { renderDriverHuman } from "../../components/driver-output";
44
45
  import { ndjsonProgressSink } from "../../components/run-progress";
@@ -172,6 +173,9 @@ interface BoundReleaseGate {
172
173
  unknownInputs?: Record<string, string[]>;
173
174
  /** The approval a resume record carried on, when it still covers what is left. */
174
175
  resumedFrom?: string;
176
+ /** The groups the plan planned as one (#4465), and the components that could have grouped and did not. */
177
+ groups?: import("../../components/release-gate").ReleasePlanGroup[];
178
+ fallbacks?: import("../../components/fan-out").FanOutGroupFallback[];
175
179
  replan: (only: ReadonlySet<string>, outputs: Record<string, Record<string, unknown>>) => Promise<ChangeSetDocument>;
176
180
  bind: (doc: ChangeSetDocument, gates: string[]) => Promise<ReleaseGateBinding>;
177
181
  }
@@ -200,6 +204,10 @@ async function bindReleaseGate(input: {
200
204
  projectPath: string;
201
205
  head: string | undefined;
202
206
  resume?: import("../../components/promote-rounds").PromoteResume;
207
+ /** The grouped fan-out (#4465): its groups plan as one. */
208
+ grouped?: import("../../components/fan-out").FanOutPlan;
209
+ /** Each group plan this binding makes is added here, the newest first, for the run to apply. */
210
+ groupRuns: import("../../components/capability").GroupRun[];
203
211
  }): Promise<BoundReleaseGate | number | undefined> {
204
212
  const { plan, under, port } = input;
205
213
  const gate = await import("../../components/release-gate");
@@ -230,8 +238,8 @@ async function bindReleaseGate(input: {
230
238
  }
231
239
 
232
240
  const digests = new Map(plan.items.map((i) => [i.component, i.digest]));
233
- const planSet = (only: ReadonlySet<string> | undefined, outputs: Record<string, Record<string, unknown>>) =>
234
- gate.planReleaseSet({
241
+ const planSet = async (only: ReadonlySet<string> | undefined, outputs: Record<string, Record<string, unknown>>) => {
242
+ const planned = await gate.planReleaseSet({
235
243
  release: under.release,
236
244
  env,
237
245
  components: input.prepared,
@@ -241,7 +249,13 @@ async function bindReleaseGate(input: {
241
249
  unsettled,
242
250
  seededOutputs: outputs,
243
251
  ...(only ? { only } : {}),
252
+ ...(input.grouped ? { grouped: input.grouped } : {}),
244
253
  });
254
+ // #4465: the run applies the plan the gate bound, the newest one for a group planned again.
255
+ for (const g of planned.groups ?? []) if (g.run) input.groupRuns.unshift(g.run);
256
+ return planned;
257
+ };
258
+ const groupsOf = (p: Awaited<ReturnType<typeof planSet>>) => ({ ...(p.groups ? { groups: p.groups } : {}), ...(p.fallbacks ? { fallbacks: p.fallbacks } : {}) });
245
259
 
246
260
  const { storeGateChangeSet } = await import("../../lifecycle/gate-change-set");
247
261
  const { readStoredChangeSet } = await import("../../lifecycle/change-set-store");
@@ -322,6 +336,7 @@ async function bindReleaseGate(input: {
322
336
  binding: { op: gate.RELEASE_GATE_OP, planDigest: stored.document.digest, releaseDigest, verifyEmpty },
323
337
  reads: fresh.reads,
324
338
  resumedFrom: stored.document.digest,
339
+ ...groupsOf(fresh),
325
340
  ...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}),
326
341
  ...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}),
327
342
  ...later,
@@ -331,7 +346,7 @@ async function bindReleaseGate(input: {
331
346
  }
332
347
  const bound = await bindDoc(fresh.doc, gates, "change set");
333
348
  if (typeof bound === "number") return bound;
334
- return { doc: fresh.doc, ...bound, reads: fresh.reads, ...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}), ...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}), ...later };
349
+ return { doc: fresh.doc, ...bound, reads: fresh.reads, ...groupsOf(fresh), ...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}), ...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}), ...later };
335
350
  }
336
351
 
337
352
  const first = await planSet(undefined, input.seededOutputs);
@@ -340,7 +355,7 @@ async function bindReleaseGate(input: {
340
355
  for (const [component, refs] of Object.entries(first.unknownInputs ?? {})) {
341
356
  console.error(formatInfo(`${component} reads ${refs.join(", ")}, known only once its upstream applies; it is planned again then, and needs its own approval if its plan moves`));
342
357
  }
343
- return { doc: first.doc, ...bound, reads: first.reads, ...(first.plannedOutputs ? { plannedOutputs: first.plannedOutputs } : {}), ...(first.unknownInputs ? { unknownInputs: first.unknownInputs } : {}), ...later };
358
+ return { doc: first.doc, ...bound, reads: first.reads, ...groupsOf(first), ...(first.plannedOutputs ? { plannedOutputs: first.plannedOutputs } : {}), ...(first.unknownInputs ? { unknownInputs: first.unknownInputs } : {}), ...later };
344
359
  }
345
360
 
346
361
  /** A later round's or wave's plan was refused (provisional or failed members); the refusal is already printed. */
@@ -518,6 +533,12 @@ async function deployPlanIn(
518
533
  }
519
534
 
520
535
  const registry = await fanOutRegistry(project.projectPath, project.config);
536
+ // #4516: the reads a capability finds in its steps' files (a template's
537
+ // Fn::ImportValue) order the promote as `deriveFanOut` orders a fan-out, so
538
+ // an importer deploys after the exporter it reads. Read once the release's
539
+ // templates are written, so they are the files read; a read of a component
540
+ // this promote does not deploy is left out.
541
+ prepared.splice(0, prepared.length, ...(await withDeclaredReads(prepared, registry, project.projectPath)));
521
542
  const port = gitGateLedgerPort();
522
543
  // #4045: under a release, every gate binds the release's change set for this environment.
523
544
  let releaseGate: ReleaseGateBinding | undefined;
@@ -536,10 +557,51 @@ async function deployPlanIn(
536
557
  console.error(formatWarning({ message: `could not read the resume record ${resumePath}: ${err instanceof Error ? err.message : String(err)}` }));
537
558
  }
538
559
  }
560
+ // ws-107 (#4465): under a release, the components a capability takes as one
561
+ // plan and apply as one group; under --wave-gate none forms (ruling 1).
562
+ // A resume groups again what is left of each group.
563
+ let grouped: import("../../components/fan-out").FanOutPlan | undefined;
564
+ const groupRuns: import("../../components/capability").GroupRun[] = [];
565
+ if (under) {
566
+ const groups = await import("../../components/groups");
567
+ const whole = await groups.formRunGroups({
568
+ components: prepared,
569
+ plan: groups.componentSetFanOut(prepared),
570
+ registry,
571
+ env: plan.to,
572
+ ...(args.waveGate !== undefined ? { waveGate: true } : {}),
573
+ });
574
+ if (resume && whole.groups?.length) {
575
+ const { remainingFanOut } = await import("../../components/fan-out");
576
+ grouped = await groups.regroupRemaining({
577
+ components: prepared,
578
+ plan: remainingFanOut(whole, prepared, { completed: resume.completed }),
579
+ registry,
580
+ env: plan.to,
581
+ groups: whole.groups,
582
+ ...(whole.fallbacks ? { fallbacks: whole.fallbacks } : {}),
583
+ });
584
+ } else {
585
+ grouped = whole;
586
+ }
587
+ }
539
588
  let pullRequests: Array<import("../../lifecycle/merge-record").MergeRecord> = [];
540
589
  if (under) {
541
590
  try {
542
- const result = await bindReleaseGate({ plan, prepared, under, registry, port, seededOutputs, actor: actor!, projectPath: project.projectPath, head, ...(resume ? { resume } : {}) });
591
+ const result = await bindReleaseGate({
592
+ plan,
593
+ prepared,
594
+ under,
595
+ registry,
596
+ port,
597
+ seededOutputs,
598
+ actor: actor!,
599
+ projectPath: project.projectPath,
600
+ head,
601
+ ...(resume ? { resume } : {}),
602
+ ...(grouped ? { grouped } : {}),
603
+ groupRuns,
604
+ });
543
605
  if (typeof result === "number") {
544
606
  tidy();
545
607
  return result;
@@ -594,6 +656,7 @@ async function deployPlanIn(
594
656
  ...(args.waveGate ? { waveGate: args.waveGate } : {}),
595
657
  replan: bound.replan,
596
658
  bind: bound.bind,
659
+ ...(grouped?.groups?.length ? { grouped } : {}),
597
660
  run: (components, outputs, binding) =>
598
661
  runPromotion({
599
662
  plan: { ...plan, items: plan.items.filter((i) => components.some((c) => c.name === i.component)) },
@@ -602,6 +665,7 @@ async function deployPlanIn(
602
665
  componentOutputs: outputs,
603
666
  gates: port,
604
667
  releaseGate: binding,
668
+ ...(grouped?.groups?.length ? { grouped, groupRuns } : {}),
605
669
  ...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
606
670
  ...(events ? { onRunEvent: events.emit } : {}),
607
671
  }),
@@ -615,6 +679,8 @@ async function deployPlanIn(
615
679
  componentOutputs: seededOutputs,
616
680
  gates: port,
617
681
  ...(releaseGate ? { releaseGate } : {}),
682
+ // #4465: with no release gate to bind, nothing planned the groups beforehand, so each plans in its wave.
683
+ ...(grouped?.groups?.length ? { grouped, groupRuns, planGroupsAtWave: bound === undefined } : {}),
618
684
  ...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
619
685
  ...(events ? { onRunEvent: events.emit } : {}),
620
686
  });
@@ -653,6 +719,15 @@ async function deployPlanIn(
653
719
  console.error(formatInfo(`resume record: ${resumePath}; the same promote carries on from here`));
654
720
  }
655
721
  }
722
+ // #4465: the groups applied as one, and how each member ended, as pr-report says it.
723
+ const { runGroupsReport, renderRunGroups } = await import("../../components/run-groups");
724
+ const groupsReport = runGroupsReport({
725
+ grouped,
726
+ ...(bound?.groups ? { planned: bound.groups } : {}),
727
+ ...(bound ? { doc: bound.doc } : {}),
728
+ ...(run.groupOutcomes ? { outcomes: run.groupOutcomes } : {}),
729
+ });
730
+ if (!args.json) for (const line of renderRunGroups(groupsReport, `the same ${verb}`)) console.error(formatInfo(line));
656
731
  // The driver settles the stream; this only ends one it left open.
657
732
  events?.settle(run.status === "fail" ? "failed" : run.status);
658
733
  if (!args.json) renderDriverHuman(run);
@@ -690,7 +765,7 @@ async function deployPlanIn(
690
765
  const withChangeSet = under && changeSetJson ? { release: { ...releaseJson.release!, ...changeSetJson } } : releaseJson;
691
766
  const stagedJson = staged ? { stages: staged.stages, ...(bound?.plannedOutputs ? { plannedOutputs: bound.plannedOutputs } : {}), ...(bound?.unknownInputs ? { unknownInputs: bound.unknownInputs } : {}) } : {};
692
767
  const prJson = pullRequests.length > 0 ? { pullRequests: pullRequests.map((r) => ({ commit: r.commit, source: r.source, plan: r.plan, digest: r.digest, approvedBy: r.approvedBy, ...(r.authorApproved ? { authorApproved: r.authorApproved } : {}) })) } : {};
693
- console.log(JSON.stringify({ ...planJson(plan, removed), ...withChangeSet, ...stagedJson, ...prJson, run, recorded, ...(outcome ? { outcome } : {}) }, null, 2));
768
+ console.log(JSON.stringify({ ...planJson(plan, removed), ...withChangeSet, ...stagedJson, ...prJson, ...groupsReport, run, recorded, ...(outcome ? { outcome } : {}) }, null, 2));
694
769
  } else {
695
770
  for (const r of recorded) {
696
771
  console.error(formatSuccess(
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * `chant query "<sql>" [dir] [--member <name>] [--json]` (#4297): one
3
- * read-only SQL statement over the snapshots, Op runs, gates, deploys and
4
- * releases on the local `chant/lifecycle` branch. The tables and the engine
3
+ * read-only SQL statement over the snapshots in the index store (#4519) and
4
+ * the Op runs, gates, deploys and releases on the local `chant/lifecycle`
5
+ * branch. The tables and the engine
5
6
  * live in `../../lifecycle/query.ts`; this reads the ledgers and prints.
6
7
  *
7
8
  * Inside a workspace every member's ledger is read, each row naming its
@@ -34,7 +35,11 @@ export async function queryLedgers(cwd: string, members?: readonly string[], at?
34
35
  const commit = resolveLedgerRevision(repo, at);
35
36
  return (member: string | null) => revisionLedgerReadPort(repo, commit, member === null ? "" : memberLedgerPrefix([member]));
36
37
  })();
37
- if (!found) return [{ member: null, port: atPort ? atPort(null) : gitLedgerReadPort({ cwd }) }];
38
+ // Snapshots come from the index store (#4519). `--at` names a commit of
39
+ // chant/lifecycle, so it reads that commit's snapshots as before.
40
+ const { resolveSnapshotStore, snapshotReadPort } = await import("../../lifecycle/snapshot-store");
41
+ const store = at === undefined ? await resolveSnapshotStore({ cwd: found?.dir ?? cwd }) : undefined;
42
+ if (!found) return [{ member: null, port: atPort ? atPort(null) : gitLedgerReadPort({ cwd }), ...(store ? { snapshots: snapshotReadPort(store, { cwd }) } : {}) }];
38
43
  // Workspace code loads only when there is a workspace, so a level-0 project never pays for it.
39
44
  const { readDeclaration, WorkspaceReadError } = await import("../../workspace/declaration");
40
45
  const { workingTree } = await import("../../workspace/tree");
@@ -51,9 +56,27 @@ export async function queryLedgers(cwd: string, members?: readonly string[], at?
51
56
  const unknown = [...wanted].filter((n) => !declaration.members.some((m) => m.name === n));
52
57
  if (unknown.length > 0) throw new QueryError(`--member ${unknown.join(", ")} names no member of the workspace`);
53
58
  }
59
+ // #4482: a TerraformApplyOp run names its root's directory; the member that holds it is `root_member`.
60
+ const { ownerOf, resolveGroups } = await import("../../workspace/declaration");
61
+ const groups = (() => {
62
+ try {
63
+ return resolveGroups(declaration, workingTree(found.dir));
64
+ } catch {
65
+ return [];
66
+ }
67
+ })();
68
+ const ownerOfPath = (path: string): string | null => {
69
+ const owner = ownerOf(declaration, groups, path);
70
+ return owner && "member" in owner ? owner.member.name : null;
71
+ };
54
72
  return declaration.members
55
73
  .filter((m) => !wanted || wanted.has(m.name))
56
- .map((m) => ({ member: m.name, port: atPort ? atPort(m.dir === "." ? null : m.name) : gitLedgerReadPort({ cwd: found.dir, member: m.dir === "." ? "." : m.name }) }));
74
+ .map((m) => ({
75
+ member: m.name,
76
+ port: atPort ? atPort(m.dir === "." ? null : m.name) : gitLedgerReadPort({ cwd: found.dir, member: m.dir === "." ? "." : m.name }),
77
+ ...(store ? { snapshots: snapshotReadPort(store, { cwd: found.dir, member: m.dir === "." ? "." : m.name }) } : {}),
78
+ ownerOfPath,
79
+ }));
57
80
  }
58
81
 
59
82
  export async function runQueryCommand(ctx: CommandContext): Promise<number> {
@@ -0,0 +1,187 @@
1
+ /**
2
+ * `chant run --components` and `chant components fan-out` order an importer
3
+ * after its exporter when the read is one a capability declares (chant#4516):
4
+ * a template's `Fn::ImportValue` of another component's export, which
5
+ * `declaredReads` (#4466a) finds and core writes into the reader's step as a
6
+ * `stackOutput()` plus a `dependsOn`. Driven through the CLI handlers, as
7
+ * run-groups-cli.test.ts drives group formation (chant#4505).
8
+ *
9
+ * Discovery, config, the capability registry and the gate ledger are fakes.
10
+ * app is discovered first and declares no `dependsOn`, so only the declared
11
+ * read can put network ahead of it. edge reads nothing.
12
+ */
13
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
14
+ import type { Component } from "../../components/component";
15
+ import type { ParsedArgs } from "../registry";
16
+
17
+ const affectedStacksMock = vi.fn();
18
+ const discoverComponentsMock = vi.fn();
19
+ const buildCapabilityRegistryMock = vi.fn();
20
+
21
+ vi.mock("../../lifecycle/affected", () => ({
22
+ affectedStacks: (...args: unknown[]) => affectedStacksMock(...args),
23
+ }));
24
+
25
+ vi.mock("../../components/discover", () => ({
26
+ discoverComponents: (...args: unknown[]) => discoverComponentsMock(...args),
27
+ }));
28
+
29
+ vi.mock("../../config", async () => {
30
+ const actual = await vi.importActual<typeof import("../../config")>("../../config");
31
+ return { ...actual, loadChantConfig: async () => ({ config: { lexicons: ["aws"] } }) };
32
+ });
33
+
34
+ vi.mock("../../components/capability-plugin-loader", () => ({
35
+ buildCapabilityRegistry: (...args: unknown[]) => buildCapabilityRegistryMock(...args),
36
+ }));
37
+
38
+ /** The real gate ledger is this repository's `chant/lifecycle` branch; a test never appends to it. */
39
+ vi.mock("../../op/gate", async () => {
40
+ const actual = await vi.importActual<typeof import("../../op/gate")>("../../op/gate");
41
+ return { ...actual, gitGateLedgerPort: () => actual.memoryGateLedgerPort(), gateIsSealed: async () => false };
42
+ });
43
+
44
+ /** The release ledger, for the same reason. */
45
+ vi.mock("../../components/auto-release", async () => {
46
+ const actual = await vi.importActual<typeof import("../../components/auto-release")>("../../components/auto-release");
47
+ return { ...actual, maybeRecordAutoRelease: async () => ({ recorded: false, reason: "opted-out" }) };
48
+ });
49
+
50
+ /** `run --components` on the local runtime: the real `runComponents`, with the test's registry. */
51
+ vi.mock("../../op/runtimes/local", async () => {
52
+ const { runComponents } = await import("../../components/cli-support");
53
+ const { memoryGateLedgerPort } = await import("../../op/gate");
54
+ return {
55
+ createLocalOpRuntime: () => ({
56
+ name: "local",
57
+ runComponents: async (path: string, selector: string, options: object) =>
58
+ runComponents(path, selector, { ...options, registry: await buildCapabilityRegistryMock(), config: {}, revision: null, gates: memoryGateLedgerPort() }),
59
+ }),
60
+ };
61
+ });
62
+
63
+ const { CapabilityRegistry } = await import("../../components/capability");
64
+ const { computePlanDigest } = await import("../../lifecycle/plan-digest");
65
+ const { runComponentsFanOut } = await import("./fan-out");
66
+ const { runOpComponents } = await import("./run");
67
+
68
+ interface StackInput {
69
+ stack: string;
70
+ imports?: Record<string, unknown>;
71
+ }
72
+
73
+ const stack = (name: string): Component => ({
74
+ name,
75
+ dependsOn: [],
76
+ deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy", stack: name, template: `${name}.template.json` }] }],
77
+ });
78
+ const COMPONENTS = [stack("app"), stack("network"), stack("edge")];
79
+ /** app's template imports `Net-VpcId`, which network's template exports from its `VpcId` output. */
80
+ const READ = { reader: "app", index: 0, upstream: "network", output: "VpcId", at: "/imports/Net-VpcId" };
81
+
82
+ let declares = true;
83
+ let applied: Array<{ stack: string; imports?: Record<string, unknown> }> = [];
84
+ let stderrLines: string[] = [];
85
+
86
+ function registry() {
87
+ const r = new CapabilityRegistry();
88
+ r.register({
89
+ kind: "cfn-deploy",
90
+ async plan(_ctx: unknown, input: StackInput) {
91
+ const planDigest = computePlanDigest("cfn-deploy", { stack: input.stack, imports: input.imports ?? null });
92
+ return {
93
+ member: input.stack,
94
+ planDigest,
95
+ artifact: { planDigest },
96
+ outputs: { known: {}, unknown: ["VpcId"] },
97
+ changeSet: {
98
+ member: { member: input.stack, lexicon: "aws", planner: "tofu" as const, status: "planned" as const, planDigest, holes: [] },
99
+ entries: [{ member: input.stack, lexicon: "aws", planner: "tofu" as const, address: "res.x", type: "res", action: "create" as const, attributes: [] }],
100
+ },
101
+ };
102
+ },
103
+ async run(_ctx: unknown, input: StackInput) {
104
+ applied.push({ stack: input.stack, ...(input.imports ? { imports: input.imports } : {}) });
105
+ return { outputs: { VpcId: `${input.stack}-vpc` } };
106
+ },
107
+ ...(declares
108
+ ? {
109
+ declaredReads(_ctx: unknown, members: ReadonlyArray<{ component: string }>) {
110
+ return members.some((m) => m.component === READ.reader) ? [READ] : [];
111
+ },
112
+ }
113
+ : {}),
114
+ } as never);
115
+ return r;
116
+ }
117
+
118
+ const baseArgs = { format: "", fix: false, watch: false, verbose: false, help: false, live: false };
119
+ const fanOutCtx = (overrides: Partial<ParsedArgs> = {}) => ({ args: { command: "components", path: "fan-out", ...baseArgs, ...overrides } as ParsedArgs, plugins: [], serializers: [] }) as never;
120
+ const runCtx = (selector: string) => ({ args: { command: "run", path: selector, components: true, on: "local", ...baseArgs } as ParsedArgs, plugins: [] }) as never;
121
+ const stderr = () => stderrLines.join("\n");
122
+ const order = () => applied.map((a) => a.stack);
123
+
124
+ beforeEach(() => {
125
+ vi.clearAllMocks();
126
+ declares = true;
127
+ applied = [];
128
+ stderrLines = [];
129
+ discoverComponentsMock.mockResolvedValue({
130
+ components: new Map(COMPONENTS.map((c) => [c.name, { component: c, exportName: c.name, filePath: `${c.name}.component.ts` }])),
131
+ sourceFiles: [],
132
+ errors: [],
133
+ });
134
+ buildCapabilityRegistryMock.mockImplementation(async () => registry());
135
+ affectedStacksMock.mockResolvedValue({ changed: ["network"], dependents: [], indeterminate: [] });
136
+ vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
137
+ stderrLines.push(args.map(String).join(" "));
138
+ });
139
+ vi.spyOn(console, "log").mockImplementation(() => {});
140
+ vi.spyOn(process.stderr, "write").mockImplementation((chunk: unknown) => {
141
+ stderrLines.push(String(chunk));
142
+ return true;
143
+ });
144
+ vi.spyOn(process.stdout, "write").mockImplementation(() => true);
145
+ });
146
+
147
+ afterEach(() => {
148
+ vi.restoreAllMocks();
149
+ });
150
+
151
+ describe("chant run --components orders an importer after its exporter (chant#4516)", () => {
152
+ test("all: network applies before app, and app's step gets network's output under imports", async () => {
153
+ expect(await runOpComponents(runCtx("all"))).toBe(0);
154
+ expect(order().indexOf("network")).toBeLessThan(order().indexOf("app"));
155
+ expect(applied.find((a) => a.stack === "app")).toEqual({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
156
+ expect(order().sort()).toEqual(["app", "edge", "network"]);
157
+ });
158
+
159
+ test("a list naming the importer pulls in its exporter, says so, and runs it first", async () => {
160
+ expect(await runOpComponents(runCtx("app,edge"))).toBe(0);
161
+ expect(stderr()).toContain("added as dependencies: network");
162
+ expect(stderr()).toMatch(/run order: .*network.*, then app/);
163
+ expect(order().indexOf("network")).toBeLessThan(order().indexOf("app"));
164
+ expect(applied.find((a) => a.stack === "app")?.imports).toEqual({ "Net-VpcId": "network-vpc" });
165
+ });
166
+
167
+ test("a single name runs that component alone; a read of a component outside the run is left out", async () => {
168
+ expect(await runOpComponents(runCtx("app"))).toBe(0);
169
+ expect(applied).toEqual([{ stack: "app" }]);
170
+ });
171
+
172
+ test("without declaredReads a list adds nothing and app gets no imports, as before", async () => {
173
+ declares = false;
174
+ expect(await runOpComponents(runCtx("app,edge"))).toBe(0);
175
+ expect(stderr()).not.toContain("added as dependencies");
176
+ expect(order().sort()).toEqual(["app", "edge"]);
177
+ expect(applied.find((a) => a.stack === "app")?.imports).toBeUndefined();
178
+ });
179
+ });
180
+
181
+ describe("chant components fan-out orders an importer after its exporter (chant#4516)", () => {
182
+ test("a changed network pulls in app, which applies after it with network's output", async () => {
183
+ expect(await runComponentsFanOut(fanOutCtx({ base: "main" }))).toBe(0);
184
+ expect(order()).toEqual(["network", "app"]);
185
+ expect(applied[1]).toEqual({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
186
+ });
187
+ });