@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
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * `chant workspace work claim|renew|release <id> --holder <name>` (#2732,
3
- * ws-055): the work lease, who is working on which work item.
3
+ * ws-055): the work lease, who is working on which work item. And `chant
4
+ * workspace work history <id>` (#2785): the item's lease history, each claim
5
+ * and how it ended, a read-contract output (`work-history.schema.json`).
4
6
  *
5
7
  * The lease itself is `../lifecycle/work-lease.ts`, the operator lease under
6
8
  * the key `work/<id>`. This file finds the work item first: in the work kind
@@ -18,7 +20,8 @@
18
20
  * could not run (usage, an unreadable kind, an unknown item).
19
21
  */
20
22
  import type { CommandContext } from "../cli/registry.js";
21
- import { type WorkLease, type WorkLeaseRefusal, type LeaseHistoryWrite } from "../lifecycle/work-lease.js";
23
+ import { type WorkLease, type WorkLeaseRefusal, type LeaseHistoryWrite, type LeaseHistoryRecord, type WorkLeaseState } from "../lifecycle/work-lease.js";
24
+ import { type LoadedRecordKind, type RecordEntry } from "./records.js";
22
25
  /** The version of the `work` output this chant writes. */
23
26
  export declare const WORK_LEASE_CONTRACT_VERSION = 1;
24
27
  /** `$id` of the JSON Schema for the `--json` output, shipped beside this file. */
@@ -59,6 +62,23 @@ export type WorkLeaseDocument = DocHead & ({
59
62
  message: string;
60
63
  };
61
64
  });
65
+ /** Why a work command could not run, with its code. */
66
+ export declare class WorkError extends Error {
67
+ readonly code: WorkErrorCode;
68
+ constructor(code: WorkErrorCode, message: string);
69
+ }
70
+ /** A work item found by id: its kind, its state, its record, and the repository root its path is from. */
71
+ export interface FoundWorkItem {
72
+ loaded: LoadedRecordKind;
73
+ state: string | null;
74
+ record: RecordEntry;
75
+ root: string;
76
+ }
77
+ /**
78
+ * The work kind holding `id`: the one `kind` names, or the one declared work
79
+ * kind with a record `id`. Throws a {@link WorkError}.
80
+ */
81
+ export declare function findWorkItem(id: string, cwd: string, kind: string | undefined): Promise<FoundWorkItem>;
62
82
  /** Parse `--ttl`: a whole number of seconds, or a duration such as 10m. */
63
83
  export declare function parseTtl(raw: string): number;
64
84
  export interface WorkLeaseRequest {
@@ -74,5 +94,96 @@ export interface WorkLeaseRequest {
74
94
  }
75
95
  /** Run one claim, renew or release and build the document `--json` prints. */
76
96
  export declare function workLease(req: WorkLeaseRequest): Promise<WorkLeaseDocument>;
97
+ /** The version of the `work history` output this chant writes: read contract 1. */
98
+ export declare const WORK_HISTORY_CONTRACT_VERSION = 1;
99
+ /** `$id` of the JSON Schema for `work history --json`, shipped beside this file. */
100
+ export declare const WORK_HISTORY_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/work-history/v1/work-history.schema.json";
101
+ /** Why `work history` read nothing. Closed. */
102
+ export declare const WORK_HISTORY_ERROR_CODES: readonly ["kind-unreadable", "work-kind-missing", "work-kind-ambiguous", "work-item-unknown", "not-a-git-repository"];
103
+ export type WorkHistoryErrorCode = (typeof WORK_HISTORY_ERROR_CODES)[number];
104
+ /**
105
+ * How a claim ended. `released`: its holder, or someone closing out an
106
+ * expired lease, gave it back, with an outcome when one was given. `held`: it
107
+ * is the live lease now. `expired`: it ran out and nobody released it or
108
+ * claimed the item since. `lost`: it ran out unreleased and another claim
109
+ * took the item.
110
+ */
111
+ export type ClaimEnd = "released" | "held" | "expired" | "lost";
112
+ /** One claim of a work item: one fencing token, from its claim to how it ended. */
113
+ export interface LeaseClaim {
114
+ token: string;
115
+ holder: string;
116
+ acquiredAt: string;
117
+ /** The expiry its last claim or renew set. */
118
+ expiresAt: string;
119
+ renewals: number;
120
+ ended: ClaimEnd;
121
+ /** The release, when it was released. */
122
+ release: {
123
+ by: string;
124
+ at: string;
125
+ outcome: string | null;
126
+ note: string | null;
127
+ } | null;
128
+ }
129
+ /** What `work history --json` prints. */
130
+ export type WorkHistoryDocument = {
131
+ $schema: string;
132
+ contract: number;
133
+ chant: string;
134
+ item: string;
135
+ /** The work kind file, from the repository root. */
136
+ kind: string;
137
+ /** The lease ref. */
138
+ ref: string;
139
+ /** The history file on the branch, under the member's prefix when the kind's member has one. */
140
+ ledger: {
141
+ branch: string;
142
+ path: string;
143
+ };
144
+ /** The lease ref's record now, live or expired, or null when there is none. Read from local refs, without fetching. */
145
+ lease: (Omit<WorkLease, "item"> & {
146
+ state: "active" | "expired";
147
+ }) | null;
148
+ /** Each claim, oldest first. */
149
+ claims: LeaseClaim[];
150
+ /** Every line of the history, oldest first. */
151
+ events: LeaseHistoryRecord[];
152
+ /** Lines of the history that are not lease events, left out. */
153
+ malformed: number;
154
+ summary: {
155
+ claims: number;
156
+ released: number;
157
+ held: number;
158
+ expired: number;
159
+ lost: number;
160
+ outcomes: Record<string, number>;
161
+ };
162
+ } | {
163
+ $schema: string;
164
+ contract: number;
165
+ chant: string;
166
+ error: {
167
+ code: WorkHistoryErrorCode;
168
+ message: string;
169
+ };
170
+ };
171
+ /** Fold a history into its claims: one per token, in the order they were first seen. */
172
+ export declare function claimsOf(events: LeaseHistoryRecord[], live: Pick<WorkLeaseState, "token" | "state"> | null): LeaseClaim[];
173
+ /**
174
+ * Read work item `id`'s lease history (#2785): every claim, renew and release
175
+ * on `_leases/<id>.jsonl` in the ledger of the member owning the work kind,
176
+ * folded into claims. Read from the local `chant/lifecycle` branch and lease
177
+ * refs; it never fetches, like the other read-contract reads.
178
+ */
179
+ export declare function workHistory(req: {
180
+ id: string;
181
+ cwd: string;
182
+ kind?: string;
183
+ }): Promise<WorkHistoryDocument>;
184
+ /** The history as lines for a person. */
185
+ export declare function formatWorkHistory(doc: Extract<WorkHistoryDocument, {
186
+ claims: unknown;
187
+ }>): string;
77
188
  export declare function runWorkspaceWork(ctx: CommandContext): Promise<number>;
78
189
  //# sourceMappingURL=work-cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"work-cli.d.ts","sourceRoot":"","sources":["../../src/workspace/work-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAML,KAAK,SAAS,EACd,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAQjC,0DAA0D;AAC1D,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,kFAAkF;AAClF,eAAO,MAAM,2BAA2B,sFAAsF,CAAC;AAE/H,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,kKAQa,CAAC;AAC3C,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,UAAU,OAAO;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,4BAA4B;AAC5B,MAAM,MAAM,iBAAiB,GAAG,OAAO,GACrC,CACE;IACE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,iBAAiB,CAAC;CAC5B,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;CAC9F,GACD;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CACpD,CAAC;AAwDJ,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,8EAA8E;AAC9E,wBAAsB,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0BjF;AAMD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C3E"}
1
+ {"version":3,"file":"work-cli.d.ts","sourceRoot":"","sources":["../../src/workspace/work-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Evidence attached to a work item's acceptance criterion by the run that
3
+ * holds its lease (#2772).
4
+ *
5
+ * A work kind with acceptance criteria (`work.acceptance` in the kind, read in
6
+ * `./work.ts`) lists what done means on the record: each criterion has an id,
7
+ * its text and the verification it expects. Evidence in the kind's pins field
8
+ * meets a criterion when it names it, carries `result: pass` and has the
9
+ * criterion's verification. {@link attachWorkEvidence} appends one such entry
10
+ * for a run under the item's work lease (an Op with `workLease`, #2748, such
11
+ * as a steward's), through `records amend`, so the record is written the way
12
+ * a person's amendment writes it.
13
+ *
14
+ * It writes only for the lease's holder, under the token the run was given:
15
+ * a run whose lease expired or went to someone else is refused, as a renewal
16
+ * would be. It refuses a criterion the record doesn't list, and a `manual`
17
+ * one: the run holding the lease is the item's implementer, and a manual
18
+ * verdict comes from someone else. A person records that verdict with
19
+ * `records amend`, naming themselves in `by`.
20
+ */
21
+ import { type EvidenceResult, type WorkAcceptance } from "./work.js";
22
+ /** Why evidence was not attached. Closed. Nothing is written with any of them. */
23
+ export declare const WORK_EVIDENCE_ERROR_CODES: readonly ["kind-unreadable", "kind-invalid", "schema-unreadable", "schema-id-mismatch", "schema-invalid", "location-missing", "write-usage-invalid", "write-input-invalid", "record-not-found", "amend-id-immutable", "record-closed", "amend-supersede-instead", "record-sign-failed", "record-unparseable", "record-schema-invalid", "record-id-duplicate", "record-supersedes-unknown", "record-supersedes-conflict", "record-remediates-unknown", "record-remediates-not-closed", "session-seal-mismatch", "session-verdict-unknown-record", "work-kind-missing", "work-kind-ambiguous", "work-item-unknown", "work-item-closed", "work-criterion-unknown", "work-acceptance-self-verified", "lease-held", "lease-not-held", "lease-token-mismatch", "not-a-git-repository"];
24
+ export type WorkEvidenceErrorCode = (typeof WORK_EVIDENCE_ERROR_CODES)[number];
25
+ export interface AttachWorkEvidenceRequest {
26
+ /** Where the workspace is found, and what `path` and `kind` resolve against. */
27
+ cwd: string;
28
+ /** The work item. */
29
+ item: string;
30
+ /** The work kind file, when the declaration names more than one with the item. */
31
+ kind?: string;
32
+ /** The lease the run holds: its holder and fencing token. */
33
+ holder: string;
34
+ token: string;
35
+ /** The criterion the evidence is for, by id. */
36
+ criterion: string;
37
+ result: EvidenceResult;
38
+ title: string;
39
+ /** A public link, or */
40
+ url?: string;
41
+ /** a workspace file, pinned by the hash of its bytes now. */
42
+ path?: string;
43
+ /** When the evidence was taken, as an ISO 8601 timestamp. Now by default. */
44
+ asOf?: string;
45
+ }
46
+ /** The version of the attach document this chant writes. */
47
+ export declare const WORK_EVIDENCE_CONTRACT_VERSION = 1;
48
+ /** `$id` of the JSON Schema for the attach document, shipped beside this file. */
49
+ export declare const WORK_EVIDENCE_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/work-evidence/v1/work-evidence.schema.json";
50
+ interface DocHead {
51
+ $schema: string;
52
+ contract: number;
53
+ }
54
+ /** What {@link attachWorkEvidence} returns: the entry written, or why nothing was. */
55
+ export type WorkEvidenceDocument = DocHead & ({
56
+ item: string;
57
+ /** The work kind file, from the repository root. */
58
+ kind: string;
59
+ /** The record, from the repository root. */
60
+ path: string;
61
+ /** The entry appended to the kind's pins field. */
62
+ evidence: Record<string, unknown>;
63
+ /** The record's criteria with the new entry counted. */
64
+ acceptance: WorkAcceptance;
65
+ } | {
66
+ error: {
67
+ code: WorkEvidenceErrorCode;
68
+ message: string;
69
+ };
70
+ });
71
+ /** Append one piece of evidence for a criterion to a leased work item. Never throws for a refusal. */
72
+ export declare function attachWorkEvidence(req: AttachWorkEvidenceRequest): Promise<WorkEvidenceDocument>;
73
+ export {};
74
+ //# sourceMappingURL=work-evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-evidence.d.ts","sourceRoot":"","sources":["../../src/workspace/work-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,EAAwD,KAAK,cAAc,EAAyB,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAG/I,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,kvBAYI,CAAC;AAC3C,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/E,MAAM,WAAW,yBAAyB;IACxC,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,4DAA4D;AAC5D,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,8BAA8B,4FAA4F,CAAC;AAExI,UAAU,OAAO;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,GACxC,CACI;IACE,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,wDAAwD;IACxD,UAAU,EAAE,cAAc,CAAC;CAC5B,GACD;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAC9D,CAAC;AAWJ,sGAAsG;AACtG,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,yBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+DtG"}
@@ -15,6 +15,8 @@
15
15
  * record is valid and not superseded;
16
16
  * - `blockedBy`: each need that is not done, with its state;
17
17
  * - `implements`: each decision it names, with that decision's state;
18
+ * - `acceptance`, for a kind with acceptance criteria (#2772): how many of the
19
+ * record's criteria passing evidence of the expected verification meets;
18
20
  *
19
21
  * and each decision `implementedBy`, the work records naming it. The
20
22
  * warnings are closed codes. `work-done-gap-open` is not raised here: it
@@ -23,7 +25,7 @@
23
25
  */
24
26
  import { type LoadedRecordKind, type ReadRecordsOptions, type RecordEntry } from "./records.js";
25
27
  /** Why a work record carries a warning. Closed, like the record warning codes. */
26
- export declare const WORK_WARNING_CODES: readonly ["work-needs-unknown", "work-implements-unknown", "work-needs-cycle", "work-implements-undecided", "work-done-unpinned", "work-closed-without-date", "work-done-gap-open"];
28
+ export declare const WORK_WARNING_CODES: readonly ["work-needs-unknown", "work-implements-unknown", "work-needs-cycle", "work-implements-undecided", "work-done-unpinned", "work-closed-without-date", "work-done-gap-open", "work-acceptance-unmet", "work-acceptance-self-verified"];
27
29
  export type WorkWarningCode = (typeof WORK_WARNING_CODES)[number];
28
30
  /** A link from a work record to another record, with that record's state now. */
29
31
  export interface WorkLink {
@@ -39,6 +41,46 @@ export interface DecisionWork {
39
41
  supersededBy: string | null;
40
42
  implementedBy: WorkLink[];
41
43
  }
44
+ /** How a criterion is to be verified (#2772): by a unit, integration or end-to-end test, by the running system, or by a person. */
45
+ export declare const VERIFICATION_TYPES: readonly ["unit", "integration", "e2e", "runtime", "manual"];
46
+ export type VerificationType = (typeof VERIFICATION_TYPES)[number];
47
+ /** The results a piece of evidence for a criterion can carry. */
48
+ export declare const EVIDENCE_RESULTS: readonly ["pass", "fail"];
49
+ export type EvidenceResult = (typeof EVIDENCE_RESULTS)[number];
50
+ /** One acceptance criterion as a work record states it. */
51
+ export interface Criterion {
52
+ id: string;
53
+ text: string;
54
+ verification: VerificationType;
55
+ }
56
+ /** One criterion on read: whether passing evidence of its verification meets it. */
57
+ export interface CriterionState {
58
+ id: string;
59
+ verification: VerificationType;
60
+ met: boolean;
61
+ }
62
+ /** A work record's acceptance criteria on read (#2772): how many are met, of how many. */
63
+ export interface WorkAcceptance {
64
+ met: number;
65
+ total: number;
66
+ criteria: CriterionState[];
67
+ }
68
+ /** The acceptance criteria a record lists in `field`, leaving out entries without a string id and a known verification (the schema reports those). */
69
+ export declare function acceptanceCriteria(data: Record<string, unknown> | null, field: string): Criterion[];
70
+ /**
71
+ * Which of a record's criteria its evidence meets. Evidence meets a criterion
72
+ * when it names the criterion, its result is `pass` and its verification is
73
+ * the criterion's. A `manual` verdict also names who gave it in `by`, and
74
+ * counts only when that is not the record's implementer; one that is lands in
75
+ * `selfVerified`. `acceptance` is null when the record lists no criteria.
76
+ */
77
+ export declare function workAcceptance(data: Record<string, unknown> | null, spec: {
78
+ field: string;
79
+ implementer: string;
80
+ }, pinsField: string): {
81
+ acceptance: WorkAcceptance | null;
82
+ selfVerified: string[];
83
+ };
42
84
  /** The strings of a front-matter list, or none. */
43
85
  export declare function idList(data: Record<string, unknown> | null, field: string): string[];
44
86
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/workspace/work.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAA+B,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE1H,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,qLAeW,CAAC;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,QAAQ,EAAE,CAAC;CAC3B;AAED,mDAAmD;AACnD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAGpF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAGvF;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAgFrJ"}
1
+ {"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/workspace/work.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,EAAmD,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE9I,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,+OAmBW,CAAC;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,QAAQ,EAAE,CAAC;CAC3B;AAED,mIAAmI;AACnI,eAAO,MAAM,kBAAkB,8DAA+D,CAAC;AAC/F,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,2BAA4B,CAAC;AAC1D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,gBAAgB,CAAC;CAChC;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,gBAAgB,CAAC;IAC/B,GAAG,EAAE,OAAO,CAAC;CACd;AAED,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,sJAAsJ;AACtJ,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAOnG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAC5C,SAAS,EAAE,MAAM,GAChB;IAAE,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAwB/D;AAED,mDAAmD;AACnD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAGpF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAGvF;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAiGrJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.91.0",
3
+ "version": "0.93.0",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "vitest";
1
+ import { beforeAll, describe, test, expect } from "vitest";
2
2
  import { fileURLToPath } from "url";
3
3
  import Ajv from "ajv";
4
4
  import { auditCommand, tokenForHost, coverageNotes, installLine, NO_LEXICONS_EXIT_CODE } from "./audit";
@@ -22,6 +22,14 @@ function loadSarifSchema(): unknown {
22
22
  return JSON.parse(readFileSync(path, "utf-8"));
23
23
  }
24
24
 
25
+ // The first loadAuditPlugins() imports every installed lexicon's plugin, the
26
+ // 15MB azure and 11MB aws generated barrels among them: 13s to 15s cold, which
27
+ // whichever test ran first paid, over the unit shards' per-test budget (#2817).
28
+ // Paid once here, the tests below time the audit, not the imports.
29
+ beforeAll(async () => {
30
+ await loadAuditPlugins();
31
+ }, 120_000);
32
+
25
33
  describe("auditCommand", () => {
26
34
  test("selects a host-specific token (no cross-host leakage)", () => {
27
35
  const env = { GITHUB_TOKEN: "gh", GITLAB_TOKEN: "gl", CODEBERG_TOKEN: "cb" } as unknown as NodeJS.ProcessEnv;
@@ -506,12 +506,13 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
506
506
 
507
507
  // Core-owned post-synth checks over the Op model (#2122, epic #2114
508
508
  // sub-issue 6) — OPS012/OPS013/OPS014, ported from a hosting lexicon's
509
- // own TMP012/TMP013/TMP014. An Op is recognized by entity type
509
+ // own TMP012/TMP013/TMP014, and SYS010 over the decide steps and the
510
+ // backends in `decide.backends` (#2828). An Op is recognized by entity type
510
511
  // (`OpResource`), not by which lexicon declared it, so this runs over the
511
512
  // FULL build result regardless of which plugins loaded — same as the
512
513
  // receipt/output/knowledge checks above.
513
514
  if (result.errors.length === 0) {
514
- const opDiags = runPostSynthChecks(coreOpChecks(), result, env, { activityContracts });
515
+ const opDiags = runPostSynthChecks(coreOpChecks({ decideBackends: config.decide?.backends }), result, env, { activityContracts });
515
516
  const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(opDiags, config.lint?.rules);
516
517
  suppressedPostSynthCount += suppressed.length;
517
518
  for (const diag of activeDiags) {
@@ -546,8 +546,14 @@ async function runOpCheckDiagnostics(
546
546
  ? await loadActivityContracts(plugins)
547
547
  : await loadActivityContracts(await resolveProjectLexicons(infraPath).catch(() => [] as string[]));
548
548
 
549
+ // SYS010 (#2828) also reads `decide.backends` from the project's config.
550
+ // A directory whose config does not load simply has none to check.
551
+ const decideBackends = await loadChantConfig(findProjectRoot(infraPath))
552
+ .then((loaded) => loaded.config.decide?.backends)
553
+ .catch(() => undefined);
554
+
549
555
  const raw = runPostSynthChecks(
550
- coreOpChecks(),
556
+ coreOpChecks({ decideBackends }),
551
557
  {
552
558
  outputs: new Map(),
553
559
  entities: entities as Map<string, never>,
@@ -3,6 +3,7 @@ import type { ParsedArgs } from "../registry";
3
3
  import { DECLARABLE_MARKER, type Declarable } from "../../declarable";
4
4
  import { AttrRef } from "../../attrref";
5
5
  import { GRAPH_IR_VERSION } from "../../graph-ir";
6
+ import { NO_LEXICON_DETECTED_MESSAGE } from "../../detectLexicon";
6
7
 
7
8
  /**
8
9
  * The aws emulator capability, as the real plugin declares it. `--live`
@@ -469,6 +470,25 @@ describe("runGraph", () => {
469
470
  expect(exit).toBe(1);
470
471
  expect(stderrBuf.join("\n")).toContain("boom");
471
472
  });
473
+
474
+ // #2841 — an Ops-only project (`lexicons: []`, no lexicon import) has no
475
+ // lexicon to predict with. Detection's sentinel means "none", not a failed
476
+ // graph, so `chant workspace graph` does not report the member failed.
477
+ test("--format ir in a project with no lexicon graphs with no plugins", async () => {
478
+ lintClean(); discovered();
479
+ resolveLexMock.mockRejectedValue(new Error(NO_LEXICON_DETECTED_MESSAGE));
480
+ loadPluginsMock.mockResolvedValue([]);
481
+ const exit = await runGraph({ args: makeArgs({ format: "ir" }), plugins: [], serializers: [] });
482
+ expect(exit).toBe(0);
483
+ expect(loadPluginsMock).toHaveBeenCalledWith([]);
484
+ expect(JSON.parse(stdoutBuf.join("\n")).nodes.length).toBe(3);
485
+ });
486
+
487
+ test("--format ir still fails on a lexicon error other than none detected", async () => {
488
+ lintClean(); discovered();
489
+ resolveLexMock.mockRejectedValue(new Error("lexicon @intentius/chant-lexicon-nope is not installed"));
490
+ await expect(runGraph({ args: makeArgs({ format: "ir" }), plugins: [], serializers: [] })).rejects.toThrow("not installed");
491
+ });
472
492
  });
473
493
 
474
494
  describe("component DAG view (--components --format ir|layout)", () => {
@@ -21,6 +21,7 @@ import { toDot } from "../../graph-dot";
21
21
  import { getLayoutEngine, toLayoutInput, type NodeSize } from "../../graph-layout";
22
22
  import { lintCommand } from "../commands/lint";
23
23
  import { loadPlugins, resolveProjectLexicons, collectBuildRootContributors } from "../plugins";
24
+ import { isNoLexiconDetected } from "../../detectLexicon";
24
25
  import { readFileSync } from "node:fs";
25
26
  import { formatError, formatWarning, formatBold } from "../format";
26
27
  import type { CommandContext, ParsedArgs } from "../registry";
@@ -31,6 +32,19 @@ import type { BuildParamProvenance } from "../../provenance";
31
32
  import { discoverComponents } from "../../components/discover";
32
33
  import { cfnDeployStacks } from "./components";
33
34
 
35
+ /**
36
+ * The project's lexicons, or none for a project that declares none and imports
37
+ * none (an Ops-only member, `lexicons: []`): detection's NO_LEXICON_DETECTED
38
+ * sentinel means "no lexicon", as `chant lint` reads it, not a failed graph (#2841).
39
+ */
40
+ async function projectLexiconsOrNone(projectPath: string): Promise<string[]> {
41
+ try {
42
+ return await resolveProjectLexicons(projectPath);
43
+ } catch (err) {
44
+ if (isNoLexiconDetected(err)) return [];
45
+ throw err;
46
+ }
47
+ }
34
48
 
35
49
  /**
36
50
  * Resolve this invocation's declared build-time parameters, the same way
@@ -223,7 +237,7 @@ async function runGraphLive(
223
237
  // `graph` is not `requiresPlugins` (Op/source-graph modes must work without a
224
238
  // lexicon), so `ctx.plugins` is empty. The live path needs the project's
225
239
  // observation plugins — load them here, mirroring the lifecycle handlers.
226
- const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(await resolveProjectLexicons(projectPath));
240
+ const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(await projectLexiconsOrNone(projectPath));
227
241
  const declaredEnvNames = environmentNames(config.environments);
228
242
  if (declaredEnvNames && !matchesDeclaredEnvironment(config.environments, environment)) {
229
243
  console.error(formatError({
@@ -828,7 +842,7 @@ async function runGraphView(
828
842
  {
829
843
  const plugins = ctx.plugins.length > 0
830
844
  ? ctx.plugins
831
- : await loadPlugins(await resolveProjectLexicons(projectPath));
845
+ : await loadPlugins(await projectLexiconsOrNone(projectPath));
832
846
  const predicted = await predictOntoIr(ir, plugins as LexiconPlugin[], ctx.args, {
833
847
  // No environment on the declared path: the file is not deployed anywhere
834
848
  // yet, and naming one would claim it was.
@@ -29,7 +29,7 @@ import {
29
29
  } from "../../op/operator";
30
30
  import { readLease, releaseLease, currentHolderId, DEFAULT_LEASE_TTL_MS } from "../../lifecycle/lease";
31
31
  import { readConvergeLedger, type ConvergeTickRecord } from "../../lifecycle/converge-ledger";
32
- import { readRunLedger } from "../../lifecycle/run-ledger";
32
+ import { readRunLedger, runEnvOf } from "../../lifecycle/run-ledger";
33
33
  import type { OpRunRecord } from "../../op/runtime";
34
34
  import type { GateResolutionRecord, PendingGateRecord } from "../../lifecycle/gate-ledger";
35
35
  import {
@@ -413,6 +413,12 @@ async function statusFor(opName: string, env: string, cwd?: string): Promise<OpS
413
413
  export interface StandaloneGateLine {
414
414
  op: string;
415
415
  gate: string;
416
+ /**
417
+ * The Op whose newest run stopped at this gate, when the gate is a
418
+ * command's own rather than the Op's (#2779): a step running `chant
419
+ * workspace upgrade` stops its run at `workspace-upgrade` / `<scope>`.
420
+ */
421
+ run?: string;
416
422
  description?: string;
417
423
  expiresAt: string;
418
424
  url?: string;
@@ -458,6 +464,32 @@ export async function runOperatorStatus(ctx: CommandContext): Promise<number> {
458
464
  }
459
465
  }
460
466
 
467
+ // A gate a command decided inside an Op's step (#2779) is recorded under
468
+ // the command's op, which is not an `*.op.ts`, so the loop above never
469
+ // reads it. The Op's newest run names it; list it against that Op while it
470
+ // still stands.
471
+ for (const [opName, discovered] of [...allOps.entries()].sort(([a], [b]) => a.localeCompare(b))) {
472
+ let newest: OpRunRecord | undefined;
473
+ try {
474
+ newest = (await readRunLedger(runEnvOf(discovered.config), opName)).records.at(-1);
475
+ } catch {
476
+ continue;
477
+ }
478
+ const gateOp = newest?.status === "gated" ? newest.gate?.op : undefined;
479
+ if (!newest?.gate || !gateOp || gateOp === opName) continue;
480
+ const record = (await pendingGatesFor(gateOp)).find((r) => r.gate === newest.gate!.name);
481
+ if (!record || covered.has(`${gateOp} ${record.gate}`)) continue;
482
+ covered.add(`${gateOp} ${record.gate}`);
483
+ standalone.push({
484
+ op: gateOp,
485
+ gate: record.gate,
486
+ run: opName,
487
+ expiresAt: record.expiresAt,
488
+ ...(record.description ? { description: record.description } : {}),
489
+ ...(record.url ? { url: record.url } : {}),
490
+ });
491
+ }
492
+
461
493
  if (ops.length === 0 && standalone.length === 0) {
462
494
  console.error(formatWarning({ message: "No ConvergeOp declarations found" }));
463
495
  return 0;
@@ -494,7 +526,7 @@ export async function runOperatorStatus(ctx: CommandContext): Promise<number> {
494
526
  if (standalone.length > 0) {
495
527
  console.log(formatBold("pending gates (no converge tick)"));
496
528
  for (const g of standalone) {
497
- console.log(` - ${g.op} gate "${g.gate}" — resolve: chant approve ${g.op} ${g.gate}`);
529
+ console.log(` - ${g.op} gate "${g.gate}"${g.run ? ` (Op ${g.run}'s run stopped here)` : ""} — resolve: chant approve ${g.op} ${g.gate}`);
498
530
  if (g.description) console.log(` ${g.description}`);
499
531
  console.log(` expires: ${g.expiresAt}`);
500
532
  if (g.url) console.log(` approve at: ${g.url}`);