@intentius/chant 0.124.45 → 0.124.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  2. package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  3. package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  4. package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  6. package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  7. package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
  8. package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
  9. package/dist/__golden__/wave-loop/op-denied.json +16 -0
  10. package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  11. package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  12. package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
  13. package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
  14. package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
  15. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  16. package/dist/__golden__/wave-loop/op-held-on.json +16 -0
  17. package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  18. package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  19. package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  20. package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  21. package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
  22. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  23. package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
  24. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  25. package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
  26. package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
  27. package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  28. package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  29. package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
  30. package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  31. package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  32. package/dist/__golden__/wave-loop/op-overridden.json +16 -0
  33. package/dist/__golden__/wave-loop/op-per-run.json +20 -0
  34. package/dist/__golden__/wave-loop/op-point.json +13 -0
  35. package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
  36. package/dist/__golden__/wave-loop/op-sealed.json +10 -0
  37. package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
  38. package/dist/__golden__/wave-loop/op-spend.json +10 -0
  39. package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
  40. package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
  41. package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
  42. package/dist/__golden__/wave-loop/op-wide.json +39 -0
  43. package/dist/action-pins.d.ts +61 -0
  44. package/dist/action-pins.d.ts.map +1 -0
  45. package/dist/action-pins.js +77 -0
  46. package/dist/capabilities/aws.paths +148 -0
  47. package/dist/capabilities/base-mappings.json +122 -0
  48. package/dist/capabilities/catalog.d.ts +89 -0
  49. package/dist/capabilities/catalog.d.ts.map +1 -0
  50. package/dist/capabilities/catalog.js +204 -0
  51. package/dist/capabilities/language.d.ts +103 -0
  52. package/dist/capabilities/language.d.ts.map +1 -0
  53. package/dist/capabilities/language.js +335 -0
  54. package/dist/capabilities/matcher.d.ts +65 -0
  55. package/dist/capabilities/matcher.d.ts.map +1 -0
  56. package/dist/capabilities/matcher.js +299 -0
  57. package/dist/capabilities/view.d.ts +207 -0
  58. package/dist/capabilities/view.d.ts.map +1 -0
  59. package/dist/capabilities/view.js +484 -0
  60. package/dist/cli/commands/carve.d.ts +3 -0
  61. package/dist/cli/commands/carve.d.ts.map +1 -1
  62. package/dist/cli/commands/carve.js +36 -7
  63. package/dist/cli/commands/import-report.d.ts +26 -0
  64. package/dist/cli/commands/import-report.d.ts.map +1 -0
  65. package/dist/cli/commands/import-report.js +65 -0
  66. package/dist/cli/commands/import.d.ts +11 -1
  67. package/dist/cli/commands/import.d.ts.map +1 -1
  68. package/dist/cli/commands/import.js +22 -3
  69. package/dist/cli/commands/lint.d.ts.map +1 -1
  70. package/dist/cli/commands/lint.js +1 -0
  71. package/dist/cli/commands/migrate.d.ts +13 -1
  72. package/dist/cli/commands/migrate.d.ts.map +1 -1
  73. package/dist/cli/commands/migrate.js +134 -10
  74. package/dist/cli/handlers/approve.d.ts.map +1 -1
  75. package/dist/cli/handlers/approve.js +21 -2
  76. package/dist/cli/handlers/build.d.ts.map +1 -1
  77. package/dist/cli/handlers/build.js +6 -1
  78. package/dist/cli/handlers/declared-graph.d.ts +44 -0
  79. package/dist/cli/handlers/declared-graph.d.ts.map +1 -0
  80. package/dist/cli/handlers/declared-graph.js +87 -0
  81. package/dist/cli/handlers/graph.d.ts +25 -0
  82. package/dist/cli/handlers/graph.d.ts.map +1 -1
  83. package/dist/cli/handlers/graph.js +93 -87
  84. package/dist/cli/handlers/ledger.d.ts +3 -0
  85. package/dist/cli/handlers/ledger.d.ts.map +1 -0
  86. package/dist/cli/handlers/ledger.js +55 -0
  87. package/dist/cli/handlers/migrate.d.ts.map +1 -1
  88. package/dist/cli/handlers/migrate.js +18 -11
  89. package/dist/cli/handlers/misc.d.ts.map +1 -1
  90. package/dist/cli/handlers/misc.js +12 -1
  91. package/dist/cli/handlers/pr-env.d.ts.map +1 -1
  92. package/dist/cli/handlers/pr-env.js +4 -3
  93. package/dist/cli/handlers/pr.d.ts +15 -1
  94. package/dist/cli/handlers/pr.d.ts.map +1 -1
  95. package/dist/cli/handlers/pr.js +143 -39
  96. package/dist/cli/handlers/query.d.ts +7 -2
  97. package/dist/cli/handlers/query.d.ts.map +1 -1
  98. package/dist/cli/handlers/query.js +16 -4
  99. package/dist/cli/handlers/release.d.ts.map +1 -1
  100. package/dist/cli/handlers/release.js +6 -3
  101. package/dist/cli/handlers/search-count.d.ts +89 -0
  102. package/dist/cli/handlers/search-count.d.ts.map +1 -0
  103. package/dist/cli/handlers/search-count.js +132 -0
  104. package/dist/cli/handlers/search.d.ts +356 -6
  105. package/dist/cli/handlers/search.d.ts.map +1 -1
  106. package/dist/cli/handlers/search.js +1039 -155
  107. package/dist/cli/main.d.ts.map +1 -1
  108. package/dist/cli/main.js +88 -17
  109. package/dist/cli/mcp/server.d.ts.map +1 -1
  110. package/dist/cli/mcp/server.js +3 -0
  111. package/dist/cli/mcp/tools/capabilities.d.ts +7 -0
  112. package/dist/cli/mcp/tools/capabilities.d.ts.map +1 -0
  113. package/dist/cli/mcp/tools/capabilities.js +27 -0
  114. package/dist/cli/mcp/workspace-tools.d.ts +3 -1
  115. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  116. package/dist/cli/mcp/workspace-tools.js +47 -2
  117. package/dist/cli/parse-args.d.ts.map +1 -1
  118. package/dist/cli/parse-args.js +100 -19
  119. package/dist/cli/registry.d.ts +36 -4
  120. package/dist/cli/registry.d.ts.map +1 -1
  121. package/dist/components/builders.d.ts +5 -1
  122. package/dist/components/builders.d.ts.map +1 -1
  123. package/dist/components/builders.js +5 -0
  124. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  125. package/dist/components/capability-plugin-loader.js +16 -1
  126. package/dist/components/capability-plugin.d.ts +14 -0
  127. package/dist/components/capability-plugin.d.ts.map +1 -1
  128. package/dist/components/pr-env-ports.d.ts +29 -0
  129. package/dist/components/pr-env-ports.d.ts.map +1 -0
  130. package/dist/components/pr-env-ports.js +77 -0
  131. package/dist/components/pr-env-run.d.ts +5 -21
  132. package/dist/components/pr-env-run.d.ts.map +1 -1
  133. package/dist/components/pr-env-run.js +6 -70
  134. package/dist/components/pr-environment.d.ts +2 -1
  135. package/dist/components/pr-environment.d.ts.map +1 -1
  136. package/dist/components/pr-environment.js +1 -1
  137. package/dist/components/pr-hooks.d.ts +21 -1
  138. package/dist/components/pr-hooks.d.ts.map +1 -1
  139. package/dist/components/pr-hooks.js +72 -4
  140. package/dist/components/pr-pipeline.d.ts +45 -10
  141. package/dist/components/pr-pipeline.d.ts.map +1 -1
  142. package/dist/components/pr-pipeline.js +47 -14
  143. package/dist/components/pr-policy.d.ts +36 -0
  144. package/dist/components/pr-policy.d.ts.map +1 -1
  145. package/dist/components/pr-policy.js +36 -0
  146. package/dist/components/starter-plugin.d.ts +1 -0
  147. package/dist/components/starter-plugin.d.ts.map +1 -1
  148. package/dist/components/starter-plugin.js +5 -1
  149. package/dist/components/verbs/index.d.ts +2 -0
  150. package/dist/components/verbs/index.d.ts.map +1 -1
  151. package/dist/components/verbs/index.js +2 -0
  152. package/dist/components/verbs/publish-artifact.d.ts +65 -0
  153. package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
  154. package/dist/components/verbs/publish-artifact.js +74 -0
  155. package/dist/components/verbs/publish-image.d.ts +129 -0
  156. package/dist/components/verbs/publish-image.d.ts.map +1 -0
  157. package/dist/components/verbs/publish-image.js +145 -0
  158. package/dist/config-environments.d.ts +112 -0
  159. package/dist/config-environments.d.ts.map +1 -0
  160. package/dist/config-environments.js +114 -0
  161. package/dist/config.d.ts +32 -84
  162. package/dist/config.d.ts.map +1 -1
  163. package/dist/config.js +13 -96
  164. package/dist/gate-decision.d.ts +11 -2
  165. package/dist/gate-decision.d.ts.map +1 -1
  166. package/dist/gate-decision.js +15 -3
  167. package/dist/graph-detail.d.ts.map +1 -1
  168. package/dist/graph-detail.js +15 -3
  169. package/dist/graph-effective.d.ts +33 -2
  170. package/dist/graph-effective.d.ts.map +1 -1
  171. package/dist/graph-effective.js +215 -68
  172. package/dist/graph-ir.d.ts +48 -0
  173. package/dist/graph-ir.d.ts.map +1 -1
  174. package/dist/graph-ir.js +130 -0
  175. package/dist/graph-sub-template.d.ts +11 -0
  176. package/dist/graph-sub-template.d.ts.map +1 -0
  177. package/dist/graph-sub-template.js +19 -0
  178. package/dist/graph-walk.d.ts +66 -0
  179. package/dist/graph-walk.d.ts.map +1 -0
  180. package/dist/graph-walk.js +70 -0
  181. package/dist/import/parser.d.ts +19 -0
  182. package/dist/import/parser.d.ts.map +1 -1
  183. package/dist/lexicon.d.ts +80 -6
  184. package/dist/lexicon.d.ts.map +1 -1
  185. package/dist/lifecycle/gate-ledger.d.ts +11 -0
  186. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  187. package/dist/lifecycle/git.d.ts +2 -5
  188. package/dist/lifecycle/git.d.ts.map +1 -1
  189. package/dist/lifecycle/ledger-read.d.ts +65 -0
  190. package/dist/lifecycle/ledger-read.d.ts.map +1 -0
  191. package/dist/lifecycle/ledger-read.js +160 -0
  192. package/dist/lifecycle/observe.d.ts +28 -0
  193. package/dist/lifecycle/observe.d.ts.map +1 -1
  194. package/dist/lifecycle/observe.js +23 -1
  195. package/dist/lifecycle/release-workstation.d.ts +7 -0
  196. package/dist/lifecycle/release-workstation.d.ts.map +1 -1
  197. package/dist/lifecycle/release-workstation.js +25 -0
  198. package/dist/lifecycle/run-ledger.d.ts +4 -3
  199. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  200. package/dist/lifecycle/run-ledger.js +1 -0
  201. package/dist/lint/discover.js +3 -1
  202. package/dist/lint/post-synth.d.ts +127 -1
  203. package/dist/lint/post-synth.d.ts.map +1 -1
  204. package/dist/lint/post-synth.js +84 -2
  205. package/dist/lint/rule.d.ts +6 -0
  206. package/dist/lint/rule.d.ts.map +1 -1
  207. package/dist/lint/rules/op/index.d.ts +1 -0
  208. package/dist/lint/rules/op/index.d.ts.map +1 -1
  209. package/dist/lint/rules/op/index.js +2 -0
  210. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
  211. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
  212. package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
  213. package/dist/live-endpoint.d.ts +1 -1
  214. package/dist/live-endpoint.d.ts.map +1 -1
  215. package/dist/live-endpoint.js +1 -1
  216. package/dist/observation.d.ts +48 -1
  217. package/dist/observation.d.ts.map +1 -1
  218. package/dist/observation.js +21 -5
  219. package/dist/op/activities/activity-contracts.d.ts +9 -6
  220. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  221. package/dist/op/activities/activity-contracts.js +5 -2
  222. package/dist/op/activities/index.d.ts +2 -2
  223. package/dist/op/activities/index.d.ts.map +1 -1
  224. package/dist/op/activities/index.js +1 -1
  225. package/dist/op/activities/review-agent.d.ts +90 -4
  226. package/dist/op/activities/review-agent.d.ts.map +1 -1
  227. package/dist/op/activities/review-agent.js +217 -19
  228. package/dist/op/activities/work-evidence.d.ts +8 -1
  229. package/dist/op/activities/work-evidence.d.ts.map +1 -1
  230. package/dist/op/activities/work-evidence.js +1 -0
  231. package/dist/op/builders.d.ts +9 -5
  232. package/dist/op/builders.d.ts.map +1 -1
  233. package/dist/op/builders.js +9 -5
  234. package/dist/op/composites/apply-op.d.ts +29 -2
  235. package/dist/op/composites/apply-op.d.ts.map +1 -1
  236. package/dist/op/composites/apply-op.js +20 -1
  237. package/dist/op/gate-approval.d.ts +11 -5
  238. package/dist/op/gate-approval.d.ts.map +1 -1
  239. package/dist/op/gate-approval.js +11 -6
  240. package/dist/op/gate-quorum.d.ts +100 -3
  241. package/dist/op/gate-quorum.d.ts.map +1 -1
  242. package/dist/op/gate-quorum.js +108 -6
  243. package/dist/op/gate-review.d.ts +9 -0
  244. package/dist/op/gate-review.d.ts.map +1 -1
  245. package/dist/op/gate-review.js +13 -0
  246. package/dist/op/gate.d.ts +44 -3
  247. package/dist/op/gate.d.ts.map +1 -1
  248. package/dist/op/gate.js +25 -4
  249. package/dist/op/index.d.ts +3 -3
  250. package/dist/op/index.d.ts.map +1 -1
  251. package/dist/op/index.js +1 -1
  252. package/dist/op/local-executor.d.ts +38 -3
  253. package/dist/op/local-executor.d.ts.map +1 -1
  254. package/dist/op/local-executor.js +48 -6
  255. package/dist/op/op-waves-run.d.ts +26 -1
  256. package/dist/op/op-waves-run.d.ts.map +1 -1
  257. package/dist/op/op-waves-run.js +259 -13
  258. package/dist/op/op-waves.d.ts +72 -5
  259. package/dist/op/op-waves.d.ts.map +1 -1
  260. package/dist/op/op-waves.js +110 -15
  261. package/dist/op/runtime.d.ts +11 -0
  262. package/dist/op/runtime.d.ts.map +1 -1
  263. package/dist/op/schedule-overdue.d.ts +16 -0
  264. package/dist/op/schedule-overdue.d.ts.map +1 -1
  265. package/dist/op/schedule-overdue.js +36 -0
  266. package/dist/op/stage-hooks.d.ts +9 -2
  267. package/dist/op/stage-hooks.d.ts.map +1 -1
  268. package/dist/op/stage-hooks.js +7 -5
  269. package/dist/op/workspace-run-env.d.ts +22 -0
  270. package/dist/op/workspace-run-env.d.ts.map +1 -0
  271. package/dist/op/workspace-run-env.js +21 -0
  272. package/dist/pr-forge.d.ts +24 -0
  273. package/dist/pr-forge.d.ts.map +1 -1
  274. package/dist/pr-forge.js +47 -0
  275. package/dist/pr-post.d.ts +42 -0
  276. package/dist/pr-post.d.ts.map +1 -1
  277. package/dist/pr-post.js +67 -1
  278. package/dist/read-filter.d.ts +65 -0
  279. package/dist/read-filter.d.ts.map +1 -0
  280. package/dist/read-filter.js +179 -0
  281. package/dist/run-event.d.ts +1 -1
  282. package/dist/run-event.d.ts.map +1 -1
  283. package/dist/terraform/carve.d.ts +24 -3
  284. package/dist/terraform/carve.d.ts.map +1 -1
  285. package/dist/terraform/carve.js +32 -14
  286. package/dist/terraform/cuts.d.ts +97 -0
  287. package/dist/terraform/cuts.d.ts.map +1 -0
  288. package/dist/terraform/cuts.js +138 -0
  289. package/dist/terraform/folds.d.ts +26 -0
  290. package/dist/terraform/folds.d.ts.map +1 -0
  291. package/dist/terraform/folds.js +38 -0
  292. package/dist/terraform/graph.d.ts.map +1 -1
  293. package/dist/terraform/graph.js +10 -0
  294. package/dist/terraform/reach.d.ts +140 -0
  295. package/dist/terraform/reach.d.ts.map +1 -0
  296. package/dist/terraform/reach.js +170 -0
  297. package/dist/terraform/score.d.ts +14 -0
  298. package/dist/terraform/score.d.ts.map +1 -1
  299. package/dist/terraform/score.js +14 -31
  300. package/dist/terraform/state.d.ts.map +1 -1
  301. package/dist/terraform/state.js +4 -2
  302. package/dist/terraform/types.d.ts +8 -0
  303. package/dist/terraform/types.d.ts.map +1 -1
  304. package/dist/wave-blocked.d.ts +10 -1
  305. package/dist/wave-blocked.d.ts.map +1 -1
  306. package/dist/wave-blocked.js +31 -3
  307. package/dist/wave-runtime.mjs +266 -256
  308. package/dist/workspace/capabilities-contract.d.ts +66 -0
  309. package/dist/workspace/capabilities-contract.d.ts.map +1 -0
  310. package/dist/workspace/capabilities-contract.js +107 -0
  311. package/dist/workspace/capabilities.schema.json +229 -0
  312. package/dist/workspace/check.schema.json +11 -2
  313. package/dist/workspace/checks/ci-branch.d.ts +44 -0
  314. package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
  315. package/dist/workspace/checks/ci-branch.js +133 -0
  316. package/dist/workspace/checks/links.d.ts +3 -0
  317. package/dist/workspace/checks/links.d.ts.map +1 -1
  318. package/dist/workspace/checks/links.js +12 -1
  319. package/dist/workspace/checks/org.d.ts +48 -0
  320. package/dist/workspace/checks/org.d.ts.map +1 -0
  321. package/dist/workspace/checks/org.js +156 -0
  322. package/dist/workspace/checks.d.ts +11 -1
  323. package/dist/workspace/checks.d.ts.map +1 -1
  324. package/dist/workspace/checks.js +59 -7
  325. package/dist/workspace/ci-branches.d.ts +16 -0
  326. package/dist/workspace/ci-branches.d.ts.map +1 -1
  327. package/dist/workspace/ci-branches.js +27 -0
  328. package/dist/workspace/ci-green-cli.js +7 -7
  329. package/dist/workspace/ci-green-workflow.d.ts +1 -1
  330. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  331. package/dist/workspace/ci-green-workflow.js +13 -8
  332. package/dist/workspace/ci-green.d.ts +14 -0
  333. package/dist/workspace/ci-green.d.ts.map +1 -1
  334. package/dist/workspace/ci-green.js +44 -11
  335. package/dist/workspace/ci-run.d.ts +9 -1
  336. package/dist/workspace/ci-run.d.ts.map +1 -1
  337. package/dist/workspace/ci-run.js +67 -6
  338. package/dist/workspace/ci-serve.d.ts +9 -0
  339. package/dist/workspace/ci-serve.d.ts.map +1 -1
  340. package/dist/workspace/ci-serve.js +114 -76
  341. package/dist/workspace/compose-graph.d.ts +23 -0
  342. package/dist/workspace/compose-graph.d.ts.map +1 -1
  343. package/dist/workspace/compose-graph.js +3 -1
  344. package/dist/workspace/composites.d.ts +4 -1
  345. package/dist/workspace/composites.d.ts.map +1 -1
  346. package/dist/workspace/composites.js +5 -2
  347. package/dist/workspace/composites.schema.json +22 -0
  348. package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  349. package/dist/workspace/conformance/index.d.ts +1 -1
  350. package/dist/workspace/conformance/index.d.ts.map +1 -1
  351. package/dist/workspace/conformance/index.js +39 -2
  352. package/dist/workspace/cross-root-lint.d.ts +56 -0
  353. package/dist/workspace/cross-root-lint.d.ts.map +1 -0
  354. package/dist/workspace/cross-root-lint.js +111 -0
  355. package/dist/workspace/dbt-models-reader.d.ts +44 -0
  356. package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
  357. package/dist/workspace/dbt-models-reader.js +356 -0
  358. package/dist/workspace/dbt-project-common.d.ts +40 -0
  359. package/dist/workspace/dbt-project-common.d.ts.map +1 -0
  360. package/dist/workspace/dbt-project-common.js +106 -0
  361. package/dist/workspace/dbt-project-reader.d.ts +4 -3
  362. package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
  363. package/dist/workspace/dbt-project-reader.js +14 -108
  364. package/dist/workspace/decision-rank.d.ts +26 -0
  365. package/dist/workspace/decision-rank.d.ts.map +1 -0
  366. package/dist/workspace/decision-rank.js +16 -0
  367. package/dist/workspace/declaration.d.ts +43 -2
  368. package/dist/workspace/declaration.d.ts.map +1 -1
  369. package/dist/workspace/declaration.js +45 -11
  370. package/dist/workspace/declaration.schema.json +133 -24
  371. package/dist/workspace/environments.d.ts +26 -2
  372. package/dist/workspace/environments.d.ts.map +1 -1
  373. package/dist/workspace/environments.js +26 -2
  374. package/dist/workspace/flyway-dir.d.ts +39 -0
  375. package/dist/workspace/flyway-dir.d.ts.map +1 -0
  376. package/dist/workspace/flyway-dir.js +104 -0
  377. package/dist/workspace/flyway-layout.d.ts +96 -0
  378. package/dist/workspace/flyway-layout.d.ts.map +1 -0
  379. package/dist/workspace/flyway-layout.js +308 -0
  380. package/dist/workspace/graph-cache.d.ts +8 -0
  381. package/dist/workspace/graph-cache.d.ts.map +1 -1
  382. package/dist/workspace/graph-cache.js +27 -3
  383. package/dist/workspace/graph-cli.d.ts +39 -2
  384. package/dist/workspace/graph-cli.d.ts.map +1 -1
  385. package/dist/workspace/graph-cli.js +92 -32
  386. package/dist/workspace/graph.schema.json +182 -0
  387. package/dist/workspace/intent.d.ts +2 -3
  388. package/dist/workspace/intent.d.ts.map +1 -1
  389. package/dist/workspace/intent.js +5 -9
  390. package/dist/workspace/kind-link-readers.d.ts +59 -2
  391. package/dist/workspace/kind-link-readers.d.ts.map +1 -1
  392. package/dist/workspace/kind-link-readers.js +17 -1
  393. package/dist/workspace/kind-readers.d.ts +3 -0
  394. package/dist/workspace/kind-readers.d.ts.map +1 -1
  395. package/dist/workspace/kind-readers.js +7 -1
  396. package/dist/workspace/kinds.d.ts +66 -2
  397. package/dist/workspace/kinds.d.ts.map +1 -1
  398. package/dist/workspace/kinds.js +98 -4
  399. package/dist/workspace/ledger.schema.json +158 -0
  400. package/dist/workspace/lexicon-outputs.d.ts +20 -1
  401. package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
  402. package/dist/workspace/lexicon-outputs.js +102 -10
  403. package/dist/workspace/lineage-check.d.ts +3 -0
  404. package/dist/workspace/lineage-check.d.ts.map +1 -1
  405. package/dist/workspace/lineage-check.js +23 -4
  406. package/dist/workspace/links.d.ts +8 -1
  407. package/dist/workspace/links.d.ts.map +1 -1
  408. package/dist/workspace/links.js +25 -1
  409. package/dist/workspace/ls.d.ts +8 -0
  410. package/dist/workspace/ls.d.ts.map +1 -1
  411. package/dist/workspace/ls.js +7 -1
  412. package/dist/workspace/ls.schema.json +7 -0
  413. package/dist/workspace/member-commands.d.ts +10 -1
  414. package/dist/workspace/member-commands.d.ts.map +1 -1
  415. package/dist/workspace/member-commands.js +71 -6
  416. package/dist/workspace/migrate-links.d.ts +45 -0
  417. package/dist/workspace/migrate-links.d.ts.map +1 -0
  418. package/dist/workspace/migrate-links.js +100 -0
  419. package/dist/workspace/migration-dirs.d.ts +74 -0
  420. package/dist/workspace/migration-dirs.d.ts.map +1 -0
  421. package/dist/workspace/migration-dirs.js +254 -0
  422. package/dist/workspace/nested-graph.d.ts +2 -0
  423. package/dist/workspace/nested-graph.d.ts.map +1 -1
  424. package/dist/workspace/nested-graph.js +32 -1
  425. package/dist/workspace/reason-codes.d.ts +18 -0
  426. package/dist/workspace/reason-codes.d.ts.map +1 -1
  427. package/dist/workspace/reason-codes.js +23 -0
  428. package/dist/workspace/records-cli.d.ts +11 -0
  429. package/dist/workspace/records-cli.d.ts.map +1 -1
  430. package/dist/workspace/records-cli.js +57 -5
  431. package/dist/workspace/records.schema.json +5 -0
  432. package/dist/workspace/release-candidates.d.ts +2 -0
  433. package/dist/workspace/release-candidates.d.ts.map +1 -1
  434. package/dist/workspace/release-candidates.js +5 -2
  435. package/dist/workspace/release-train.d.ts +53 -0
  436. package/dist/workspace/release-train.d.ts.map +1 -0
  437. package/dist/workspace/release-train.js +134 -0
  438. package/dist/workspace/release-workflow.d.ts.map +1 -1
  439. package/dist/workspace/release-workflow.js +4 -3
  440. package/dist/workspace/repo-ref.d.ts +45 -0
  441. package/dist/workspace/repo-ref.d.ts.map +1 -0
  442. package/dist/workspace/repo-ref.js +114 -0
  443. package/dist/workspace/run-event.schema.json +2 -2
  444. package/dist/workspace/runs-cli.d.ts +9 -0
  445. package/dist/workspace/runs-cli.d.ts.map +1 -1
  446. package/dist/workspace/runs-cli.js +48 -3
  447. package/dist/workspace/runs.schema.json +7 -0
  448. package/dist/workspace/search-cli.d.ts +204 -0
  449. package/dist/workspace/search-cli.d.ts.map +1 -0
  450. package/dist/workspace/search-cli.js +466 -0
  451. package/dist/workspace/search-contract.d.ts +56 -0
  452. package/dist/workspace/search-contract.d.ts.map +1 -0
  453. package/dist/workspace/search-contract.js +70 -0
  454. package/dist/workspace/search.schema.json +822 -0
  455. package/dist/workspace/status-decisions.d.ts +37 -0
  456. package/dist/workspace/status-decisions.d.ts.map +1 -0
  457. package/dist/workspace/status-decisions.js +147 -0
  458. package/dist/workspace/status-gates.d.ts +9 -0
  459. package/dist/workspace/status-gates.d.ts.map +1 -1
  460. package/dist/workspace/status.d.ts +4 -0
  461. package/dist/workspace/status.d.ts.map +1 -1
  462. package/dist/workspace/status.js +14 -2
  463. package/dist/workspace/status.schema.json +6 -0
  464. package/dist/workspace/work-cli.d.ts.map +1 -1
  465. package/dist/workspace/work-cli.js +5 -3
  466. package/dist/workspace/work-evidence-ops.d.ts +83 -0
  467. package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
  468. package/dist/workspace/work-evidence-ops.js +169 -0
  469. package/dist/workspace/work-evidence.d.ts +12 -2
  470. package/dist/workspace/work-evidence.d.ts.map +1 -1
  471. package/dist/workspace/work-evidence.js +21 -3
  472. package/dist/workspace/work-evidence.schema.json +49 -2
  473. package/dist/workspace/workspace-gates.d.ts +110 -0
  474. package/dist/workspace/workspace-gates.d.ts.map +1 -0
  475. package/dist/workspace/workspace-gates.js +140 -0
  476. package/dist/workspace/workspace-kinds.schema.json +58 -3
  477. package/dist/workspace/workspace-ledger.d.ts +76 -0
  478. package/dist/workspace/workspace-ledger.d.ts.map +1 -0
  479. package/dist/workspace/workspace-ledger.js +91 -0
  480. package/dist/workspace/workspace-run.d.ts +112 -0
  481. package/dist/workspace/workspace-run.d.ts.map +1 -0
  482. package/dist/workspace/workspace-run.js +432 -0
  483. package/package.json +1 -1
  484. package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  485. package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  486. package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  487. package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  488. package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  489. package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  490. package/src/__golden__/wave-loop/op-cost-member.json +13 -0
  491. package/src/__golden__/wave-loop/op-denied-source.json +16 -0
  492. package/src/__golden__/wave-loop/op-denied.json +16 -0
  493. package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  494. package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  495. package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
  496. package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
  497. package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
  498. package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  499. package/src/__golden__/wave-loop/op-held-on.json +16 -0
  500. package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  501. package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  502. package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  503. package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  504. package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
  505. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  506. package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
  507. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  508. package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
  509. package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
  510. package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  511. package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  512. package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
  513. package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  514. package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  515. package/src/__golden__/wave-loop/op-overridden.json +16 -0
  516. package/src/__golden__/wave-loop/op-per-run.json +20 -0
  517. package/src/__golden__/wave-loop/op-point.json +13 -0
  518. package/src/__golden__/wave-loop/op-pr-review.json +10 -0
  519. package/src/__golden__/wave-loop/op-sealed.json +10 -0
  520. package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
  521. package/src/__golden__/wave-loop/op-spend.json +10 -0
  522. package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
  523. package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
  524. package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
  525. package/src/__golden__/wave-loop/op-wide.json +39 -0
  526. package/src/__snapshots__/okf.test.ts.snap +10 -0
  527. package/src/action-pins.test.ts +78 -0
  528. package/src/action-pins.ts +92 -0
  529. package/src/capabilities/aws.paths +148 -0
  530. package/src/capabilities/base-mappings.json +122 -0
  531. package/src/capabilities/catalog.ts +230 -0
  532. package/src/capabilities/language.test.ts +191 -0
  533. package/src/capabilities/language.ts +373 -0
  534. package/src/capabilities/matcher.ts +315 -0
  535. package/src/capabilities/view-compose.test.ts +76 -0
  536. package/src/capabilities/view.ts +631 -0
  537. package/src/cli/commands/carve-score-once.test.ts +99 -0
  538. package/src/cli/commands/carve.ts +37 -6
  539. package/src/cli/commands/check-lexicon.test.ts +2 -2
  540. package/src/cli/commands/import-report.ts +71 -0
  541. package/src/cli/commands/import.ts +33 -3
  542. package/src/cli/commands/lint.ts +1 -0
  543. package/src/cli/commands/migrate-dialect.test.ts +145 -0
  544. package/src/cli/commands/migrate.ts +132 -11
  545. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
  546. package/src/cli/handlers/approve.ts +23 -2
  547. package/src/cli/handlers/build.ts +7 -1
  548. package/src/cli/handlers/declared-graph.ts +99 -0
  549. package/src/cli/handlers/graph.test.ts +94 -3
  550. package/src/cli/handlers/graph.ts +123 -96
  551. package/src/cli/handlers/ledger.ts +54 -0
  552. package/src/cli/handlers/migrate.ts +21 -12
  553. package/src/cli/handlers/misc.ts +10 -1
  554. package/src/cli/handlers/pr-env.ts +3 -4
  555. package/src/cli/handlers/pr.ts +138 -36
  556. package/src/cli/handlers/query.ts +16 -4
  557. package/src/cli/handlers/release.ts +6 -3
  558. package/src/cli/handlers/search-build-roots.test.ts +144 -0
  559. package/src/cli/handlers/search-count.test.ts +191 -0
  560. package/src/cli/handlers/search-count.ts +165 -0
  561. package/src/cli/handlers/search-json.test.ts +333 -0
  562. package/src/cli/handlers/search-live.test.ts +387 -0
  563. package/src/cli/handlers/search-paths.test.ts +235 -0
  564. package/src/cli/handlers/search.ts +1291 -166
  565. package/src/cli/main.test.ts +43 -3
  566. package/src/cli/main.ts +88 -17
  567. package/src/cli/mcp/server.test.ts +3 -3
  568. package/src/cli/mcp/server.ts +3 -0
  569. package/src/cli/mcp/tools/capabilities.ts +32 -0
  570. package/src/cli/mcp/workspace-tools.e2e.test.ts +21 -1
  571. package/src/cli/mcp/workspace-tools.ts +47 -2
  572. package/src/cli/parse-args.ts +79 -15
  573. package/src/cli/registry.ts +36 -4
  574. package/src/components/builders.ts +8 -0
  575. package/src/components/capability-plugin-loader.ts +13 -1
  576. package/src/components/capability-plugin.ts +16 -0
  577. package/src/components/pr-env-ports.ts +89 -0
  578. package/src/components/pr-env-run-bundle.test.ts +54 -0
  579. package/src/components/pr-env-run.ts +5 -76
  580. package/src/components/pr-environment.ts +2 -1
  581. package/src/components/pr-hooks.test.ts +73 -5
  582. package/src/components/pr-hooks.ts +95 -5
  583. package/src/components/pr-pipeline.ts +64 -16
  584. package/src/components/pr-policy.test.ts +64 -1
  585. package/src/components/pr-policy.ts +53 -0
  586. package/src/components/registry.test.ts +1 -1
  587. package/src/components/starter-plugin.ts +6 -0
  588. package/src/components/verbs/index.ts +2 -0
  589. package/src/components/verbs/publish-artifact.test.ts +60 -0
  590. package/src/components/verbs/publish-artifact.ts +122 -0
  591. package/src/components/verbs/publish-image.test.ts +101 -0
  592. package/src/components/verbs/publish-image.ts +265 -0
  593. package/src/config-environments.ts +160 -0
  594. package/src/config.ts +44 -124
  595. package/src/gate-decision-bundle.test.ts +1 -0
  596. package/src/gate-decision-identity.test.ts +9 -0
  597. package/src/gate-decision.ts +26 -3
  598. package/src/graph-detail.ts +15 -3
  599. package/src/graph-effective.ts +226 -75
  600. package/src/graph-ir.test.ts +163 -0
  601. package/src/graph-ir.ts +174 -0
  602. package/src/graph-sub-template.ts +22 -0
  603. package/src/graph-walk.test.ts +44 -0
  604. package/src/graph-walk.ts +102 -0
  605. package/src/import/parser.ts +20 -0
  606. package/src/lexicon.ts +84 -6
  607. package/src/lifecycle/gate-ledger.ts +8 -0
  608. package/src/lifecycle/git.ts +2 -2
  609. package/src/lifecycle/ledger-read.test.ts +107 -0
  610. package/src/lifecycle/ledger-read.ts +195 -0
  611. package/src/lifecycle/observe.test.ts +27 -1
  612. package/src/lifecycle/observe.ts +43 -1
  613. package/src/lifecycle/release-workstation.ts +24 -0
  614. package/src/lifecycle/run-ledger.ts +5 -2
  615. package/src/lint/cross-root.test.ts +122 -0
  616. package/src/lint/discover.ts +3 -1
  617. package/src/lint/post-synth.ts +212 -2
  618. package/src/lint/rule.ts +6 -0
  619. package/src/lint/rules/op/index.ts +2 -0
  620. package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
  621. package/src/live-endpoint.ts +1 -1
  622. package/src/observation.test.ts +25 -0
  623. package/src/observation.ts +69 -5
  624. package/src/op/activities/activity-contracts.ts +5 -2
  625. package/src/op/activities/index.ts +2 -2
  626. package/src/op/activities/review-agent.test.ts +221 -4
  627. package/src/op/activities/review-agent.ts +265 -22
  628. package/src/op/activities/work-evidence.ts +9 -1
  629. package/src/op/builders.ts +9 -5
  630. package/src/op/composites/apply-op.test.ts +108 -0
  631. package/src/op/composites/apply-op.ts +37 -2
  632. package/src/op/gate-approval.test.ts +6 -1
  633. package/src/op/gate-approval.ts +12 -6
  634. package/src/op/gate-quorum-at-base.test.ts +211 -0
  635. package/src/op/gate-quorum.ts +156 -8
  636. package/src/op/gate-review.ts +14 -0
  637. package/src/op/gate.ts +67 -8
  638. package/src/op/index.ts +3 -2
  639. package/src/op/local-executor.ts +69 -9
  640. package/src/op/op-waves-depends-on.test.ts +81 -0
  641. package/src/op/op-waves-hook-targets.test.ts +4 -2
  642. package/src/op/op-waves-quorum-product.test.ts +158 -0
  643. package/src/op/op-waves-run.ts +288 -14
  644. package/src/op/op-waves.ts +143 -14
  645. package/src/op/runtime.ts +8 -0
  646. package/src/op/schedule-overdue.ts +33 -0
  647. package/src/op/stage-hooks.ts +13 -5
  648. package/src/op/workspace-run-env.ts +29 -0
  649. package/src/pr-forge-bundle.test.ts +2 -2
  650. package/src/pr-forge.test.ts +47 -0
  651. package/src/pr-forge.ts +68 -0
  652. package/src/pr-post-open.e2e.test.ts +36 -0
  653. package/src/pr-post.test.ts +102 -3
  654. package/src/pr-post.ts +89 -1
  655. package/src/read-filter.test.ts +54 -0
  656. package/src/read-filter.ts +193 -0
  657. package/src/run-event.ts +1 -1
  658. package/src/stage-hooks-bundle.test.ts +1 -0
  659. package/src/terraform/carve.ts +52 -15
  660. package/src/terraform/cuts.test.ts +173 -0
  661. package/src/terraform/cuts.ts +188 -0
  662. package/src/terraform/folds.ts +44 -0
  663. package/src/terraform/graph.ts +9 -0
  664. package/src/terraform/radius.test.ts +90 -0
  665. package/src/terraform/reach.test.ts +146 -0
  666. package/src/terraform/reach.ts +247 -0
  667. package/src/terraform/score.ts +27 -29
  668. package/src/terraform/state.ts +3 -1
  669. package/src/terraform/types.ts +8 -0
  670. package/src/wave-blocked.ts +28 -3
  671. package/src/wave-loop-golden.test.ts +4 -3
  672. package/src/workspace/behold-kinds.test.ts +1 -1
  673. package/src/workspace/capabilities-contract.test.ts +88 -0
  674. package/src/workspace/capabilities-contract.ts +132 -0
  675. package/src/workspace/capabilities.schema.json +229 -0
  676. package/src/workspace/check-contract.test.ts +7 -6
  677. package/src/workspace/check.schema.json +11 -2
  678. package/src/workspace/checks/ci-branch.test.ts +128 -0
  679. package/src/workspace/checks/ci-branch.ts +141 -0
  680. package/src/workspace/checks/links.ts +12 -1
  681. package/src/workspace/checks/org.ts +169 -0
  682. package/src/workspace/checks.ts +64 -7
  683. package/src/workspace/ci-branches.ts +31 -0
  684. package/src/workspace/ci-green-branches.test.ts +153 -0
  685. package/src/workspace/ci-green-cli.ts +7 -7
  686. package/src/workspace/ci-green-workflow.test.ts +4 -3
  687. package/src/workspace/ci-green-workflow.ts +13 -9
  688. package/src/workspace/ci-green.ts +49 -12
  689. package/src/workspace/ci-run.test.ts +72 -1
  690. package/src/workspace/ci-run.ts +68 -8
  691. package/src/workspace/ci-serve.test.ts +95 -0
  692. package/src/workspace/ci-serve.ts +106 -65
  693. package/src/workspace/component-environments.test.ts +25 -2
  694. package/src/workspace/compose-graph.ts +19 -3
  695. package/src/workspace/composites.schema.json +22 -0
  696. package/src/workspace/composites.test.ts +39 -8
  697. package/src/workspace/composites.ts +6 -2
  698. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  699. package/src/workspace/conformance/conformance.e2e.test.ts +14 -1
  700. package/src/workspace/conformance/index.ts +31 -2
  701. package/src/workspace/cross-root-lint.test.ts +90 -0
  702. package/src/workspace/cross-root-lint.ts +126 -0
  703. package/src/workspace/dbt-kind.test.ts +3 -2
  704. package/src/workspace/dbt-models-reader.ts +362 -0
  705. package/src/workspace/dbt-models.test.ts +248 -0
  706. package/src/workspace/dbt-project-common.ts +113 -0
  707. package/src/workspace/dbt-project-reader.ts +29 -112
  708. package/src/workspace/decision-rank.ts +40 -0
  709. package/src/workspace/declaration.schema.json +133 -24
  710. package/src/workspace/declaration.ts +84 -15
  711. package/src/workspace/environments.ts +40 -4
  712. package/src/workspace/flyway-dir.ts +113 -0
  713. package/src/workspace/flyway-layout.ts +337 -0
  714. package/src/workspace/graph-cache.ts +27 -3
  715. package/src/workspace/graph-cli.ts +119 -32
  716. package/src/workspace/graph-contract.test.ts +4 -2
  717. package/src/workspace/graph.schema.json +182 -0
  718. package/src/workspace/identity.test.ts +14 -2
  719. package/src/workspace/intent.ts +6 -14
  720. package/src/workspace/kind-link-readers.ts +68 -3
  721. package/src/workspace/kind-readers.e2e.test.ts +28 -0
  722. package/src/workspace/kind-readers.test.ts +1 -1
  723. package/src/workspace/kind-readers.ts +7 -1
  724. package/src/workspace/kinds.test.ts +12 -7
  725. package/src/workspace/kinds.ts +132 -7
  726. package/src/workspace/ledger.schema.json +158 -0
  727. package/src/workspace/lexicon-outputs.ts +132 -13
  728. package/src/workspace/lineage-check.ts +30 -7
  729. package/src/workspace/links.ts +24 -1
  730. package/src/workspace/ls-contract.test.ts +1 -1
  731. package/src/workspace/ls.schema.json +7 -0
  732. package/src/workspace/ls.ts +10 -1
  733. package/src/workspace/member-commands.ts +82 -3
  734. package/src/workspace/member-file-schema.test.ts +124 -0
  735. package/src/workspace/migrate-links.test.ts +99 -0
  736. package/src/workspace/migrate-links.ts +108 -0
  737. package/src/workspace/migration-dirs.test.ts +272 -0
  738. package/src/workspace/migration-dirs.ts +267 -0
  739. package/src/workspace/nested-graph.ts +32 -1
  740. package/src/workspace/org-scope.test.ts +238 -0
  741. package/src/workspace/reason-codes.test.ts +13 -1
  742. package/src/workspace/reason-codes.ts +23 -0
  743. package/src/workspace/records-cli.ts +58 -5
  744. package/src/workspace/records.schema.json +5 -0
  745. package/src/workspace/release-candidates.ts +7 -2
  746. package/src/workspace/release-train.ts +157 -0
  747. package/src/workspace/release-workflow.ts +4 -3
  748. package/src/workspace/repo-ref.ts +113 -0
  749. package/src/workspace/run-event.schema.json +2 -2
  750. package/src/workspace/runs-cli.ts +48 -4
  751. package/src/workspace/runs.schema.json +7 -0
  752. package/src/workspace/search-cli.e2e.test.ts +305 -0
  753. package/src/workspace/search-cli.ts +591 -0
  754. package/src/workspace/search-contract.ts +95 -0
  755. package/src/workspace/search.schema.json +822 -0
  756. package/src/workspace/status-contract.test.ts +46 -1
  757. package/src/workspace/status-decisions.test.ts +100 -0
  758. package/src/workspace/status-decisions.ts +151 -0
  759. package/src/workspace/status-gates.ts +9 -0
  760. package/src/workspace/status.schema.json +6 -0
  761. package/src/workspace/status.ts +17 -3
  762. package/src/workspace/where-filters.test.ts +39 -0
  763. package/src/workspace/work-cli.ts +5 -3
  764. package/src/workspace/work-evidence-ops.test.ts +176 -0
  765. package/src/workspace/work-evidence-ops.ts +189 -0
  766. package/src/workspace/work-evidence.schema.json +49 -2
  767. package/src/workspace/work-evidence.ts +22 -3
  768. package/src/workspace/workspace-gates.ts +200 -0
  769. package/src/workspace/workspace-kinds.schema.json +58 -3
  770. package/src/workspace/workspace-ledger.ts +130 -0
  771. package/src/workspace/workspace-run.test.ts +322 -0
  772. package/src/workspace/workspace-run.ts +461 -0
@@ -0,0 +1,160 @@
1
+ /**
2
+ * The pure helpers over a loaded config's `environments` and `ownership`:
3
+ * names, patterns, endpoints and the ownership stack. ./config.ts re-exports
4
+ * them. They import nothing at runtime, so ./components/pr-environment.ts and
5
+ * ./live-endpoint.ts use them without bundling the config loader.
6
+ */
7
+
8
+ import type { ChantConfig } from "./config";
9
+
10
+ /**
11
+ * One project-declared environment (chant #1166). Historically always a bare
12
+ * name (`"floci"`); an entry can now instead carry the endpoint that
13
+ * environment's `--live` reads should target (`{ name: "floci", endpoint:
14
+ * "http://localhost:4566" }`), so a project pointed at a local emulator is
15
+ * self-sufficient — no ambient `AWS_ENDPOINT_URL` export required to avoid
16
+ * silently querying real AWS. See {@link environmentName}, {@link
17
+ * environmentNames}, {@link environmentEndpoint} below, and
18
+ * `./live-endpoint.ts`'s `applyLiveEndpoint`, the CLI-side consumer.
19
+ *
20
+ * The array's order is the member's promotion order (#4030, see
21
+ * `./workspace/promotion-order.ts`), and `canary: true` marks a step as the
22
+ * canary step of that order. The canary is declared and surfaced; chant does
23
+ * not yet act on it.
24
+ *
25
+ * `executor` names the forge and the committed workflow that deploys the
26
+ * environment (#4402), so a reader such as behold knows a release there runs
27
+ * through CI rather than a local `chant run`. chant declares and prints it
28
+ * (`chant workspace graph --composites`); it never dispatches it.
29
+ */
30
+ export type EnvironmentDeclaration = string | { name: string; endpoint?: string; canary?: boolean; executor?: EnvironmentExecutor };
31
+
32
+ /** The forges an environment's executor can name (#4402). */
33
+ export const EXECUTOR_FORGES = ["github", "gitlab", "forgejo"] as const;
34
+
35
+ /** The forge workflow that deploys one environment (#4402). */
36
+ export interface EnvironmentExecutor {
37
+ forge: (typeof EXECUTOR_FORGES)[number];
38
+ /** The committed workflow file the forge runs, such as `deploy-prod.yml` under `.github/workflows/`, or `.gitlab-ci.yml`. */
39
+ workflow: string;
40
+ }
41
+
42
+ /**
43
+ * `ownership.env`: a literal environment identity, or a reference to a
44
+ * declared build parameter whose resolved value becomes the identity (#1396).
45
+ */
46
+ export type OwnershipEnv = string | { param: string };
47
+
48
+ /** The declared name of one `environments` entry, whichever form it takes. */
49
+ export function environmentName(entry: EnvironmentDeclaration): string {
50
+ return typeof entry === "string" ? entry : entry.name;
51
+ }
52
+
53
+ /**
54
+ * Every declared environment's name, in `environments` order. `undefined` in,
55
+ * `undefined` out — mirrors the field itself being optional, so a caller that
56
+ * already writes `config.environments?.something` can keep doing so:
57
+ * `environmentNames(config.environments)?.includes(name)`.
58
+ */
59
+ export function environmentNames(environments: EnvironmentDeclaration[] | undefined): string[] | undefined {
60
+ return environments?.map(environmentName);
61
+ }
62
+
63
+ /**
64
+ * Whether a declared environment name is a glob pattern rather than a literal
65
+ * (#1221) — it contains at least one `*`.
66
+ */
67
+ export function isEnvironmentPattern(declaredName: string): boolean {
68
+ return declaredName.includes("*");
69
+ }
70
+
71
+ /**
72
+ * Anchored `*`-glob match (#1221): each `*` in `pattern` matches any run of
73
+ * characters (possibly empty); everything else matches itself. Deliberately
74
+ * the whole surface — no `?`, no character classes, no regex. A pattern with
75
+ * no `*` degenerates to string equality.
76
+ */
77
+ export function matchesEnvironmentPattern(pattern: string, name: string): boolean {
78
+ const parts = pattern.split("*");
79
+ if (parts.length === 1) return pattern === name;
80
+ const first = parts[0];
81
+ const last = parts[parts.length - 1];
82
+ if (!name.startsWith(first)) return false;
83
+ let cursor = first.length;
84
+ for (let i = 1; i < parts.length - 1; i++) {
85
+ const part = parts[i];
86
+ if (part === "") continue;
87
+ const at = name.indexOf(part, cursor);
88
+ if (at === -1) return false;
89
+ cursor = at + part.length;
90
+ }
91
+ return name.length - cursor >= last.length && name.endsWith(last);
92
+ }
93
+
94
+ /**
95
+ * Environment-membership test (#1221): is `name` covered by this project's
96
+ * declared `environments`? A literal entry matches by equality; an entry
97
+ * containing `*` matches as a glob pattern (`"pr-*"` covers `pr-42`).
98
+ * Literals are checked first across the whole list, then patterns — so a
99
+ * name that is declared outright never depends on pattern order. `undefined`
100
+ * / empty `environments` returns `false`; callers that treat "no declared
101
+ * environments" as "anything goes" (e.g. {@link unknownEnvError} in
102
+ * `./env.ts`) guard that case themselves.
103
+ */
104
+ export function matchesDeclaredEnvironment(
105
+ environments: EnvironmentDeclaration[] | undefined,
106
+ name: string,
107
+ ): boolean {
108
+ const names = environmentNames(environments) ?? [];
109
+ if (names.includes(name)) return true;
110
+ return names.some((declared) => isEnvironmentPattern(declared) && matchesEnvironmentPattern(declared, name));
111
+ }
112
+
113
+ /**
114
+ * The endpoint `name` declares (chant #1166) — `undefined` for a bare-string
115
+ * entry, an entry with no `endpoint` set, or a name this project doesn't
116
+ * declare at all. `./live-endpoint.ts`'s `applyLiveEndpoint` is the consumer:
117
+ * it injects this into the ambient env var each observing lexicon's CLI
118
+ * shell-out reads (e.g. `AWS_ENDPOINT_URL`), unless that var is already set —
119
+ * ambient always wins.
120
+ *
121
+ * A pattern entry (#1221) can carry an endpoint too: `{ name: "pr-*",
122
+ * endpoint }` supplies the endpoint for every `pr-<n>` environment. A literal
123
+ * entry always wins over a pattern — declaring `pr-special` alongside
124
+ * `pr-*` resolves `pr-special` to the literal entry's endpoint (or none).
125
+ */
126
+ export function environmentEndpoint(environments: EnvironmentDeclaration[] | undefined, name: string): string | undefined {
127
+ const found =
128
+ environments?.find((e) => environmentName(e) === name) ??
129
+ environments?.find((e) => isEnvironmentPattern(environmentName(e)) && matchesEnvironmentPattern(environmentName(e), name));
130
+ return found && typeof found !== "string" ? found.endpoint : undefined;
131
+ }
132
+
133
+ /**
134
+ * The executor `name` declares (#4402), resolved like {@link
135
+ * environmentEndpoint}: a literal entry wins over a pattern, and a literal
136
+ * entry with no executor does not fall through to a pattern's.
137
+ */
138
+ export function environmentExecutor(environments: EnvironmentDeclaration[] | undefined, name: string): EnvironmentExecutor | undefined {
139
+ const found =
140
+ environments?.find((e) => environmentName(e) === name) ??
141
+ environments?.find((e) => isEnvironmentPattern(environmentName(e)) && matchesEnvironmentPattern(environmentName(e), name));
142
+ return found && typeof found !== "string" ? found.executor : undefined;
143
+ }
144
+
145
+ /** Whether an `ownership.env` entry is a build-parameter reference rather than a literal. */
146
+ export function isOwnershipParamRef(env: OwnershipEnv | undefined): env is { param: string } {
147
+ return typeof env === "object" && env !== null && typeof env.param === "string";
148
+ }
149
+
150
+ /**
151
+ * The ownership stack identity alone — `ownership.stack` when marking is on
152
+ * (no `stack`, or `enabled: false`, means off). For callers that need the
153
+ * stack and nothing else (a field manager, a prune selector) and so have no
154
+ * build parameters to resolve `env` against.
155
+ */
156
+ export function resolveOwnershipStack(config: Pick<ChantConfig, "ownership">): string | undefined {
157
+ const o = config.ownership;
158
+ if (!o || !o.stack || o.enabled === false) return undefined;
159
+ return o.stack;
160
+ }
package/src/config.ts CHANGED
@@ -14,113 +14,25 @@ import { lexiconNames, pathLexiconRoot, registerLexiconDeclarations, type Lexico
14
14
  import { decideConfigSchema, type DecideConfig } from "./op/decide-config";
15
15
  import { PublishDeclarationSchema, type PublishDeclaration } from "./lifecycle/publish-declaration";
16
16
 
17
- /**
18
- * One project-declared environment (chant #1166). Historically always a bare
19
- * name (`"floci"`); an entry can now instead carry the endpoint that
20
- * environment's `--live` reads should target (`{ name: "floci", endpoint:
21
- * "http://localhost:4566" }`), so a project pointed at a local emulator is
22
- * self-sufficient — no ambient `AWS_ENDPOINT_URL` export required to avoid
23
- * silently querying real AWS. See {@link environmentName}, {@link
24
- * environmentNames}, {@link environmentEndpoint} below, and
25
- * `./live-endpoint.ts`'s `applyLiveEndpoint`, the CLI-side consumer.
26
- *
27
- * The array's order is the member's promotion order (#4030, see
28
- * `./workspace/promotion-order.ts`), and `canary: true` marks a step as the
29
- * canary step of that order. The canary is declared and surfaced; chant does
30
- * not yet act on it.
31
- */
32
- export type EnvironmentDeclaration = string | { name: string; endpoint?: string; canary?: boolean };
33
-
34
- /**
35
- * `ownership.env`: a literal environment identity, or a reference to a
36
- * declared build parameter whose resolved value becomes the identity (#1396).
37
- */
38
- export type OwnershipEnv = string | { param: string };
39
-
40
- /** The declared name of one `environments` entry, whichever form it takes. */
41
- export function environmentName(entry: EnvironmentDeclaration): string {
42
- return typeof entry === "string" ? entry : entry.name;
43
- }
44
-
45
- /**
46
- * Every declared environment's name, in `environments` order. `undefined` in,
47
- * `undefined` out — mirrors the field itself being optional, so a caller that
48
- * already writes `config.environments?.something` can keep doing so:
49
- * `environmentNames(config.environments)?.includes(name)`.
50
- */
51
- export function environmentNames(environments: EnvironmentDeclaration[] | undefined): string[] | undefined {
52
- return environments?.map(environmentName);
53
- }
54
-
55
- /**
56
- * Whether a declared environment name is a glob pattern rather than a literal
57
- * (#1221) — it contains at least one `*`.
58
- */
59
- export function isEnvironmentPattern(declaredName: string): boolean {
60
- return declaredName.includes("*");
61
- }
62
-
63
- /**
64
- * Anchored `*`-glob match (#1221): each `*` in `pattern` matches any run of
65
- * characters (possibly empty); everything else matches itself. Deliberately
66
- * the whole surface — no `?`, no character classes, no regex. A pattern with
67
- * no `*` degenerates to string equality.
68
- */
69
- export function matchesEnvironmentPattern(pattern: string, name: string): boolean {
70
- const parts = pattern.split("*");
71
- if (parts.length === 1) return pattern === name;
72
- const first = parts[0];
73
- const last = parts[parts.length - 1];
74
- if (!name.startsWith(first)) return false;
75
- let cursor = first.length;
76
- for (let i = 1; i < parts.length - 1; i++) {
77
- const part = parts[i];
78
- if (part === "") continue;
79
- const at = name.indexOf(part, cursor);
80
- if (at === -1) return false;
81
- cursor = at + part.length;
82
- }
83
- return name.length - cursor >= last.length && name.endsWith(last);
84
- }
85
-
86
- /**
87
- * Environment-membership test (#1221): is `name` covered by this project's
88
- * declared `environments`? A literal entry matches by equality; an entry
89
- * containing `*` matches as a glob pattern (`"pr-*"` covers `pr-42`).
90
- * Literals are checked first across the whole list, then patterns — so a
91
- * name that is declared outright never depends on pattern order. `undefined`
92
- * / empty `environments` returns `false`; callers that treat "no declared
93
- * environments" as "anything goes" (e.g. {@link unknownEnvError} in
94
- * `./env.ts`) guard that case themselves.
95
- */
96
- export function matchesDeclaredEnvironment(
97
- environments: EnvironmentDeclaration[] | undefined,
98
- name: string,
99
- ): boolean {
100
- const names = environmentNames(environments) ?? [];
101
- if (names.includes(name)) return true;
102
- return names.some((declared) => isEnvironmentPattern(declared) && matchesEnvironmentPattern(declared, name));
103
- }
104
-
105
- /**
106
- * The endpoint `name` declares (chant #1166) — `undefined` for a bare-string
107
- * entry, an entry with no `endpoint` set, or a name this project doesn't
108
- * declare at all. `./live-endpoint.ts`'s `applyLiveEndpoint` is the consumer:
109
- * it injects this into the ambient env var each observing lexicon's CLI
110
- * shell-out reads (e.g. `AWS_ENDPOINT_URL`), unless that var is already set —
111
- * ambient always wins.
112
- *
113
- * A pattern entry (#1221) can carry an endpoint too: `{ name: "pr-*",
114
- * endpoint }` supplies the endpoint for every `pr-<n>` environment. A literal
115
- * entry always wins over a pattern — declaring `pr-special` alongside
116
- * `pr-*` resolves `pr-special` to the literal entry's endpoint (or none).
117
- */
118
- export function environmentEndpoint(environments: EnvironmentDeclaration[] | undefined, name: string): string | undefined {
119
- const found =
120
- environments?.find((e) => environmentName(e) === name) ??
121
- environments?.find((e) => isEnvironmentPattern(environmentName(e)) && matchesEnvironmentPattern(environmentName(e), name));
122
- return found && typeof found !== "string" ? found.endpoint : undefined;
123
- }
17
+ // The environment and ownership helpers that read a config already loaded
18
+ // live in ./config-environments.ts, which loads nothing, so a bundle that
19
+ // needs only them stays clear of the loader below (#4356 follow-up).
20
+ export {
21
+ environmentEndpoint,
22
+ environmentExecutor,
23
+ environmentName,
24
+ EXECUTOR_FORGES,
25
+ environmentNames,
26
+ isEnvironmentPattern,
27
+ isOwnershipParamRef,
28
+ matchesDeclaredEnvironment,
29
+ matchesEnvironmentPattern,
30
+ resolveOwnershipStack,
31
+ type EnvironmentDeclaration,
32
+ type EnvironmentExecutor,
33
+ type OwnershipEnv,
34
+ } from "./config-environments";
35
+ import { EXECUTOR_FORGES, isOwnershipParamRef, resolveOwnershipStack, type EnvironmentDeclaration, type OwnershipEnv } from "./config-environments";
124
36
 
125
37
  /**
126
38
  * Zod schema for ChantConfig validation.
@@ -131,6 +43,10 @@ const EnvironmentEntrySchema = z.union([
131
43
  name: z.string().min(1),
132
44
  endpoint: z.string().min(1).optional(),
133
45
  canary: z.boolean().optional(),
46
+ executor: z.object({
47
+ forge: z.enum(EXECUTOR_FORGES),
48
+ workflow: z.string().min(1),
49
+ }).strict().optional(),
134
50
  }),
135
51
  ]);
136
52
 
@@ -157,6 +73,10 @@ export const ChantConfigSchema = z.object({
157
73
  build: z.object({
158
74
  fold: z.boolean().optional(),
159
75
  }).optional(),
76
+ // Strict like `run`: a misspelt `lint` would leave the gate on with nothing said.
77
+ graph: z.object({
78
+ lint: z.enum(["gate", "report"]).optional(),
79
+ }).strict().optional(),
160
80
  buildParams: z.record(
161
81
  z.string(),
162
82
  z.object({
@@ -299,6 +219,23 @@ export interface ChantConfig {
299
219
  /** Lint configuration (rules, extends, overrides, plugins) */
300
220
  lint?: LintConfig;
301
221
 
222
+ /**
223
+ * How `chant graph` treats lint errors (INTENTIUS/behold#919).
224
+ *
225
+ * `"gate"` (the default) refuses to emit the entity graph for source that
226
+ * fails `chant lint`: the graph stands for source chant will build.
227
+ * `"report"` emits it anyway and carries every lint finding on the IR's
228
+ * `meta.lint`, for a project that only reads source it did not author. The
229
+ * reader project `chant workspace graph` writes for a terraform or choudoufu
230
+ * member sets it, and so does behold's scratch project for a bare Terraform
231
+ * folder: an error-severity finding there describes the estate, and the
232
+ * person needs the picture to look at it. A chant older than the key
233
+ * ignores it and gates as before.
234
+ */
235
+ graph?: {
236
+ lint?: "gate" | "report";
237
+ };
238
+
302
239
  /**
303
240
  * Telemetry attribution (#2558, D22): lexicons that declare workloads stamp
304
241
  * resource attributes (`chant.workspace`, `chant.member`, `chant.decl`,
@@ -764,23 +701,6 @@ function warnIfFragmentShadowsProjectConfig(configPath: string): void {
764
701
  /** Top-level keys that make a config a *project* config rather than a lint fragment. */
765
702
  const PROJECT_CONFIG_KEYS = new Set(Object.keys(ChantConfigSchema.shape).filter((k) => k !== "lint"));
766
703
 
767
- /** Whether an `ownership.env` entry is a build-parameter reference rather than a literal. */
768
- export function isOwnershipParamRef(env: OwnershipEnv | undefined): env is { param: string } {
769
- return typeof env === "object" && env !== null && typeof env.param === "string";
770
- }
771
-
772
- /**
773
- * The ownership stack identity alone — `ownership.stack` when marking is on
774
- * (no `stack`, or `enabled: false`, means off). For callers that need the
775
- * stack and nothing else (a field manager, a prune selector) and so have no
776
- * build parameters to resolve `env` against.
777
- */
778
- export function resolveOwnershipStack(config: ChantConfig): string | undefined {
779
- const o = config.ownership;
780
- if (!o || !o.stack || o.enabled === false) return undefined;
781
- return o.stack;
782
- }
783
-
784
704
  /**
785
705
  * Resolve the `env` half of the ownership marker (#1396). A literal is
786
706
  * returned as-is. A `{ param }` reference is looked up in this build's resolved
@@ -48,6 +48,7 @@ describe("the gate-decision bundle", () => {
48
48
  "packages/core/src/op/gate-point.ts",
49
49
  "packages/core/src/op/gate-quorum.ts",
50
50
  "packages/core/src/op/op-waves.ts",
51
+ "packages/core/src/wave-blocked.ts",
51
52
  "packages/core/src/wave-layout.ts",
52
53
  "packages/core/src/workspace/class-data.ts",
53
54
  "packages/core/src/workspace/identity-gate-rule.ts",
@@ -218,6 +218,15 @@ describe.skipIf(!hasSshKeygen)("identity.gates read at base, as chant reads it",
218
218
  expect(decided.status === "approved" && decided.via === "ledger" ? decided.resolution : null).toEqual(check.satisfied ? check.resolution : null);
219
219
  }
220
220
  });
221
+
222
+ test("a gate's quorum at base, as chant reads it (#4324)", () => {
223
+ const rules = [{ targets: ["prod"], count: 2, roles: ["platform"] }, { count: 1 }];
224
+ const { r, base } = setup(() => ({}), { identity: { gates: { ship: { quorum: rules }, deploy: { class: "human" } } } });
225
+ const here = identityGateAdmissionAt(r.dir, base, "ship")!;
226
+ expect(here.requirement.quorum).toEqual(rules);
227
+ expect(here.requirement.quorum).toEqual(gateAdmission(r.dir, "ship", base)!.requirement.quorum);
228
+ expect(identityGateAdmissionAt(r.dir, base, "deploy")!.requirement).toEqual({ gate: "deploy", class: "human" });
229
+ });
221
230
  });
222
231
 
223
232
  describe("admitApprover", () => {
@@ -30,7 +30,10 @@
30
30
  * Approval rules (#4290), a quorum as a list of `{ targets, count, roles,
31
31
  * notAuthor }`, are judged with `./op/gate-quorum.ts`, re-exported here:
32
32
  * {@link trustRolesAt} and {@link gateSignersAt} read what
33
- * `trustQuorumJudge` judges by, at base.
33
+ * `trustQuorumJudge` judges by, at base. A product's own review lines
34
+ * (#4333) become one approval per reviewer with `recordedReviewApprovals`,
35
+ * and `changeInvolvement` names everyone involved in a change for the
36
+ * judge to leave out.
34
37
  *
35
38
  * The module reads the ledger lines and the review it is handed; reading
36
39
  * them is the caller's. It imports no TypeScript, esbuild, zod, ajv, lint,
@@ -63,6 +66,7 @@ import { CORE_CLASSES, admitApprover, type ClassGrant, type GateAdmissionRule, t
63
66
  import { diskFiles, findInstalledPackage, mergePinClasses, parseClassDataByHand, readClassFiles, type PinClassRead } from "./workspace/class-data";
64
67
  import type { GateResolutionRecord, PendingGateRecord } from "./lifecycle/gate-ledger";
65
68
  import type { MergedReview } from "./op/gate-review";
69
+ import { quorumProblems as quorumProblemsOf, type GateQuorumSpec as QuorumSpec } from "./op/gate-quorum";
66
70
  import type { GateApprovalSource } from "./op/op-waves";
67
71
 
68
72
  export { GATE_APPROVAL_SOURCES, type GateApprovalSource } from "./op/op-waves";
@@ -124,6 +128,14 @@ export {
124
128
  targetGlobMatch,
125
129
  trustQuorumJudge,
126
130
  UNPROVEN_JUDGE,
131
+ changeInvolvement,
132
+ involvedWhy,
133
+ principalNames,
134
+ recordedReviewApprovals,
135
+ recordedReviewOf,
136
+ requestedByTrailers,
137
+ type QuorumInvolvement,
138
+ type RecordedReview,
127
139
  type GateQuorumJudge,
128
140
  type GateQuorumRule,
129
141
  type GateQuorumRuleProgress,
@@ -213,6 +225,11 @@ export function trustRolesAt(repo: string, base: string): Record<string, string[
213
225
  export interface IdentityGate {
214
226
  gate: string;
215
227
  class: string | null;
228
+ /**
229
+ * `identity.gates.<gate>.quorum` (#4324): the approval rules an Op gate of
230
+ * this name takes in place of its own. Absent when the entry sets none.
231
+ */
232
+ quorum?: QuorumSpec;
216
233
  }
217
234
 
218
235
  /** The declaration at `base`, parsed, or null when there is none. Throws when it cannot be parsed. */
@@ -228,8 +245,14 @@ function declarationAt(repo: string, base: string): { file: string; value: unkno
228
245
  }
229
246
 
230
247
  function identityGatesOf(declaration: unknown): IdentityGate[] {
231
- const gates = (declaration as { identity?: { gates?: Record<string, { class?: unknown } | null> } } | null)?.identity?.gates ?? {};
232
- return Object.entries(gates).map(([gate, entry]) => ({ gate, class: typeof entry?.class === "string" ? entry.class : null }));
248
+ const gates = (declaration as { identity?: { gates?: Record<string, { class?: unknown; quorum?: unknown } | null> } } | null)?.identity?.gates ?? {};
249
+ return Object.entries(gates).map(([gate, entry]) => {
250
+ if (entry?.quorum === undefined) return { gate, class: typeof entry?.class === "string" ? entry.class : null };
251
+ // #4324: a quorum chant would refuse leaves the gate undecidable, as chant's own read does.
252
+ const [problem] = quorumProblemsOf(entry.quorum, `identity.gates.${gate}.quorum`, { notAuthor: false });
253
+ if (problem) throw new Error(`chant.workspace.json at base: ${problem.replace(/`/g, "")}, so the gate cannot be decided`);
254
+ return { gate, class: typeof entry.class === "string" ? entry.class : null, quorum: structuredClone(entry.quorum) as QuorumSpec };
255
+ });
233
256
  }
234
257
 
235
258
  /**
@@ -1,4 +1,5 @@
1
1
  import type { GraphIR, IRNode, IREdge } from "./graph-ir";
2
+ import { subTemplateRefs } from "./graph-sub-template";
2
3
 
3
4
  /**
4
5
  * Detail tiers — the diagram "detail dial". Each level is a pure IR → IR
@@ -60,13 +61,13 @@ function paintAttrs(attrs: Record<string, unknown>): Record<string, unknown> {
60
61
  return out;
61
62
  }
62
63
 
63
- /** A `{ $ref: "producer.attribute" }` envelope — a reference, not a property tree. */
64
+ /** A `{ $ref: "producer.attribute" }` or `{ $sub: "..." }` (#4373) envelope — a reference, not a property tree. */
64
65
  function isRefEnvelope(v: unknown): boolean {
65
66
  return (
66
67
  typeof v === "object" &&
67
68
  v !== null &&
68
69
  !Array.isArray(v) &&
69
- typeof (v as { $ref?: unknown }).$ref === "string"
70
+ (typeof (v as { $ref?: unknown }).$ref === "string" || typeof (v as { $sub?: unknown }).$sub === "string")
70
71
  );
71
72
  }
72
73
 
@@ -271,7 +272,8 @@ function toAttributes(ir: GraphIR): GraphIR {
271
272
  return { ...ir, edges };
272
273
  }
273
274
 
274
- /** Find the attribute in a `{ $ref: "producer.attribute" }` envelope under attrs. */
275
+ /** Find the attribute in a `{ $ref: "producer.attribute" }` envelope under attrs,
276
+ * or in a `{ $sub }` envelope's `${producer.attribute}` (#4373). */
275
277
  function findRefAttr(attrs: Record<string, unknown>, producer: string): string | undefined {
276
278
  let found: string | undefined;
277
279
  const visit = (v: unknown): void => {
@@ -288,6 +290,16 @@ function findRefAttr(attrs: Record<string, unknown>, producer: string): string |
288
290
  return;
289
291
  }
290
292
  }
293
+ const sub = (v as { $sub?: unknown; $vars?: unknown }).$sub;
294
+ if (typeof sub === "string") {
295
+ const vars = (v as { $vars?: unknown }).$vars;
296
+ const bound = new Set(vars && typeof vars === "object" ? Object.keys(vars) : []);
297
+ const hit = subTemplateRefs(sub, bound).find((r) => r.name === producer && r.attr);
298
+ if (hit) {
299
+ found = hit.attr;
300
+ return;
301
+ }
302
+ }
291
303
  for (const val of Object.values(v as Record<string, unknown>)) visit(val);
292
304
  };
293
305
  visit(attrs);