@intentius/chant 0.124.31 → 0.124.33

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 (509) hide show
  1. package/bin/chant +7 -2
  2. package/dist/ci-jobs.d.ts +4 -0
  3. package/dist/ci-jobs.d.ts.map +1 -1
  4. package/dist/ci-jobs.js +9 -2
  5. package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
  6. package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
  7. package/dist/cli/commands/check-lexicon-plugin.js +10 -7
  8. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  9. package/dist/cli/commands/check-lexicon.js +18 -12
  10. package/dist/cli/commands/import.d.ts +10 -0
  11. package/dist/cli/commands/import.d.ts.map +1 -1
  12. package/dist/cli/commands/import.js +37 -0
  13. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  14. package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
  15. package/dist/cli/commands/onboard.d.ts.map +1 -1
  16. package/dist/cli/commands/onboard.js +8 -4
  17. package/dist/cli/commands/update.d.ts.map +1 -1
  18. package/dist/cli/commands/update.js +2 -1
  19. package/dist/cli/dependencies.d.ts +18 -0
  20. package/dist/cli/dependencies.d.ts.map +1 -0
  21. package/dist/cli/dependencies.js +120 -0
  22. package/dist/cli/handlers/build.d.ts.map +1 -1
  23. package/dist/cli/handlers/build.js +38 -4
  24. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  25. package/dist/cli/handlers/fan-out.js +12 -4
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/graph.js +16 -6
  28. package/dist/cli/handlers/lifecycle-health.d.ts +16 -0
  29. package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
  30. package/dist/cli/handlers/lifecycle-health.js +150 -0
  31. package/dist/cli/handlers/lifecycle.d.ts +26 -0
  32. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  33. package/dist/cli/handlers/lifecycle.js +1 -1
  34. package/dist/cli/handlers/lint.d.ts.map +1 -1
  35. package/dist/cli/handlers/lint.js +6 -0
  36. package/dist/cli/handlers/operator.d.ts +2 -2
  37. package/dist/cli/handlers/operator.js +3 -3
  38. package/dist/cli/handlers/pr.d.ts +16 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -1
  40. package/dist/cli/handlers/pr.js +610 -32
  41. package/dist/cli/handlers/promote.d.ts.map +1 -1
  42. package/dist/cli/handlers/promote.js +19 -2
  43. package/dist/cli/handlers/release.d.ts +16 -1
  44. package/dist/cli/handlers/release.d.ts.map +1 -1
  45. package/dist/cli/handlers/release.js +83 -11
  46. package/dist/cli/handlers/run.d.ts +13 -1
  47. package/dist/cli/handlers/run.d.ts.map +1 -1
  48. package/dist/cli/handlers/run.js +38 -15
  49. package/dist/cli/main.d.ts.map +1 -1
  50. package/dist/cli/main.js +121 -33
  51. package/dist/cli/parse-args.d.ts.map +1 -1
  52. package/dist/cli/parse-args.js +37 -0
  53. package/dist/cli/registry.d.ts +29 -6
  54. package/dist/cli/registry.d.ts.map +1 -1
  55. package/dist/cli/registry.js +6 -2
  56. package/dist/codegen/generate-post-synth-barrel.js +2 -2
  57. package/dist/codegen/lexicon-regen.d.ts +4 -0
  58. package/dist/codegen/lexicon-regen.d.ts.map +1 -1
  59. package/dist/codegen/lexicon-regen.js +1 -1
  60. package/dist/codegen/pinned-upgrade.js +2 -2
  61. package/dist/components/capability.d.ts +44 -3
  62. package/dist/components/capability.d.ts.map +1 -1
  63. package/dist/components/capability.js +21 -0
  64. package/dist/components/changed-files.d.ts +7 -1
  65. package/dist/components/changed-files.d.ts.map +1 -1
  66. package/dist/components/changed-files.js +9 -1
  67. package/dist/components/deploy-inputs.d.ts +91 -0
  68. package/dist/components/deploy-inputs.d.ts.map +1 -0
  69. package/dist/components/deploy-inputs.js +184 -0
  70. package/dist/components/driver.d.ts +38 -0
  71. package/dist/components/driver.d.ts.map +1 -1
  72. package/dist/components/driver.js +56 -6
  73. package/dist/components/fan-out-record.d.ts +6 -1
  74. package/dist/components/fan-out-record.d.ts.map +1 -1
  75. package/dist/components/fan-out-record.js +24 -0
  76. package/dist/components/fan-out-run.d.ts +20 -0
  77. package/dist/components/fan-out-run.d.ts.map +1 -1
  78. package/dist/components/fan-out-run.js +21 -1
  79. package/dist/components/gate-plan.d.ts +8 -0
  80. package/dist/components/gate-plan.d.ts.map +1 -1
  81. package/dist/components/gate-plan.js +6 -0
  82. package/dist/components/pr-pipeline.d.ts +98 -12
  83. package/dist/components/pr-pipeline.d.ts.map +1 -1
  84. package/dist/components/pr-pipeline.js +146 -23
  85. package/dist/components/pr-run.d.ts +128 -30
  86. package/dist/components/pr-run.d.ts.map +1 -1
  87. package/dist/components/pr-run.js +290 -70
  88. package/dist/components/release-compile.d.ts +37 -2
  89. package/dist/components/release-compile.d.ts.map +1 -1
  90. package/dist/components/release-compile.js +64 -8
  91. package/dist/components/release-promote.d.ts +17 -3
  92. package/dist/components/release-promote.d.ts.map +1 -1
  93. package/dist/components/release-promote.js +79 -18
  94. package/dist/components/verbs/bom-writer.d.ts +1 -1
  95. package/dist/components/verbs/bom-writer.d.ts.map +1 -1
  96. package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
  97. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
  98. package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
  99. package/dist/components/wave-plan.d.ts +15 -2
  100. package/dist/components/wave-plan.d.ts.map +1 -1
  101. package/dist/components/wave-plan.js +44 -5
  102. package/dist/discovery/fold-import.d.ts.map +1 -1
  103. package/dist/discovery/fold-import.js +16 -6
  104. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  105. package/dist/discovery/sandbox/bundle.js +6 -0
  106. package/dist/discovery/specifier-resolve.d.ts.map +1 -1
  107. package/dist/discovery/specifier-resolve.js +8 -2
  108. package/dist/fold/fold.d.ts.map +1 -1
  109. package/dist/fold/fold.js +68 -1
  110. package/dist/fold/subset.d.ts +37 -0
  111. package/dist/fold/subset.d.ts.map +1 -1
  112. package/dist/fold/subset.js +88 -0
  113. package/dist/graph-detail.d.ts.map +1 -1
  114. package/dist/graph-detail.js +32 -7
  115. package/dist/health.d.ts +110 -0
  116. package/dist/health.d.ts.map +1 -0
  117. package/dist/health.js +105 -0
  118. package/dist/health.schema.json +191 -0
  119. package/dist/lexicon-module.d.ts +10 -0
  120. package/dist/lexicon-module.d.ts.map +1 -1
  121. package/dist/lexicon-module.js +53 -8
  122. package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
  123. package/dist/lexicon-plugin-helpers.js +6 -4
  124. package/dist/lexicon.d.ts +29 -0
  125. package/dist/lexicon.d.ts.map +1 -1
  126. package/dist/lifecycle/affected.d.ts.map +1 -1
  127. package/dist/lifecycle/affected.js +7 -1
  128. package/dist/lifecycle/merge-record.d.ts +104 -0
  129. package/dist/lifecycle/merge-record.d.ts.map +1 -0
  130. package/dist/lifecycle/merge-record.js +102 -0
  131. package/dist/lifecycle/publish-attachments.d.ts +8 -5
  132. package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
  133. package/dist/lifecycle/publish-attachments.js +27 -13
  134. package/dist/lifecycle/publish-npm.d.ts +3 -2
  135. package/dist/lifecycle/publish-npm.d.ts.map +1 -1
  136. package/dist/lifecycle/publish-npm.js +4 -3
  137. package/dist/lifecycle/release-at.d.ts +40 -0
  138. package/dist/lifecycle/release-at.d.ts.map +1 -0
  139. package/dist/lifecycle/release-at.js +83 -0
  140. package/dist/lifecycle/release-cut.d.ts.map +1 -1
  141. package/dist/lifecycle/release-cut.js +23 -12
  142. package/dist/lifecycle/release-ledger.d.ts +21 -0
  143. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  144. package/dist/lifecycle/release-ledger.js +24 -0
  145. package/dist/lifecycle/release-publish.d.ts +28 -12
  146. package/dist/lifecycle/release-publish.d.ts.map +1 -1
  147. package/dist/lifecycle/release-publish.js +29 -17
  148. package/dist/lifecycle/release-store.d.ts +25 -2
  149. package/dist/lifecycle/release-store.d.ts.map +1 -1
  150. package/dist/lifecycle/release-store.js +40 -13
  151. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/run-ledger.js +1 -0
  153. package/dist/lifecycle/work-dir.d.ts +45 -0
  154. package/dist/lifecycle/work-dir.d.ts.map +1 -0
  155. package/dist/lifecycle/work-dir.js +78 -0
  156. package/dist/lint/discover.d.ts +17 -9
  157. package/dist/lint/discover.d.ts.map +1 -1
  158. package/dist/lint/discover.js +62 -54
  159. package/dist/lint/rules/op/index.d.ts +2 -1
  160. package/dist/lint/rules/op/index.d.ts.map +1 -1
  161. package/dist/lint/rules/op/index.js +4 -2
  162. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
  163. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
  164. package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
  165. package/dist/module-source.d.ts +57 -0
  166. package/dist/module-source.d.ts.map +1 -0
  167. package/dist/module-source.js +104 -0
  168. package/dist/op/activities/activity-contracts.d.ts +5 -0
  169. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  170. package/dist/op/activities/activity-contracts.js +3 -0
  171. package/dist/op/activities/factory.js +1 -1
  172. package/dist/op/activities/shell.d.ts +38 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -1
  174. package/dist/op/activities/shell.js +89 -3
  175. package/dist/op/builders.d.ts +7 -0
  176. package/dist/op/builders.d.ts.map +1 -1
  177. package/dist/op/builders.js +7 -0
  178. package/dist/op/discover.d.ts.map +1 -1
  179. package/dist/op/discover.js +13 -3
  180. package/dist/op/gate.d.ts.map +1 -1
  181. package/dist/op/gate.js +3 -0
  182. package/dist/op/op-waves-run.d.ts.map +1 -1
  183. package/dist/op/op-waves-run.js +20 -5
  184. package/dist/op/operator.d.ts +2 -2
  185. package/dist/op/operator.js +2 -2
  186. package/dist/op/runtime.d.ts +2 -0
  187. package/dist/op/runtime.d.ts.map +1 -1
  188. package/dist/op/steward.d.ts +6 -4
  189. package/dist/op/steward.d.ts.map +1 -1
  190. package/dist/op/steward.js +5 -3
  191. package/dist/op/work-lease-run.d.ts +20 -7
  192. package/dist/op/work-lease-run.d.ts.map +1 -1
  193. package/dist/op/work-lease-run.js +56 -12
  194. package/dist/pr-forge.d.ts +10 -0
  195. package/dist/pr-forge.d.ts.map +1 -1
  196. package/dist/pr-forge.js +39 -0
  197. package/dist/pr-loop.d.ts +155 -7
  198. package/dist/pr-loop.d.ts.map +1 -1
  199. package/dist/pr-loop.js +137 -11
  200. package/dist/pr-report-url.d.ts +4 -4
  201. package/dist/pr-report-url.d.ts.map +1 -1
  202. package/dist/pr-report-url.js +5 -5
  203. package/dist/runner-start.d.ts +179 -0
  204. package/dist/runner-start.d.ts.map +1 -0
  205. package/dist/runner-start.js +277 -0
  206. package/dist/ts-loader.d.ts +38 -4
  207. package/dist/ts-loader.d.ts.map +1 -1
  208. package/dist/ts-loader.js +190 -16
  209. package/dist/wave-runtime.mjs +238 -231
  210. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
  211. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
  212. package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
  213. package/dist/workspace/chant-migrations.d.ts.map +1 -1
  214. package/dist/workspace/chant-migrations.js +2 -0
  215. package/dist/workspace/check.schema.json +70 -2
  216. package/dist/workspace/checks/boxes.d.ts +6 -6
  217. package/dist/workspace/checks/boxes.js +9 -9
  218. package/dist/workspace/checks/security.d.ts +35 -0
  219. package/dist/workspace/checks/security.d.ts.map +1 -0
  220. package/dist/workspace/checks/security.js +305 -0
  221. package/dist/workspace/checks.d.ts +2 -0
  222. package/dist/workspace/checks.d.ts.map +1 -1
  223. package/dist/workspace/checks.js +5 -0
  224. package/dist/workspace/ci-builds.d.ts +163 -0
  225. package/dist/workspace/ci-builds.d.ts.map +1 -0
  226. package/dist/workspace/ci-builds.js +315 -0
  227. package/dist/workspace/ci-green-cli.d.ts +2 -1
  228. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  229. package/dist/workspace/ci-green-cli.js +25 -5
  230. package/dist/workspace/ci-green-forge.d.ts +18 -4
  231. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  232. package/dist/workspace/ci-green-forge.js +12 -0
  233. package/dist/workspace/ci-green-workflow.d.ts +55 -1
  234. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  235. package/dist/workspace/ci-green-workflow.js +128 -1
  236. package/dist/workspace/ci-green.d.ts +117 -16
  237. package/dist/workspace/ci-green.d.ts.map +1 -1
  238. package/dist/workspace/ci-green.js +358 -43
  239. package/dist/workspace/ci-last-green.schema.json +49 -0
  240. package/dist/workspace/ci-list.schema.json +47 -7
  241. package/dist/workspace/ci-report-url.d.ts +18 -0
  242. package/dist/workspace/ci-report-url.d.ts.map +1 -0
  243. package/dist/workspace/ci-report-url.js +33 -0
  244. package/dist/workspace/ci-run-index.d.ts +13 -1
  245. package/dist/workspace/ci-run-index.d.ts.map +1 -1
  246. package/dist/workspace/ci-run-index.js +6 -4
  247. package/dist/workspace/ci-run-index.schema.json +6 -4
  248. package/dist/workspace/ci-run.d.ts +85 -6
  249. package/dist/workspace/ci-run.d.ts.map +1 -1
  250. package/dist/workspace/ci-run.js +262 -64
  251. package/dist/workspace/ci-runner-key.d.ts +16 -3
  252. package/dist/workspace/ci-runner-key.d.ts.map +1 -1
  253. package/dist/workspace/ci-runner-key.js +30 -10
  254. package/dist/workspace/ci-runner-start.d.ts +77 -0
  255. package/dist/workspace/ci-runner-start.d.ts.map +1 -0
  256. package/dist/workspace/ci-runner-start.js +185 -0
  257. package/dist/workspace/ci-serve.d.ts +130 -11
  258. package/dist/workspace/ci-serve.d.ts.map +1 -1
  259. package/dist/workspace/ci-serve.js +323 -40
  260. package/dist/workspace/declaration.d.ts +25 -0
  261. package/dist/workspace/declaration.d.ts.map +1 -1
  262. package/dist/workspace/declaration.js +14 -2
  263. package/dist/workspace/declaration.schema.json +30 -2
  264. package/dist/workspace/export.d.ts +1 -1
  265. package/dist/workspace/export.d.ts.map +1 -1
  266. package/dist/workspace/export.js +7 -3
  267. package/dist/workspace/ls.d.ts +8 -1
  268. package/dist/workspace/ls.d.ts.map +1 -1
  269. package/dist/workspace/ls.js +2 -1
  270. package/dist/workspace/ls.schema.json +9 -2
  271. package/dist/workspace/member-pipeline.d.ts +1 -0
  272. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  273. package/dist/workspace/member-pipeline.js +2 -0
  274. package/dist/workspace/merge-record.schema.json +49 -0
  275. package/dist/workspace/pin-integrity.d.ts.map +1 -1
  276. package/dist/workspace/pin-integrity.js +3 -2
  277. package/dist/workspace/pr-report.schema.json +75 -8
  278. package/dist/workspace/reason-codes.d.ts +18 -1
  279. package/dist/workspace/reason-codes.d.ts.map +1 -1
  280. package/dist/workspace/reason-codes.js +20 -2
  281. package/dist/workspace/release-candidates.d.ts +129 -0
  282. package/dist/workspace/release-candidates.d.ts.map +1 -0
  283. package/dist/workspace/release-candidates.js +233 -0
  284. package/dist/workspace/release-candidates.schema.json +353 -0
  285. package/dist/workspace/run-event.schema.json +3 -1
  286. package/dist/workspace/security.d.ts +40 -0
  287. package/dist/workspace/security.d.ts.map +1 -0
  288. package/dist/workspace/security.js +99 -0
  289. package/dist/workspace/status.schema.json +3 -1
  290. package/dist/workspace/write-scope.d.ts +9 -0
  291. package/dist/workspace/write-scope.d.ts.map +1 -1
  292. package/dist/workspace/write-scope.js +11 -1
  293. package/package.json +8 -1
  294. package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
  295. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
  296. package/src/ci-jobs.ts +11 -2
  297. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
  298. package/src/cli/commands/audit.test.ts +2 -2
  299. package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
  300. package/src/cli/commands/check-lexicon-plugin.ts +11 -8
  301. package/src/cli/commands/check-lexicon.test.ts +1 -1
  302. package/src/cli/commands/check-lexicon.ts +16 -11
  303. package/src/cli/commands/import.ts +40 -0
  304. package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
  305. package/src/cli/commands/init-lexicon.test.ts +8 -5
  306. package/src/cli/commands/onboard.test.ts +45 -0
  307. package/src/cli/commands/onboard.ts +8 -4
  308. package/src/cli/commands/update.test.ts +6 -0
  309. package/src/cli/commands/update.ts +4 -1
  310. package/src/cli/compiled-cli.e2e.test.ts +76 -11
  311. package/src/cli/dependencies.e2e.test.ts +101 -0
  312. package/src/cli/dependencies.test.ts +93 -0
  313. package/src/cli/dependencies.ts +122 -0
  314. package/src/cli/handlers/build.test.ts +105 -0
  315. package/src/cli/handlers/build.ts +35 -4
  316. package/src/cli/handlers/fan-out.test.ts +73 -0
  317. package/src/cli/handlers/fan-out.ts +11 -4
  318. package/src/cli/handlers/graph.test.ts +76 -0
  319. package/src/cli/handlers/graph.ts +19 -12
  320. package/src/cli/handlers/lifecycle-health.test.ts +123 -0
  321. package/src/cli/handlers/lifecycle-health.ts +157 -0
  322. package/src/cli/handlers/lifecycle.ts +1 -1
  323. package/src/cli/handlers/lint.test.ts +42 -0
  324. package/src/cli/handlers/lint.ts +6 -0
  325. package/src/cli/handlers/operator.ts +3 -3
  326. package/src/cli/handlers/pr-deploy-inputs.test.ts +209 -0
  327. package/src/cli/handlers/pr-record.test.ts +201 -0
  328. package/src/cli/handlers/pr-waves.test.ts +449 -0
  329. package/src/cli/handlers/pr.test.ts +156 -0
  330. package/src/cli/handlers/pr.ts +648 -33
  331. package/src/cli/handlers/promote.test.ts +43 -1
  332. package/src/cli/handlers/promote.ts +19 -3
  333. package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
  334. package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
  335. package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
  336. package/src/cli/handlers/release.e2e.test.ts +19 -28
  337. package/src/cli/handlers/release.ts +81 -11
  338. package/src/cli/handlers/run-components-exit.test.ts +99 -0
  339. package/src/cli/handlers/run-signer.test.ts +79 -0
  340. package/src/cli/handlers/run.ts +34 -16
  341. package/src/cli/main.test.ts +18 -0
  342. package/src/cli/main.ts +120 -33
  343. package/src/cli/parse-args.ts +28 -0
  344. package/src/cli/registry.ts +35 -8
  345. package/src/codegen/generate-post-synth-barrel.ts +2 -2
  346. package/src/codegen/lexicon-regen.ts +1 -1
  347. package/src/codegen/pinned-upgrade.ts +2 -2
  348. package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
  349. package/src/components/capability.ts +51 -3
  350. package/src/components/changed-files.test.ts +16 -1
  351. package/src/components/changed-files.ts +9 -1
  352. package/src/components/deploy-inputs.test.ts +108 -0
  353. package/src/components/deploy-inputs.ts +225 -0
  354. package/src/components/driver.test.ts +36 -1
  355. package/src/components/driver.ts +87 -4
  356. package/src/components/fan-out-record.ts +29 -1
  357. package/src/components/fan-out-run.test.ts +35 -0
  358. package/src/components/fan-out-run.ts +40 -1
  359. package/src/components/gate-plan.ts +9 -0
  360. package/src/components/pr-pipeline.test.ts +100 -0
  361. package/src/components/pr-pipeline.ts +184 -28
  362. package/src/components/pr-run.test.ts +323 -18
  363. package/src/components/pr-run.ts +355 -76
  364. package/src/components/release-compile.test.ts +34 -0
  365. package/src/components/release-compile.ts +89 -8
  366. package/src/components/release-promote.test.ts +55 -2
  367. package/src/components/release-promote.ts +93 -23
  368. package/src/components/verbs/bom-writer.ts +1 -1
  369. package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
  370. package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
  371. package/src/components/wave-plan.ts +48 -8
  372. package/src/discovery/fold-host-method.test.ts +87 -0
  373. package/src/discovery/fold-import.ts +15 -5
  374. package/src/discovery/fold-package-composite.test.ts +27 -0
  375. package/src/discovery/fold-specifiers.test.ts +8 -0
  376. package/src/discovery/sandbox/bundle.ts +6 -0
  377. package/src/discovery/specifier-resolve.ts +8 -2
  378. package/src/fold/fold.test.ts +72 -0
  379. package/src/fold/fold.ts +71 -0
  380. package/src/fold/subset.test.ts +31 -0
  381. package/src/fold/subset.ts +99 -0
  382. package/src/graph-detail.test.ts +57 -0
  383. package/src/graph-detail.ts +33 -7
  384. package/src/health.schema.json +191 -0
  385. package/src/health.test.ts +62 -0
  386. package/src/health.ts +178 -0
  387. package/src/lexicon-dist.e2e.test.ts +254 -0
  388. package/src/lexicon-module.test.ts +47 -0
  389. package/src/lexicon-module.ts +49 -7
  390. package/src/lexicon-plugin-helpers.ts +6 -4
  391. package/src/lexicon.ts +43 -1
  392. package/src/lifecycle/affected.test.ts +7 -0
  393. package/src/lifecycle/affected.ts +6 -1
  394. package/src/lifecycle/merge-record.test.ts +111 -0
  395. package/src/lifecycle/merge-record.ts +154 -0
  396. package/src/lifecycle/publish-attachments.ts +25 -13
  397. package/src/lifecycle/publish-npm.ts +4 -3
  398. package/src/lifecycle/publish-targets.test.ts +34 -4
  399. package/src/lifecycle/release-at.test.ts +48 -0
  400. package/src/lifecycle/release-at.ts +100 -0
  401. package/src/lifecycle/release-cut.test.ts +41 -0
  402. package/src/lifecycle/release-cut.ts +22 -11
  403. package/src/lifecycle/release-ledger.ts +34 -0
  404. package/src/lifecycle/release-publish.test.ts +43 -13
  405. package/src/lifecycle/release-publish.ts +38 -18
  406. package/src/lifecycle/release-store.ts +57 -13
  407. package/src/lifecycle/run-ledger.test.ts +13 -0
  408. package/src/lifecycle/run-ledger.ts +1 -0
  409. package/src/lifecycle/work-dir.test.ts +77 -0
  410. package/src/lifecycle/work-dir.ts +82 -0
  411. package/src/lint/discover.test.ts +46 -2
  412. package/src/lint/discover.ts +55 -49
  413. package/src/lint/rules/op/index.ts +4 -2
  414. package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
  415. package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
  416. package/src/module-source.test.ts +85 -0
  417. package/src/module-source.ts +112 -0
  418. package/src/op/activities/activity-contracts.ts +3 -0
  419. package/src/op/activities/factory.ts +1 -1
  420. package/src/op/activities/shell-container.e2e.test.ts +67 -0
  421. package/src/op/activities/shell.test.ts +44 -1
  422. package/src/op/activities/shell.ts +110 -3
  423. package/src/op/builders.ts +7 -0
  424. package/src/op/discover-root.test.ts +31 -2
  425. package/src/op/discover.ts +14 -4
  426. package/src/op/gate.test.ts +30 -0
  427. package/src/op/gate.ts +3 -0
  428. package/src/op/op-waves-run.ts +20 -5
  429. package/src/op/op-waves.test.ts +49 -0
  430. package/src/op/operator.ts +2 -2
  431. package/src/op/runtime.ts +2 -0
  432. package/src/op/step-console.test.ts +4 -2
  433. package/src/op/steward.ts +6 -4
  434. package/src/op/work-lease-run.test.ts +88 -2
  435. package/src/op/work-lease-run.ts +52 -12
  436. package/src/pr-forge-bundle.test.ts +2 -2
  437. package/src/pr-forge.test.ts +42 -0
  438. package/src/pr-forge.ts +40 -0
  439. package/src/pr-loop-bundle.test.ts +2 -1
  440. package/src/pr-loop.test.ts +146 -1
  441. package/src/pr-loop.ts +278 -17
  442. package/src/pr-report-url.ts +7 -7
  443. package/src/runner-start-bundle.test.ts +29 -0
  444. package/src/runner-start.test.ts +179 -0
  445. package/src/runner-start.ts +329 -0
  446. package/src/terraform/__fixtures__/advise.test.ts +21 -2
  447. package/src/ts-loader.test.ts +89 -1
  448. package/src/ts-loader.ts +180 -13
  449. package/src/workspace/changes.test.ts +1 -1
  450. package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
  451. package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
  452. package/src/workspace/chant-migrations.e2e.test.ts +5 -0
  453. package/src/workspace/chant-migrations.ts +2 -0
  454. package/src/workspace/check-contract.test.ts +3 -2
  455. package/src/workspace/check.schema.json +70 -2
  456. package/src/workspace/checks/boxes.ts +9 -9
  457. package/src/workspace/checks/security.test.ts +138 -0
  458. package/src/workspace/checks/security.ts +305 -0
  459. package/src/workspace/checks.ts +5 -0
  460. package/src/workspace/ci-builds.e2e.test.ts +208 -0
  461. package/src/workspace/ci-builds.test.ts +174 -0
  462. package/src/workspace/ci-builds.ts +385 -0
  463. package/src/workspace/ci-green-builds.test.ts +180 -0
  464. package/src/workspace/ci-green-cli.test.ts +54 -0
  465. package/src/workspace/ci-green-cli.ts +26 -5
  466. package/src/workspace/ci-green-forge.ts +30 -4
  467. package/src/workspace/ci-green-runs.test.ts +53 -11
  468. package/src/workspace/ci-green-workflow.test.ts +84 -1
  469. package/src/workspace/ci-green-workflow.ts +139 -2
  470. package/src/workspace/ci-green.test.ts +6 -3
  471. package/src/workspace/ci-green.ts +408 -48
  472. package/src/workspace/ci-last-green.schema.json +49 -0
  473. package/src/workspace/ci-list.schema.json +47 -7
  474. package/src/workspace/ci-report-url.test.ts +220 -0
  475. package/src/workspace/ci-report-url.ts +33 -0
  476. package/src/workspace/ci-run-index.schema.json +6 -4
  477. package/src/workspace/ci-run-index.test.ts +42 -3
  478. package/src/workspace/ci-run-index.ts +19 -5
  479. package/src/workspace/ci-run.test.ts +203 -8
  480. package/src/workspace/ci-run.ts +295 -63
  481. package/src/workspace/ci-runner-key.test.ts +55 -17
  482. package/src/workspace/ci-runner-key.ts +36 -11
  483. package/src/workspace/ci-runner-start.test.ts +151 -0
  484. package/src/workspace/ci-runner-start.ts +193 -0
  485. package/src/workspace/ci-serve-builds.test.ts +86 -0
  486. package/src/workspace/ci-serve.test.ts +209 -6
  487. package/src/workspace/ci-serve.ts +341 -42
  488. package/src/workspace/declaration.schema.json +30 -2
  489. package/src/workspace/declaration.test.ts +40 -0
  490. package/src/workspace/declaration.ts +40 -3
  491. package/src/workspace/export.ts +6 -3
  492. package/src/workspace/ls.schema.json +9 -2
  493. package/src/workspace/ls.ts +10 -4
  494. package/src/workspace/member-pipeline.ts +2 -1
  495. package/src/workspace/merge-record.schema.json +49 -0
  496. package/src/workspace/pin-integrity.test.ts +5 -0
  497. package/src/workspace/pin-integrity.ts +3 -2
  498. package/src/workspace/pr-report.schema.json +75 -8
  499. package/src/workspace/reason-codes.test.ts +2 -0
  500. package/src/workspace/reason-codes.ts +20 -2
  501. package/src/workspace/release-candidates.schema.json +353 -0
  502. package/src/workspace/release-candidates.test.ts +106 -0
  503. package/src/workspace/release-candidates.ts +315 -0
  504. package/src/workspace/run-event.schema.json +3 -1
  505. package/src/workspace/security.test.ts +70 -0
  506. package/src/workspace/security.ts +118 -0
  507. package/src/workspace/status.schema.json +3 -1
  508. package/src/workspace/write-scope.test.ts +29 -1
  509. package/src/workspace/write-scope.ts +12 -1
@@ -177,6 +177,11 @@
177
177
  "properties": {
178
178
  "green": {
179
179
  "$ref": "#/$defs/ciGreen"
180
+ },
181
+ "reportUrl": {
182
+ "type": "string",
183
+ "minLength": 1,
184
+ "description": "Where the pull-request jobs copy their reports and events, and where chant ci run keeps the run index, <reportUrl>/runs/index.json (#4160): an s3://<bucket>/<prefix> or file://<directory> URL, as --report-url takes. chant build --pr-loop, chant ci run, chant ci serve and chant ci runs use it when --report-url is not given, and the flag wins. Readers find it in chant workspace ls --json as ci.reportUrl. Added in schema 1 by chant 0.124.32, so a declaration that uses it sets minReader to 0.124.32 or newer."
180
185
  }
181
186
  }
182
187
  },
@@ -231,6 +236,14 @@
231
236
  "description": "A deploy counts as failed when, within this many days after it, the commit it deployed is revoked or the environment is rolled back from it. The default is 7."
232
237
  }
233
238
  }
239
+ },
240
+ "security": {
241
+ "type": "array",
242
+ "uniqueItems": true,
243
+ "description": "The security groups the workspace opts into (#4168), for every member; a member's own security adds to them. With none, a security feature the workspace has not turned on never refuses, warns or hides anything. verified-releases: release publish and promote --release take only a verified release. supply-chain: a publish without OIDC provenance warns, and a target with no SBOM source is refused. who-ran-it: ci tick needs a runner key. review-rules: pr-apply requires a forge review. isolated-runners: an apply job requires a runner-start statement. workspace check reports what a declared group lacks (WSP161 to WSP165). Added in schema 1 by chant 0.124.33, so a declaration that uses it sets minReader to 0.124.33 or newer.",
244
+ "items": {
245
+ "enum": ["verified-releases", "supply-chain", "who-ran-it", "review-rules", "isolated-runners"]
246
+ }
234
247
  }
235
248
  },
236
249
  "patternProperties": {
@@ -482,6 +495,14 @@
482
495
  "type": "boolean",
483
496
  "description": "Whether the member goes with an export (#2524 D10, #2552). chant workspace export writes only members that set travel to true into the export member, and refuses to name one that does not. Added in schema 1 by chant 0.101.0, so a declaration that uses it sets minReader to 0.101.0 or newer."
484
497
  },
498
+ "security": {
499
+ "type": "array",
500
+ "uniqueItems": true,
501
+ "description": "The security groups this member opts into, added to the declaration's top-level security (#4168). A release, publish or pull-request job of this member runs under both lists. Added in schema 1 by chant 0.124.33, so a declaration that uses it sets minReader to 0.124.33 or newer.",
502
+ "items": {
503
+ "enum": ["verified-releases", "supply-chain", "who-ran-it", "review-rules", "isolated-runners"]
504
+ }
505
+ },
485
506
  "because": {
486
507
  "type": "string",
487
508
  "minLength": 1,
@@ -581,7 +602,7 @@
581
602
  },
582
603
  "box": {
583
604
  "type": "object",
584
- "description": "The member is a box, or holds a box's declarations (#2726). A box holds no credential: each capability it needs outside itself is reached through a broker, a runtime such as a lobby or a door, which holds the credential and enforces the scope. chant workspace check fails when a file in the member's directory carries a literal secret (WSP121) and when a capability names no broker (WSP122). chant workspace status --json lists the capabilities, so a broker can read the scopes. Its host, slot, ports, state and cookies state the box's isolation (#2727): chant derives each value from the box's identity, its host, the member's name and its slot, and prints them in chant workspace status --json, so a runtime reads them instead of choosing its own. chant workspace check fails when two boxes on a host resolve to the same value (WSP123) and when a box hard-codes a machine path (WSP124). A member that builds the fountain lexicon's Box declares the callback token fountain gives its persistent sandbox as the capability fountain-callback, brokered by fountain, with scope owner, or chant workspace check fails (WSP125, #2780). Its intent names the decision record that says what the box is for (#2850): chant workspace status --json reports the record's state and answer, and chant workspace check fails when no decision record has the id (WSP126) and warns when the record constrains no member or path of this workspace (WSP127, #2857). Its services list what the box runs under its supervisor (#2880), which the fly lexicon observes, restarts and applies through sprite-env, and which chant workspace status --json prints. Its factory declares what the box builds, how a build is checked, which member declares the builder agents and where a finished build is published (#3146, ws-077), its listing what the box shows of itself (#3146), and its replicate where the box's work in progress is pushed so a lost box loses none of it (#3172, ws-085). Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
605
+ "description": "The member is a box, or holds a box's declarations (#2726). A box holds no credential: each capability it needs outside itself is reached through a broker, a runtime such as a lobby or a door, which holds the credential and enforces the scope. chant workspace check fails when a file in the member's directory carries a literal secret (WSP121) and when a capability names no broker (WSP122). chant workspace status --json lists the capabilities, so a broker can read the scopes. Its host, slot, ports, state and cookies state the box's isolation (#2727): chant derives each value from the box's identity, its host, the member's name and its slot, and prints them in chant workspace status --json, so a runtime reads them instead of choosing its own. chant workspace check fails when two boxes on a host resolve to the same value (WSP123) and when a box hard-codes a machine path (WSP124). A member that builds the fountain lexicon's Box declares the callback token fountain gives its sandbox as the capability fountain-callback, brokered by fountain, with scope owner, or chant workspace check fails (WSP125, #2780). Its intent names the decision record that says what the box is for (#2850): chant workspace status --json reports the record's state and answer, and chant workspace check fails when no decision record has the id (WSP126) and warns when the record constrains no member or path of this workspace (WSP127, #2857). Its services list what the box runs under its supervisor (#2880), which the fly lexicon observes, restarts and applies through sprite-env, and which chant workspace status --json prints. Its factory declares what the box builds, how a build is checked, which member declares the builder agents and where a finished build is published (#3146, ws-077), its listing what the box shows of itself (#3146), and its replicate where the box's work in progress is pushed so a lost box loses none of it (#3172, ws-085). Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
585
606
  "properties": {
586
607
  "intent": {
587
608
  "type": "string",
@@ -1518,7 +1539,7 @@
1518
1539
  "signedSince": {
1519
1540
  "type": "string",
1520
1541
  "pattern": "^[0-9a-f]{40}([0-9a-f]{24})?$",
1521
- "description": "Added by #4031, read by chant 0.124.28 and newer. The full sha of the first commit on branch whose ci/green and ci/revoked tags must carry a DSSE statement in their annotation, signed by a key .chant/trust.json at base lists under runners for a principal holding the runner role. A tag on a strict first-parent ancestor of this commit counts unsigned, so existing tags keep working; a tag on any other commit, this one included, needs a statement. Position in history decides, never a date, which whoever makes a commit or a tag sets. A reader refuses a sha that names no commit in its clone with declaration-invalid. Absent, no tag needs a statement."
1542
+ "description": "Added by #4031, read by chant 0.124.28 and newer. The full sha of the first commit on branch whose ci/green and ci/revoked tags must carry a DSSE statement in their annotation, signed by a key .chant/trust.json at base lists under runners for a principal holding the runner role. A tag on a strict first-parent ancestor of this commit counts unsigned, so existing tags keep working; a tag on any other commit, this one included, needs a statement. Position in history decides, never a date, which whoever makes a commit or a tag sets. A reader refuses a sha that names no commit in its clone with declaration-invalid. Absent, no tag needs a statement. Since chant 0.124.32 (#4156) it covers Op run records the same way, when ci.green.source is runs: an unsigned run counts on a strict first-parent ancestor of this commit and needs a statement on any other, ci serve refuses to start without a runner key trusted at the target's head, and ci run and chant run warn about a run they leave unsigned. Absent, an unsigned run counts and nothing asks for a key."
1522
1543
  },
1523
1544
  "source": {
1524
1545
  "enum": [
@@ -1557,6 +1578,13 @@
1557
1578
  "fail"
1558
1579
  ],
1559
1580
  "description": "What a check run that finished as skipped counts as. fail (the default): it never passes. pass: it passes, for a job a path filter runs only on some commits."
1581
+ },
1582
+ "build": {
1583
+ "enum": [
1584
+ "every",
1585
+ "newest"
1586
+ ],
1587
+ "description": "Added by #4169, read by chant 0.124.33 and newer. Which first-parent commits of the branch the phase runs on. every (the default): each one. newest: only the newest commit when a runner frees. Under either, a run that was cancelled leaves the commit unbuilt rather than red. Under newest, a commit a newer run superseded is unbuilt too, and a red commit starts a bisect over the unbuilt commits back to the last one the phase passed on. chant ci workflow writes the triggers and concurrency of the workflows holding a phase that sets build, and leaves them alone for a phase that does not."
1560
1588
  }
1561
1589
  },
1562
1590
  "patternProperties": {
@@ -436,6 +436,46 @@ describe("retention (#4036)", () => {
436
436
  });
437
437
  });
438
438
 
439
+ describe("ci.reportUrl (#4160)", () => {
440
+ test("an s3:// or file:// URL is read without its trailing slash, beside green or alone, and is null when absent", () => {
441
+ expect(parse(base([])).ci).toBeNull();
442
+ expect(parse(base([], { ci: {} })).ci).toEqual({ green: null, reportUrl: null });
443
+ expect(parse(base([], { ci: { reportUrl: "s3://acme-reports/prod/" } })).ci).toEqual({ green: null, reportUrl: "s3://acme-reports/prod" });
444
+ const green = { branch: "main", phases: { build: ["build"] }, require: ["build"] };
445
+ const d = parse(base([], { ci: { green, reportUrl: "file:///srv/chant-reports" } }));
446
+ expect(d.ci?.reportUrl).toBe("file:///srv/chant-reports");
447
+ expect(d.ci?.green?.branch).toBe("main");
448
+ });
449
+
450
+ test("a URL no job can upload to is declaration-invalid, at ci.reportUrl, with the reason --report-url gives", () => {
451
+ for (const reportUrl of ["https://reports.example/acme", "ftp://example/x", "reports/"]) {
452
+ const err = failure(base([], { ci: { reportUrl } }));
453
+ expect(err.code).toBe("declaration-invalid");
454
+ expect(err.message).toBe(`ci.reportUrl ${reportUrl}: takes an s3://<bucket>/<prefix> or file://<directory> URL`);
455
+ expect(err.location?.line).toBeGreaterThan(1);
456
+ }
457
+ expect(failure(base([], { ci: { reportUrl: "" } })).code).toBe("declaration-invalid");
458
+ expect(failure(base([], { ci: { reportUrl: 7 } })).code).toBe("declaration-invalid");
459
+ });
460
+ });
461
+
462
+ describe("security (#4168)", () => {
463
+ test("the groups are read in file order, empty when absent, and securityGroupsOf reads them", async () => {
464
+ const { securityGroupsOf } = await import("./security");
465
+ expect(parse(base([])).security).toEqual([]);
466
+ const decl = parse(base([], { security: ["supply-chain", "verified-releases"] }));
467
+ expect(decl.security).toEqual(["supply-chain", "verified-releases"]);
468
+ expect([...securityGroupsOf(decl)]).toEqual(["supply-chain", "verified-releases"]);
469
+ expect(securityGroupsOf(null).size).toBe(0);
470
+ });
471
+
472
+ test("an unknown group, a repeated group and a non-array are refused", () => {
473
+ for (const security of [["signed"], ["supply-chain", "supply-chain"], "supply-chain"]) {
474
+ expect(failure(base([], { security })).code).toBe("declaration-invalid");
475
+ }
476
+ });
477
+ });
478
+
439
479
  describe("metrics (#4039)", () => {
440
480
  test("failureWindowDays is read as written, without x- keys, and the block is null when absent", () => {
441
481
  expect(parse(base([])).metrics).toBeNull();
@@ -17,11 +17,13 @@
17
17
  */
18
18
 
19
19
  import { RETENTION_KINDS, type RetentionOverride } from "../lifecycle/retention-policy";
20
+ import { parseReportUrl } from "../pr-report-url";
20
21
  import schema from "./declaration.schema.json" with { type: "json" };
21
22
  import { expandGlob } from "./glob";
22
23
  import { EXAMPLES_KIND, holdsChantProject } from "./kinds";
23
24
  import { parseJsonText, pointerToken, type TextLocation } from "./jsonc";
24
25
  import type { ReasonCode } from "./reason-codes";
26
+ import type { SecurityGroup } from "./security";
25
27
  import { joinPath, type WorkspaceTree } from "./tree";
26
28
  import { loadAjv2020 } from "./ajv2020";
27
29
  import { readChantPackageVersion } from "../package-version";
@@ -183,6 +185,13 @@ export interface AgentDeclaration {
183
185
  /** What a check run that finished as skipped counts as in a CI phase (#3573). */
184
186
  export type CiSkipped = "pass" | "fail";
185
187
 
188
+ /**
189
+ * Which commits a phase runs on (#4169): `every` first-parent commit of the
190
+ * branch, or only the `newest` one when a runner frees, the commits between
191
+ * left unbuilt and a red one bisected.
192
+ */
193
+ export type CiBuild = "every" | "newest";
194
+
186
195
  /** One phase of `ci.green`: the check runs that make it up (#3573, ws-103). */
187
196
  export interface CiPhase {
188
197
  name: string;
@@ -190,6 +199,12 @@ export interface CiPhase {
190
199
  runs: string[];
191
200
  /** `fail` (the default): a skipped run never passes. `pass`: it passes, for a job a path filter runs only on some commits. */
192
201
  skipped: CiSkipped;
202
+ /**
203
+ * Which commits the phase runs on (#4169), when the declaration says.
204
+ * Absent means `every`, and `ci workflow` then leaves the phase's
205
+ * workflows as they are.
206
+ */
207
+ build?: CiBuild;
193
208
  pointer: string;
194
209
  }
195
210
 
@@ -232,6 +247,14 @@ export type CiSource = "checks" | "runs";
232
247
  /** The declaration's `ci` block (#3573). */
233
248
  export interface CiDeclaration {
234
249
  green: CiGreen | null;
250
+ /**
251
+ * `ci.reportUrl` (#4160): where the pull-request jobs copy their reports
252
+ * and `chant ci run` keeps the run index, `<reportUrl>/runs/index.json`.
253
+ * An `s3://` or `file://` URL, as `--report-url` takes, without a trailing
254
+ * slash. The commands that take `--report-url` default to it. Null when
255
+ * the declaration sets none.
256
+ */
257
+ reportUrl: string | null;
235
258
  }
236
259
 
237
260
  export interface MemberRole {
@@ -548,6 +571,8 @@ export interface Member {
548
571
  because: string | null;
549
572
  /** Whether `chant workspace export` takes the member (#2552, D10). False when the entry does not say. */
550
573
  travel: boolean;
574
+ /** The security groups this member adds to the declaration's top-level `security` (#4168 step 7), in file order; empty when it names none. */
575
+ security: SecurityGroup[];
551
576
  suppress: Suppression[];
552
577
  /** The entry's JSON Pointer in the file, for messages. */
553
578
  pointer: string;
@@ -615,6 +640,8 @@ export interface Declaration {
615
640
  * then uses 7.
616
641
  */
617
642
  metrics: { failureWindowDays?: number } | null;
643
+ /** The security groups the workspace opts into (#4168 section 8, ./security.ts), in file order; empty when the declaration has no `security` key. */
644
+ security: SecurityGroup[];
618
645
  /** The file, relative to the workspace root's tree (`chant.workspace.json` or `.jsonc`). */
619
646
  file: string;
620
647
  }
@@ -841,6 +868,7 @@ export function parseDeclaration(text: string, file: string, reader: string = re
841
868
  upstream: (e.upstream as string | undefined) ?? null,
842
869
  because: (e.because as string | undefined) ?? null,
843
870
  travel: e.travel === true,
871
+ security: [...((e.security as SecurityGroup[] | undefined) ?? [])],
844
872
  suppress,
845
873
  pointer,
846
874
  };
@@ -993,6 +1021,7 @@ export function parseDeclaration(text: string, file: string, reader: string = re
993
1021
  ci,
994
1022
  retention: retentionOf(obj.retention),
995
1023
  metrics: metricsOf(obj.metrics),
1024
+ security: [...((obj.security as SecurityGroup[] | undefined) ?? [])],
996
1025
  file,
997
1026
  };
998
1027
  written.set(declaration, raw);
@@ -1087,13 +1116,21 @@ function retentionOf(raw: unknown): RetentionOverride | null {
1087
1116
 
1088
1117
  function ciOf(raw: unknown, at: (pointer: string, key?: boolean) => ErrorLocation): CiDeclaration | null {
1089
1118
  if (raw === undefined) return null;
1090
- const block = raw as { green?: { branch: string; window?: string; phases: Record<string, string[] | { runs: string[]; skipped?: CiSkipped }>; require: string[]; signedSince?: string; source?: CiSource } };
1091
- if (block.green === undefined) return { green: null };
1119
+ const block = raw as { reportUrl?: string; green?: { branch: string; window?: string; phases: Record<string, string[] | { runs: string[]; skipped?: CiSkipped; build?: CiBuild }>; require: string[]; signedSince?: string; source?: CiSource } };
1120
+ let reportUrl: string | null = null;
1121
+ if (block.reportUrl !== undefined) {
1122
+ // #4160: refused here as pr-plan and ci run refuse the flag, so a reader never gets a URL no job can write to.
1123
+ const target = parseReportUrl(block.reportUrl, "ci.reportUrl");
1124
+ if ("error" in target) throw new WorkspaceReadError("declaration-invalid", target.error, at("/ci/reportUrl"));
1125
+ reportUrl = target.url;
1126
+ }
1127
+ if (block.green === undefined) return { green: null, reportUrl };
1092
1128
  const g = block.green;
1093
1129
  const phases: CiPhase[] = Object.entries(g.phases).map(([name, p]) => ({
1094
1130
  name,
1095
1131
  runs: [...(Array.isArray(p) ? p : p.runs)],
1096
1132
  skipped: Array.isArray(p) ? "fail" : (p.skipped ?? "fail"),
1133
+ ...(!Array.isArray(p) && p.build !== undefined ? { build: p.build } : {}),
1097
1134
  pointer: `/ci/green/phases/${pointerToken(name)}`,
1098
1135
  }));
1099
1136
  for (const [i, name] of g.require.entries()) {
@@ -1104,7 +1141,7 @@ function ciOf(raw: unknown, at: (pointer: string, key?: boolean) => ErrorLocatio
1104
1141
  at(`/ci/green/require/${i}`),
1105
1142
  );
1106
1143
  }
1107
- return { green: { branch: g.branch, window: g.window ?? DEFAULT_CI_WINDOW, phases, require: [...g.require], signedSince: g.signedSince ?? null, source: g.source ?? "checks", pointer: "/ci/green" } };
1144
+ return { green: { branch: g.branch, window: g.window ?? DEFAULT_CI_WINDOW, phases, require: [...g.require], signedSince: g.signedSince ?? null, source: g.source ?? "checks", pointer: "/ci/green" }, reportUrl };
1108
1145
  }
1109
1146
 
1110
1147
  function agentsOf(raw: unknown, members: Member[], at: (pointer: string, key?: boolean) => ErrorLocation): AgentDeclaration[] {
@@ -44,6 +44,7 @@ import { parseJsonText } from "./jsonc";
44
44
  import { fileHash, LOCK_FILE, LockError, parseLock, renderLock, type Lineage, type LineageLock } from "./lineage-lock";
45
45
  import { loadRecordKind } from "./records";
46
46
  import { workingTree } from "./tree";
47
+ import { isWorkDir } from "../lifecycle/work-dir";
47
48
 
48
49
  /** The role that marks the member an export is written into. */
49
50
  export const EXPORT_ROLE = "export";
@@ -142,7 +143,7 @@ export function gitTopOf(dir: string): string | undefined {
142
143
  /**
143
144
  * The files under `dir` (absolute) that git tracks or would track, relative
144
145
  * to `dir`, that exist in the working tree. Outside git, every file, leaving
145
- * out `.git` and `node_modules`.
146
+ * out `.git`, `node_modules` and `.chant/work`.
146
147
  */
147
148
  export function listFiles(dir: string): string[] {
148
149
  if (!existsSync(dir)) return [];
@@ -167,8 +168,10 @@ export function listFiles(dir: string): string[] {
167
168
  for (const d of readdirSync(join(dir, rel), { withFileTypes: true })) {
168
169
  if (d.name === ".git" || d.name === "node_modules") continue;
169
170
  const p = rel ? `${rel}/${d.name}` : d.name;
170
- if (d.isDirectory()) walk(p);
171
- else if (d.isFile()) out.push(p);
171
+ // `.chant/work` holds work worktrees, each a copy of the checkout (#2893).
172
+ if (d.isDirectory()) {
173
+ if (!isWorkDir(p)) walk(p);
174
+ } else if (d.isFile()) out.push(p);
172
175
  }
173
176
  };
174
177
  walk("");
@@ -21,7 +21,8 @@
21
21
  "properties": {
22
22
  "name": { "type": "string" },
23
23
  "runs": { "type": "array", "items": { "type": "string" }, "description": "Check-run name patterns, * standing for any run of characters." },
24
- "skipped": { "enum": ["pass", "fail"], "description": "What a run that finished as skipped counts as." }
24
+ "skipped": { "enum": ["pass", "fail"], "description": "What a run that finished as skipped counts as." },
25
+ "build": { "enum": ["every", "newest"], "description": "Added in contract 1 by #4169, written by chant 0.124.33 and newer, and only when the declaration sets it: whether the phase runs on every first-parent commit or only the newest one when a runner frees. Absent means every." }
25
26
  }
26
27
  }
27
28
  },
@@ -103,7 +104,13 @@
103
104
  {
104
105
  "type": "object",
105
106
  "required": ["green"],
106
- "properties": { "green": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/ciGreen" }] } }
107
+ "properties": {
108
+ "green": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/ciGreen" }] },
109
+ "reportUrl": {
110
+ "type": "string",
111
+ "description": "Added in contract 1 by chant 0.124.32 (#4160). The declaration's ci.reportUrl, an s3:// or file:// URL without a trailing slash, present only when it is set. The run index is at <reportUrl>/runs/index.json (ci-run-index), and each job's report under <reportUrl>/<pr>/<commit>[/<member>]/."
112
+ }
113
+ }
107
114
  }
108
115
  ]
109
116
  },
@@ -142,7 +142,8 @@ export interface LsDiagram {
142
142
  export interface LsCiGreen {
143
143
  branch: string;
144
144
  window: string;
145
- phases: { name: string; runs: string[]; skipped: "pass" | "fail" }[];
145
+ /** `build` is present only when the declaration sets it (#4169). */
146
+ phases: { name: string; runs: string[]; skipped: "pass" | "fail"; build?: "every" | "newest" }[];
146
147
  require: string[];
147
148
  /** The first commit whose ci tags need a signed statement (#4031). Present only when the declaration sets it. */
148
149
  signedSince?: string;
@@ -186,8 +187,12 @@ export type LsDocument =
186
187
  groups: LsGroup[];
187
188
  /** Every declared diagram, the workspace's own first, then each member's, in file order (#2764). */
188
189
  diagrams: LsDiagram[];
189
- /** What the workspace's CI decides about its commits (#3573), or null with no `ci` block. */
190
- ci: { green: LsCiGreen | null } | null;
190
+ /**
191
+ * What the workspace's CI decides about its commits (#3573), or null
192
+ * with no `ci` block. `reportUrl` (#4160) is the declared report URL,
193
+ * where the run index is kept, present only when it is set.
194
+ */
195
+ ci: { green: LsCiGreen | null; reportUrl?: string } | null;
191
196
  summary: { members: number; unreadable: number; groups: number; matches: number };
192
197
  }
193
198
  | {
@@ -324,12 +329,13 @@ function readListing(query: LsQuery): { doc: LsDocument; declaration?: Declarati
324
329
  ? {
325
330
  branch: declaration.ci.green.branch,
326
331
  window: declaration.ci.green.window,
327
- phases: declaration.ci.green.phases.map((p) => ({ name: p.name, runs: p.runs, skipped: p.skipped })),
332
+ phases: declaration.ci.green.phases.map((p) => ({ name: p.name, runs: p.runs, skipped: p.skipped, ...(p.build ? { build: p.build } : {}) })),
328
333
  require: declaration.ci.green.require,
329
334
  ...(declaration.ci.green.signedSince !== null ? { signedSince: declaration.ci.green.signedSince } : {}),
330
335
  ...(declaration.ci.green.source === "runs" ? { source: "runs" as const } : {}),
331
336
  }
332
337
  : null,
338
+ ...(declaration.ci.reportUrl !== null ? { reportUrl: declaration.ci.reportUrl } : {}),
333
339
  }
334
340
  : null,
335
341
  summary: {
@@ -212,7 +212,7 @@ export interface ComponentPlanInput {
212
212
  params?: string[];
213
213
  paramsFile?: string;
214
214
  /** `--pr-loop`, with its `--gate` and `--branch` (#3465). */
215
- prLoop?: { gate?: string; branch?: string };
215
+ prLoop?: { gate?: string; branch?: string; applyOnMerge?: boolean };
216
216
  /** `--wave-gate` with its `--canary` and `--base` (#3049). */
217
217
  waveGate?: { gate: string; canary?: string[]; base?: string };
218
218
  /** `--image` (#4002). */
@@ -258,6 +258,7 @@ export function planMemberComponentPipeline(input: ComponentPlanInput): MemberCo
258
258
  parts.push("--pr-loop");
259
259
  if (input.prLoop.gate) parts.push("--gate", input.prLoop.gate);
260
260
  if (input.prLoop.branch) parts.push("--branch", input.prLoop.branch);
261
+ if (input.prLoop.applyOnMerge) parts.push("--apply-on-merge");
261
262
  }
262
263
  if (input.image) parts.push("--image", input.image);
263
264
  for (const line of input.beforeScript ?? []) parts.push("--before-script", line);
@@ -0,0 +1,49 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/merge-record/v1/merge-record.schema.json",
4
+ "title": "chant merge record",
5
+ "description": "What landed on the target branch, keyed by commit: _merges/<commit>.json on chant/lifecycle (#4168, chant 0.124.33 and newer). The record job writes it on merge. It applies nothing; a release that carries the commit deploys it.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["$schema", "contract", "commit", "base", "env", "source", "op", "gate", "digest", "plan", "approvedBy", "components", "recordedAt"],
9
+ "properties": {
10
+ "$schema": { "const": "https://intentius.io/chant/schemas/workspace/merge-record/v1/merge-record.schema.json" },
11
+ "contract": { "const": 1 },
12
+ "commit": { "type": "string", "pattern": "^[0-9a-f]{40,64}$", "description": "The merged commit." },
13
+ "base": { "type": "string", "pattern": "^[0-9a-f]{40,64}$", "description": "The commit the change is measured from." },
14
+ "env": { "type": "string", "minLength": 1 },
15
+ "member": { "type": "string", "minLength": 1, "description": "The workspace member whose pipeline wrote it." },
16
+ "source": {
17
+ "description": "Where the change came from: the pull request that merged it, else the work items its Chant-Record: work:<id> trailers name, else a direct push.",
18
+ "oneOf": [
19
+ { "type": "object", "additionalProperties": false, "required": ["kind", "pr"], "properties": { "kind": { "const": "pull-request" }, "pr": { "type": "integer", "minimum": 1 } } },
20
+ {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["kind", "records"],
24
+ "properties": {
25
+ "kind": { "const": "work-item" },
26
+ "records": {
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "items": { "type": "object", "additionalProperties": false, "required": ["kind", "id"], "properties": { "kind": { "const": "work" }, "id": { "type": "string", "minLength": 1 } } }
30
+ }
31
+ }
32
+ },
33
+ { "type": "object", "additionalProperties": false, "required": ["kind"], "properties": { "kind": { "const": "direct-push" } } }
34
+ ]
35
+ },
36
+ "op": { "type": ["string", "null"], "description": "The pull request's gate op, pr-<n> or pr-<n>-<member>; null without a pull request." },
37
+ "gate": { "type": "string", "minLength": 1 },
38
+ "digest": { "type": ["string", "null"], "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "The change-set digest planned on the merged commit; null when nothing was planned. The change set is stored under _change-sets/." },
39
+ "plan": {
40
+ "enum": ["approved", "changed", "unapproved", "nothing", "plan-failed"],
41
+ "description": "approved: an approval stands for digest. changed: one stands for approvedDigest, so the plan moved after review; the record job's chant/record status fails. unapproved: none stands. nothing: no component deploys what the change touches. plan-failed: a member failed to plan."
42
+ },
43
+ "approvedDigest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$" },
44
+ "approvedBy": { "type": "array", "items": { "type": "string" } },
45
+ "authorApproved": { "type": "array", "items": { "type": "string" }, "description": "Approvers who wrote the change (#4000), read with a forge." },
46
+ "components": { "type": "array", "items": { "type": "string" } },
47
+ "recordedAt": { "type": "string", "minLength": 1, "description": "ISO 8601." }
48
+ }
49
+ }
@@ -51,6 +51,11 @@ describe("integrityOf", () => {
51
51
  expect(integrityOf(join(dir({ "d/a": "1", "d/b": "2", "d/e": "" }), "d")).integrity).not.toBe(base);
52
52
  });
53
53
 
54
+ test("a work worktree under .chant/work is left out, and the rest of .chant is hashed (#2893)", () => {
55
+ const root = dir({ "d/a": "1", "d/.chant/work/W-1/a": "copy", "d/.chant/work/m/W-2/a": "copy", "d/.chant/notes": "n" });
56
+ expect(pinnedFiles(join(root, "d"))).toEqual([".chant/notes", "a"]);
57
+ });
58
+
54
59
  test("node_modules and .git are left out, and a symbolic link is refused", () => {
55
60
  const root = dir({ "d/a": "1", "d/node_modules/x/index.js": "x", "d/.git/HEAD": "ref" });
56
61
  expect(pinnedFiles(join(root, "d"))).toEqual(["a"]);
@@ -28,6 +28,7 @@
28
28
  import { createHash } from "node:crypto";
29
29
  import { lstatSync, readdirSync, readFileSync } from "node:fs";
30
30
  import { join } from "node:path";
31
+ import { isWorkDir } from "../lifecycle/work-dir";
31
32
 
32
33
  export type IntegrityAlgorithm = "sha256" | "sha384" | "sha512";
33
34
 
@@ -39,7 +40,7 @@ export function parseIntegrity(value: string): { algorithm: IntegrityAlgorithm;
39
40
  return m ? { algorithm: m[1] as IntegrityAlgorithm, digest: m[2] } : undefined;
40
41
  }
41
42
 
42
- /** Directories a plugin hash never looks inside. */
43
+ /** Directories a plugin hash never looks inside, with `.chant/work`, where work worktrees are (#2893). */
43
44
  const SKIPPED_DIRS = new Set(["node_modules", ".git"]);
44
45
 
45
46
  /** Thrown when a path can't be hashed: it is missing, or holds a symbolic link. */
@@ -50,7 +51,7 @@ function walk(dir: string, prefix: string, out: string[]): void {
50
51
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
51
52
  if (entry.isSymbolicLink()) throw new PinHashError(`${rel} is a symbolic link, which a pinned plugin may not contain`);
52
53
  if (entry.isDirectory()) {
53
- if (!SKIPPED_DIRS.has(entry.name)) walk(join(dir, entry.name), rel, out);
54
+ if (!SKIPPED_DIRS.has(entry.name) && !isWorkDir(rel)) walk(join(dir, entry.name), rel, out);
54
55
  } else if (entry.isFile()) {
55
56
  out.push(rel);
56
57
  }
@@ -8,7 +8,7 @@
8
8
  "properties": {
9
9
  "$schema": { "const": "https://intentius.io/chant/schemas/workspace/pr-report/v1/pr-report.schema.json" },
10
10
  "contract": { "const": 1 },
11
- "stage": { "enum": ["plan", "apply"] },
11
+ "stage": { "enum": ["plan", "apply", "record"], "description": "plan: on the pull request. record (#4168, chant 0.124.33 and newer): on merge, the default; it plans the merged commit and writes the merge record, applying nothing. apply: on merge with --apply-on-merge." },
12
12
  "pr": {
13
13
  "type": ["integer", "null"],
14
14
  "minimum": 1,
@@ -33,12 +33,12 @@
33
33
  "description": "The change-set digest of what this stage planned: computePlanDigest(\"change-set\", ...) over every member's { member, planDigest }. What the gate binds."
34
34
  },
35
35
  "status": {
36
- "enum": ["planned", "plan-failed", "nothing", "applied", "failed", "refused"],
37
- "description": "planned: every member planned (plan stage). plan-failed: a member failed to plan, so nothing can apply. nothing: no component deploys what the change touches. applied: every member applied. failed: a member failed to apply and its dependents did not run. refused: nothing applied, see refusal."
36
+ "enum": ["planned", "recorded", "plan-failed", "nothing", "applied", "failed", "wave-applied", "refused", "waiting"],
37
+ "description": "planned: every member planned (plan stage). recorded (#4168, chant 0.124.33 and newer): every member planned on the merged commit and the merge record was written (record stage); approval says whether the plan is the approved one, and nothing applied. plan-failed: a member failed to plan, so nothing can apply. nothing: no component deploys what the change touches. applied: every member applied. failed: a member failed to apply and its dependents did not run. wave-applied (#4003, chant 0.124.32 and newer): with --wave-gate and --wave, the wave applied and a later wave is still to run. refused: nothing applied, see refusal. waiting (#3999): the approved plans applied except members held back after an upstream applied, which wait on an approval of the plan the last of rounds made."
38
38
  },
39
39
  "refusal": {
40
- "enum": ["not-approved", "plan-changed", "not-a-reviewer", "no-pull-request"],
41
- "description": "Why an apply refused. plan-changed: an approval stands for another digest, so the plan changed after review."
40
+ "enum": ["not-approved", "plan-changed", "not-a-reviewer", "author-approved", "no-pull-request", "wave-not-approved", "wave-plan-changed", "earlier-wave"],
41
+ "description": "Why an apply refused. plan-changed: an approval stands for another digest, so the plan changed after review. author-approved (#4000): under --require-review, an approval names the pull request's author or an author or committer of one of its commits. With --wave-gate (#4003, chant 0.124.32 and newer): wave-not-approved, a wave's new plan is not covered by the approved one and no approval of its gate stands for it; wave-plan-changed, an approval of its gate stands for another digest; earlier-wave, an earlier wave has work left or no record says it applied. The waves that applied before a wave refused stay applied; waves says which."
42
42
  },
43
43
  "message": { "type": "string", "description": "The refusal or failure as printed." },
44
44
  "resumed": {
@@ -54,6 +54,61 @@
54
54
  "description": "Added within contract version 1 by #4104, written by chant 0.124.30 and newer. Per dependency a member was planned against, the names of the outputs read from the deployed estate through its capability's outputs, sorted. A dependency outside the change is listed here too, and one whose stack is not deployed yet lists []. Outputs given with --seed-outputs, or carried from an earlier attempt's record, are not listed. Absent when no dependency was read, and on a resumed apply.",
55
55
  "additionalProperties": { "type": "array", "items": { "type": "string" } }
56
56
  },
57
+ "waveGate": {
58
+ "type": "string",
59
+ "description": "Added within contract version 1 by #4003, written by chant 0.124.32 and newer. pr-apply --wave-gate <name>: the apply runs a wave at a time, each planned after the one before it applied, and wave k waits on <name>-wave-<k> under op when its plan moved. Absent without it."
60
+ },
61
+ "waves": {
62
+ "type": "array",
63
+ "description": "With waveGate: each wave reached so far, in order, with the approval it applied or waits under.",
64
+ "items": {
65
+ "type": "object",
66
+ "required": ["wave", "components", "status", "approval", "gate", "digest"],
67
+ "properties": {
68
+ "wave": { "type": "integer", "minimum": 1, "description": "1-based, from selection.waves." },
69
+ "components": { "type": "array", "items": { "type": "string" }, "description": "The components planned in it on the run that reached it." },
70
+ "status": { "enum": ["applied", "failed", "plan-failed", "waiting"] },
71
+ "approval": { "enum": ["pull-request", "wave"], "description": "pull-request: the approved change set covers the wave's plan, and it applies under the pull request's approval (gate and digest are the report's). wave: its plan moved, and it needs an approval of its own gate for its new plan." },
72
+ "gate": { "type": "string", "description": "The gate it applied or waits under: the report's gate, or <waveGate>-wave-<k>." },
73
+ "digest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "The digest that gate binds: the report's digest, or the change-set digest of the wave's new plan." },
74
+ "approvedBy": { "type": "array", "items": { "type": "string" } },
75
+ "approved": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Waiting: an approval of the wave's gate stands for this other digest." },
76
+ "moved": { "type": "array", "items": { "type": "string" }, "description": "Why the approved change set does not cover the wave's plan, one line per member." }
77
+ }
78
+ }
79
+ },
80
+ "plannedOutputs": {
81
+ "type": "object",
82
+ "description": "Added within contract version 1 by #3999, written by chant 0.124.32 and newer. Per dependency in the change that a member was planned against, the names of the outputs its plan knows, sorted. An output a member reads that is not listed is known only after apply, and the member lists it under unknownInputs. Absent when no member read one.",
83
+ "additionalProperties": { "type": "array", "items": { "type": "string" } }
84
+ },
85
+ "rounds": {
86
+ "type": "array",
87
+ "description": "Added within contract version 1 by #3999. Apply stage: the rounds planned after an upstream applied, in order. A member whose plan read an upstream output that applied as another value, or was known only after apply, is held back and planned again against the outputs the apply left; each round has its own gate and digest. Absent when nothing was held.",
88
+ "items": {
89
+ "type": "object",
90
+ "required": ["round", "gate", "digest", "components", "approval", "status", "changeSet"],
91
+ "properties": {
92
+ "round": { "type": "integer", "minimum": 2 },
93
+ "gate": { "type": "string", "description": "The gate the round waits on: <gate>-round-<round>." },
94
+ "digest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "The change-set digest of what the round planned. What its gate binds." },
95
+ "components": { "type": "array", "items": { "type": "string" }, "description": "The components planned again, in apply order." },
96
+ "approval": {
97
+ "type": "object",
98
+ "required": ["status"],
99
+ "description": "Where the approval stands for digest, as the top-level approval.",
100
+ "properties": {
101
+ "status": { "enum": ["approved", "changed", "pending"] },
102
+ "approvedBy": { "type": "array", "items": { "type": "string" } },
103
+ "approved": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$" }
104
+ }
105
+ },
106
+ "status": { "enum": ["applied", "failed", "waiting", "plan-failed"] },
107
+ "message": { "type": "string", "description": "With waiting: why an approval that stands does not count under --require-review." },
108
+ "changeSet": { "type": "object", "description": "The change-set document the round planned. Its digest equals digest." }
109
+ }
110
+ }
111
+ },
57
112
  "approval": {
58
113
  "type": "object",
59
114
  "required": ["status"],
@@ -85,7 +140,7 @@
85
140
  "member": { "type": "string", "description": "The member's name in the change set: the root, for a terraform-family step." },
86
141
  "component": { "type": "string" },
87
142
  "planDigest": { "type": ["string", "null"], "description": "What a gate on this member alone binds. null when it failed to plan." },
88
- "status": { "enum": ["planned", "plan-failed", "applied", "failed", "blocked"] },
143
+ "status": { "enum": ["planned", "plan-failed", "applied", "failed", "blocked", "waiting"], "description": "waiting (#3999): held back because its plan read an upstream output that applied as another value, or was known only after apply; it waits on an approval of its plan in rounds." },
89
144
  "counts": {
90
145
  "type": "object",
91
146
  "required": ["create", "update", "replace", "delete"],
@@ -100,8 +155,20 @@
100
155
  "inputsMoved": {
101
156
  "type": "array",
102
157
  "items": { "type": "string" },
103
- "description": "Apply stage: components this one depends on whose outputs changed when they applied. It applied the plan it was approved with; the next run plans it against the new values."
104
- }
158
+ "description": "Apply stage: components this one depends on whose outputs changed when they applied. It applied the plan it was approved with; the next run plans it against the new values. Not written by chant 0.124.32 and newer, which holds such a member back instead (held, round)."
159
+ },
160
+ "unknownInputs": {
161
+ "type": "array",
162
+ "items": { "type": "string" },
163
+ "description": "#3999: the upstream outputs its plan read that the change's plans could not say, as <component>.<output>, sorted. Known only after that upstream applies; the approval does not cover what this member does with them."
164
+ },
165
+ "buildInputs": {
166
+ "type": "array",
167
+ "items": { "type": "string" },
168
+ "description": "#3999: the published artifact identities its plan read from a build in the same change, as <component>.publish.<field>, sorted. Known only after the build runs and never approved again: the build's provenance binds them, so the member applies without a later round."
169
+ },
170
+ "round": { "type": "integer", "minimum": 2, "description": "Apply stage (#3999): the round whose plan it applied or waits on, when not the first. planDigest and counts are that round's." },
171
+ "held": { "type": "string", "description": "Apply stage (#3999): why the first round's plan did not apply." }
105
172
  }
106
173
  }
107
174
  },
@@ -28,6 +28,7 @@ import { STATUS_ERROR_CODES, STATUS_GATE_REASON_CODES, STATUS_REASON_CODES, STAT
28
28
  import { WORK_WARNING_CODES } from "./work";
29
29
  import { BOX_FINDING_CODES } from "./checks/boxes";
30
30
  import { DIAGRAM_FINDING_CODES } from "./checks/diagrams";
31
+ import { SECURITY_FINDING_CODES } from "./checks/security";
31
32
  import { WORK_ERROR_CODES, WORK_HISTORY_ERROR_CODES, WORK_LEASE_REFUSALS } from "./work-cli";
32
33
  import { RUN_STATEMENT_ERROR_CODES, RUNS_ERROR_CODES, RUNS_REASON_CODES, RUNS_WRITE_ERROR_CODES } from "./runs-cli";
33
34
  import { RUN_STATEMENT_FAILURE_CODES } from "./trust/run-statement";
@@ -66,6 +67,7 @@ const PER_COMMAND: Record<string, readonly string[]> = {
66
67
  CHECK_ERROR_CODES,
67
68
  BOX_FINDING_CODES,
68
69
  DIAGRAM_FINDING_CODES,
70
+ SECURITY_FINDING_CODES,
69
71
  STATUS_REASON_CODES,
70
72
  STATUS_ERROR_CODES,
71
73
  STATUS_GATE_REASON_CODES,