@intentius/chant 0.91.0 → 0.93.0

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 (344) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/lint.d.ts.map +1 -1
  3. package/dist/cli/handlers/graph.d.ts.map +1 -1
  4. package/dist/cli/handlers/operator.d.ts +6 -0
  5. package/dist/cli/handlers/operator.d.ts.map +1 -1
  6. package/dist/cli/handlers/run.d.ts.map +1 -1
  7. package/dist/cli/main.d.ts.map +1 -1
  8. package/dist/cli/mcp/workspace-tools.d.ts +2 -1
  9. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  10. package/dist/cli/plugins.d.ts.map +1 -1
  11. package/dist/cli/registry.d.ts +12 -2
  12. package/dist/cli/registry.d.ts.map +1 -1
  13. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  14. package/dist/config.d.ts +22 -0
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/lexicon-module.d.ts +22 -0
  17. package/dist/lexicon-module.d.ts.map +1 -1
  18. package/dist/lifecycle/converge-ledger.d.ts +19 -0
  19. package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
  20. package/dist/lifecycle/run-ledger.d.ts +2 -0
  21. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  22. package/dist/lifecycle/symptoms.d.ts +51 -0
  23. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  24. package/dist/lint/rules/index.d.ts +4 -2
  25. package/dist/lint/rules/index.d.ts.map +1 -1
  26. package/dist/lint/rules/op/index.d.ts +14 -3
  27. package/dist/lint/rules/op/index.d.ts.map +1 -1
  28. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -1
  29. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts +29 -0
  30. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts.map +1 -0
  31. package/dist/lint/rules/sys001-no-literal-key.d.ts +3 -0
  32. package/dist/lint/rules/sys001-no-literal-key.d.ts.map +1 -0
  33. package/dist/op/__fixtures__/decide-stub-backend.d.ts +53 -0
  34. package/dist/op/__fixtures__/decide-stub-backend.d.ts.map +1 -0
  35. package/dist/op/activities/activity-contracts.d.ts +201 -0
  36. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  37. package/dist/op/activities/apply.d.ts.map +1 -1
  38. package/dist/op/activities/change-coverage.d.ts +44 -0
  39. package/dist/op/activities/change-coverage.d.ts.map +1 -0
  40. package/dist/op/activities/converge.d.ts +24 -1
  41. package/dist/op/activities/converge.d.ts.map +1 -1
  42. package/dist/op/activities/decide.d.ts +107 -0
  43. package/dist/op/activities/decide.d.ts.map +1 -0
  44. package/dist/op/activities/index.d.ts +10 -0
  45. package/dist/op/activities/index.d.ts.map +1 -1
  46. package/dist/op/activities/shell.d.ts +32 -0
  47. package/dist/op/activities/shell.d.ts.map +1 -1
  48. package/dist/op/activities/source-release.d.ts +86 -0
  49. package/dist/op/activities/source-release.d.ts.map +1 -0
  50. package/dist/op/activities/source-rollback.d.ts +100 -0
  51. package/dist/op/activities/source-rollback.d.ts.map +1 -0
  52. package/dist/op/activities/work-evidence.d.ts +42 -0
  53. package/dist/op/activities/work-evidence.d.ts.map +1 -0
  54. package/dist/op/activity-contract.d.ts +1 -0
  55. package/dist/op/activity-contract.d.ts.map +1 -1
  56. package/dist/op/activity-profiles.d.ts +16 -0
  57. package/dist/op/activity-profiles.d.ts.map +1 -1
  58. package/dist/op/builders.d.ts +84 -2
  59. package/dist/op/builders.d.ts.map +1 -1
  60. package/dist/op/composites/converge-op.d.ts +31 -4
  61. package/dist/op/composites/converge-op.d.ts.map +1 -1
  62. package/dist/op/decide-backend.d.ts +116 -0
  63. package/dist/op/decide-backend.d.ts.map +1 -0
  64. package/dist/op/decide-config.d.ts +120 -0
  65. package/dist/op/decide-config.d.ts.map +1 -0
  66. package/dist/op/decide-read-inputs.d.ts +40 -0
  67. package/dist/op/decide-read-inputs.d.ts.map +1 -0
  68. package/dist/op/gate-wait.d.ts +43 -0
  69. package/dist/op/gate-wait.d.ts.map +1 -0
  70. package/dist/op/gate.d.ts +5 -2
  71. package/dist/op/gate.d.ts.map +1 -1
  72. package/dist/op/index.d.ts +11 -4
  73. package/dist/op/index.d.ts.map +1 -1
  74. package/dist/op/local-executor.d.ts +29 -4
  75. package/dist/op/local-executor.d.ts.map +1 -1
  76. package/dist/op/local-output.d.ts +2 -0
  77. package/dist/op/local-output.d.ts.map +1 -1
  78. package/dist/op/op-ir.d.ts +2 -0
  79. package/dist/op/op-ir.d.ts.map +1 -1
  80. package/dist/op/op-verb-class.d.ts.map +1 -1
  81. package/dist/op/operator.d.ts +97 -1
  82. package/dist/op/operator.d.ts.map +1 -1
  83. package/dist/op/runtime.d.ts +37 -5
  84. package/dist/op/runtime.d.ts.map +1 -1
  85. package/dist/op/runtimes/local.d.ts.map +1 -1
  86. package/dist/op/source-archive.d.ts +63 -0
  87. package/dist/op/source-archive.d.ts.map +1 -0
  88. package/dist/op/steward-points.d.ts +136 -0
  89. package/dist/op/steward-points.d.ts.map +1 -0
  90. package/dist/op/steward-turn.d.ts +53 -0
  91. package/dist/op/steward-turn.d.ts.map +1 -0
  92. package/dist/op/steward.d.ts +22 -1
  93. package/dist/op/steward.d.ts.map +1 -1
  94. package/dist/op/types.d.ts +7 -0
  95. package/dist/op/types.d.ts.map +1 -1
  96. package/dist/op/work-lease-run.d.ts +1 -1
  97. package/dist/op/work-lease-run.d.ts.map +1 -1
  98. package/dist/workspace/__fixtures__/decide-workspace.d.ts +100 -0
  99. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -0
  100. package/dist/workspace/answers-ledger.d.ts +76 -0
  101. package/dist/workspace/answers-ledger.d.ts.map +1 -0
  102. package/dist/workspace/changes-cli.d.ts +16 -0
  103. package/dist/workspace/changes-cli.d.ts.map +1 -0
  104. package/dist/workspace/changes.d.ts +200 -0
  105. package/dist/workspace/changes.d.ts.map +1 -0
  106. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts +59 -0
  107. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts.map +1 -0
  108. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts +51 -0
  109. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts.map +1 -0
  110. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts +26 -0
  111. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts.map +1 -0
  112. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts +59 -0
  113. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts.map +1 -0
  114. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts +22 -0
  115. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts.map +1 -0
  116. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts +71 -0
  117. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -0
  118. package/dist/workspace/chant-migrations.d.ts +99 -0
  119. package/dist/workspace/chant-migrations.d.ts.map +1 -0
  120. package/dist/workspace/checks/boxes.d.ts +34 -1
  121. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  122. package/dist/workspace/checks/diagrams.d.ts +31 -0
  123. package/dist/workspace/checks/diagrams.d.ts.map +1 -0
  124. package/dist/workspace/checks/records.d.ts +7 -0
  125. package/dist/workspace/checks/records.d.ts.map +1 -1
  126. package/dist/workspace/checks.d.ts +3 -0
  127. package/dist/workspace/checks.d.ts.map +1 -1
  128. package/dist/workspace/compose-graph.d.ts +2 -0
  129. package/dist/workspace/compose-graph.d.ts.map +1 -1
  130. package/dist/workspace/conformance/index.d.ts.map +1 -1
  131. package/dist/workspace/decide.d.ts +49 -4
  132. package/dist/workspace/decide.d.ts.map +1 -1
  133. package/dist/workspace/declaration.d.ts +52 -0
  134. package/dist/workspace/declaration.d.ts.map +1 -1
  135. package/dist/workspace/declaration.schema.json +114 -1
  136. package/dist/workspace/declared-kinds.d.ts +20 -0
  137. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  138. package/dist/workspace/generated-files.d.ts +7 -0
  139. package/dist/workspace/generated-files.d.ts.map +1 -1
  140. package/dist/workspace/intent.d.ts.map +1 -1
  141. package/dist/workspace/lineage-check.d.ts +3 -0
  142. package/dist/workspace/lineage-check.d.ts.map +1 -1
  143. package/dist/workspace/lineage-upgrade.d.ts +6 -1
  144. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  145. package/dist/workspace/ls.d.ts +39 -1
  146. package/dist/workspace/ls.d.ts.map +1 -1
  147. package/dist/workspace/point-answer.schema.json +95 -0
  148. package/dist/workspace/points-cli.d.ts.map +1 -1
  149. package/dist/workspace/points.d.ts +1 -1
  150. package/dist/workspace/reason-codes.d.ts +14 -2
  151. package/dist/workspace/reason-codes.d.ts.map +1 -1
  152. package/dist/workspace/records-cli.d.ts +11 -1
  153. package/dist/workspace/records-cli.d.ts.map +1 -1
  154. package/dist/workspace/records-close.d.ts +1 -1
  155. package/dist/workspace/records-close.d.ts.map +1 -1
  156. package/dist/workspace/records-write.d.ts +11 -5
  157. package/dist/workspace/records-write.d.ts.map +1 -1
  158. package/dist/workspace/records.d.ts +34 -4
  159. package/dist/workspace/records.d.ts.map +1 -1
  160. package/dist/workspace/status-gates.d.ts +7 -2
  161. package/dist/workspace/status-gates.d.ts.map +1 -1
  162. package/dist/workspace/status-stewards.d.ts +59 -1
  163. package/dist/workspace/status-stewards.d.ts.map +1 -1
  164. package/dist/workspace/status.d.ts +16 -0
  165. package/dist/workspace/status.d.ts.map +1 -1
  166. package/dist/workspace/work-cli.d.ts +113 -2
  167. package/dist/workspace/work-cli.d.ts.map +1 -1
  168. package/dist/workspace/work-evidence.d.ts +74 -0
  169. package/dist/workspace/work-evidence.d.ts.map +1 -0
  170. package/dist/workspace/work.d.ts +43 -1
  171. package/dist/workspace/work.d.ts.map +1 -1
  172. package/package.json +1 -1
  173. package/src/cli/commands/audit.test.ts +9 -1
  174. package/src/cli/commands/build.ts +3 -2
  175. package/src/cli/commands/lint.ts +7 -1
  176. package/src/cli/handlers/graph.test.ts +20 -0
  177. package/src/cli/handlers/graph.ts +16 -2
  178. package/src/cli/handlers/operator.ts +34 -2
  179. package/src/cli/handlers/run.test.ts +154 -2
  180. package/src/cli/handlers/run.ts +121 -2
  181. package/src/cli/main.test.ts +10 -0
  182. package/src/cli/main.ts +19 -0
  183. package/src/cli/mcp/workspace-tools.test.ts +35 -19
  184. package/src/cli/mcp/workspace-tools.ts +62 -4
  185. package/src/cli/plugins.ts +11 -3
  186. package/src/cli/registry.ts +12 -2
  187. package/src/codegen/pinned-upgrade.ts +2 -1
  188. package/src/codegen/release-wiring.test.ts +49 -2
  189. package/src/components/capability-plugin-loader.ts +3 -3
  190. package/src/components/cli-support.ts +2 -2
  191. package/src/config.ts +11 -0
  192. package/src/lexicon-module.ts +56 -1
  193. package/src/lexicon-package.test.ts +96 -0
  194. package/src/lifecycle/converge-ledger.ts +20 -0
  195. package/src/lifecycle/run-ledger.ts +6 -0
  196. package/src/lifecycle/symptoms.ts +95 -0
  197. package/src/lint/rules/index.ts +6 -2
  198. package/src/lint/rules/op/index.ts +17 -4
  199. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +23 -1
  200. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +10 -6
  201. package/src/lint/rules/op/sys010-key-over-plain-http.test.ts +52 -0
  202. package/src/lint/rules/op/sys010-key-over-plain-http.ts +100 -0
  203. package/src/lint/rules/sys001-no-literal-key.test.ts +31 -0
  204. package/src/lint/rules/sys001-no-literal-key.ts +67 -0
  205. package/src/op/__fixtures__/decide-stub-backend.ts +143 -0
  206. package/src/op/activities/activity-contracts.ts +190 -1
  207. package/src/op/activities/apply.ts +7 -6
  208. package/src/op/activities/change-coverage.ts +60 -0
  209. package/src/op/activities/converge.test.ts +55 -1
  210. package/src/op/activities/converge.ts +208 -29
  211. package/src/op/activities/decide.live.test.ts +78 -0
  212. package/src/op/activities/decide.test.ts +300 -0
  213. package/src/op/activities/decide.ts +267 -0
  214. package/src/op/activities/index.ts +21 -0
  215. package/src/op/activities/shell.test.ts +91 -1
  216. package/src/op/activities/shell.ts +91 -2
  217. package/src/op/activities/source-release.test.ts +118 -0
  218. package/src/op/activities/source-release.ts +168 -0
  219. package/src/op/activities/source-rollback.test.ts +131 -0
  220. package/src/op/activities/source-rollback.ts +239 -0
  221. package/src/op/activities/work-evidence.ts +62 -0
  222. package/src/op/activity-contract-registry.test.ts +2 -0
  223. package/src/op/activity-contract-registry.ts +2 -2
  224. package/src/op/activity-contract.test.ts +12 -0
  225. package/src/op/activity-contract.ts +6 -1
  226. package/src/op/activity-profiles.ts +29 -0
  227. package/src/op/activity-registry.test.ts +1 -1
  228. package/src/op/activity-registry.ts +2 -2
  229. package/src/op/builders.ts +119 -5
  230. package/src/op/command-gate.test.ts +192 -0
  231. package/src/op/composites/converge-op.test.ts +27 -1
  232. package/src/op/composites/converge-op.ts +69 -15
  233. package/src/op/decide-backend.test.ts +44 -0
  234. package/src/op/decide-backend.ts +212 -0
  235. package/src/op/decide-config.test.ts +52 -0
  236. package/src/op/decide-config.ts +80 -0
  237. package/src/op/decide-read-inputs.ts +117 -0
  238. package/src/op/gate-approval.ts +2 -2
  239. package/src/op/gate-wait.ts +57 -0
  240. package/src/op/gate.ts +8 -3
  241. package/src/op/generate-pipeline.ts +2 -2
  242. package/src/op/index.ts +18 -3
  243. package/src/op/local-executor.ts +151 -15
  244. package/src/op/local-output.test.ts +33 -0
  245. package/src/op/local-output.ts +20 -2
  246. package/src/op/op-ir.test.ts +10 -0
  247. package/src/op/op-ir.ts +4 -0
  248. package/src/op/op-verb-class.ts +1 -0
  249. package/src/op/operator.ts +290 -11
  250. package/src/op/runtime.ts +31 -8
  251. package/src/op/runtimes/local.ts +3 -1
  252. package/src/op/source-archive.ts +161 -0
  253. package/src/op/steward-points.test.ts +313 -0
  254. package/src/op/steward-points.ts +194 -0
  255. package/src/op/steward-turn.ts +79 -0
  256. package/src/op/steward.test.ts +87 -3
  257. package/src/op/steward.ts +25 -1
  258. package/src/op/types.ts +7 -0
  259. package/src/op/work-lease-run.test.ts +20 -1
  260. package/src/op/work-lease-run.ts +2 -2
  261. package/src/workspace/__fixtures__/decide-workspace.ts +129 -0
  262. package/src/workspace/__fixtures__/studio-template-84c8b21.json +67 -0
  263. package/src/workspace/answers-ledger.ts +118 -0
  264. package/src/workspace/changes-cli.ts +56 -0
  265. package/src/workspace/changes.schema.json +472 -0
  266. package/src/workspace/changes.test.ts +315 -0
  267. package/src/workspace/changes.ts +512 -0
  268. package/src/workspace/chant-migrations/chud-lexicon-exit-fly-site.ts +234 -0
  269. package/src/workspace/chant-migrations/chud-lexicon-exit-live-names.ts +164 -0
  270. package/src/workspace/chant-migrations/chud-lexicon-exit-rollback.ts +223 -0
  271. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.ts +195 -0
  272. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-policy.ts +108 -0
  273. package/src/workspace/chant-migrations/chud-lexicon-exit.ts +882 -0
  274. package/src/workspace/chant-migrations.e2e.test.ts +1089 -0
  275. package/src/workspace/chant-migrations.ts +164 -0
  276. package/src/workspace/check-contract.test.ts +4 -2
  277. package/src/workspace/check.schema.json +15 -5
  278. package/src/workspace/checks/boxes.test.ts +80 -1
  279. package/src/workspace/checks/boxes.ts +136 -1
  280. package/src/workspace/checks/diagrams.test.ts +134 -0
  281. package/src/workspace/checks/diagrams.ts +108 -0
  282. package/src/workspace/checks/records.ts +47 -0
  283. package/src/workspace/checks.ts +8 -1
  284. package/src/workspace/compose-graph.ts +2 -0
  285. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +10 -0
  286. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +26 -0
  287. package/src/workspace/conformance/index.ts +5 -0
  288. package/src/workspace/decide.test.ts +1 -1
  289. package/src/workspace/decide.ts +156 -23
  290. package/src/workspace/declaration.schema.json +114 -1
  291. package/src/workspace/declaration.test.ts +58 -0
  292. package/src/workspace/declaration.ts +104 -0
  293. package/src/workspace/declared-kinds.test.ts +5 -5
  294. package/src/workspace/declared-kinds.ts +46 -1
  295. package/src/workspace/generated-files.ts +14 -0
  296. package/src/workspace/graph-cli.ts +1 -1
  297. package/src/workspace/graph.schema.json +9 -1
  298. package/src/workspace/intent.schema.json +8 -2
  299. package/src/workspace/intent.ts +3 -10
  300. package/src/workspace/lineage-check.ts +16 -1
  301. package/src/workspace/lineage-upgrade-cli.ts +1 -1
  302. package/src/workspace/lineage-upgrade.test.ts +70 -0
  303. package/src/workspace/lineage-upgrade.ts +81 -10
  304. package/src/workspace/ls-contract.test.ts +57 -0
  305. package/src/workspace/ls.schema.json +46 -1
  306. package/src/workspace/ls.ts +62 -3
  307. package/src/workspace/points-cli.ts +14 -3
  308. package/src/workspace/points-write.schema.json +11 -1
  309. package/src/workspace/points.schema.json +33 -0
  310. package/src/workspace/points.test.ts +1 -1
  311. package/src/workspace/points.ts +1 -1
  312. package/src/workspace/read-contract.test.ts +1 -1
  313. package/src/workspace/reason-codes.test.ts +11 -1
  314. package/src/workspace/reason-codes.ts +18 -2
  315. package/src/workspace/records-amend.schema.json +2 -0
  316. package/src/workspace/records-cli.ts +13 -3
  317. package/src/workspace/records-close.schema.json +2 -0
  318. package/src/workspace/records-new.schema.json +2 -0
  319. package/src/workspace/records-review.schema.json +2 -0
  320. package/src/workspace/records-sessions-write.e2e.test.ts +77 -0
  321. package/src/workspace/records-sessions-write.test.ts +2 -34
  322. package/src/workspace/records-write.e2e.test.ts +108 -0
  323. package/src/workspace/records-write.test.ts +32 -41
  324. package/src/workspace/records-write.ts +33 -15
  325. package/src/workspace/records.schema.json +36 -2
  326. package/src/workspace/records.test.ts +48 -3
  327. package/src/workspace/records.ts +109 -3
  328. package/src/workspace/status-contract.test.ts +13 -8
  329. package/src/workspace/status-gates.ts +9 -4
  330. package/src/workspace/status-stewards.ts +108 -4
  331. package/src/workspace/status.schema.json +111 -7
  332. package/src/workspace/status.ts +36 -1
  333. package/src/workspace/work-acceptance.test.ts +274 -0
  334. package/src/workspace/{work-cli.test.ts → work-cli.e2e.test.ts} +1 -1
  335. package/src/workspace/work-cli.ts +193 -10
  336. package/src/workspace/work-evidence.schema.json +212 -0
  337. package/src/workspace/work-evidence.ts +169 -0
  338. package/src/workspace/work-history.schema.json +349 -0
  339. package/src/workspace/work-history.test.ts +156 -0
  340. package/src/workspace/work.test.ts +3 -2
  341. package/src/workspace/work.ts +100 -1
  342. /package/src/cli/{discovery-skip.test.ts → discovery-skip.e2e.test.ts} +0 -0
  343. /package/src/workspace/conformance/{conformance.test.ts → conformance.e2e.test.ts} +0 -0
  344. /package/src/workspace/{which-chant.test.ts → which-chant.e2e.test.ts} +0 -0
@@ -103,9 +103,14 @@ export const defaultGateLedgerReader: GateLedgerReader = async (dir, commit, cwd
103
103
  return files;
104
104
  };
105
105
 
106
- /** The exact `chant approve` line for a gate. */
107
- export function approveCommand(component: string, gate: string, env: string | null): string {
108
- return `chant approve ${component} ${gate}${env !== null ? ` --env ${env}` : ""}`;
106
+ /**
107
+ * The exact `chant approve` line for a gate. A gate bound to a plan (#2300)
108
+ * gets `--plan <digest>` too (#2832), so running the line back approves the
109
+ * plan this read showed and not whatever happens to be pending by the time
110
+ * someone runs it.
111
+ */
112
+ export function approveCommand(component: string, gate: string, env: string | null, planDigest?: string | null): string {
113
+ return `chant approve ${component} ${gate}${env !== null ? ` --env ${env}` : ""}${planDigest ? ` --plan ${planDigest}` : ""}`;
109
114
  }
110
115
 
111
116
  const approvalOf = (r: GateResolutionRecord): StatusGateApproval => ({ principal: r.resolvedBy, channel: r.origin ?? null, at: r.timestamp });
@@ -150,7 +155,7 @@ function decide(component: string, standing: PendingGateRecord, resolutions: Gat
150
155
  expiresAt: standing.expiresAt,
151
156
  approvals: approvals.map(approvalOf),
152
157
  needed,
153
- approve: approveCommand(component, gate, env),
158
+ approve: approveCommand(component, gate, env, planDigest),
154
159
  };
155
160
  }
156
161
 
@@ -14,6 +14,9 @@
14
14
  * - each Op's last run is the newest record in its run ledger,
15
15
  * `<env>/runs__<op>.jsonl` under the member's ledger prefix, where `<env>`
16
16
  * is the Op's own `labels.Env` or `local`;
17
+ * - `waiting` lists the open decision points the steward waits on (#2749):
18
+ * each Op whose newest run is the steward's own and stopped on a question,
19
+ * as the run ledger records it. The question's state now is `points`'s;
17
20
  * - `lease` is the local steward's own lease ref
18
21
  * (`refs/chant/lease/[<prefix>]_stewards/<name>`), present while a
19
22
  * `chant operator --steward` holds it or until it expires;
@@ -27,6 +30,7 @@ import { dirname, join, relative, resolve } from "node:path";
27
30
  import { discoverStewards } from "../op/discover";
28
31
  import { stewardFormFor, stewardLeaseName, type StewardForm } from "../op/steward";
29
32
  import { readRunLedger, runEnvOf } from "../lifecycle/run-ledger";
33
+ import { readConvergeLedger, type ConvergeTickRecord } from "../lifecycle/converge-ledger";
30
34
  import { leaseRef } from "../lifecycle/lease";
31
35
  import { readBlobBySha, readRefSha } from "../lifecycle/git";
32
36
  import { resolveMemberLedger } from "../lifecycle/member-ledger";
@@ -34,6 +38,7 @@ import { listWorkLeases } from "../lifecycle/work-lease";
34
38
  import { stewardWorkHolder } from "../op/work-lease-run";
35
39
  import type { OpConfig } from "../op/types";
36
40
  import type { OpRunRecord } from "../op/runtime";
41
+ import { approveCommand } from "./status-gates";
37
42
  import type { ReasonCode } from "./reason-codes";
38
43
 
39
44
  /** Why a member's stewards can't be fully listed. Closed: a new code is a contract change. */
@@ -42,7 +47,7 @@ export const STEWARD_REASON_CODES = [
42
47
  "stewards-unreadable",
43
48
  /** A steward was dropped: its name, or an Op it lists, belongs to another steward. */
44
49
  "stewards-conflict",
45
- /** Reading an Op's run ledger failed, so its last run is null. */
50
+ /** Reading an Op's run ledger, or a ConvergeOp's converge ledger, failed, so its last run or last tick is null. */
46
51
  "steward-runs-unreadable",
47
52
  ] as const satisfies readonly ReasonCode[];
48
53
  export type StewardReasonCode = (typeof STEWARD_REASON_CODES)[number];
@@ -52,8 +57,48 @@ export interface StatusStewardRun {
52
57
  status: OpRunRecord["status"];
53
58
  started: string;
54
59
  ended: string;
55
- /** The gate the run stopped at, for a `gated` run. */
56
- gate: { name: string; since: string } | null;
60
+ /**
61
+ * The gate the run stopped at, for a `gated` run: its name, when the run
62
+ * stopped there, the op it is recorded under (the Op's own, or the
63
+ * command's for a step whose command stopped at its own gate, #2779, such
64
+ * as `workspace-upgrade`), and the command that approves it.
65
+ */
66
+ gate: { name: string; since: string; op: string; approve: string } | null;
67
+ /** The open decision point the run stopped on, for a `waiting` run (#2749). */
68
+ point: StatusStewardWait | null;
69
+ }
70
+
71
+ /** An open decision point a steward's run stopped on (#2749), as the run ledger records it. */
72
+ export interface StatusStewardWait {
73
+ /** The answer record's id: what `points --open` lists and `points answer` names. */
74
+ id: string;
75
+ point: string;
76
+ /** The question's state when the run stopped. */
77
+ state: "escalated" | "proposed";
78
+ path: string;
79
+ subject: string | null;
80
+ since: string;
81
+ }
82
+
83
+ /** A ConvergeOp's newest tick on the converge ledger (#2778). */
84
+ export interface StatusStewardTick {
85
+ /** The tick's id, or null for a tick recorded before ticks had ids. */
86
+ id: string | null;
87
+ timestamp: string;
88
+ /** The tick's one log line. */
89
+ log: string;
90
+ /** Every rule that fired. */
91
+ firedRuleIds: string[];
92
+ /** What each fired rule did, and for which resource on a ConvergeOp with an observer step. */
93
+ outcomes: {
94
+ ruleId: string;
95
+ action: ConvergeTickRecord["outcomes"][number]["action"];
96
+ op: string | null;
97
+ resource: string | null;
98
+ reason: string | null;
99
+ }[];
100
+ /** What the observer step reported, or null for a ConvergeOp that observes a lexicon environment. */
101
+ resources: { name: string; status: "in-sync" | "drifted" | "unknown"; detail: string | null }[] | null;
57
102
  }
58
103
 
59
104
  export interface StatusStewardOp {
@@ -64,6 +109,8 @@ export interface StatusStewardOp {
64
109
  env: string;
65
110
  /** The newest run in its run ledger, or null when it has none. */
66
111
  lastRun: StatusStewardRun | null;
112
+ /** For a ConvergeOp, its newest tick on the converge ledger (#2778); null for any other Op, or before its first tick. */
113
+ lastTick: StatusStewardTick | null;
67
114
  /** Whether the Op changes the checkout, and so runs under a work lease on a branch of its own (#2748). */
68
115
  changesCheckout: boolean;
69
116
  /**
@@ -103,6 +150,11 @@ export interface StatusSteward {
103
150
  /** The local steward's own lease, or null when no local operator has held it. */
104
151
  lease: { holder: string; acquiredAt: string; expiresAt: string; live: boolean } | null;
105
152
  ops: StatusStewardOp[];
153
+ /**
154
+ * The open decision points the steward waits on (#2749): each Op whose
155
+ * newest run is the steward's own and stopped on a question.
156
+ */
157
+ waiting: (StatusStewardWait & { op: string; run: string })[];
106
158
  }
107
159
 
108
160
  export interface MemberStewards {
@@ -110,6 +162,39 @@ export interface MemberStewards {
110
162
  reasons: { code: StewardReasonCode; message: string }[];
111
163
  }
112
164
 
165
+ function waitOf(p: NonNullable<OpRunRecord["point"]>): StatusStewardWait {
166
+ return {
167
+ id: p.id,
168
+ point: p.point,
169
+ state: p.state === "proposed" ? "proposed" : "escalated",
170
+ path: p.path,
171
+ subject: p.subject ?? null,
172
+ since: p.since,
173
+ };
174
+ }
175
+
176
+ function gateOf(g: NonNullable<OpRunRecord["gate"]>, opName: string): NonNullable<StatusStewardRun["gate"]> {
177
+ const op = g.op ?? opName;
178
+ return { name: g.name, since: g.since, op, approve: approveCommand(op, g.name, null) };
179
+ }
180
+
181
+ function tickOf(t: ConvergeTickRecord): StatusStewardTick {
182
+ return {
183
+ id: t.id ?? null,
184
+ timestamp: t.timestamp,
185
+ log: t.log,
186
+ firedRuleIds: [...t.firedRuleIds],
187
+ outcomes: t.outcomes.map((o) => ({
188
+ ruleId: o.ruleId,
189
+ action: o.action,
190
+ op: o.op ?? null,
191
+ resource: o.resource ?? null,
192
+ reason: o.reason ?? null,
193
+ })),
194
+ resources: t.resources ? t.resources.map((r) => ({ name: r.name, status: r.status, detail: r.detail ?? null })) : null,
195
+ };
196
+ }
197
+
113
198
  /** Whether a directory is a chant project of its own. */
114
199
  function isChantProject(dir: string): boolean {
115
200
  return existsSync(join(dir, "chant.config.ts")) || existsSync(join(dir, "chant.config.json"));
@@ -176,6 +261,7 @@ export async function readMemberStewards(
176
261
  const stewards: StatusSteward[] = [];
177
262
  for (const { declaration, filePath } of [...found.values()].sort((a, b) => a.declaration.name.localeCompare(b.declaration.name))) {
178
263
  const ops: StatusStewardOp[] = [];
264
+ const waiting: StatusSteward["waiting"] = [];
179
265
  for (const op of declaration.ops) {
180
266
  const opEnv = runEnvOf(op);
181
267
  let lastRun: StatusStewardRun | null = null;
@@ -187,8 +273,12 @@ export async function readMemberStewards(
187
273
  status: newest.status,
188
274
  started: newest.started,
189
275
  ended: newest.ended,
190
- gate: newest.gate ? { name: newest.gate.name, since: newest.gate.since } : null,
276
+ gate: newest.gate ? gateOf(newest.gate, op.name) : null,
277
+ point: newest.point ? waitOf(newest.point) : null,
191
278
  };
279
+ if (newest.status === "waiting" && lastRun.point && newest.steward === declaration.name) {
280
+ waiting.push({ op: op.name, run: newest.id, ...lastRun.point });
281
+ }
192
282
  }
193
283
  } catch (err) {
194
284
  reasons.push({
@@ -196,11 +286,24 @@ export async function readMemberStewards(
196
286
  message: `${opEnv}/runs__${op.name}.jsonl: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
197
287
  });
198
288
  }
289
+ let lastTick: StatusStewardTick | null = null;
290
+ if (op.labels?.Converge === "true") {
291
+ try {
292
+ const newest = (await readConvergeLedger(opEnv, { cwd: memberDir })).records.filter((r) => r.op === op.name).at(-1);
293
+ if (newest) lastTick = tickOf(newest);
294
+ } catch (err) {
295
+ reasons.push({
296
+ code: "steward-runs-unreadable",
297
+ message: `${opEnv}/converge.jsonl: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
298
+ });
299
+ }
300
+ }
199
301
  ops.push({
200
302
  name: op.name,
201
303
  schedule: op.schedule ? { cron: op.schedule.cron, overlap: "skip" } : null,
202
304
  env: opEnv,
203
305
  lastRun,
306
+ lastTick,
204
307
  changesCheckout: op.changesCheckout === true,
205
308
  workLease: op.workLease
206
309
  ? { kind: op.workLease.kind ?? null, held: await readHeldWorkLeases(declaration.name, op, memberDir, now) }
@@ -219,6 +322,7 @@ export async function readMemberStewards(
219
322
  }),
220
323
  lease: await readStewardLease(declaration.name, memberDir, now),
221
324
  ops,
325
+ waiting,
222
326
  });
223
327
  }
224
328
  return { stewards, reasons };
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://intentius.io/chant/schemas/workspace/status/v1/status.schema.json",
4
4
  "title": "chant workspace status output",
5
- "description": "What `chant workspace status <env> --json` prints, version 1 of the read contract for releases across members (#2524 D15, D19, #2544). Readers ignore fields they do not know; a field is only ever added within a version. The reason and error codes are closed lists: a new code is a new contract version. Contract version 1 is written by chant 0.81.0 and newer; a reader that needs it refuses output whose `contract` it doesn't know. Every code is in the one closed list of `reason-codes.ts`. Each member's gates, read from its gate ledger on the same branch, are in the JSON only (#2674), and so is each member's box block, from the declaration (#2726), with its isolation resolved (#2727). So are its stewards, their Ops and each Op's last run (#2731), and the work lease each Op's turn holds (#2748).",
5
+ "description": "What `chant workspace status <env> --json` prints, version 1 of the read contract for releases across members (#2524 D15, D19, #2544). Readers ignore fields they do not know; a field is only ever added within a version. The reason and error codes are closed lists: a new code is a new contract version. Contract version 1 is written by chant 0.81.0 and newer; a reader that needs it refuses output whose `contract` it doesn't know. Every code is in the one closed list of `reason-codes.ts`. Each member's gates, read from its gate ledger on the same branch, are in the JSON only (#2674), and so is each member's box block, from the declaration (#2726), with its isolation resolved (#2727). So are its stewards, their Ops and each Op's last run (#2731), the work lease each Op's turn holds (#2748), and the open decision points a steward waits on (#2749).",
6
6
  "oneOf": [{ "$ref": "#/$defs/result" }, { "$ref": "#/$defs/failure" }],
7
7
  "$defs": {
8
8
  "result": {
@@ -50,6 +50,11 @@
50
50
  "type": "array",
51
51
  "items": { "$ref": "#/$defs/lease" }
52
52
  },
53
+ "acceptance": {
54
+ "description": "Added in contract 1 by #2772. Each current work item of a declared work kind whose work block names acceptance criteria, when the item lists some, by declared kind and then item, read in the working tree: how many of its criteria passing evidence meets. Empty when no declared work kind has criteria. A done item with a criterion unmet is what chant workspace check fails on (WSP117).",
55
+ "type": "array",
56
+ "items": { "$ref": "#/$defs/acceptance" }
57
+ },
53
58
  "summary": {
54
59
  "type": "object",
55
60
  "required": ["members", "released", "unreadable", "differing"],
@@ -66,6 +71,18 @@
66
71
  }
67
72
  }
68
73
  },
74
+ "acceptance": {
75
+ "type": "object",
76
+ "required": ["member", "kind", "item", "state", "met", "total"],
77
+ "properties": {
78
+ "member": { "type": ["string", "null"], "description": "The member that declares the work kind, or null for the workspace's own." },
79
+ "kind": { "type": "string", "description": "The work kind file, from the workspace root." },
80
+ "item": { "type": "string", "description": "The work item's id." },
81
+ "state": { "type": ["string", "null"], "description": "The item's state." },
82
+ "met": { "type": "integer", "minimum": 0, "description": "Criteria met by evidence naming them, with result pass and the criterion's verification; a manual verdict counts only from someone other than the implementer." },
83
+ "total": { "type": "integer", "minimum": 0, "description": "Criteria the item lists." }
84
+ }
85
+ },
69
86
  "lease": {
70
87
  "type": "object",
71
88
  "required": ["item", "member", "ref", "holder", "token", "acquiredAt", "expiresAt", "state"],
@@ -135,7 +152,7 @@
135
152
  "stewardForm": { "enum": ["local", "fountain"] },
136
153
  "steward": {
137
154
  "type": "object",
138
- "required": ["name", "file", "form", "forms", "vault", "capabilities", "lease", "ops"],
155
+ "required": ["name", "file", "form", "forms", "vault", "capabilities", "lease", "ops", "waiting"],
139
156
  "properties": {
140
157
  "name": { "type": "string", "description": "The steward's name; on Fountain, its Agent's and Teammate's." },
141
158
  "file": { "type": "string", "description": "The *.op.ts file that declares it, relative to the member's directory." },
@@ -187,7 +204,7 @@
187
204
  "type": "array",
188
205
  "items": {
189
206
  "type": "object",
190
- "required": ["name", "schedule", "env", "lastRun", "changesCheckout", "workLease"],
207
+ "required": ["name", "schedule", "env", "lastRun", "lastTick", "changesCheckout", "workLease"],
191
208
  "properties": {
192
209
  "name": { "type": "string" },
193
210
  "schedule": {
@@ -208,16 +225,77 @@
208
225
  { "type": "null" },
209
226
  {
210
227
  "type": "object",
211
- "required": ["id", "status", "started", "ended", "gate"],
228
+ "required": ["id", "status", "started", "ended", "gate", "point"],
212
229
  "properties": {
213
230
  "id": { "type": "string" },
214
- "status": { "enum": ["ok", "fail", "gated"] },
231
+ "status": { "enum": ["ok", "fail", "gated", "waiting"], "description": "waiting: an activity asked a decision point that is still open (#2749), and the run stopped there." },
215
232
  "started": { "type": "string" },
216
233
  "ended": { "type": "string" },
217
234
  "gate": {
218
235
  "oneOf": [
219
236
  { "type": "null" },
220
- { "type": "object", "required": ["name", "since"], "properties": { "name": { "type": "string" }, "since": { "type": "string" } } }
237
+ {
238
+ "type": "object",
239
+ "required": ["name", "since"],
240
+ "properties": {
241
+ "name": { "type": "string" },
242
+ "since": { "type": "string" },
243
+ "op": { "type": "string", "description": "The op the gate is recorded under: the Op's own, or the command's when a step's command stopped at a gate of its own (#2779), such as workspace-upgrade." },
244
+ "approve": { "type": "string", "description": "The command that approves the gate, run in the member's directory." }
245
+ }
246
+ }
247
+ ]
248
+ },
249
+ "point": {
250
+ "description": "The open decision point a waiting run stopped on (#2749), as the run ledger records it, or null.",
251
+ "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/stewardWait" }]
252
+ }
253
+ }
254
+ }
255
+ ]
256
+ },
257
+ "lastTick": {
258
+ "description": "For a ConvergeOp, its newest tick on the converge ledger (#2778): the rules that fired, what each did and for which resource, and what its observer step reported. null for any other Op, or before its first tick.",
259
+ "oneOf": [
260
+ { "type": "null" },
261
+ {
262
+ "type": "object",
263
+ "required": ["id", "timestamp", "log", "firedRuleIds", "outcomes", "resources"],
264
+ "properties": {
265
+ "id": { "type": ["string", "null"] },
266
+ "timestamp": { "type": "string" },
267
+ "log": { "type": "string" },
268
+ "firedRuleIds": { "type": "array", "items": { "type": "string" } },
269
+ "outcomes": {
270
+ "type": "array",
271
+ "items": {
272
+ "type": "object",
273
+ "required": ["ruleId", "action", "op", "resource", "reason"],
274
+ "properties": {
275
+ "ruleId": { "type": "string" },
276
+ "action": { "enum": ["ran", "reported", "skipped-budget", "skipped-flap", "gated"] },
277
+ "op": { "type": ["string", "null"] },
278
+ "resource": { "type": ["string", "null"], "description": "The resource the rule fired for, on a ConvergeOp with an observer step." },
279
+ "reason": { "type": ["string", "null"] }
280
+ }
281
+ }
282
+ },
283
+ "resources": {
284
+ "description": "What the observer step reported, or null for a ConvergeOp that observes a lexicon environment.",
285
+ "oneOf": [
286
+ { "type": "null" },
287
+ {
288
+ "type": "array",
289
+ "items": {
290
+ "type": "object",
291
+ "required": ["name", "status", "detail"],
292
+ "properties": {
293
+ "name": { "type": "string" },
294
+ "status": { "enum": ["in-sync", "drifted", "unknown"] },
295
+ "detail": { "type": ["string", "null"] }
296
+ }
297
+ }
298
+ }
221
299
  ]
222
300
  }
223
301
  }
@@ -255,9 +333,35 @@
255
333
  }
256
334
  }
257
335
  }
336
+ },
337
+ "waiting": {
338
+ "description": "The open decision points the steward waits on (#2749): one for each of its Ops whose newest run is the steward's own and stopped on a question, in ops order. The state is the question's when the run stopped; `chant workspace points --open` has its state now, and hud asks a person there. The steward never answers one, and runs the Op again on the first round after it is answered.",
339
+ "type": "array",
340
+ "items": {
341
+ "allOf": [
342
+ { "$ref": "#/$defs/stewardWait" },
343
+ {
344
+ "type": "object",
345
+ "required": ["op", "run"],
346
+ "properties": { "op": { "type": "string" }, "run": { "type": "string", "description": "The waiting run's id." } }
347
+ }
348
+ ]
349
+ }
258
350
  }
259
351
  }
260
352
  },
353
+ "stewardWait": {
354
+ "type": "object",
355
+ "required": ["id", "point", "state", "path", "subject", "since"],
356
+ "properties": {
357
+ "id": { "type": "string", "description": "The answer record's id, as `points` lists the question and `points answer` names it." },
358
+ "point": { "type": "string" },
359
+ "state": { "enum": ["escalated", "proposed"] },
360
+ "path": { "type": "string", "description": "The answer record, from the repository root." },
361
+ "subject": { "type": ["string", "null"] },
362
+ "since": { "type": "string", "description": "When the run stopped on it." }
363
+ }
364
+ },
261
365
  "box": {
262
366
  "type": "object",
263
367
  "required": ["capabilities", "isolation"],
@@ -371,7 +475,7 @@
371
475
  }
372
476
  },
373
477
  "needed": { "type": "integer", "minimum": 1, "description": "The human approvals the gate needs: its quorum's count, 1 without one." },
374
- "approve": { "type": "string", "description": "The chant approve line for the gate, run in the member's directory: chant approve <component> <gate>, with --env <env> when env is not null." }
478
+ "approve": { "type": "string", "description": "The chant approve line for the gate, run in the member's directory: chant approve <component> <gate>, with --env <env> when env is not null and --plan <planDigest> when planDigest is not null (#2832), so the line approves the plan this read showed." }
375
479
  }
376
480
  },
377
481
  "environment": {
@@ -43,7 +43,7 @@ import { readReleasePlan, type ReleasePlan } from "../lifecycle/plan-ledger";
43
43
  import { listWorkLeases, type WorkLeaseState } from "../lifecycle/work-lease";
44
44
  import { findWorkspaceRoot } from "../project-root";
45
45
  import { resolveBoxes, type ResolvedIsolation } from "./box-isolation";
46
- import { readDeclaration, readerVersion, WorkspaceReadError, type ErrorLocation, type Member } from "./declaration";
46
+ import { declaredRecordKinds, readDeclaration, readerVersion, WorkspaceReadError, type Declaration, type ErrorLocation, type Member } from "./declaration";
47
47
  import type { ReasonCode } from "./reason-codes";
48
48
  import { GATE_REASON_CODES, readMemberGates, type GateLedgerReader, type StatusGate, type StatusGateLedger } from "./status-gates";
49
49
  import { STEWARD_REASON_CODES, readMemberStewards, type StatusSteward, type StewardReasonCode } from "./status-stewards";
@@ -190,6 +190,21 @@ export interface StatusLease extends Omit<WorkLeaseState, "ref"> {
190
190
  ref: string;
191
191
  }
192
192
 
193
+ /**
194
+ * One work item's acceptance criteria, counted (#2772): each current record
195
+ * of a declared work kind with acceptance criteria that lists some.
196
+ */
197
+ export interface StatusAcceptance {
198
+ /** The member that declares the work kind, or null for the workspace's own. */
199
+ member: string | null;
200
+ /** The work kind file, from the workspace root. */
201
+ kind: string;
202
+ item: string;
203
+ state: string | null;
204
+ met: number;
205
+ total: number;
206
+ }
207
+
193
208
  export type StatusDocument =
194
209
  | {
195
210
  $schema: string;
@@ -202,6 +217,8 @@ export type StatusDocument =
202
217
  members: StatusMember[];
203
218
  /** Every work lease in the workspace's ledgers, active and expired, by member then item (#2732). A released lease has no ref and is not listed. */
204
219
  leases: StatusLease[];
220
+ /** Each work item's acceptance criteria, met of total, by declared kind then item (#2772). Empty when no declared work kind has criteria. */
221
+ acceptance: StatusAcceptance[];
205
222
  summary: { members: number; released: number; unreadable: number; differing: number | null };
206
223
  }
207
224
  | {
@@ -395,6 +412,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
395
412
  for (const m of members) m.gateLedger.shared = m.gateLedger.layout === "flat" && flatGates > 1;
396
413
 
397
414
  const leases = await readWorkspaceLeases(declaration.members, found.dir, new Date(now));
415
+ const acceptance = await readWorkspaceAcceptance(declaration, found.dir);
398
416
 
399
417
  return {
400
418
  ...head,
@@ -404,6 +422,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
404
422
  workspace: { name: declaration.name, root: rootDir === "" ? "." : rootDir, file: declaration.file },
405
423
  members,
406
424
  leases,
425
+ acceptance,
407
426
  summary: {
408
427
  members: members.length,
409
428
  released: members.filter((m) => m.environments[0].releases.length > 0).length,
@@ -436,6 +455,16 @@ async function readWorkspaceLeases(members: Member[], cwd: string, now: Date): P
436
455
  return out;
437
456
  }
438
457
 
458
+ /** The acceptance counts of every declared work kind with criteria (#2772), read in the working tree. */
459
+ async function readWorkspaceAcceptance(declaration: Declaration, root: string): Promise<StatusAcceptance[]> {
460
+ if (declaredRecordKinds(declaration).length === 0) return [];
461
+ const { loadDeclaredKinds } = await import("./declared-kinds");
462
+ const kinds = await loadDeclaredKinds(declaration, workingTree(root), root, { acceptance: true });
463
+ return kinds.flatMap((k) =>
464
+ (k.acceptance ?? []).map((a) => ({ member: k.declared.member, kind: k.declared.path, item: a.item, state: a.state, met: a.met, total: a.total })),
465
+ );
466
+ }
467
+
439
468
  export async function runWorkspaceStatus(ctx: CommandContext): Promise<number> {
440
469
  const { args } = ctx;
441
470
  const env = args.extraPositional;
@@ -525,6 +554,12 @@ export function formatStatus(doc: Extract<StatusDocument, { members: unknown }>)
525
554
  for (const l of doc.leases) rows.push([l.member ? `${l.member}/${l.item}` : l.item, l.holder, l.expiresAt, l.state]);
526
555
  lines.push(...table(rows));
527
556
  }
557
+ if (doc.acceptance.length > 0) {
558
+ lines.push("");
559
+ const rows: string[][] = [["WORK ITEM", "STATE", "CRITERIA MET"]];
560
+ for (const a of doc.acceptance) rows.push([a.member ? `${a.member}/${a.item}` : a.item, a.state ?? "-", `${a.met}/${a.total}`]);
561
+ lines.push(...table(rows));
562
+ }
528
563
  const boxes = doc.members.filter((m) => m.box?.isolation);
529
564
  if (boxes.length > 0) {
530
565
  lines.push("");