@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
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { execFileSync } from "node:child_process";
10
- import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
10
+ import { cpSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
11
11
  import { tmpdir } from "node:os";
12
12
  import { dirname, join } from "node:path";
13
13
  import Ajv2020 from "ajv/dist/2020";
@@ -26,6 +26,8 @@ import {
26
26
  type StatusDocument,
27
27
  } from "./status";
28
28
  import schema from "./status.schema.json";
29
+ import { REPO } from "./__fixtures__/contract-repo";
30
+ import { parseFrontMatter } from "./records";
29
31
  import { appendRunRecord } from "../lifecycle/run-ledger";
30
32
  import { acquireStewardLease } from "../op/operator";
31
33
  import { stewardWorkHolder } from "../op/work-lease-run";
@@ -525,6 +527,8 @@ describe("gate state in chant workspace status --json (#2674)", () => {
525
527
  approvals: [{ principal: "alice", channel: "cli", relayedBy: null, at: "2026-09-20T01:00:00.000Z" }],
526
528
  needed: 1,
527
529
  signed: null,
530
+ // No record kind is declared, so no decision covers web.
531
+ decisions: [],
528
532
  approve: `chant approve web deploy --env staging --plan ${D("1")}`,
529
533
  },
530
534
  {
@@ -538,6 +542,7 @@ describe("gate state in chant workspace status --json (#2674)", () => {
538
542
  approvals: [],
539
543
  needed: 1,
540
544
  signed: null,
545
+ decisions: [],
541
546
  approve: `chant approve web deploy --env prod --plan ${D("2")}`,
542
547
  },
543
548
  {
@@ -552,6 +557,7 @@ describe("gate state in chant workspace status --json (#2674)", () => {
552
557
  approvals: [{ principal: "bob", channel: "cli", relayedBy: null, at: "2026-09-20T02:00:00.000Z" }],
553
558
  needed: 2,
554
559
  signed: null,
560
+ decisions: [],
555
561
  approve: `chant approve web review --env staging --plan ${D("4")}`,
556
562
  },
557
563
  ]);
@@ -629,6 +635,45 @@ describe("gate state in chant workspace status --json (#2674)", () => {
629
635
  });
630
636
  });
631
637
 
638
+ describe("the decisions covering a gate's member (#3616)", () => {
639
+ test("each gate names the current decisions covering its member, ranked as why ranks them", async () => {
640
+ const ref = join(REPO, "reference-workspace", "decisions");
641
+ const fm = parseFrontMatter(readFileSync(join(ref, "ref-001-how-the-app-is-deployed.md"), "utf-8"));
642
+ if (!fm.ok) throw new Error(fm.message);
643
+ const base = fm.value;
644
+ const decision = (id: string, fields: Record<string, unknown>) =>
645
+ `---\n${JSON.stringify({ ...base, id, title: `Decision ${id}`, state: "decided", supersedes: [], evidence: [], reviews: [], ...fields }, null, 2)}\n---\n\n# ${id}\n`;
646
+ const root = repo({
647
+ "chant.workspace.json": JSON.stringify({
648
+ name: "acme",
649
+ schema: 1,
650
+ records: [{ kind: "decisions/decision.kind.mjs" }],
651
+ members: [
652
+ { name: "web", dir: "apps/web", kind: "other", because: "the app" },
653
+ { name: "api", dir: "apps/api", kind: "other", because: "the api" },
654
+ ],
655
+ }),
656
+ "decisions/decision.kind.mjs": readFileSync(join(ref, "decision.kind.mjs"), "utf-8"),
657
+ "decisions/decision.schema.json": readFileSync(join(ref, "decision.schema.json"), "utf-8"),
658
+ "apps/web/server.ts": "export {};\n",
659
+ "decisions/s-001-d.md": decision("s-001", { constrains: ["member:web"] }),
660
+ "decisions/s-002-d.md": decision("s-002", { constrains: ["path:apps"] }),
661
+ "decisions/s-003-d.md": decision("s-003", { constrains: ["path:apps/web/server.ts"] }),
662
+ "decisions/s-004-d.md": decision("s-004", { constrains: ["path:apps/web"] }),
663
+ "decisions/s-005-d.md": decision("s-005", { constrains: ["path:elsewhere"], supersedes: [{ decision: "s-004" }] }),
664
+ "decisions/s-006-d.md": decision("s-006", { constrains: ["member:api"] }),
665
+ });
666
+ lifecycle(root, { "_members/web/_gates/web.jsonl": jsonl(pending("web", "deploy", "2026-09-20T00:00:00.000Z", { environment: "staging", planDigest: D("1") })) });
667
+ const doc = result(await workspaceStatus({ cwd: root, env: "staging", now: NOW }));
668
+ expectValid(doc);
669
+ const [web, api] = doc.members;
670
+ // s-002 by a path above, s-001 by member, s-003 by a path inside; s-004 stands for s-005, which supersedes it.
671
+ expect(web.gates.map((g) => g.decisions)).toEqual([["decision/s-002", "decision/s-001", "decision/s-003", "decision/s-005"]]);
672
+ // A member with no gate reads no decisions.
673
+ expect(api.gates).toEqual([]);
674
+ });
675
+ });
676
+
632
677
  describe("stewards in chant workspace status --json (#2731)", () => {
633
678
  const op = (name: string, cron?: string) => ({
634
679
  name,
@@ -0,0 +1,100 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { Declaration } from "./declaration";
3
+ import type { LoadedRecordKind, RecordEntry } from "./records";
4
+ import { memberDecisionsReader, type DecisionKindReader } from "./status-decisions";
5
+
6
+ const members = [
7
+ { name: "root", dir: "." },
8
+ { name: "api", dir: "services/api" },
9
+ { name: "edge", dir: "services/api/edge" },
10
+ { name: "web", dir: "web" },
11
+ ];
12
+
13
+ function declaration(kinds: string[]): Declaration {
14
+ return {
15
+ records: kinds.map((path) => ({ kind: path, path, name: null, member: null, pointer: "/records/0" })),
16
+ members: members.map((m) => ({ ...m, records: [] })),
17
+ } as unknown as Declaration;
18
+ }
19
+
20
+ function kind(name: string, extra: Record<string, unknown> = {}): LoadedRecordKind {
21
+ return { kind: { name, constrains: { field: "constrains" }, closedStates: ["accepted"], ...extra } } as unknown as LoadedRecordKind;
22
+ }
23
+
24
+ function record(id: string, constrains: string[], state = "proposed", supersededBy: string | null = null): RecordEntry {
25
+ return { id, path: `decisions/${id}.md`, state, supersededBy, data: { constrains } } as unknown as RecordEntry;
26
+ }
27
+
28
+ function reader(kinds: Record<string, { loaded: LoadedRecordKind; records: RecordEntry[]; workspaceRoot?: string } | Error>): DecisionKindReader {
29
+ return async (file) => {
30
+ const k = Object.entries(kinds).find(([path]) => file.endsWith(path))?.[1];
31
+ if (!k) throw new Error(`no kind ${file}`);
32
+ if (k instanceof Error) throw k;
33
+ return { loaded: k.loaded, top: undefined, workspaceRoot: k.workspaceRoot ?? ".", records: k.records };
34
+ };
35
+ }
36
+
37
+ describe("the decisions covering a gate's member (#3616)", () => {
38
+ test("path above, member and path inside, ranked as why ranks them", async () => {
39
+ const read = reader({
40
+ "decision.kind.mjs": {
41
+ loaded: kind("decision"),
42
+ records: [
43
+ record("d-inside", ["path:services/api/src/handler.ts"]),
44
+ record("d-member", ["member:api"]),
45
+ record("d-services", ["path:services"]),
46
+ record("d-api", ["path:services/api"], "accepted"),
47
+ record("d-api-open", ["path:services/api"]),
48
+ record("d-web", ["path:web", "member:web"]),
49
+ record("d-edge-only", ["path:services/api/edge/x.ts"]),
50
+ ],
51
+ },
52
+ });
53
+ const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo", "", read);
54
+ // Closed before open at one path; a longer path before a shorter one; then member; then inside.
55
+ expect(covering(members[1])).toEqual(["decision/d-api", "decision/d-api-open", "decision/d-services", "decision/d-member", "decision/d-inside"]);
56
+ // A path inside a nested member is the nested member's, and the path above covers it too.
57
+ expect(covering(members[2])).toEqual(["decision/d-api", "decision/d-api-open", "decision/d-services", "decision/d-edge-only"]);
58
+ expect(covering(members[3])).toEqual(["decision/d-web"]);
59
+ // The root member holds services itself, and no path another member holds.
60
+ expect(covering(members[0])).toEqual(["decision/d-services"]);
61
+ });
62
+
63
+ test("a superseded covering decision stands for the current one at the end of its chain", async () => {
64
+ const read = reader({
65
+ "decision.kind.mjs": {
66
+ loaded: kind("decision"),
67
+ records: [record("old", ["member:web"], "superseded", "mid"), record("mid", [], "superseded", "new"), record("new", ["path:elsewhere"], "accepted"), record("gone", ["member:web"], "superseded", "missing")],
68
+ },
69
+ });
70
+ const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo", "", read);
71
+ expect(covering(members[3])).toEqual(["decision/new"]);
72
+ });
73
+
74
+ test("path entries resolve from the kind's workspace root, and a member's dir from the workspace's", async () => {
75
+ const read = reader({
76
+ "decision.kind.mjs": { loaded: kind("decision"), workspaceRoot: "ws", records: [record("d", ["path:web"])] },
77
+ });
78
+ const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo/ws", "ws", read);
79
+ expect(covering(members[3])).toEqual(["decision/d"]);
80
+ expect(covering(members[1])).toEqual([]);
81
+ });
82
+
83
+ test("work kinds, kinds without constrains and unreadable kinds cover nothing", async () => {
84
+ const read = reader({
85
+ "work.kind.mjs": { loaded: kind("work", { work: {} }), records: [record("w", ["member:web"])] },
86
+ "note.kind.mjs": { loaded: kind("note", { constrains: undefined }), records: [record("n", ["member:web"])] },
87
+ "broken.kind.mjs": new Error("kind-unreadable"),
88
+ "adr.kind.mjs": { loaded: kind("adr"), records: [record("a", ["member:web"])] },
89
+ });
90
+ const covering = await memberDecisionsReader(declaration(["work.kind.mjs", "note.kind.mjs", "broken.kind.mjs", "adr.kind.mjs"]), "/repo", "", read);
91
+ expect(covering(members[3])).toEqual(["adr/a"]);
92
+ });
93
+
94
+ test("no declared record kind reads nothing", async () => {
95
+ const covering = await memberDecisionsReader(declaration([]), "/repo", "", async () => {
96
+ throw new Error("not read");
97
+ });
98
+ expect(covering(members[3])).toEqual([]);
99
+ });
100
+ });
@@ -0,0 +1,151 @@
1
+ /**
2
+ * The decisions covering each member, for the gates in `chant workspace
3
+ * status --json` (#3616): a reader showing a gate to the person about to
4
+ * approve it names the decision the gate enforces without a
5
+ * `graph --intent` walk of its own.
6
+ *
7
+ * This is the part of the intent walk (`intent.ts`) that reads only records.
8
+ * A decision covers a member when one of its `constrains` entries is
9
+ * `member:<name>`, or a `path:` that is the member's directory, a directory
10
+ * above it, or a path inside it that the member holds (not a member nested
11
+ * in it). A superseded covering decision stands for the decision that
12
+ * supersedes it, at the end of its chain. Only current decisions are listed,
13
+ * as `<kind>/<id>`, ranked as `why.decisions` ranks them
14
+ * (`decision-rank.ts`). `carried` needs the member's history, so it never
15
+ * applies, and neither do `issue` or `contract`, which need commits. Every
16
+ * declared record kind other than a work kind is read, as the intent walk
17
+ * reads them; a kind that can't be read is left out.
18
+ */
19
+
20
+ import { declaredRecordKinds, type Declaration } from "./declaration";
21
+ import { declaredKindFile } from "./declared-kinds";
22
+ import { compareDecisionRank, type DecisionRankKey, type WhyRelevance } from "./decision-rank";
23
+ import { decidedCommits } from "./record-decided";
24
+ import { constraintCovers, isWorkspacePath, memberHolding } from "./record-assets";
25
+ import type { LoadedRecordKind, RecordEntry } from "./records";
26
+ import { joinPath } from "./tree";
27
+
28
+ interface ReadKind {
29
+ loaded: LoadedRecordKind;
30
+ top: string | undefined;
31
+ /** Where the kind's `path:` entries resolve, from the git top. */
32
+ prefix: string;
33
+ records: RecordEntry[];
34
+ byId: Map<string, RecordEntry>;
35
+ }
36
+
37
+ /** Reads one kind's records, current and superseded; `readRecordsFor` in the working tree unless a test swaps it. */
38
+ export type DecisionKindReader = (file: string, root: string) => Promise<{ loaded: LoadedRecordKind; top: string | undefined; workspaceRoot: string; records: RecordEntry[] }>;
39
+
40
+ const defaultReader: DecisionKindReader = async (file, root) => {
41
+ const { readRecordsFor } = await import("./records-cli");
42
+ const read = await readRecordsFor({ kind: file, cwd: root });
43
+ return { loaded: read.loaded, top: read.top, workspaceRoot: read.workspaceRoot, records: read.result.records };
44
+ };
45
+
46
+ /**
47
+ * Read the declared decision kinds once and return the covering decisions of
48
+ * a member. `root` is the workspace root on disk and `rootDir` the same from
49
+ * the git top (`""` at the top).
50
+ */
51
+ export async function memberDecisionsReader(
52
+ declaration: Declaration,
53
+ root: string,
54
+ rootDir: string,
55
+ read: DecisionKindReader = defaultReader,
56
+ ): Promise<(member: { name: string; dir: string }) => string[]> {
57
+ const kinds: ReadKind[] = [];
58
+ for (const d of declaredRecordKinds(declaration)) {
59
+ try {
60
+ const r = await read(declaredKindFile(d, root), root);
61
+ if (r.loaded.kind.work) continue;
62
+ const byId = new Map<string, RecordEntry>();
63
+ for (const v of r.records) if (v.id !== null) byId.set(v.id, v);
64
+ kinds.push({ loaded: r.loaded, top: r.top, prefix: r.workspaceRoot === "." ? "" : r.workspaceRoot, records: r.records, byId });
65
+ } catch {
66
+ // A kind that can't be read covers nothing here; workspace check and records report why.
67
+ }
68
+ }
69
+ // When each current decision was decided, read once per kind on first need.
70
+ const decidedOn = new Map<ReadKind, Map<string, string | null>>();
71
+ const decidedDate = (k: ReadKind, v: RecordEntry): string | null => {
72
+ if (!k.loaded.kind.approval || !k.top) return null;
73
+ let dates = decidedOn.get(k);
74
+ if (!dates) {
75
+ const current = k.records.filter((r) => r.id !== null && r.supersededBy === null).map((r) => r.path);
76
+ const decided = decidedCommits(k.top, "HEAD", current, k.loaded.kind);
77
+ dates = new Map(current.map((p) => [p, decided.get(p)?.date ?? null]));
78
+ decidedOn.set(k, dates);
79
+ }
80
+ return dates.get(v.path) ?? null;
81
+ };
82
+
83
+ return (member) => {
84
+ const memberFull = joinPath(rootDir, member.dir);
85
+ const ranked: { key: DecisionRankKey; label: string }[] = [];
86
+ for (const k of kinds) {
87
+ const field = k.loaded.kind.constrains?.field;
88
+ if (!field) continue;
89
+ const name = k.loaded.kind.name;
90
+ /** How each record covers the member: the relevance and the longest covering path entry. */
91
+ const covers = (v: RecordEntry): { relevance: WhyRelevance; specificity: number } | null => {
92
+ const list = v.data?.[field];
93
+ if (!Array.isArray(list)) return null;
94
+ let path = 0;
95
+ let byMember = false;
96
+ let inside = false;
97
+ for (const entry of list) {
98
+ if (typeof entry !== "string") continue;
99
+ if (entry.startsWith("member:")) {
100
+ if (entry.slice("member:".length) === member.name) byMember = true;
101
+ } else if (entry.startsWith("path:")) {
102
+ const p = entry.slice("path:".length);
103
+ if (!isWorkspacePath(p)) continue;
104
+ const full = joinPath(k.prefix, p);
105
+ if (memberFull !== "" && constraintCovers(full, memberFull)) path = Math.max(path, entry.length);
106
+ else if (memberFull === "" || full.startsWith(`${memberFull}/`)) {
107
+ // Inside the member's directory, and not in a member nested in it.
108
+ const inWorkspace = rootDir === "" ? full : full.startsWith(`${rootDir}/`) ? full.slice(rootDir.length + 1) : null;
109
+ if (inWorkspace !== null && memberHolding(inWorkspace, declaration.members) === member.name) inside = true;
110
+ }
111
+ }
112
+ }
113
+ if (path > 0) return { relevance: "path", specificity: path };
114
+ if (byMember) return { relevance: "member", specificity: 0 };
115
+ return inside ? { relevance: "related", specificity: 0 } : null;
116
+ };
117
+ // Each covering record, and the current record at the end of its supersession chain.
118
+ const current = new Set<string>();
119
+ for (const v of k.records) {
120
+ if (v.id === null || covers(v) === null) continue;
121
+ let at: RecordEntry = v;
122
+ const seen = new Set<string>();
123
+ while (at.supersededBy !== null && !seen.has(at.id!)) {
124
+ seen.add(at.id!);
125
+ const next = k.byId.get(at.supersededBy);
126
+ if (!next) break;
127
+ at = next;
128
+ }
129
+ if (at.supersededBy === null && at.id !== null) current.add(at.id);
130
+ }
131
+ for (const id of current) {
132
+ const v = k.byId.get(id)!;
133
+ // A decision in the list only through the chain is related, as in why.
134
+ const c = covers(v) ?? { relevance: "related" as const, specificity: 0 };
135
+ ranked.push({
136
+ label: `${name}/${id}`,
137
+ key: {
138
+ id: `record:${name}/${id}`,
139
+ current: true,
140
+ relevance: c.relevance,
141
+ lines: 0,
142
+ closed: v.state !== null && (k.loaded.kind.closedStates ?? []).includes(v.state),
143
+ specificity: c.specificity,
144
+ decidedOn: decidedDate(k, v),
145
+ },
146
+ });
147
+ }
148
+ }
149
+ return ranked.sort((a, b) => compareDecisionRank(a.key, b.key)).map((r) => r.label);
150
+ };
151
+ }
@@ -82,6 +82,15 @@ export interface StatusGate {
82
82
  * `release-revoked`. Added by `workspace status`; absent otherwise.
83
83
  */
84
84
  revoked?: ReleaseRevocation;
85
+ /**
86
+ * The current decisions covering the gate's member (#3616), as
87
+ * `<kind>/<id>`, most relevant first: by a `path:` at or above the
88
+ * member's directory, by `member:`, then by a path inside it or through
89
+ * supersession, ranked as the intent graph's `why.decisions`. Read from
90
+ * the records only, without history. Added by `workspace status`; absent
91
+ * otherwise.
92
+ */
93
+ decisions?: string[];
85
94
  /** When the run recorded the pending fact the state is read against. */
86
95
  recordedAt: string;
87
96
  /** The commit the run reached the gate at (#4020), from the pending fact. Absent on a fact written before chant 0.124.28. */
@@ -104,6 +104,7 @@
104
104
  "required": ["name", "root", "file"],
105
105
  "properties": {
106
106
  "name": { "type": "string" },
107
+ "repo": { "type": ["string", "null"], "description": "Added in contract 1 by #3168. The repository the document came from: the URL of the remote origin of the git repository that holds the workspace, with any user name or password removed, or null when there is no origin or the workspace is outside git. With name, root and the revision, it says which repository's workspace a document describes, so a reader that gathers several repositories' documents, such as an org workspace's repo members, tells them apart." },
107
108
  "root": { "type": "string", "description": "The workspace root relative to the git root, with / separators, \".\" for the git root itself." },
108
109
  "file": { "enum": ["chant.workspace.json", "chant.workspace.jsonc"] }
109
110
  }
@@ -987,6 +988,11 @@
987
988
  "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." },
988
989
  "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." },
989
990
  "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." },
991
+ "decisions": {
992
+ "type": "array",
993
+ "items": { "type": "string", "pattern": "^[^/]+/.+$" },
994
+ "description": "Added in contract 1 by #3616, written by chant 0.124.47 and newer. The current decisions covering the gate's member, as <kind>/<id>, most relevant first, so a reader names the decision a gate enforces without a graph --intent walk. A decision covers the member by a path: constraint that is the member's directory or a directory above it, by member:<name>, or by a path: inside the directory that the member holds; a superseded covering decision stands for the current one at the end of its chain. Ranked as the intent graph's why.decisions ranks them (path, then member, then the rest; then closed, longer path, newest decided, id), without carried, issue or contract, which need history. Read from every declared record kind but work kinds, in the working tree; a kind that can't be read is left out. The same list on every gate of a member, and empty when nothing covers it. Absent from an older chant."
995
+ },
990
996
  "expiresAt": { "type": "string" },
991
997
  "approvals": {
992
998
  "description": "The approvals that count toward the gate for its plan, oldest first.",
@@ -50,6 +50,7 @@ import { findWorkspaceRoot } from "../project-root";
50
50
  import { resolveBoxes, type ResolvedIsolation } from "./box-isolation";
51
51
  import { resolveBoxIntents, unresolvedIntent, type BoxIntent } from "./box-intent";
52
52
  import { loadKindRegistry, resolveMemberFields, type MemberFields } from "./kinds";
53
+ import { repoIdentity } from "./repo-ref";
53
54
  import { factoryView, listingView, plantability, treeBytes, type FactoryView, type ListingView, type Plantable } from "./box-factory";
54
55
  import { declaredRecordKinds, extensionsAt, readDeclaration, readerVersion, WorkspaceReadError, type Declaration, type ErrorLocation, type Member } from "./declaration";
55
56
  import type { ReasonCode } from "./reason-codes";
@@ -63,6 +64,7 @@ import { scopeSource } from "./write-scope";
63
64
  import { GATE_REASON_CODES, readMemberGates, type GateLedgerReader, type StatusGate, type StatusGateLedger } from "./status-gates";
64
65
  import { trustQuorumJudge } from "../op/gate-quorum";
65
66
  import { STEWARD_REASON_CODES, readMemberStewards, type StatusSteward, type StewardReasonCode } from "./status-stewards";
67
+ import { memberDecisionsReader, type DecisionKindReader } from "./status-decisions";
66
68
  import { gitTop, workingTree } from "./tree";
67
69
  import { handToRootChant } from "./which-chant";
68
70
 
@@ -387,7 +389,7 @@ export type StatusDocument =
387
389
  lifecycle: { ref: string; commit: string | null };
388
390
  /** The branch, head and base of the checkout read (#3160). `records --uncommitted` lists the records it holds uncommitted. */
389
391
  checkout: CheckoutHead;
390
- workspace: { name: string; root: string; file: string };
392
+ workspace: { name: string; root: string; file: string; repo: string | null };
391
393
  /** Whether a host can plant the workspace as one box (#3146): exactly one member's box block declares services. */
392
394
  plantable: Plantable;
393
395
  members: StatusMember[];
@@ -433,6 +435,8 @@ export interface StatusQuery {
433
435
  readStewards?: typeof readMemberStewards;
434
436
  /** Reads one member's promotion order from its directory; its chant.config.ts unless a test swaps it. */
435
437
  readPromotionOrder?: (dir: string) => Promise<PromotionStep[] | null>;
438
+ /** Reads one record kind for the decisions covering each gate's member (#3616); the working tree unless a test swaps it. */
439
+ readDecisionKind?: DecisionKindReader;
436
440
  }
437
441
 
438
442
  /** A factory view with the declaration's x- keys on it and on its check, publish and tiers (#3595). */
@@ -727,6 +731,9 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
727
731
  const revoked = () => (revokedCommits ??= revokedCommitsAt(top, ruleSource.declaration?.ci?.green ?? null).catch(() => new Map()));
728
732
  // #4024: the flag records, read once for every member. Unreadable records list as null.
729
733
  const flags = await readStatusFlags(declaration, found.dir);
734
+ // #3616: the decisions covering each member, read from the records once and only when a gate is met.
735
+ let coveringReader: ReturnType<typeof memberDecisionsReader> | undefined;
736
+ const covering = () => (coveringReader ??= memberDecisionsReader(declaration, found.dir, rootDir, query.readDecisionKind));
730
737
  const members: StatusMember[] = [];
731
738
  for (const m of declaration.members) {
732
739
  const revokedOf = revokedReleaseLookup(resolve(found.dir, m.dir), revoked);
@@ -748,7 +755,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
748
755
  compare: query.compareTo === undefined ? null : compareEnvironments(environments[0], environments[environments.length - 1]),
749
756
  readable: environments.every((e) => e.reason === null),
750
757
  gateLedger: gates.ledger,
751
- gates: await supersedeRevokedGates(gates.gates, revokedOf),
758
+ gates: await withDecisions(await supersedeRevokedGates(gates.gates, revokedOf), m, covering),
752
759
  box:
753
760
  m.box === null
754
761
  ? null
@@ -807,7 +814,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
807
814
  compareTo: query.compareTo ?? null,
808
815
  lifecycle: { ref: LIFECYCLE_REF, commit },
809
816
  checkout: readCheckoutHead(top),
810
- workspace: { name: declaration.name, root: rootDir === "" ? "." : rootDir, file: declaration.file },
817
+ workspace: { name: declaration.name, root: rootDir === "" ? "." : rootDir, file: declaration.file, repo: repoIdentity(found.dir) },
811
818
  plantable: plantability(declaration),
812
819
  members,
813
820
  leases,
@@ -889,6 +896,13 @@ async function readStatusFlags(declaration: Declaration, root: string): Promise<
889
896
  }
890
897
  }
891
898
 
899
+ /** Each gate with the current decisions covering its member (#3616), when the member has gates. */
900
+ async function withDecisions(gates: StatusGate[], m: { name: string; dir: string }, covering: () => ReturnType<typeof memberDecisionsReader>): Promise<StatusGate[]> {
901
+ if (gates.length === 0) return gates;
902
+ const decisions = (await covering())(m);
903
+ return gates.map((g) => ({ ...g, decisions: [...decisions] }));
904
+ }
905
+
892
906
  /** The overlap report (#4025); null when no work kind is declared or it can't be read. */
893
907
  async function readStatusOverlap(declaration: Declaration, root: string, top: string, changeSets: OverlapChangeSetRef[]): Promise<OverlapReport | null> {
894
908
  if (declaredRecordKinds(declaration).length === 0) return null;
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parseArgs } from "../cli/main";
3
+ import { matchesWhere, parseWhere } from "../read-filter";
4
+ import { filterRecordsDocument, RECORD_FILTER_FIELDS, type RecordsDocument } from "./records-cli";
5
+ import { RUN_FILTER_FIELDS, RunsFilterError, workspaceRuns } from "./runs-cli";
6
+
7
+ describe("--where on records and runs (#4363)", () => {
8
+ it("parses --where as a repeatable flag", () => {
9
+ expect(parseArgs(["ledger", "gates", "--where", "op=tf-apply", "--where", "kind=pending"]).where).toEqual(["op=tf-apply", "kind=pending"]);
10
+ expect(() => parseArgs(["ledger", "gates", "--where"])).toThrow(/--where needs a clause/);
11
+ });
12
+
13
+ it("filters the records a read lists and counts summary over them", () => {
14
+ const rec = (id: string, state: string, valid: boolean, data: Record<string, unknown>) => ({ id, path: `d/${id}.md`, state, valid, data, supersededBy: null, provenance: { level: "unattested" } });
15
+ const doc = {
16
+ $schema: "x",
17
+ contract: 1,
18
+ records: [rec("D-1", "accepted", true, { owner: "ops" }), rec("D-2", "proposed", true, { owner: "dev" }), rec("D-3", "accepted", false, { owner: "dev" })],
19
+ summary: { total: 3, valid: 2, invalid: 1, superseded: 4 },
20
+ } as unknown as RecordsDocument;
21
+ const where = ["state=accepted", "data.owner=dev"];
22
+ const out = filterRecordsDocument(doc, parseWhere(where, RECORD_FILTER_FIELDS), where);
23
+ if ("error" in out) throw new Error("failed");
24
+ expect(out.records.map((r) => r.id)).toEqual(["D-3"]);
25
+ expect(out.summary).toEqual({ total: 1, valid: 0, invalid: 1, superseded: 4 });
26
+ expect(out.where).toEqual(where);
27
+ expect(filterRecordsDocument(doc, [], [])).toBe(doc);
28
+ });
29
+
30
+ it("filters runs on their typed fields", () => {
31
+ const run = { id: "r1", state: "ended", startedAt: "2026-10-22T00:00:00.000Z", model: "opus", unit: { id: "W-1", kind: "work" }, cost: { amount: 1.5, currency: "USD" } };
32
+ expect(matchesWhere(run, parseWhere(["cost.amount>1", "unit.id=W-1", "startedAt>=2026-10-21"], RUN_FILTER_FIELDS))).toBe(true);
33
+ expect(matchesWhere(run, parseWhere(["model!=opus"], RUN_FILTER_FIELDS))).toBe(false);
34
+ });
35
+
36
+ it("refuses a runs --where it can't apply before reading anything", async () => {
37
+ await expect(workspaceRuns({ cwd: "/nonexistent", where: ["tokens>5"] })).rejects.toThrow(RunsFilterError);
38
+ });
39
+ });
@@ -436,7 +436,8 @@ export function formatWorkHistory(doc: Extract<WorkHistoryDocument, { claims: un
436
436
  * <file|->` (#3159): the `workEvidence` activity (#2772) as a command, so a
437
437
  * writer that is not an Op, such as hud, attaches evidence through chant under
438
438
  * the lease it holds. `--from` gives the entry as JSON: criterion, result,
439
- * title, a url or a path, and optionally as_of. It always prints the
439
+ * title, a url, a path or an ops result to cite (#3171), and optionally
440
+ * as_of. It always prints the
440
441
  * work-evidence document; exit 0 when the entry was appended, 1 otherwise.
441
442
  */
442
443
  async function runWorkEvidence(ctx: CommandContext): Promise<number> {
@@ -452,7 +453,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
452
453
  if (!id) return fail("evidence needs a work item id");
453
454
  if (!args.holder) return fail("evidence needs --holder <name>: the lease's holder");
454
455
  if (!args.token) return fail("evidence needs --token <token>: the lease's fencing token, as its claim printed it");
455
- if (args.migrateFrom === undefined) return fail("evidence needs --from <file|->: the entry as JSON, with criterion, result, title and a url or a path");
456
+ if (args.migrateFrom === undefined) return fail("evidence needs --from <file|->: the entry as JSON, with criterion, result, title and a url, a path or an ops result");
456
457
  for (const [flag, v] of [["--ttl", args.ttl], ["--outcome", args.outcome], ["--note", args.note]] as const) {
457
458
  if (v !== undefined) return fail(`evidence takes no ${flag}`);
458
459
  }
@@ -470,7 +471,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
470
471
  1,
471
472
  );
472
473
  }
473
- const known = ["criterion", "result", "title", "url", "path", "as_of"];
474
+ const known = ["criterion", "result", "title", "url", "path", "ops", "as_of"];
474
475
  const unknown = Object.keys(fields).filter((k) => !known.includes(k));
475
476
  if (unknown.length > 0) return fail(`the entry takes ${known.join(", ")}, not ${unknown.join(", ")}`);
476
477
  const str = (k: string): string | undefined => (typeof fields[k] === "string" ? (fields[k] as string) : undefined);
@@ -485,6 +486,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
485
486
  title: str("title") ?? "",
486
487
  url: str("url"),
487
488
  path: str("path"),
489
+ ops: fields.ops as never,
488
490
  asOf: str("as_of"),
489
491
  });
490
492
  return print(doc, "error" in doc ? 1 : 0);