@intentius/chant 0.124.27 → 0.124.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (681) hide show
  1. package/README.md +1 -1
  2. package/dist/__golden__/wave-loop/fan-out-gated.json +8 -0
  3. package/dist/__golden__/wave-loop/fan-out-no-members.json +4 -0
  4. package/dist/__golden__/wave-loop/fan-out-only.json +6 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  6. package/dist/__golden__/wave-loop/op-cost-member.json +3 -0
  7. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  8. package/dist/__golden__/wave-loop/op-held-on.json +2 -0
  9. package/dist/__golden__/wave-loop/op-hooks-held.json +2 -0
  10. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  11. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  12. package/dist/__golden__/wave-loop/op-hooks-share.json +3 -0
  13. package/dist/__golden__/wave-loop/op-per-run.json +7 -0
  14. package/dist/__golden__/wave-loop/op-pr-review.json +7 -0
  15. package/dist/__golden__/wave-loop/op-sealed.json +3 -0
  16. package/dist/__golden__/wave-loop/op-spend.json +3 -0
  17. package/dist/__golden__/wave-loop/op-wave-commands.json +7 -0
  18. package/dist/__golden__/wave-loop/op-wide-waiting.json +4 -0
  19. package/dist/build-params.d.ts +34 -1
  20. package/dist/build-params.d.ts.map +1 -1
  21. package/dist/build-params.js +31 -1
  22. package/dist/change-set-graph.d.ts +63 -0
  23. package/dist/change-set-graph.d.ts.map +1 -0
  24. package/dist/change-set-graph.js +130 -0
  25. package/dist/change-set.d.ts +62 -3
  26. package/dist/change-set.d.ts.map +1 -1
  27. package/dist/change-set.js +36 -4
  28. package/dist/chant-version.d.ts +9 -0
  29. package/dist/chant-version.d.ts.map +1 -0
  30. package/dist/chant-version.js +16 -0
  31. package/dist/cli/build-params-cli.d.ts +7 -1
  32. package/dist/cli/build-params-cli.d.ts.map +1 -1
  33. package/dist/cli/build-params-cli.js +17 -8
  34. package/dist/cli/commands/build.d.ts +8 -0
  35. package/dist/cli/commands/build.d.ts.map +1 -1
  36. package/dist/cli/commands/build.js +15 -11
  37. package/dist/cli/commands/check-lexicon-docs.d.ts.map +1 -1
  38. package/dist/cli/commands/check-lexicon-docs.js +30 -2
  39. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  40. package/dist/cli/commands/check-lexicon.js +13 -2
  41. package/dist/cli/commands/init-lexicon/templates/docs.d.ts +4 -1
  42. package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -1
  43. package/dist/cli/commands/init-lexicon/templates/docs.js +6 -6
  44. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  45. package/dist/cli/commands/init-lexicon.js +17 -8
  46. package/dist/cli/handlers/approve.d.ts.map +1 -1
  47. package/dist/cli/handlers/approve.js +64 -4
  48. package/dist/cli/handlers/build.d.ts.map +1 -1
  49. package/dist/cli/handlers/build.js +43 -4
  50. package/dist/cli/handlers/change-set.d.ts +10 -0
  51. package/dist/cli/handlers/change-set.d.ts.map +1 -1
  52. package/dist/cli/handlers/change-set.js +51 -1
  53. package/dist/cli/handlers/fan-out.d.ts +10 -1
  54. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  55. package/dist/cli/handlers/fan-out.js +54 -6
  56. package/dist/cli/handlers/lifecycle-gc.d.ts +19 -0
  57. package/dist/cli/handlers/lifecycle-gc.d.ts.map +1 -0
  58. package/dist/cli/handlers/lifecycle-gc.js +143 -0
  59. package/dist/cli/handlers/pr.d.ts +16 -2
  60. package/dist/cli/handlers/pr.d.ts.map +1 -1
  61. package/dist/cli/handlers/pr.js +269 -37
  62. package/dist/cli/handlers/promote.d.ts +7 -0
  63. package/dist/cli/handlers/promote.d.ts.map +1 -1
  64. package/dist/cli/handlers/promote.js +440 -28
  65. package/dist/cli/handlers/release.d.ts +91 -0
  66. package/dist/cli/handlers/release.d.ts.map +1 -0
  67. package/dist/cli/handlers/release.js +589 -0
  68. package/dist/cli/handlers/run.d.ts +38 -2
  69. package/dist/cli/handlers/run.d.ts.map +1 -1
  70. package/dist/cli/handlers/run.js +234 -16
  71. package/dist/cli/main.d.ts.map +1 -1
  72. package/dist/cli/main.js +143 -17
  73. package/dist/cli/mcp/workspace-tools.js +1 -1
  74. package/dist/cli/parse-args.d.ts.map +1 -1
  75. package/dist/cli/parse-args.js +73 -5
  76. package/dist/cli/registry.d.ts +43 -5
  77. package/dist/cli/registry.d.ts.map +1 -1
  78. package/dist/cli/run-events.d.ts +30 -0
  79. package/dist/cli/run-events.d.ts.map +1 -0
  80. package/dist/cli/run-events.js +49 -0
  81. package/dist/cli/version.d.ts +3 -5
  82. package/dist/cli/version.d.ts.map +1 -1
  83. package/dist/cli/version.js +3 -13
  84. package/dist/codegen/docs-in-site.d.ts +71 -0
  85. package/dist/codegen/docs-in-site.d.ts.map +1 -0
  86. package/dist/codegen/docs-in-site.js +177 -0
  87. package/dist/codegen/docs-types.d.ts +14 -1
  88. package/dist/codegen/docs-types.d.ts.map +1 -1
  89. package/dist/codegen/docs.d.ts +18 -1
  90. package/dist/codegen/docs.d.ts.map +1 -1
  91. package/dist/codegen/docs.js +40 -7
  92. package/dist/codegen/rehype-base-url.mjs +15 -9
  93. package/dist/components/auto-release.d.ts +6 -1
  94. package/dist/components/auto-release.d.ts.map +1 -1
  95. package/dist/components/auto-release.js +3 -0
  96. package/dist/components/capability.d.ts +9 -0
  97. package/dist/components/capability.d.ts.map +1 -1
  98. package/dist/components/cli-support.d.ts +6 -0
  99. package/dist/components/cli-support.d.ts.map +1 -1
  100. package/dist/components/cli-support.js +10 -9
  101. package/dist/components/driver.d.ts +50 -9
  102. package/dist/components/driver.d.ts.map +1 -1
  103. package/dist/components/driver.js +116 -54
  104. package/dist/components/fan-out-inputs.d.ts +69 -0
  105. package/dist/components/fan-out-inputs.d.ts.map +1 -0
  106. package/dist/components/fan-out-inputs.js +169 -0
  107. package/dist/components/fan-out-record.d.ts +13 -0
  108. package/dist/components/fan-out-record.d.ts.map +1 -1
  109. package/dist/components/fan-out-record.js +16 -0
  110. package/dist/components/fan-out-run.d.ts +7 -0
  111. package/dist/components/fan-out-run.d.ts.map +1 -1
  112. package/dist/components/fan-out-run.js +85 -26
  113. package/dist/components/fan-out.d.ts +4 -0
  114. package/dist/components/fan-out.d.ts.map +1 -1
  115. package/dist/components/pr-pipeline.d.ts +25 -0
  116. package/dist/components/pr-pipeline.d.ts.map +1 -1
  117. package/dist/components/pr-pipeline.js +22 -4
  118. package/dist/components/pr-run.d.ts +11 -0
  119. package/dist/components/pr-run.d.ts.map +1 -1
  120. package/dist/components/pr-run.js +20 -1
  121. package/dist/components/promote-order.d.ts +38 -0
  122. package/dist/components/promote-order.d.ts.map +1 -0
  123. package/dist/components/promote-order.js +62 -0
  124. package/dist/components/promote.d.ts +38 -2
  125. package/dist/components/promote.d.ts.map +1 -1
  126. package/dist/components/promote.js +77 -2
  127. package/dist/components/release-compile.d.ts +142 -0
  128. package/dist/components/release-compile.d.ts.map +1 -0
  129. package/dist/components/release-compile.js +382 -0
  130. package/dist/components/release-gate.d.ts +135 -0
  131. package/dist/components/release-gate.d.ts.map +1 -0
  132. package/dist/components/release-gate.js +288 -0
  133. package/dist/components/release-promote.d.ts +96 -0
  134. package/dist/components/release-promote.d.ts.map +1 -0
  135. package/dist/components/release-promote.js +204 -0
  136. package/dist/components/run-progress.d.ts +7 -0
  137. package/dist/components/run-progress.d.ts.map +1 -1
  138. package/dist/components/wave-plan.d.ts +8 -1
  139. package/dist/components/wave-plan.d.ts.map +1 -1
  140. package/dist/components/wave-plan.js +11 -3
  141. package/dist/config.d.ts +45 -0
  142. package/dist/config.d.ts.map +1 -1
  143. package/dist/config.js +3 -0
  144. package/dist/flag-params.d.ts +54 -0
  145. package/dist/flag-params.d.ts.map +1 -0
  146. package/dist/flag-params.js +130 -0
  147. package/dist/index.d.ts +1 -0
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +2 -0
  150. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +120 -0
  151. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -0
  152. package/dist/lifecycle/__fixtures__/publish-fakes.js +304 -0
  153. package/dist/lifecycle/change-set-store.d.ts +68 -0
  154. package/dist/lifecycle/change-set-store.d.ts.map +1 -0
  155. package/dist/lifecycle/change-set-store.js +97 -0
  156. package/dist/lifecycle/commit-sha.d.ts +13 -0
  157. package/dist/lifecycle/commit-sha.d.ts.map +1 -0
  158. package/dist/lifecycle/commit-sha.js +21 -0
  159. package/dist/lifecycle/delivery-metrics.d.ts +139 -0
  160. package/dist/lifecycle/delivery-metrics.d.ts.map +1 -0
  161. package/dist/lifecycle/delivery-metrics.js +145 -0
  162. package/dist/lifecycle/deploy-outcome.d.ts +81 -0
  163. package/dist/lifecycle/deploy-outcome.d.ts.map +1 -0
  164. package/dist/lifecycle/deploy-outcome.js +101 -0
  165. package/dist/lifecycle/gate-change-set.d.ts +78 -0
  166. package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
  167. package/dist/lifecycle/gate-change-set.js +138 -0
  168. package/dist/lifecycle/gate-ledger.d.ts +51 -4
  169. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  170. package/dist/lifecycle/gate-ledger.js +18 -0
  171. package/dist/lifecycle/git.d.ts +30 -1
  172. package/dist/lifecycle/git.d.ts.map +1 -1
  173. package/dist/lifecycle/git.js +31 -5
  174. package/dist/lifecycle/index.d.ts +4 -0
  175. package/dist/lifecycle/index.d.ts.map +1 -1
  176. package/dist/lifecycle/index.js +4 -0
  177. package/dist/lifecycle/mixed-environment.d.ts +95 -0
  178. package/dist/lifecycle/mixed-environment.d.ts.map +1 -0
  179. package/dist/lifecycle/mixed-environment.js +154 -0
  180. package/dist/lifecycle/publish-attachments.d.ts +79 -0
  181. package/dist/lifecycle/publish-attachments.d.ts.map +1 -0
  182. package/dist/lifecycle/publish-attachments.js +179 -0
  183. package/dist/lifecycle/publish-credentials.d.ts +37 -0
  184. package/dist/lifecycle/publish-credentials.d.ts.map +1 -0
  185. package/dist/lifecycle/publish-credentials.js +69 -0
  186. package/dist/lifecycle/publish-declaration.d.ts +97 -0
  187. package/dist/lifecycle/publish-declaration.d.ts.map +1 -0
  188. package/dist/lifecycle/publish-declaration.js +83 -0
  189. package/dist/lifecycle/publish-forge.d.ts +53 -0
  190. package/dist/lifecycle/publish-forge.d.ts.map +1 -0
  191. package/dist/lifecycle/publish-forge.js +298 -0
  192. package/dist/lifecycle/publish-npm.d.ts +61 -0
  193. package/dist/lifecycle/publish-npm.d.ts.map +1 -0
  194. package/dist/lifecycle/publish-npm.js +242 -0
  195. package/dist/lifecycle/publish-oci.d.ts +64 -0
  196. package/dist/lifecycle/publish-oci.d.ts.map +1 -0
  197. package/dist/lifecycle/publish-oci.js +383 -0
  198. package/dist/lifecycle/publish-record.d.ts +66 -0
  199. package/dist/lifecycle/publish-record.d.ts.map +1 -0
  200. package/dist/lifecycle/publish-record.js +84 -0
  201. package/dist/lifecycle/publish-targets.d.ts +45 -0
  202. package/dist/lifecycle/publish-targets.d.ts.map +1 -0
  203. package/dist/lifecycle/publish-targets.js +85 -0
  204. package/dist/lifecycle/release-cut.d.ts +154 -0
  205. package/dist/lifecycle/release-cut.d.ts.map +1 -0
  206. package/dist/lifecycle/release-cut.js +366 -0
  207. package/dist/lifecycle/release-join.d.ts +95 -0
  208. package/dist/lifecycle/release-join.d.ts.map +1 -0
  209. package/dist/lifecycle/release-join.js +139 -0
  210. package/dist/lifecycle/release-ledger.d.ts +54 -0
  211. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  212. package/dist/lifecycle/release-ledger.js +53 -20
  213. package/dist/lifecycle/release-publish.d.ts +312 -0
  214. package/dist/lifecycle/release-publish.d.ts.map +1 -0
  215. package/dist/lifecycle/release-publish.js +335 -0
  216. package/dist/lifecycle/release-revocation.d.ts +80 -0
  217. package/dist/lifecycle/release-revocation.d.ts.map +1 -0
  218. package/dist/lifecycle/release-revocation.js +123 -0
  219. package/dist/lifecycle/release-store.d.ts +200 -0
  220. package/dist/lifecycle/release-store.d.ts.map +1 -0
  221. package/dist/lifecycle/release-store.js +320 -0
  222. package/dist/lifecycle/release-verify.d.ts +61 -0
  223. package/dist/lifecycle/release-verify.d.ts.map +1 -0
  224. package/dist/lifecycle/release-verify.js +92 -0
  225. package/dist/lifecycle/release-workstation.d.ts +91 -0
  226. package/dist/lifecycle/release-workstation.d.ts.map +1 -0
  227. package/dist/lifecycle/release-workstation.js +180 -0
  228. package/dist/lifecycle/retention-policy.d.ts +45 -0
  229. package/dist/lifecycle/retention-policy.d.ts.map +1 -0
  230. package/dist/lifecycle/retention-policy.js +43 -0
  231. package/dist/lifecycle/retention.d.ts +185 -0
  232. package/dist/lifecycle/retention.d.ts.map +1 -0
  233. package/dist/lifecycle/retention.js +400 -0
  234. package/dist/lifecycle/run-ledger.d.ts +4 -0
  235. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  236. package/dist/lifecycle/run-ledger.js +2 -0
  237. package/dist/op/activities/change-coverage.d.ts.map +1 -1
  238. package/dist/op/activities/change-coverage.js +4 -2
  239. package/dist/op/activities/source-release.d.ts.map +1 -1
  240. package/dist/op/activities/source-release.js +7 -3
  241. package/dist/op/activities/source-rollback.d.ts.map +1 -1
  242. package/dist/op/activities/source-rollback.js +7 -3
  243. package/dist/op/gate-name.d.ts +11 -2
  244. package/dist/op/gate-name.d.ts.map +1 -1
  245. package/dist/op/gate-name.js +12 -3
  246. package/dist/op/gate-run-locator.d.ts +22 -0
  247. package/dist/op/gate-run-locator.d.ts.map +1 -1
  248. package/dist/op/gate-run-locator.js +31 -0
  249. package/dist/op/gate.d.ts +27 -3
  250. package/dist/op/gate.d.ts.map +1 -1
  251. package/dist/op/gate.js +57 -3
  252. package/dist/op/local-executor.d.ts +36 -1
  253. package/dist/op/local-executor.d.ts.map +1 -1
  254. package/dist/op/local-executor.js +158 -52
  255. package/dist/op/op-waves-run.d.ts.map +1 -1
  256. package/dist/op/op-waves-run.js +4 -0
  257. package/dist/op/run-live.d.ts +2 -0
  258. package/dist/op/run-live.d.ts.map +1 -1
  259. package/dist/op/run-live.js +1 -1
  260. package/dist/op/runtime.d.ts +46 -0
  261. package/dist/op/runtime.d.ts.map +1 -1
  262. package/dist/op/runtimes/local.d.ts.map +1 -1
  263. package/dist/op/runtimes/local.js +8 -0
  264. package/dist/plan-summary.d.ts.map +1 -1
  265. package/dist/plan-summary.js +8 -2
  266. package/dist/point-decision.d.ts +2 -0
  267. package/dist/point-decision.d.ts.map +1 -1
  268. package/dist/point-decision.js +9 -2
  269. package/dist/pr-loop.d.ts +7 -0
  270. package/dist/pr-loop.d.ts.map +1 -1
  271. package/dist/pr-loop.js +23 -4
  272. package/dist/pr-report-url.d.ts +82 -0
  273. package/dist/pr-report-url.d.ts.map +1 -0
  274. package/dist/pr-report-url.js +174 -0
  275. package/dist/provenance.d.ts +2 -2
  276. package/dist/provenance.d.ts.map +1 -1
  277. package/dist/run-event-store.d.ts +104 -0
  278. package/dist/run-event-store.d.ts.map +1 -0
  279. package/dist/run-event-store.js +251 -0
  280. package/dist/run-event-stream.d.ts +133 -0
  281. package/dist/run-event-stream.d.ts.map +1 -0
  282. package/dist/run-event-stream.js +242 -0
  283. package/dist/run-event.d.ts +285 -0
  284. package/dist/run-event.d.ts.map +1 -0
  285. package/dist/run-event.js +209 -0
  286. package/dist/wave-runtime.mjs +262 -226
  287. package/dist/workspace/__fixtures__/flag-workspace.d.ts +31 -0
  288. package/dist/workspace/__fixtures__/flag-workspace.d.ts.map +1 -0
  289. package/dist/workspace/__fixtures__/flag-workspace.js +114 -0
  290. package/dist/workspace/__fixtures__/run-event-check.d.ts +19 -0
  291. package/dist/workspace/__fixtures__/run-event-check.d.ts.map +1 -0
  292. package/dist/workspace/__fixtures__/run-event-check.js +59 -0
  293. package/dist/workspace/change-set-show.d.ts +56 -0
  294. package/dist/workspace/change-set-show.d.ts.map +1 -0
  295. package/dist/workspace/change-set-show.js +54 -0
  296. package/dist/workspace/change-set-show.schema.json +102 -0
  297. package/dist/workspace/change-set.schema.json +32 -1
  298. package/dist/workspace/changes-cli.d.ts.map +1 -1
  299. package/dist/workspace/changes-cli.js +10 -1
  300. package/dist/workspace/changes.d.ts +37 -0
  301. package/dist/workspace/changes.d.ts.map +1 -1
  302. package/dist/workspace/changes.js +49 -2
  303. package/dist/workspace/changes.schema.json +135 -0
  304. package/dist/workspace/check.schema.json +4 -2
  305. package/dist/workspace/checks/records.d.ts +9 -1
  306. package/dist/workspace/checks/records.d.ts.map +1 -1
  307. package/dist/workspace/checks/records.js +35 -1
  308. package/dist/workspace/checks.d.ts +1 -0
  309. package/dist/workspace/checks.d.ts.map +1 -1
  310. package/dist/workspace/checks.js +2 -1
  311. package/dist/workspace/ci-green-cli.d.ts +19 -4
  312. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  313. package/dist/workspace/ci-green-cli.js +75 -12
  314. package/dist/workspace/ci-green-forge.d.ts +20 -3
  315. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  316. package/dist/workspace/ci-green-forge.js +6 -4
  317. package/dist/workspace/ci-green-workflow.d.ts +11 -0
  318. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  319. package/dist/workspace/ci-green-workflow.js +6 -0
  320. package/dist/workspace/ci-green.d.ts +281 -13
  321. package/dist/workspace/ci-green.d.ts.map +1 -1
  322. package/dist/workspace/ci-green.js +456 -38
  323. package/dist/workspace/ci-last-green.schema.json +32 -2
  324. package/dist/workspace/ci-list.schema.json +525 -0
  325. package/dist/workspace/commit-links.d.ts +85 -0
  326. package/dist/workspace/commit-links.d.ts.map +1 -0
  327. package/dist/workspace/commit-links.js +163 -0
  328. package/dist/workspace/declaration.d.ts +35 -0
  329. package/dist/workspace/declaration.d.ts.map +1 -1
  330. package/dist/workspace/declaration.js +27 -1
  331. package/dist/workspace/declaration.schema.json +76 -0
  332. package/dist/workspace/declared-kinds.d.ts +16 -0
  333. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  334. package/dist/workspace/declared-kinds.js +25 -0
  335. package/dist/workspace/delivery-metrics.d.ts +91 -0
  336. package/dist/workspace/delivery-metrics.d.ts.map +1 -0
  337. package/dist/workspace/delivery-metrics.js +217 -0
  338. package/dist/workspace/delivery-metrics.schema.json +519 -0
  339. package/dist/workspace/flags-read.d.ts +37 -0
  340. package/dist/workspace/flags-read.d.ts.map +1 -0
  341. package/dist/workspace/flags-read.js +103 -0
  342. package/dist/workspace/flags.d.ts +100 -0
  343. package/dist/workspace/flags.d.ts.map +1 -0
  344. package/dist/workspace/flags.js +98 -0
  345. package/dist/workspace/graph-cli.js +1 -1
  346. package/dist/workspace/identity-gate-rule.d.ts +37 -0
  347. package/dist/workspace/identity-gate-rule.d.ts.map +1 -1
  348. package/dist/workspace/identity-gate-rule.js +72 -7
  349. package/dist/workspace/identity.d.ts +12 -0
  350. package/dist/workspace/identity.d.ts.map +1 -1
  351. package/dist/workspace/identity.js +13 -1
  352. package/dist/workspace/intent-cli.d.ts +11 -2
  353. package/dist/workspace/intent-cli.d.ts.map +1 -1
  354. package/dist/workspace/intent-cli.js +54 -5
  355. package/dist/workspace/intent-trace.d.ts +219 -0
  356. package/dist/workspace/intent-trace.d.ts.map +1 -0
  357. package/dist/workspace/intent-trace.js +314 -0
  358. package/dist/workspace/intent.d.ts +36 -7
  359. package/dist/workspace/intent.d.ts.map +1 -1
  360. package/dist/workspace/intent.js +192 -22
  361. package/dist/workspace/intent.schema.json +702 -6
  362. package/dist/workspace/ls.d.ts +4 -0
  363. package/dist/workspace/ls.d.ts.map +1 -1
  364. package/dist/workspace/ls.js +2 -0
  365. package/dist/workspace/ls.schema.json +3 -1
  366. package/dist/workspace/member-pipeline.d.ts +6 -0
  367. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  368. package/dist/workspace/member-pipeline.js +6 -0
  369. package/dist/workspace/overlap.d.ts +146 -0
  370. package/dist/workspace/overlap.d.ts.map +1 -0
  371. package/dist/workspace/overlap.js +276 -0
  372. package/dist/workspace/promotion-order.d.ts +41 -0
  373. package/dist/workspace/promotion-order.d.ts.map +1 -0
  374. package/dist/workspace/promotion-order.js +95 -0
  375. package/dist/workspace/reason-codes.d.ts +4 -0
  376. package/dist/workspace/reason-codes.d.ts.map +1 -1
  377. package/dist/workspace/reason-codes.js +7 -1
  378. package/dist/workspace/records.d.ts +15 -2
  379. package/dist/workspace/records.d.ts.map +1 -1
  380. package/dist/workspace/records.js +32 -0
  381. package/dist/workspace/records.schema.json +21 -2
  382. package/dist/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  383. package/dist/workspace/reference-kinds/flag/flag.schema.json +53 -0
  384. package/dist/workspace/releases.d.ts +81 -0
  385. package/dist/workspace/releases.d.ts.map +1 -0
  386. package/dist/workspace/releases.js +103 -0
  387. package/dist/workspace/releases.schema.json +513 -0
  388. package/dist/workspace/run-event.schema.json +295 -0
  389. package/dist/workspace/status-gates.d.ts +34 -1
  390. package/dist/workspace/status-gates.d.ts.map +1 -1
  391. package/dist/workspace/status-gates.js +31 -2
  392. package/dist/workspace/status-stewards.d.ts +4 -0
  393. package/dist/workspace/status-stewards.d.ts.map +1 -1
  394. package/dist/workspace/status-stewards.js +2 -0
  395. package/dist/workspace/status.d.ts +117 -0
  396. package/dist/workspace/status.d.ts.map +1 -1
  397. package/dist/workspace/status.js +218 -4
  398. package/dist/workspace/status.schema.json +268 -2
  399. package/dist/workspace/trust/ci-tag-statement.d.ts +102 -0
  400. package/dist/workspace/trust/ci-tag-statement.d.ts.map +1 -0
  401. package/dist/workspace/trust/ci-tag-statement.js +123 -0
  402. package/dist/workspace/trust/op-run-statement.d.ts +91 -0
  403. package/dist/workspace/trust/op-run-statement.d.ts.map +1 -0
  404. package/dist/workspace/trust/op-run-statement.js +143 -0
  405. package/dist/workspace/trust/rotation.d.ts +18 -2
  406. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  407. package/dist/workspace/trust/rotation.js +65 -16
  408. package/dist/workspace/trust/seal.d.ts +11 -0
  409. package/dist/workspace/trust/seal.d.ts.map +1 -1
  410. package/dist/workspace/trust/seal.js +9 -0
  411. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  412. package/dist/workspace/trust/ssh-commit.js +10 -10
  413. package/dist/workspace/wip.d.ts.map +1 -1
  414. package/dist/workspace/wip.js +11 -3
  415. package/package.json +1 -1
  416. package/src/__golden__/wave-loop/fan-out-gated.json +8 -0
  417. package/src/__golden__/wave-loop/fan-out-no-members.json +4 -0
  418. package/src/__golden__/wave-loop/fan-out-only.json +6 -0
  419. package/src/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  420. package/src/__golden__/wave-loop/op-cost-member.json +3 -0
  421. package/src/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  422. package/src/__golden__/wave-loop/op-held-on.json +2 -0
  423. package/src/__golden__/wave-loop/op-hooks-held.json +2 -0
  424. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  425. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  426. package/src/__golden__/wave-loop/op-hooks-share.json +3 -0
  427. package/src/__golden__/wave-loop/op-per-run.json +7 -0
  428. package/src/__golden__/wave-loop/op-pr-review.json +7 -0
  429. package/src/__golden__/wave-loop/op-sealed.json +3 -0
  430. package/src/__golden__/wave-loop/op-spend.json +3 -0
  431. package/src/__golden__/wave-loop/op-wave-commands.json +7 -0
  432. package/src/__golden__/wave-loop/op-wide-waiting.json +4 -0
  433. package/src/build-params.test.ts +46 -0
  434. package/src/build-params.ts +55 -1
  435. package/src/change-set-graph.test.ts +72 -0
  436. package/src/change-set-graph.ts +141 -0
  437. package/src/change-set.ts +87 -6
  438. package/src/chant-version.ts +16 -0
  439. package/src/cli/build-params-cli.ts +22 -9
  440. package/src/cli/commands/build.ts +25 -11
  441. package/src/cli/commands/check-lexicon-docs.test.ts +51 -0
  442. package/src/cli/commands/check-lexicon-docs.ts +39 -2
  443. package/src/cli/commands/check-lexicon.ts +14 -2
  444. package/src/cli/commands/init-lexicon/templates/docs.ts +7 -6
  445. package/src/cli/commands/init-lexicon.test.ts +25 -0
  446. package/src/cli/commands/init-lexicon.ts +18 -8
  447. package/src/cli/handlers/approve-release.test.ts +84 -0
  448. package/src/cli/handlers/approve-revoked.test.ts +155 -0
  449. package/src/cli/handlers/approve.ts +65 -2
  450. package/src/cli/handlers/build.test.ts +67 -0
  451. package/src/cli/handlers/build.ts +46 -4
  452. package/src/cli/handlers/change-set.ts +49 -1
  453. package/src/cli/handlers/fan-out.test.ts +228 -1
  454. package/src/cli/handlers/fan-out.ts +53 -6
  455. package/src/cli/handlers/intent-trace.e2e.test.ts +201 -0
  456. package/src/cli/handlers/lifecycle-gc.test.ts +126 -0
  457. package/src/cli/handlers/lifecycle-gc.ts +146 -0
  458. package/src/cli/handlers/operator.test.ts +37 -0
  459. package/src/cli/handlers/pr.test.ts +341 -0
  460. package/src/cli/handlers/pr.ts +292 -47
  461. package/src/cli/handlers/promote.test.ts +669 -7
  462. package/src/cli/handlers/promote.ts +464 -29
  463. package/src/cli/handlers/release-implicit.e2e.test.ts +161 -0
  464. package/src/cli/handlers/release-join.e2e.test.ts +185 -0
  465. package/src/cli/handlers/release-publish-targets.e2e.test.ts +295 -0
  466. package/src/cli/handlers/release-verify.e2e.test.ts +117 -0
  467. package/src/cli/handlers/release-workstation-ci.e2e.test.ts +135 -0
  468. package/src/cli/handlers/release.e2e.test.ts +199 -0
  469. package/src/cli/handlers/release.ts +593 -0
  470. package/src/cli/handlers/run-auto-release.test.ts +80 -0
  471. package/src/cli/handlers/run-events-cmd.test.ts +92 -0
  472. package/src/cli/handlers/run-release.test.ts +55 -0
  473. package/src/cli/handlers/run.test.ts +30 -0
  474. package/src/cli/handlers/run.ts +243 -18
  475. package/src/cli/main.test.ts +8 -0
  476. package/src/cli/main.ts +143 -17
  477. package/src/cli/mcp/never-over-mcp.test.ts +2 -0
  478. package/src/cli/mcp/workspace-tools.ts +1 -1
  479. package/src/cli/parse-args.ts +56 -5
  480. package/src/cli/registry.ts +43 -5
  481. package/src/cli/run-events.ts +57 -0
  482. package/src/cli/version.ts +3 -13
  483. package/src/codegen/docs-in-site.test.ts +166 -0
  484. package/src/codegen/docs-in-site.ts +182 -0
  485. package/src/codegen/docs-site/AgentPrompt.astro +26 -1
  486. package/src/codegen/docs-types.ts +14 -1
  487. package/src/codegen/docs.ts +60 -7
  488. package/src/codegen/rehype-base-url.d.mts +3 -1
  489. package/src/codegen/rehype-base-url.mjs +15 -9
  490. package/src/codegen/rehype-base-url.test.ts +34 -0
  491. package/src/components/auto-release.test.ts +30 -0
  492. package/src/components/auto-release.ts +9 -1
  493. package/src/components/capability.ts +9 -0
  494. package/src/components/cli-support.test.ts +82 -0
  495. package/src/components/cli-support.ts +16 -9
  496. package/src/components/driver.test.ts +24 -0
  497. package/src/components/driver.ts +165 -56
  498. package/src/components/fan-out-inputs.test.ts +85 -0
  499. package/src/components/fan-out-inputs.ts +192 -0
  500. package/src/components/fan-out-record.test.ts +10 -0
  501. package/src/components/fan-out-record.ts +19 -0
  502. package/src/components/fan-out-run.ts +104 -35
  503. package/src/components/fan-out.ts +4 -0
  504. package/src/components/pr-pipeline.ts +35 -4
  505. package/src/components/pr-run.ts +30 -1
  506. package/src/components/promote-order.test.ts +90 -0
  507. package/src/components/promote-order.ts +75 -0
  508. package/src/components/promote.test.ts +10 -1
  509. package/src/components/promote.ts +94 -3
  510. package/src/components/release-compile.test.ts +147 -0
  511. package/src/components/release-compile.ts +459 -0
  512. package/src/components/release-gate.test.ts +215 -0
  513. package/src/components/release-gate.ts +355 -0
  514. package/src/components/release-promote.test.ts +159 -0
  515. package/src/components/release-promote.ts +232 -0
  516. package/src/components/run-progress.ts +7 -0
  517. package/src/components/wave-plan.ts +16 -3
  518. package/src/config.ts +15 -1
  519. package/src/flag-params.test.ts +144 -0
  520. package/src/flag-params.ts +134 -0
  521. package/src/index.ts +2 -0
  522. package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
  523. package/src/lifecycle/change-set-store.test.ts +217 -0
  524. package/src/lifecycle/change-set-store.ts +113 -0
  525. package/src/lifecycle/commit-sha.ts +23 -0
  526. package/src/lifecycle/delivery-metrics.ts +263 -0
  527. package/src/lifecycle/deploy-outcome.ts +147 -0
  528. package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
  529. package/src/lifecycle/gate-change-set.ts +164 -0
  530. package/src/lifecycle/gate-ledger.test.ts +33 -0
  531. package/src/lifecycle/gate-ledger.ts +68 -3
  532. package/src/lifecycle/git.ts +61 -8
  533. package/src/lifecycle/index.ts +4 -0
  534. package/src/lifecycle/mixed-environment.test.ts +97 -0
  535. package/src/lifecycle/mixed-environment.ts +204 -0
  536. package/src/lifecycle/publish-attachments.ts +196 -0
  537. package/src/lifecycle/publish-credentials.ts +84 -0
  538. package/src/lifecycle/publish-declaration.ts +95 -0
  539. package/src/lifecycle/publish-forge.ts +325 -0
  540. package/src/lifecycle/publish-npm.ts +259 -0
  541. package/src/lifecycle/publish-oci.ts +396 -0
  542. package/src/lifecycle/publish-record.ts +113 -0
  543. package/src/lifecycle/publish-resume.test.ts +168 -0
  544. package/src/lifecycle/publish-targets.test.ts +494 -0
  545. package/src/lifecycle/publish-targets.ts +100 -0
  546. package/src/lifecycle/release-cut-signed.test.ts +180 -0
  547. package/src/lifecycle/release-cut.test.ts +483 -0
  548. package/src/lifecycle/release-cut.ts +503 -0
  549. package/src/lifecycle/release-flag.test.ts +112 -0
  550. package/src/lifecycle/release-join.test.ts +68 -0
  551. package/src/lifecycle/release-join.ts +182 -0
  552. package/src/lifecycle/release-ledger.test.ts +14 -0
  553. package/src/lifecycle/release-ledger.ts +85 -17
  554. package/src/lifecycle/release-publish.test.ts +225 -0
  555. package/src/lifecycle/release-publish.ts +568 -0
  556. package/src/lifecycle/release-revocation.ts +147 -0
  557. package/src/lifecycle/release-store.ts +434 -0
  558. package/src/lifecycle/release-verify.test.ts +110 -0
  559. package/src/lifecycle/release-verify.ts +120 -0
  560. package/src/lifecycle/release-workstation.test.ts +204 -0
  561. package/src/lifecycle/release-workstation.ts +216 -0
  562. package/src/lifecycle/retention-growth.e2e.test.ts +279 -0
  563. package/src/lifecycle/retention-policy.ts +63 -0
  564. package/src/lifecycle/retention.test.ts +363 -0
  565. package/src/lifecycle/retention.ts +508 -0
  566. package/src/lifecycle/run-ledger.test.ts +10 -0
  567. package/src/lifecycle/run-ledger.ts +6 -0
  568. package/src/op/activities/change-coverage.ts +4 -1
  569. package/src/op/activities/source-release.ts +8 -3
  570. package/src/op/activities/source-rollback.ts +8 -4
  571. package/src/op/commit-run-gate-deploy-join.test.ts +117 -0
  572. package/src/op/gate-name.ts +13 -3
  573. package/src/op/gate-release.test.ts +126 -0
  574. package/src/op/gate-run-locator.test.ts +110 -0
  575. package/src/op/gate-run-locator.ts +35 -0
  576. package/src/op/gate.ts +88 -6
  577. package/src/op/local-executor.ts +207 -52
  578. package/src/op/op-waves-run.ts +4 -0
  579. package/src/op/run-events.test.ts +166 -0
  580. package/src/op/run-live.ts +1 -1
  581. package/src/op/runtime.ts +39 -0
  582. package/src/op/runtimes/local.test.ts +16 -0
  583. package/src/op/runtimes/local.ts +9 -0
  584. package/src/plan-summary.test.ts +20 -0
  585. package/src/plan-summary.ts +8 -1
  586. package/src/point-decision.ts +12 -2
  587. package/src/pr-loop.ts +25 -4
  588. package/src/pr-report-url.test.ts +131 -0
  589. package/src/pr-report-url.ts +209 -0
  590. package/src/provenance.ts +2 -2
  591. package/src/run-event-store.test.ts +144 -0
  592. package/src/run-event-store.ts +273 -0
  593. package/src/run-event-stream.test.ts +175 -0
  594. package/src/run-event-stream.ts +309 -0
  595. package/src/run-event.test.ts +277 -0
  596. package/src/run-event.ts +471 -0
  597. package/src/wave-loop-golden.test.ts +9 -0
  598. package/src/workspace/__fixtures__/flag-workspace.ts +132 -0
  599. package/src/workspace/__fixtures__/older-records/change-set-984534ea9.json +100 -0
  600. package/src/workspace/__fixtures__/older-records/older-records.json +326 -0
  601. package/src/workspace/__fixtures__/run-event-check.ts +58 -0
  602. package/src/workspace/ancestry-index.test.ts +93 -0
  603. package/src/workspace/change-set-show.schema.json +102 -0
  604. package/src/workspace/change-set-show.ts +72 -0
  605. package/src/workspace/change-set.schema.json +32 -1
  606. package/src/workspace/changes-cli.ts +10 -1
  607. package/src/workspace/changes.schema.json +135 -0
  608. package/src/workspace/changes.test.ts +1 -1
  609. package/src/workspace/changes.ts +84 -2
  610. package/src/workspace/check.schema.json +4 -2
  611. package/src/workspace/checks/records.ts +35 -1
  612. package/src/workspace/checks.ts +2 -1
  613. package/src/workspace/ci-green-cli.ts +75 -13
  614. package/src/workspace/ci-green-forge.ts +24 -4
  615. package/src/workspace/ci-green-runs.test.ts +242 -0
  616. package/src/workspace/ci-green-signed.test.ts +302 -0
  617. package/src/workspace/ci-green-workflow.test.ts +16 -0
  618. package/src/workspace/ci-green-workflow.ts +12 -0
  619. package/src/workspace/ci-green.test.ts +131 -2
  620. package/src/workspace/ci-green.ts +635 -42
  621. package/src/workspace/ci-last-green.schema.json +32 -2
  622. package/src/workspace/ci-list.schema.json +525 -0
  623. package/src/workspace/commit-links.test.ts +279 -0
  624. package/src/workspace/commit-links.ts +183 -0
  625. package/src/workspace/declaration.schema.json +76 -0
  626. package/src/workspace/declaration.test.ts +28 -0
  627. package/src/workspace/declaration.ts +60 -2
  628. package/src/workspace/declared-kinds.ts +40 -1
  629. package/src/workspace/delivery-metrics.schema.json +519 -0
  630. package/src/workspace/delivery-metrics.test.ts +236 -0
  631. package/src/workspace/delivery-metrics.ts +286 -0
  632. package/src/workspace/flags-read.ts +121 -0
  633. package/src/workspace/flags.test.ts +141 -0
  634. package/src/workspace/flags.ts +157 -0
  635. package/src/workspace/graph-cli.ts +1 -1
  636. package/src/workspace/identity-gate-rule.ts +91 -7
  637. package/src/workspace/identity.ts +14 -1
  638. package/src/workspace/intent-cli.ts +46 -5
  639. package/src/workspace/intent-trace.test.ts +173 -0
  640. package/src/workspace/intent-trace.ts +484 -0
  641. package/src/workspace/intent.schema.json +702 -6
  642. package/src/workspace/intent.ts +196 -26
  643. package/src/workspace/ls.schema.json +3 -1
  644. package/src/workspace/ls.ts +6 -0
  645. package/src/workspace/member-pipeline.test.ts +17 -0
  646. package/src/workspace/member-pipeline.ts +9 -0
  647. package/src/workspace/older-records.test.ts +412 -0
  648. package/src/workspace/overlap.test.ts +165 -0
  649. package/src/workspace/overlap.ts +340 -0
  650. package/src/workspace/promotion-order.ts +97 -0
  651. package/src/workspace/read-contract.e2e.test.ts +5 -1
  652. package/src/workspace/reason-codes.test.ts +7 -1
  653. package/src/workspace/reason-codes.ts +7 -1
  654. package/src/workspace/record-assets.test.ts +2 -1
  655. package/src/workspace/records-contract.e2e.test.ts +2 -1
  656. package/src/workspace/records.schema.json +21 -2
  657. package/src/workspace/records.ts +36 -2
  658. package/src/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  659. package/src/workspace/reference-kinds/flag/flag.schema.json +53 -0
  660. package/src/workspace/releases.schema.json +513 -0
  661. package/src/workspace/releases.test.ts +108 -0
  662. package/src/workspace/releases.ts +133 -0
  663. package/src/workspace/run-event.schema.json +295 -0
  664. package/src/workspace/status-contract.test.ts +81 -1
  665. package/src/workspace/status-gates.ts +64 -1
  666. package/src/workspace/status-mixed.test.ts +152 -0
  667. package/src/workspace/status-revoked.test.ts +153 -0
  668. package/src/workspace/status-stewards.ts +6 -0
  669. package/src/workspace/status.schema.json +268 -2
  670. package/src/workspace/status.ts +334 -4
  671. package/src/workspace/trust/ci-tag-statement.ts +151 -0
  672. package/src/workspace/trust/op-run-statement.ts +148 -0
  673. package/src/workspace/trust/rotation.ts +61 -14
  674. package/src/workspace/trust/seal.ts +10 -0
  675. package/src/workspace/trust/ssh-commit.ts +10 -9
  676. package/src/workspace/wip.ts +11 -2
  677. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -14
  678. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +0 -16
  679. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +0 -8
  680. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +0 -15
  681. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +0 -10
@@ -123,6 +123,10 @@
123
123
  "type": "array",
124
124
  "items": { "$ref": "#/$defs/acceptance" }
125
125
  },
126
+ "overlap": {
127
+ "description": "Added in contract 1 by #4025, written by chant 0.124.29 and newer; absent from older output, so a reader treats a missing field as unknown. Overlap between in-flight work items: a work item (a current record of a declared work kind) is in flight unless it implements at least one decision and every one is confirmed (in one of its kind's closed states and superseded by nothing, as featureFlags reads it). Its commits are the ones linked to it as #4029 defines linked (a Chant-Record: <work kind>:<id> trailer, or a Chant-Lease trailer that resolves to it), read from every local and remote-tracking branch and HEAD, the chant/ ledger branches left out, merges skipped, and never fetched. Two items overlap when their commits touch the same file, or when one entry of a change set a pending or approved gate binds is attributed to both: an entry is attributed to an item when a commit linked to the item changed the entry's source file (recorded on the stored change set) and that commit is in the history the change set was planned from. A report only: nothing is locked or refused. Null when the workspace declares no work kind, or the work records or history can't be read.",
128
+ "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/overlap" }]
129
+ },
126
130
  "summary": {
127
131
  "type": "object",
128
132
  "required": ["members", "released", "unreadable", "differing"],
@@ -228,9 +232,135 @@
228
232
  "message": { "type": "string" }
229
233
  }
230
234
  }
235
+ },
236
+ "promotionOrder": {
237
+ "description": "The member's promotion order (#4030): the literal entries of the environments array in its chant.config.ts, in order, with a pattern entry such as pr-* left out. A release moves from each step to the next, and components promote --to defaults --from to the step before. Empty when the config declares no environments, and null when it could not be read. canary is declared and shown only; no chant command acts on it yet. Optional: written from chant 0.124.28, absent from older output.",
238
+ "type": ["array", "null"],
239
+ "items": {
240
+ "type": "object",
241
+ "required": ["name", "canary"],
242
+ "properties": {
243
+ "name": { "type": "string" },
244
+ "canary": { "type": "boolean", "description": "True when the entry sets canary: true." }
245
+ }
246
+ }
247
+ },
248
+ "releaseCuts": {
249
+ "description": "The member's release cuts (#4026, ws-104), oldest first, from _releases/cuts.jsonl on the local chant/lifecycle, each with whether its signature verifies (#4031). Empty when none is cut, null when the cuts could not be read. Optional: written from chant 0.124.28, absent from older output.",
250
+ "type": ["array", "null"],
251
+ "items": {
252
+ "type": "object",
253
+ "required": ["releaseDigest", "label", "commit", "actor", "timestamp", "signature", "signatureCheck"],
254
+ "properties": {
255
+ "releaseDigest": { "type": "string", "pattern": "^(jcs1-)?sha256:[0-9a-f]{64}$" },
256
+ "label": { "type": ["string", "null"] },
257
+ "commit": { "type": ["string", "null"], "description": "The release's commit, or null when its release file can't be read." },
258
+ "actor": { "type": "string", "description": "Who cut it." },
259
+ "timestamp": { "type": "string", "description": "ISO 8601." },
260
+ "signature": { "type": ["string", "null"], "description": "The cut's armored ssh signature in the chant-release namespace over the release digest, the label (empty for none), the actor and the timestamp, joined by LF. Null for an unsigned cut." },
261
+ "signatureCheck": {
262
+ "type": "object",
263
+ "description": "Whether signature verifies for actor against the signers file at base and, when the declaration at base names a release gate in identity.gates with a class, whether .chant/trust.json at base puts actor in it. Judged on every read.",
264
+ "required": ["status", "key", "reason"],
265
+ "properties": {
266
+ "status": { "enum": ["verified", "unsigned", "unverified"] },
267
+ "key": { "type": ["string", "null"], "description": "The fingerprint of the key in the signature. Reported, never trusted." },
268
+ "reason": { "type": "string" }
269
+ }
270
+ }
271
+ }
272
+ }
273
+ },
274
+ "featureFlags": {
275
+ "description": "The member's feature flags (#4024): each record of a declared flag kind whose member field names this member, sorted by id. A flag is a workspace record the member's build reads as one build-time parameter, with chant build --env <env>; its value in an environment is recorded on the build, and on a release's target, as a param whose source is flag:<id>. Named featureFlags because a release record's flags already holds legacy-digest. Empty when no flag names the member, and null when the flag records could not be read. Optional: written from chant 0.124.29, absent from older output.",
276
+ "type": ["array", "null"],
277
+ "items": { "$ref": "#/$defs/featureFlag" }
231
278
  }
232
279
  }
233
280
  },
281
+ "overlap": {
282
+ "type": "object",
283
+ "required": ["items", "pairs", "changeSets", "unattributed"],
284
+ "properties": {
285
+ "items": {
286
+ "type": "array",
287
+ "description": "Each in-flight work item with at least one linked commit, sorted by item.",
288
+ "items": {
289
+ "type": "object",
290
+ "required": ["item", "path", "state", "commits"],
291
+ "properties": {
292
+ "item": { "type": "string", "description": "<work kind>:<id>, as a Chant-Record trailer names it." },
293
+ "path": { "type": "string", "description": "The work record file, from the repository root." },
294
+ "state": { "type": ["string", "null"] },
295
+ "commits": { "type": "array", "items": { "type": "string" }, "description": "The commits linked to the item, newest first." }
296
+ }
297
+ }
298
+ },
299
+ "pairs": {
300
+ "type": "array",
301
+ "description": "Each pair of items that share a file or a change-set entry, sorted by the first item and then the second. Empty when nothing overlaps.",
302
+ "items": {
303
+ "type": "object",
304
+ "required": ["items", "files", "addresses"],
305
+ "properties": {
306
+ "items": { "type": "array", "items": { "type": "string" }, "minItems": 2, "maxItems": 2, "description": "The two items, in sorted order." },
307
+ "files": { "type": "array", "items": { "type": "string" }, "description": "The paths, from the repository root, that both items' linked commits add, change or delete, sorted. A rename counts as a delete and an add." },
308
+ "addresses": {
309
+ "type": "array",
310
+ "description": "The change-set entries attributed to both items, by change set, member and address.",
311
+ "items": {
312
+ "type": "object",
313
+ "required": ["changeSet", "ledgerMember", "member", "address", "node", "source"],
314
+ "properties": {
315
+ "changeSet": { "type": "string", "description": "The change set's digest, for chant change-set show." },
316
+ "ledgerMember": { "type": ["string", "null"], "description": "The workspace member whose ledger stores the change set, or null for the flat ledger." },
317
+ "member": { "type": "string", "description": "The entry's change-set member." },
318
+ "address": { "type": "string", "description": "The entry's planner address." },
319
+ "node": { "type": ["string", "null"], "description": "The entry's graph node." },
320
+ "source": { "type": "string", "description": "The entry's source file, from the repository root, that both items' commits changed." }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+ },
327
+ "changeSets": { "type": "array", "items": { "type": "string" }, "description": "The digests of the stored change sets read: those a pending or approved gate binds, sorted." },
328
+ "unattributed": { "type": "integer", "minimum": 0, "description": "Entries of those change sets with no source (stored by a chant before 0.124.29, or mapped onto no node with a source location), so attributed to no item." }
329
+ }
330
+ },
331
+ "featureFlag": {
332
+ "type": "object",
333
+ "required": ["id", "param", "owner", "values", "work", "implements", "stale", "kind", "path"],
334
+ "properties": {
335
+ "id": { "type": "string", "description": "The flag's name, its record's id." },
336
+ "param": { "type": "string", "description": "The build parameter of the member the flag sets: a key of buildParams in its chant.config.ts." },
337
+ "owner": { "type": "string", "description": "Who owns the flag, and removes it when its work is settled." },
338
+ "values": {
339
+ "type": "object",
340
+ "description": "The flag's value per environment, as the record writes it. An environment it leaves out builds with the parameter's declared default.",
341
+ "additionalProperties": { "oneOf": [{ "type": "string" }, { "type": "number" }, { "type": "boolean" }] }
342
+ },
343
+ "work": {
344
+ "description": "The work item the flag hides, with that item's state, which is null when no record of the flag kind's work kind has the id. Null when the record names none.",
345
+ "oneOf": [
346
+ { "type": "null" },
347
+ { "type": "object", "required": ["id", "state"], "properties": { "id": { "type": "string" }, "state": { "type": ["string", "null"] } } }
348
+ ]
349
+ },
350
+ "implements": {
351
+ "type": "array",
352
+ "description": "Each decision the work item implements, with its state, and confirmed: true when the decision is in one of its kind's closed states and nothing supersedes it.",
353
+ "items": {
354
+ "type": "object",
355
+ "required": ["id", "state", "confirmed"],
356
+ "properties": { "id": { "type": "string" }, "state": { "type": ["string", "null"] }, "confirmed": { "type": "boolean" } }
357
+ }
358
+ },
359
+ "stale": { "type": "boolean", "description": "True when the work item implements at least one decision and every one is confirmed: the flag is due for removal, and chant workspace check reports it (WSP118)." },
360
+ "kind": { "type": "string", "description": "The flag kind file, from the workspace root." },
361
+ "path": { "type": "string", "description": "The flag record file, from the workspace root." }
362
+ }
363
+ },
234
364
  "stewardForm": { "enum": ["local", "fountain"] },
235
365
  "steward": {
236
366
  "type": "object",
@@ -313,6 +443,17 @@
313
443
  "status": { "enum": ["ok", "fail", "gated", "waiting"], "description": "waiting: an activity asked a decision point that is still open (#2749), and the run stopped there." },
314
444
  "started": { "type": "string" },
315
445
  "ended": { "type": "string" },
446
+ "gitSha": { "type": "string", "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The commit the run built from. Absent on a record written by an older chant, and when the run knew no commit." },
447
+ "runOrigin": {
448
+ "type": "object",
449
+ "required": ["forge"],
450
+ "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The CI run the Op ran in, the shape a release's runOrigin has: the forge (github for GitHub and Forgejo, gitlab), the repo or project, and a link to the run. Absent outside CI.",
451
+ "properties": {
452
+ "forge": { "enum": ["github", "gitlab", "op", "local"] },
453
+ "repo": { "type": "string" },
454
+ "url": { "type": "string" }
455
+ }
456
+ },
316
457
  "gate": {
317
458
  "oneOf": [
318
459
  { "type": "null" },
@@ -825,9 +966,14 @@
825
966
  "planDigest": { "type": ["string", "null"], "description": "The plan the run reached the gate with (#2300), or null for a gate that binds no plan. An approval counts only for this plan." },
826
967
  "state": {
827
968
  "enum": ["pending", "approved", "expired", "superseded"],
828
- "description": "Read from the newest pending fact for the gate in env, as a run reads it. approved: the approvals recorded since it, for its plan, pass the gate (its quorum, or a policy permit in enforce mode). expired: not approved, and the pending fact is past expiresAt, so the next run records a fresh one. superseded: not approved, and an approval recorded since it names a different plan, so it doesn't count. pending: none of these."
969
+ "description": "Read from the newest pending fact for the gate in env, as a run reads it. approved: the approvals recorded since it, for its plan, pass the gate (its quorum, or a policy permit in enforce mode). expired: not approved, and the pending fact is past expiresAt, so the next run records a fresh one. superseded: not approved, and an approval recorded since it names a different plan, so it doesn't count; or, on a release gate that is not expired, its release was cut from a revoked commit (#4033, ws-105), so chant approve refuses it with release-revoked and revoked is set. pending: none of these."
829
970
  },
830
971
  "recordedAt": { "type": "string", "description": "When the run recorded the pending fact." },
972
+ "gitSha": { "type": "string", "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The commit the run reached the gate at, from the pending fact. Absent on a fact recorded by an older chant, and when the run knew no commit. It joins the gate to a release's gitSha and to a run's." },
973
+ "runId": { "type": "string", "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The run that reached the gate: an Op run id, or the CI run id for a component gate that ran in CI. Absent when the run had none." },
974
+ "changeSet": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Added in contract 1 by #4022, written by chant 0.124.28 and newer. The change set the gate binds: planDigest, when a change-set document is stored under it in the member's _change-sets/ on chant/lifecycle, as a pull-request gate's apply and a release gate (#4045) store it. chant change-set show <changeSet> --json prints it, each entry with its graph node. Absent when none is stored, as for a component gate, which binds a lifecycle-plan digest." },
975
+ "releaseDigest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Added in contract 1 by #4045, written by chant 0.124.28 and newer. The release the gate binds, from the pending fact: set on a release gate, the gate chant components promote --release passes for an environment, whose component is the op release. An approval counts toward it only when it was recorded for this release, environment and planDigest. Absent on every other gate." },
976
+ "revoked": { "$ref": "#/$defs/revocation", "description": "Added in contract 1 by #4033 (ws-105), written by chant 0.124.29 and newer. Set on a release gate whose release was cut from a commit with a ci/revoked/<sha> tag, judged as release cut judges it: the tag. The gate's state is then superseded, or expired when its pending fact has expired. Absent otherwise." },
831
977
  "expiresAt": { "type": "string" },
832
978
  "approvals": {
833
979
  "description": "The approvals that count toward the gate for its plan, oldest first.",
@@ -904,6 +1050,59 @@
904
1050
  }
905
1051
  }
906
1052
  ]
1053
+ },
1054
+ "mixed": { "$ref": "#/$defs/mixed" }
1055
+ }
1056
+ },
1057
+ "mixed": {
1058
+ "type": "object",
1059
+ "description": "Added in contract 1 by #4035, written by chant 0.124.29 and newer. Set when the environment runs a mix: a components promote, rollback or redeploy left a component failed or gated (its <env>/outcomes.jsonl on chant/lifecycle says so) and the release ledger has recorded nothing for it since, or the latest records of its components name more than one release, a record of no release counting as one, with at least one naming a release. Derived when read. Absent otherwise.",
1060
+ "required": ["components", "redeploy", "rollback"],
1061
+ "properties": {
1062
+ "components": {
1063
+ "description": "Every component the ledger records in the environment or a run left unsettled, sorted by name.",
1064
+ "type": "array",
1065
+ "items": {
1066
+ "type": "object",
1067
+ "required": ["component", "digest", "releaseDigest", "releaseLabel", "state", "attempt"],
1068
+ "properties": {
1069
+ "component": { "type": "string" },
1070
+ "digest": { "type": ["string", "null"], "description": "The digest the release ledger records the component running, or null when it has no record in the environment." },
1071
+ "releaseDigest": { "type": ["string", "null"], "description": "The release that record names, or null." },
1072
+ "releaseLabel": { "type": ["string", "null"], "description": "That release's label, or null." },
1073
+ "state": {
1074
+ "enum": ["settled", "failed", "gated"],
1075
+ "description": "settled: the record is what the component runs. failed or gated: the newest run that named it failed on it or stopped at its gate after the steps before the gate ran, and nothing has been recorded for it since, so what it runs is not known."
1076
+ },
1077
+ "attempt": {
1078
+ "description": "For an unsettled component, the run that left it so and what it was deploying. Null when settled.",
1079
+ "oneOf": [
1080
+ { "type": "null" },
1081
+ {
1082
+ "type": "object",
1083
+ "required": ["verb", "runId", "timestamp", "digest", "releaseDigest", "releaseLabel"],
1084
+ "properties": {
1085
+ "verb": { "enum": ["promote", "rollback", "redeploy"] },
1086
+ "runId": { "type": "string" },
1087
+ "timestamp": { "type": "string" },
1088
+ "digest": { "type": "string" },
1089
+ "releaseDigest": { "type": ["string", "null"] },
1090
+ "releaseLabel": { "type": ["string", "null"] }
1091
+ }
1092
+ }
1093
+ ]
1094
+ }
1095
+ }
1096
+ }
1097
+ },
1098
+ "redeploy": {
1099
+ "type": "array",
1100
+ "items": { "type": "string" },
1101
+ "description": "chant components redeploy <env> --component <component> for each unsettled component the ledger records, run in the member's directory: it puts the component's recorded release back. Empty when no component is unsettled."
1102
+ },
1103
+ "rollback": {
1104
+ "type": ["string", "null"],
1105
+ "description": "chant components rollback <env> --release <label|digest>, run in the member's directory: it restores every component of the newest release the environment ran, other than the one it was moving to, that is still kept and not revoked. Null when there is none."
907
1106
  }
908
1107
  }
909
1108
  },
@@ -912,19 +1111,86 @@
912
1111
  "required": ["component", "digest", "gitSha", "inputDigest", "runId", "timestamp", "actor", "flags", "plan"],
913
1112
  "properties": {
914
1113
  "component": { "type": "string" },
915
- "digest": { "type": "string", "description": "The artifact digest the release deployed." },
1114
+ "digest": { "type": "string", "description": "What the deploy record names, as its producer writes it: an artifact digest, a release-plan digest for a runner that records plans (_plans/<digest>.json, ws-055), or a product's own digest such as a schema digest (ws-104 question 3)." },
916
1115
  "gitSha": { "type": "string", "description": "The commit the artifact was built from." },
917
1116
  "inputDigest": { "type": ["string", "null"], "description": "The input-side digest when digest is a rendered one. Compare joins on it when present." },
918
1117
  "runId": { "type": "string" },
919
1118
  "timestamp": { "type": "string" },
920
1119
  "actor": { "type": "string" },
1120
+ "approver": { "type": ["string", "null"], "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer; the ledger has carried it since #1035. Who approved the change at its gate, or null for an ungated release." },
1121
+ "admission": {
1122
+ "description": "Added in contract 1 by #4020, written by chant 0.124.28 and newer. The gate resolution that admitted the release, or null for an ungated release and for one recorded by an older chant. With approver it names the line in the gate ledger.",
1123
+ "oneOf": [
1124
+ { "type": "null" },
1125
+ {
1126
+ "type": "object",
1127
+ "required": ["op", "gate", "resolvedAt"],
1128
+ "properties": {
1129
+ "op": { "type": "string", "description": "The op, or for a component gate the component, whose gate ledger (_gates/<op>.jsonl) holds the resolution." },
1130
+ "gate": { "type": "string", "description": "The gate's name." },
1131
+ "resolvedAt": { "type": "string", "description": "When the resolution was recorded. The newest one, when several approvals counted." }
1132
+ }
1133
+ }
1134
+ ]
1135
+ },
1136
+ "releaseDigest": { "type": ["string", "null"], "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Added in contract 1 by #4043, written by chant 0.124.29 and newer. The release this deploy was made from: the releaseDigest of _releases/<releaseDigest>.json. A promote with --release writes it, a run --components with --release writes it, and a rollback or redeploy copies it from the record it restores. Null for a deploy that named no release. With the item's environment it names the release target." },
1137
+ "releaseLabel": { "type": ["string", "null"], "description": "Added in contract 1 by #4043, written by chant 0.124.29 and newer. The label that release was cut with, from _releases/cuts.jsonl. Null when releaseDigest is null, when the release has no label, and when the cuts can't be read." },
921
1138
  "flags": { "type": "array", "items": { "enum": ["legacy-digest"] } },
922
1139
  "plan": {
923
1140
  "type": ["object", "null"],
924
1141
  "description": "The release plan digest names, read from _plans/<digest>.json on chant/lifecycle (ws-055, #2733): the work items and evidence this release shipped. Null when this checkout has no plan stored under that digest — most releases carry no plan, and a plan not yet fetched also reads null."
1142
+ },
1143
+ "revoked": {
1144
+ "description": "Added in contract 1 by #4033 (ws-105), written by chant 0.124.29 and newer. Set when the deploy record names a release in releaseDigest and that release was cut from a commit with a ci/revoked/<sha> tag: the environment runs a revoked release. Read from local tags at read time and judged as release cut judges them, so with ci.green.signedSince an unsigned revoked tag is ignored. Absent when the release is not revoked, when the record names no release, and when the ci tags can't be judged.",
1145
+ "allOf": [
1146
+ { "$ref": "#/$defs/revocation" },
1147
+ {
1148
+ "type": "object",
1149
+ "required": ["releaseDigest", "label", "rollback"],
1150
+ "properties": {
1151
+ "releaseDigest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "The revoked release the environment runs." },
1152
+ "label": { "type": ["string", "null"], "description": "The release's label, or null when its cuts gave it none." },
1153
+ "rollback": { "type": "string", "description": "The line that rolls the environment back, run in the member's directory. Since #4035 (chant 0.124.29): chant components rollback <env> --release <label|digest>, naming the newest release the environment ran before this one that is still kept and not revoked. When there is none, and from chant 0.124.28: chant components rollback <env> --component <component>." }
1154
+ }
1155
+ }
1156
+ ]
925
1157
  }
926
1158
  }
927
1159
  },
1160
+ "revocation": {
1161
+ "type": "object",
1162
+ "description": "The ci/revoked/<sha> tag on a release's commit (#4033, ws-105), as chant ci list --json shows a commit's revoked tag, with the commit.",
1163
+ "required": ["commit", "tag", "tagged", "phase", "run", "signer"],
1164
+ "properties": {
1165
+ "commit": { "type": "string", "description": "The release's commit, which the tag names." },
1166
+ "tag": { "type": "string", "description": "ci/revoked/<sha>." },
1167
+ "tagged": { "type": ["string", "null"], "description": "When the tag was made, ISO 8601, or null for a lightweight tag." },
1168
+ "phase": { "type": ["string", "null"], "description": "The phase the annotation names as failed, or null when the annotation can't be read." },
1169
+ "run": {
1170
+ "description": "The run the annotation names as failed, or null.",
1171
+ "oneOf": [
1172
+ { "type": "null" },
1173
+ {
1174
+ "type": "object",
1175
+ "required": ["name", "id", "conclusion", "url"],
1176
+ "properties": {
1177
+ "name": { "type": "string" },
1178
+ "id": { "type": ["integer", "null"], "description": "The check run's id, or null for a chant Op run." },
1179
+ "conclusion": { "type": ["string", "null"] },
1180
+ "url": { "type": ["string", "null"] },
1181
+ "opRun": {
1182
+ "type": "object",
1183
+ "required": ["id", "env", "signer"],
1184
+ "properties": { "id": { "type": "string" }, "env": { "type": "string" }, "signer": { "type": "string" } },
1185
+ "description": "Present only when the run is a chant Op run (ci.green.source runs, #4044): its id, the env it is recorded under and the runner whose statement it carries. id is then null."
1186
+ }
1187
+ }
1188
+ }
1189
+ ]
1190
+ },
1191
+ "signer": { "type": ["string", "null"], "description": "The runner principal whose statement the tag carries, or null when it counts unsigned." }
1192
+ }
1193
+ },
928
1194
  "compare": {
929
1195
  "type": "object",
930
1196
  "required": ["differs", "components"],
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The statement a ci tag carries (#4031): a runner's signed word that a
3
+ * commit went green, or went red after it was green.
4
+ *
5
+ * `ci/green/<sha>` and `ci/revoked/<sha>` are plain git tags (ws-103), so
6
+ * anyone who may push a tag could make one by hand and go around CI. When the
7
+ * declaration sets `ci.green.signedSince` to a commit, a tag on any commit
8
+ * that is not a strict first-parent ancestor of it counts only when its
9
+ * annotation holds a statement signed by a runner key, and readers ignore
10
+ * and report a tag without a valid one.
11
+ *
12
+ * The statement reuses what runner evidence (#2553, ws-069) and the agent-run
13
+ * statement (#3192, ws-090) already use: an in-toto Statement v1 in a DSSE
14
+ * envelope (./dsse.ts), signed with an Ed25519 key that `.chant/trust.json`
15
+ * at base lists under `runners`. The key's principal must also hold the
16
+ * `runner` role there, since a tag says CI ran. A key the signers file lists
17
+ * is never a runner key (./policy.ts).
18
+ *
19
+ * - `subject`: the tagged commit, by `digest.gitCommit`.
20
+ * - `predicate`: the signer's principal and the tag's JSON record as the
21
+ * annotation holds it (`tag`, `commit`, `branch`, `at`, and the phases'
22
+ * runs for a green tag or the failed phase and run for a revoked one).
23
+ *
24
+ * The envelope sits in the annotation's JSON record as `statement`, beside
25
+ * the fields it signs, so a reader that does not know it reads the record as
26
+ * before. Verifying needs the tag, the envelope and the runner keys at base,
27
+ * so it works offline, and every read verifies again.
28
+ */
29
+ import { z } from "zod";
30
+ import { type DsseEnvelope } from "./dsse.js";
31
+ import type { KeyObject } from "node:crypto";
32
+ import type { RunnerKey } from "./policy.js";
33
+ export declare const CI_TAG_PREDICATE = "https://intentius.io/chant/ci-tag/v1";
34
+ /** The role a tag's signer must hold in `.chant/trust.json` (#4031): the core class `runner`. */
35
+ export declare const CI_TAG_SIGNER_ROLE = "runner";
36
+ /** The statement a ci tag carries. Strict at the top, so a verifier never acts on a field it does not know. */
37
+ export declare const ciTagStatementSchema: z.ZodObject<{
38
+ _type: z.ZodLiteral<"https://in-toto.io/Statement/v1">;
39
+ subject: z.ZodArray<z.ZodObject<{
40
+ name: z.ZodString;
41
+ digest: z.ZodObject<{
42
+ gitCommit: z.ZodString;
43
+ }, z.core.$strict>;
44
+ }, z.core.$strict>>;
45
+ predicateType: z.ZodLiteral<"https://intentius.io/chant/ci-tag/v1">;
46
+ predicate: z.ZodObject<{
47
+ signer: z.ZodString;
48
+ record: z.ZodObject<{
49
+ schema: z.ZodLiteral<1>;
50
+ tag: z.ZodEnum<{
51
+ green: "green";
52
+ revoked: "revoked";
53
+ }>;
54
+ commit: z.ZodString;
55
+ branch: z.ZodString;
56
+ at: z.ZodString;
57
+ }, z.core.$loose>;
58
+ }, z.core.$strict>;
59
+ }, z.core.$strict>;
60
+ export type CiTagStatement = z.infer<typeof ciTagStatementSchema>;
61
+ /** A tag's JSON record, without the statement. */
62
+ export type CiTagRecord = Record<string, unknown> & {
63
+ tag: "green" | "revoked";
64
+ commit: string;
65
+ branch: string;
66
+ };
67
+ /** Whoever signs the tags a tick makes: a runner key and the principal `.chant/trust.json` lists it for. */
68
+ export interface CiTagSigner {
69
+ principal: string;
70
+ key: KeyObject;
71
+ publicKey: string;
72
+ }
73
+ export declare function buildCiTagStatement(record: CiTagRecord, signer: string): CiTagStatement;
74
+ /** The envelope a tag's record carries as `statement`, signed by `signer`. */
75
+ export declare function signCiTagRecord(record: CiTagRecord, signer: CiTagSigner): DsseEnvelope;
76
+ /**
77
+ * Why a tag is ignored: it has no statement, the statement is not one, no
78
+ * runner key at base signed it, or it signs another tag's facts. The same
79
+ * words a run's attestation uses (`./run-statement.ts`).
80
+ */
81
+ export type CiTagFailure = "unsigned" | "invalid" | "untrusted" | "mismatch";
82
+ export type CiTagVerdict = {
83
+ status: "signed";
84
+ signer: string;
85
+ keyid: string;
86
+ reason: string;
87
+ } | {
88
+ status: CiTagFailure;
89
+ reason: string;
90
+ };
91
+ /**
92
+ * Verify the statement in a tag's record. `expect` is what the tag itself
93
+ * says: the commit its name gives, its kind and the declared branch. The
94
+ * signer's key must be a runner key at base and its principal must hold the
95
+ * `runner` role in `roles`. Never throws.
96
+ */
97
+ export declare function verifyCiTagStatement(record: Record<string, unknown> | null, expect: {
98
+ sha: string;
99
+ kind: "green" | "revoked";
100
+ branch: string;
101
+ }, runners: readonly RunnerKey[], roles: Readonly<Record<string, readonly string[]>>): CiTagVerdict;
102
+ //# sourceMappingURL=ci-tag-statement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-tag-statement.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/ci-tag-statement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAsD,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE/F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AAEvE,iGAAiG;AACjG,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAK3C,+GAA+G;AAC/G,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;kBAqBtB,CAAC;AACZ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjH,4GAA4G;AAC5G,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAOvF;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,YAAY,CAGtF;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7E,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAI7C;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAClE,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GACjD,YAAY,CAgCd"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * The statement a ci tag carries (#4031): a runner's signed word that a
3
+ * commit went green, or went red after it was green.
4
+ *
5
+ * `ci/green/<sha>` and `ci/revoked/<sha>` are plain git tags (ws-103), so
6
+ * anyone who may push a tag could make one by hand and go around CI. When the
7
+ * declaration sets `ci.green.signedSince` to a commit, a tag on any commit
8
+ * that is not a strict first-parent ancestor of it counts only when its
9
+ * annotation holds a statement signed by a runner key, and readers ignore
10
+ * and report a tag without a valid one.
11
+ *
12
+ * The statement reuses what runner evidence (#2553, ws-069) and the agent-run
13
+ * statement (#3192, ws-090) already use: an in-toto Statement v1 in a DSSE
14
+ * envelope (./dsse.ts), signed with an Ed25519 key that `.chant/trust.json`
15
+ * at base lists under `runners`. The key's principal must also hold the
16
+ * `runner` role there, since a tag says CI ran. A key the signers file lists
17
+ * is never a runner key (./policy.ts).
18
+ *
19
+ * - `subject`: the tagged commit, by `digest.gitCommit`.
20
+ * - `predicate`: the signer's principal and the tag's JSON record as the
21
+ * annotation holds it (`tag`, `commit`, `branch`, `at`, and the phases'
22
+ * runs for a green tag or the failed phase and run for a revoked one).
23
+ *
24
+ * The envelope sits in the annotation's JSON record as `statement`, beside
25
+ * the fields it signs, so a reader that does not know it reads the record as
26
+ * before. Verifying needs the tag, the envelope and the runner keys at base,
27
+ * so it works offline, and every read verifies again.
28
+ */
29
+ import { z } from "zod";
30
+ import { canonicalJson } from "../../effect-receipt.js";
31
+ import { IN_TOTO_PAYLOAD_TYPE, signEnvelope, verifyEnvelope } from "./dsse.js";
32
+ import { STATEMENT_TYPE } from "./evidence.js";
33
+ export const CI_TAG_PREDICATE = "https://intentius.io/chant/ci-tag/v1";
34
+ /** The role a tag's signer must hold in `.chant/trust.json` (#4031): the core class `runner`. */
35
+ export const CI_TAG_SIGNER_ROLE = "runner";
36
+ const fullCommit = z.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/);
37
+ const text = z.string().min(1);
38
+ /** The statement a ci tag carries. Strict at the top, so a verifier never acts on a field it does not know. */
39
+ export const ciTagStatementSchema = z
40
+ .object({
41
+ _type: z.literal(STATEMENT_TYPE),
42
+ subject: z
43
+ .array(z
44
+ .object({ name: fullCommit, digest: z.object({ gitCommit: fullCommit }).strict() })
45
+ .strict()
46
+ .refine((s) => s.name === s.digest.gitCommit, "a commit subject is named by its own id"))
47
+ .length(1),
48
+ predicateType: z.literal(CI_TAG_PREDICATE),
49
+ predicate: z
50
+ .object({
51
+ signer: text,
52
+ record: z
53
+ .object({ schema: z.literal(1), tag: z.enum(["green", "revoked"]), commit: fullCommit, branch: text, at: text })
54
+ .passthrough(),
55
+ })
56
+ .strict(),
57
+ })
58
+ .strict();
59
+ export function buildCiTagStatement(record, signer) {
60
+ return {
61
+ _type: STATEMENT_TYPE,
62
+ subject: [{ name: record.commit, digest: { gitCommit: record.commit } }],
63
+ predicateType: CI_TAG_PREDICATE,
64
+ predicate: { signer, record: record },
65
+ };
66
+ }
67
+ /** The envelope a tag's record carries as `statement`, signed by `signer`. */
68
+ export function signCiTagRecord(record, signer) {
69
+ const statement = buildCiTagStatement(record, signer.principal);
70
+ return signEnvelope(IN_TOTO_PAYLOAD_TYPE, Buffer.from(canonicalJson(statement), "utf8"), signer.key, signer.publicKey);
71
+ }
72
+ const normalise = (name) => name.normalize("NFKC").trim().toLowerCase();
73
+ /**
74
+ * Verify the statement in a tag's record. `expect` is what the tag itself
75
+ * says: the commit its name gives, its kind and the declared branch. The
76
+ * signer's key must be a runner key at base and its principal must hold the
77
+ * `runner` role in `roles`. Never throws.
78
+ */
79
+ export function verifyCiTagStatement(record, expect, runners, roles) {
80
+ const tag = `ci/${expect.kind}/${expect.sha}`;
81
+ if (record === null)
82
+ return { status: "unsigned", reason: `${tag} has no JSON record in its annotation, so it carries no statement (a lightweight tag, or one made by hand)` };
83
+ const { statement: envelope, ...fields } = record;
84
+ if (envelope === undefined)
85
+ return { status: "unsigned", reason: `${tag} carries no statement signed by a runner key` };
86
+ const v = verifyEnvelope(envelope, runners);
87
+ if (!v.ok)
88
+ return { status: v.code === "envelope-untrusted" ? "untrusted" : "invalid", reason: `${tag}: ${v.reason}` };
89
+ if (!(roles[CI_TAG_SIGNER_ROLE] ?? []).some((p) => normalise(p) === normalise(v.principal))) {
90
+ return { status: "untrusted", reason: `${tag} is signed by ${v.principal}'s runner key, and ${v.principal} holds no ${CI_TAG_SIGNER_ROLE} role in .chant/trust.json at base` };
91
+ }
92
+ if (v.payloadType !== IN_TOTO_PAYLOAD_TYPE)
93
+ return { status: "invalid", reason: `${tag}: payload type ${v.payloadType} is not ${IN_TOTO_PAYLOAD_TYPE}` };
94
+ let raw;
95
+ try {
96
+ raw = JSON.parse(v.payload.toString("utf8"));
97
+ }
98
+ catch {
99
+ return { status: "invalid", reason: `${tag}: the statement's payload is not JSON` };
100
+ }
101
+ const parsed = ciTagStatementSchema.safeParse(raw);
102
+ if (!parsed.success) {
103
+ const detail = parsed.error.issues.map((i) => `${i.path.join(".") || "/"}: ${i.message}`).join("; ");
104
+ return { status: "invalid", reason: `${tag}: the payload is not a ${CI_TAG_PREDICATE} statement: ${detail}` };
105
+ }
106
+ const p = parsed.data.predicate;
107
+ if (p.signer !== v.principal)
108
+ return { status: "invalid", reason: `${tag}: the statement names signer ${JSON.stringify(p.signer)}, but ${v.principal}'s key signed it` };
109
+ const differs = [];
110
+ if (parsed.data.subject[0].name !== expect.sha)
111
+ differs.push(`it is for commit ${parsed.data.subject[0].name.slice(0, 12)}`);
112
+ if (p.record.commit !== expect.sha)
113
+ differs.push(`its record names commit ${p.record.commit.slice(0, 12)}`);
114
+ if (p.record.tag !== expect.kind)
115
+ differs.push(`it signs a ${p.record.tag} tag`);
116
+ if (p.record.branch !== expect.branch)
117
+ differs.push(`it is for branch ${p.record.branch}, and ci.green names ${expect.branch}`);
118
+ if (canonicalJson(p.record) !== canonicalJson(fields))
119
+ differs.push("the annotation's record is not the one signed");
120
+ if (differs.length > 0)
121
+ return { status: "mismatch", reason: `${tag} is signed by ${v.principal}, but the statement does not match the tag: ${differs.join("; ")}` };
122
+ return { status: "signed", signer: v.principal, keyid: v.keyid, reason: `signed by ${v.principal} (${CI_TAG_SIGNER_ROLE})` };
123
+ }