@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
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Answer records held on the lifecycle ledger (#2786).
3
+ *
4
+ * A steward's writes never touch the checkout's index or working tree
5
+ * (`../op/steward.ts`): the working tree is the coding agent's. A decision
6
+ * point asked in a steward's turn still has to leave its question somewhere a
7
+ * person finds it after the turn ends, and an Op's leased worktree is removed
8
+ * with the run. So a question asked in a steward's turn is written to
9
+ * `chant/lifecycle`, beside the lease histories and run records, under
10
+ * `_answers/<kind name>/<id>.md` in the ledger of the member that owns the
11
+ * answer kind. The file is the same Markdown record the kind's directory
12
+ * would hold, and it is written with git plumbing, like every ledger write.
13
+ *
14
+ * Readers see the ledger's answers as if they sat in the kind's directory:
15
+ * {@link withLedgerAnswers} lays them over the working tree, so `points`,
16
+ * `points --open`, a later `points ask` of the same question and `points
17
+ * answer` all find them. A record on the ledger wins over a file of the same
18
+ * name in the tree, because the ledger copy is the one a steward rewrote.
19
+ * People's answer to a question held on the ledger is written back there, so
20
+ * answering through hud in a box does not touch the checkout either.
21
+ *
22
+ * `points --at <rev>` reads a revision of the working branch, which the
23
+ * ledger is not part of, so it lists the tree's records only.
24
+ */
25
+
26
+ import { basename, dirname } from "node:path";
27
+ import { fetchLifecycleStatus, ledgerDir, listFilesInDir, pushLifecycle, readBlobBySha, readPathSha, writeBlobToPath } from "../lifecycle/git";
28
+ import type { RecordSource } from "./record-source";
29
+ import { overlay } from "./records-write";
30
+
31
+ /** The directory on `chant/lifecycle`, under the member's prefix, that holds answer records. */
32
+ export const ANSWERS_LEDGER_DIR = "_answers";
33
+
34
+ const BRANCH = "chant/lifecycle";
35
+
36
+ /** One answer record on the ledger. */
37
+ export interface LedgerAnswer {
38
+ /** Where the record reads as being: the kind's directory, from the repository root. */
39
+ path: string;
40
+ /** Where it is: `chant/lifecycle:<path on the branch>`, which `git show` reads. */
41
+ ledger: string;
42
+ text: string;
43
+ /** Its blob sha, for a compare-and-set rewrite. */
44
+ sha: string;
45
+ }
46
+
47
+ /** The answer records one kind holds on the ledger. */
48
+ export interface LedgerAnswers {
49
+ /** Where the ledger is resolved from: the kind file's directory, so the member owning the kind owns its answers. */
50
+ cwd: string;
51
+ /** The directory on the branch, relative to the member's prefix. */
52
+ dir: string;
53
+ /** The kind's records directory, from the repository root. */
54
+ dirRel: string;
55
+ /** By the path each record reads as. */
56
+ byPath: Map<string, LedgerAnswer>;
57
+ }
58
+
59
+ /** The ledger directory of the kind named `kindName`. */
60
+ export function answersLedgerDir(kindName: string): string {
61
+ return `${ANSWERS_LEDGER_DIR}/${kindName.replace(/[^A-Za-z0-9._-]/g, "_")}`;
62
+ }
63
+
64
+ function treePath(dirRel: string, name: string): string {
65
+ return dirRel === "." ? name : `${dirRel}/${name}`;
66
+ }
67
+
68
+ /**
69
+ * Read the answer records the kind at `kindFile` holds on the ledger. Empty
70
+ * when there are none, when there is no ledger branch, and outside a git
71
+ * repository.
72
+ */
73
+ export async function readLedgerAnswers(kind: { file: string; name: string; dirRel: string }): Promise<LedgerAnswers> {
74
+ const cwd = dirname(kind.file);
75
+ const dir = answersLedgerDir(kind.name);
76
+ const out: LedgerAnswers = { cwd, dir, dirRel: kind.dirRel, byPath: new Map() };
77
+ try {
78
+ const names = (await listFilesInDir(dir, { cwd })).filter((n) => n.endsWith(".md"));
79
+ if (names.length === 0) return out;
80
+ const full = await ledgerDir(dir, { cwd });
81
+ for (const name of names) {
82
+ const sha = await readPathSha(dir, name, { cwd });
83
+ const text = sha ? await readBlobBySha(sha, { cwd }) : null;
84
+ if (sha === null || text === null) continue;
85
+ const path = treePath(kind.dirRel, name);
86
+ out.byPath.set(path, { path, ledger: `${BRANCH}:${full}/${name}`, text, sha });
87
+ }
88
+ } catch {
89
+ // No repository, or a member ledger that can't be placed: the tree's records are all there is.
90
+ }
91
+ return out;
92
+ }
93
+
94
+ /** `base` with each ledger answer at the path it reads as, over any file of the same name. */
95
+ export function withLedgerAnswers(base: RecordSource, answers: LedgerAnswers): RecordSource {
96
+ let source = base;
97
+ for (const a of answers.byPath.values()) source = overlay(source, a.path, a.text);
98
+ return source;
99
+ }
100
+
101
+ /** Fetch `chant/lifecycle` before a ledger write when it fast-forwards, so a question another clone asked is found. Best effort. */
102
+ export async function refreshLedger(kindFile: string): Promise<void> {
103
+ await fetchLifecycleStatus({ cwd: dirname(kindFile) }).catch(() => undefined);
104
+ }
105
+
106
+ /**
107
+ * Write the record read as `path` to the ledger, expecting the blob it had
108
+ * when it was read (`prior`, null for a new record), then push the branch.
109
+ * A changed blob throws `RefCASConflictError` from `../lifecycle/git`. The
110
+ * push is best effort: a question that did not reach the remote is still
111
+ * open here. Returns where the record went.
112
+ */
113
+ export async function writeLedgerAnswer(answers: LedgerAnswers, path: string, text: string, message: string, prior: string | null): Promise<{ ledger: string; pushed: boolean }> {
114
+ const name = basename(path);
115
+ await writeBlobToPath(answers.dir, name, text, message, { cwd: answers.cwd, expectPriorPathSha: prior });
116
+ const pushed = await pushLifecycle({ cwd: answers.cwd }).catch(() => false);
117
+ return { ledger: `${BRANCH}:${await ledgerDir(answers.dir, { cwd: answers.cwd })}/${name}`, pushed };
118
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `chant workspace check --changes <base>..<head> [--work <id>] [--severity
3
+ * off|warn|fail] [--kind <kind file>...] [--json]` (#2773): the forward
4
+ * coverage check (`changes.ts`), printed as JSON with `--json` or as one line
5
+ * per changed path, then the findings.
6
+ */
7
+
8
+ import { resolve } from "node:path";
9
+ import { formatError } from "../cli/format";
10
+ import type { CommandContext } from "../cli/registry";
11
+ import { CHANGE_SEVERITIES, checkChanges, type ChangesDocument } from "./changes";
12
+ import type { ChangeSeverity } from "./declaration";
13
+
14
+ const USAGE = "chant workspace check --changes <base>..<head> [--work <id>] [--severity off|warn|fail] [--kind <kind file>...] [--json]";
15
+
16
+ type Result = Exclude<ChangesDocument, { error: unknown }>;
17
+
18
+ /** One line per changed path, then the findings and a summary. */
19
+ export function formatChanges(doc: Result): string {
20
+ const out: string[] = [];
21
+ const work = doc.work ? `, work item ${doc.work.record} in hand` : "";
22
+ out.push(`changes ${doc.range.base.slice(0, 8)}..${doc.range.head.slice(0, 8)} (${doc.range.spec}), severity ${doc.severity}${work}`);
23
+ for (const p of doc.paths) {
24
+ const why =
25
+ p.status === "covered"
26
+ ? `by ${p.coveredBy.map((c) => `${c.record} (${c.entry})`).join(", ")}`
27
+ : p.status === "out-of-scope"
28
+ ? `by ${p.outOfScopeBy.map((c) => `${c.record} (${c.entry})`).join(", ")}`
29
+ : p.status === "ignored"
30
+ ? `by ${p.ignoredBy}`
31
+ : "";
32
+ out.push(`${p.status.padEnd(12)} ${p.change.padEnd(8)} ${p.path}${p.from ? ` (from ${p.from})` : ""}${why ? `; ${why}` : ""}`);
33
+ }
34
+ for (const f of doc.findings) out.push(`${f.severity === "fail" ? "error " : "warning"} ${f.code}: ${f.message}`);
35
+ const s = doc.summary;
36
+ out.push(`${s.paths} changed paths: ${s.covered} covered, ${s.uncovered} uncovered, ${s.outOfScope} out of scope, ${s.ignored} ignored, ${s.records} records; ${doc.findings.length} findings`);
37
+ return out.join("\n");
38
+ }
39
+
40
+ export async function runWorkspaceChanges(ctx: CommandContext, cwd: string): Promise<number> {
41
+ const { args } = ctx;
42
+ const severity = args.severity as ChangeSeverity | undefined;
43
+ if (severity !== undefined && !(CHANGE_SEVERITIES as readonly string[]).includes(severity)) {
44
+ console.error(formatError({ message: `--severity ${severity} is not off, warn or fail`, hint: USAGE }));
45
+ return 1;
46
+ }
47
+ const kinds = args.kinds ?? (args.kind !== undefined ? [args.kind] : undefined);
48
+ const { doc, failed } = await checkChanges({ cwd, range: args.changes!, kinds: kinds?.map((k) => resolve(k)), work: args.work, severity });
49
+ if (args.json || args.format === "json") console.log(JSON.stringify(doc, null, 2));
50
+ if ("error" in doc) {
51
+ console.error(formatError({ message: `${doc.error.code}: ${doc.error.message}`, hint: USAGE }));
52
+ return 1;
53
+ }
54
+ if (!args.json && args.format !== "json") console.log(formatChanges(doc));
55
+ return failed ? 1 : 0;
56
+ }
@@ -0,0 +1,472 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/changes/v1/changes.schema.json",
4
+ "title": "chant workspace check --changes output",
5
+ "description": "What `chant workspace check --changes <base>..<head> --json` prints: the forward coverage check (#2773). Each path the diff changes, mapped to the current records whose constrains cover it, and a finding for each path no current decided record or open work item covers (change-uncovered), or that a record in hand for the change puts out of scope (change-out-of-scope). Readers ignore fields they do not know; a field is only ever added within a version. The finding and error codes are closed lists, and every one is in the one closed list of `reason-codes.ts`. Contract version 1 is written by chant 0.81.0 and newer, and this document was added to it by #2773; a chant without --changes refuses the flag.",
6
+ "oneOf": [
7
+ {
8
+ "$ref": "#/$defs/result"
9
+ },
10
+ {
11
+ "$ref": "#/$defs/failure"
12
+ }
13
+ ],
14
+ "$defs": {
15
+ "result": {
16
+ "description": "The diff and the records were read. Exit code 0, or 1 when severity is fail and there is a finding; the document is printed either way.",
17
+ "type": "object",
18
+ "required": [
19
+ "$schema",
20
+ "contract",
21
+ "chant",
22
+ "workspace",
23
+ "range",
24
+ "severity",
25
+ "ignore",
26
+ "work",
27
+ "kinds",
28
+ "paths",
29
+ "findings",
30
+ "summary",
31
+ "ok"
32
+ ],
33
+ "properties": {
34
+ "$schema": {
35
+ "const": "https://intentius.io/chant/schemas/workspace/changes/v1/changes.schema.json"
36
+ },
37
+ "contract": {
38
+ "const": 1
39
+ },
40
+ "chant": {
41
+ "type": "string",
42
+ "description": "The chant that wrote the document."
43
+ },
44
+ "workspace": {
45
+ "type": "object",
46
+ "required": [
47
+ "name",
48
+ "root"
49
+ ],
50
+ "properties": {
51
+ "name": {
52
+ "type": "string"
53
+ },
54
+ "root": {
55
+ "type": "string",
56
+ "description": "The workspace root relative to the git root, \".\" for the git root."
57
+ }
58
+ }
59
+ },
60
+ "range": {
61
+ "type": "object",
62
+ "required": [
63
+ "spec",
64
+ "base",
65
+ "head"
66
+ ],
67
+ "properties": {
68
+ "spec": {
69
+ "type": "string",
70
+ "description": "The range as given: <base>..<head>, <base>...<head> or <base>."
71
+ },
72
+ "base": {
73
+ "type": "string",
74
+ "pattern": "^[0-9a-f]{40,64}$",
75
+ "description": "The commit the diff starts from: <base>, or for <base>...<head> the merge base."
76
+ },
77
+ "head": {
78
+ "type": "string",
79
+ "pattern": "^[0-9a-f]{40,64}$",
80
+ "description": "The commit the diff ends at. The declaration and the records are read here."
81
+ }
82
+ }
83
+ },
84
+ "severity": {
85
+ "enum": [
86
+ "off",
87
+ "warn",
88
+ "fail"
89
+ ],
90
+ "description": "From --severity, else the declaration's changes.severity, else warn. off reports no finding."
91
+ },
92
+ "ignore": {
93
+ "type": "array",
94
+ "items": {
95
+ "type": "string"
96
+ },
97
+ "description": "The declaration's changes.ignore globs."
98
+ },
99
+ "work": {
100
+ "description": "The work item in hand (--work), or null.",
101
+ "oneOf": [
102
+ {
103
+ "type": "null"
104
+ },
105
+ {
106
+ "type": "object",
107
+ "required": [
108
+ "record",
109
+ "state"
110
+ ],
111
+ "properties": {
112
+ "record": {
113
+ "type": "string"
114
+ },
115
+ "state": {
116
+ "type": [
117
+ "string",
118
+ "null"
119
+ ]
120
+ }
121
+ }
122
+ }
123
+ ]
124
+ },
125
+ "kinds": {
126
+ "type": "array",
127
+ "description": "The record kinds read: the --kind files, or every kind the declaration names. role is work for a kind with a work block, decision for another kind with constrains, and other for a kind that covers nothing.",
128
+ "items": {
129
+ "type": "object",
130
+ "required": [
131
+ "file",
132
+ "name",
133
+ "role"
134
+ ],
135
+ "properties": {
136
+ "file": {
137
+ "type": "string"
138
+ },
139
+ "name": {
140
+ "type": "string"
141
+ },
142
+ "role": {
143
+ "enum": [
144
+ "decision",
145
+ "work",
146
+ "other"
147
+ ]
148
+ }
149
+ }
150
+ }
151
+ },
152
+ "paths": {
153
+ "type": "array",
154
+ "items": {
155
+ "$ref": "#/$defs/path"
156
+ }
157
+ },
158
+ "findings": {
159
+ "type": "array",
160
+ "items": {
161
+ "$ref": "#/$defs/finding"
162
+ }
163
+ },
164
+ "summary": {
165
+ "type": "object",
166
+ "required": [
167
+ "paths",
168
+ "covered",
169
+ "uncovered",
170
+ "outOfScope",
171
+ "ignored",
172
+ "records"
173
+ ],
174
+ "properties": {
175
+ "paths": {
176
+ "type": "integer",
177
+ "minimum": 0
178
+ },
179
+ "covered": {
180
+ "type": "integer",
181
+ "minimum": 0
182
+ },
183
+ "uncovered": {
184
+ "type": "integer",
185
+ "minimum": 0
186
+ },
187
+ "outOfScope": {
188
+ "type": "integer",
189
+ "minimum": 0
190
+ },
191
+ "ignored": {
192
+ "type": "integer",
193
+ "minimum": 0
194
+ },
195
+ "records": {
196
+ "type": "integer",
197
+ "minimum": 0
198
+ }
199
+ }
200
+ },
201
+ "ok": {
202
+ "type": "boolean",
203
+ "description": "False only when severity is fail and there is a finding."
204
+ }
205
+ }
206
+ },
207
+ "path": {
208
+ "type": "object",
209
+ "required": [
210
+ "path",
211
+ "change",
212
+ "from",
213
+ "member",
214
+ "status",
215
+ "coveredBy",
216
+ "outOfScopeBy",
217
+ "ignoredBy"
218
+ ],
219
+ "properties": {
220
+ "path": {
221
+ "type": "string",
222
+ "description": "From the workspace root."
223
+ },
224
+ "change": {
225
+ "enum": [
226
+ "added",
227
+ "modified",
228
+ "deleted",
229
+ "renamed"
230
+ ]
231
+ },
232
+ "from": {
233
+ "type": [
234
+ "string",
235
+ "null"
236
+ ],
237
+ "description": "For a rename, the path at base."
238
+ },
239
+ "member": {
240
+ "type": [
241
+ "string",
242
+ "null"
243
+ ],
244
+ "description": "The member whose directory holds the path."
245
+ },
246
+ "generated": {
247
+ "type": "boolean",
248
+ "description": "Added by #2794: whether the path is a generated file, declared in a member's generated entries or one core registers, as graph --intent reads a region's generated. The finding-triage point reads it as region.generated."
249
+ },
250
+ "status": {
251
+ "enum": [
252
+ "covered",
253
+ "uncovered",
254
+ "out-of-scope",
255
+ "ignored",
256
+ "record"
257
+ ],
258
+ "description": "record: the path is a record file of a kind read, so the change is to the records themselves. ignored: a changes.ignore glob matches it. out-of-scope takes precedence over covered."
259
+ },
260
+ "coveredBy": {
261
+ "type": "array",
262
+ "items": {
263
+ "type": "object",
264
+ "additionalProperties": false,
265
+ "required": [
266
+ "record",
267
+ "state",
268
+ "entry"
269
+ ],
270
+ "properties": {
271
+ "record": {
272
+ "type": "string",
273
+ "description": "The record, as <kind name>/<id>."
274
+ },
275
+ "state": {
276
+ "type": [
277
+ "string",
278
+ "null"
279
+ ]
280
+ },
281
+ "entry": {
282
+ "type": "string",
283
+ "description": "The constrains entry that covers the path (path:<path> or member:<name>), or the out_of_scope path that puts it out."
284
+ }
285
+ }
286
+ },
287
+ "description": "The current records whose constrains cover the path: decisions not superseded and in a decided state, and work items not in a closed state."
288
+ },
289
+ "outOfScopeBy": {
290
+ "type": "array",
291
+ "items": {
292
+ "type": "object",
293
+ "additionalProperties": false,
294
+ "required": [
295
+ "record",
296
+ "state",
297
+ "entry"
298
+ ],
299
+ "properties": {
300
+ "record": {
301
+ "type": "string",
302
+ "description": "The record, as <kind name>/<id>."
303
+ },
304
+ "state": {
305
+ "type": [
306
+ "string",
307
+ "null"
308
+ ]
309
+ },
310
+ "entry": {
311
+ "type": "string",
312
+ "description": "The constrains entry that covers the path (path:<path> or member:<name>), or the out_of_scope path that puts it out."
313
+ }
314
+ }
315
+ },
316
+ "description": "The records in hand whose out_of_scope lists the path or a directory above it."
317
+ },
318
+ "ignoredBy": {
319
+ "type": [
320
+ "string",
321
+ "null"
322
+ ],
323
+ "description": "The glob that matched an ignored path."
324
+ }
325
+ }
326
+ },
327
+ "finding": {
328
+ "type": "object",
329
+ "required": [
330
+ "id",
331
+ "code",
332
+ "path",
333
+ "message",
334
+ "severity",
335
+ "records",
336
+ "triage"
337
+ ],
338
+ "properties": {
339
+ "id": {
340
+ "type": "string",
341
+ "description": "finding:<code>:<path>."
342
+ },
343
+ "code": {
344
+ "enum": [
345
+ "change-uncovered",
346
+ "change-out-of-scope"
347
+ ]
348
+ },
349
+ "path": {
350
+ "type": "string"
351
+ },
352
+ "message": {
353
+ "type": "string"
354
+ },
355
+ "severity": {
356
+ "enum": [
357
+ "warn",
358
+ "fail"
359
+ ]
360
+ },
361
+ "records": {
362
+ "type": "array",
363
+ "items": {
364
+ "type": "string"
365
+ },
366
+ "description": "For change-out-of-scope, the records that put the path out of scope."
367
+ },
368
+ "triage": {
369
+ "type": "object",
370
+ "required": [
371
+ "finding",
372
+ "region"
373
+ ],
374
+ "description": "The source a work item seeded from this finding carries: work.schema.json's sourceGap. The finding-triage decision point (#2741) reads it.",
375
+ "properties": {
376
+ "finding": {
377
+ "enum": [
378
+ "change-uncovered",
379
+ "change-out-of-scope"
380
+ ]
381
+ },
382
+ "region": {
383
+ "type": "string"
384
+ }
385
+ }
386
+ },
387
+ "addressed": {
388
+ "type": "boolean",
389
+ "description": "Added by #2794, present when a work kind was read: whether a work item addresses the finding, because the item's source.finding is this code and its source.region is this path or a directory above it, in any state, as graph --intent reads a gap source (#2683). The finding-triage point reads it as finding.addressed."
390
+ },
391
+ "addressedBy": {
392
+ "type": "array",
393
+ "items": {
394
+ "type": "object",
395
+ "additionalProperties": false,
396
+ "required": [
397
+ "record",
398
+ "state"
399
+ ],
400
+ "properties": {
401
+ "record": {
402
+ "type": "string",
403
+ "description": "The work item, as <kind name>/<id>."
404
+ },
405
+ "state": {
406
+ "type": [
407
+ "string",
408
+ "null"
409
+ ]
410
+ }
411
+ }
412
+ },
413
+ "description": "Added by #2794, present when a work kind was read: the work items addressing the finding, each with its state."
414
+ }
415
+ }
416
+ },
417
+ "failure": {
418
+ "description": "The range, the declaration, a record kind or the --work item could not be read, and nothing was checked. Exit code 1.",
419
+ "type": "object",
420
+ "required": [
421
+ "$schema",
422
+ "contract",
423
+ "chant",
424
+ "error"
425
+ ],
426
+ "properties": {
427
+ "$schema": {
428
+ "const": "https://intentius.io/chant/schemas/workspace/changes/v1/changes.schema.json"
429
+ },
430
+ "contract": {
431
+ "const": 1
432
+ },
433
+ "chant": {
434
+ "type": "string"
435
+ },
436
+ "error": {
437
+ "type": "object",
438
+ "required": [
439
+ "code",
440
+ "message"
441
+ ],
442
+ "properties": {
443
+ "code": {
444
+ "enum": [
445
+ "declaration-missing",
446
+ "declaration-ambiguous",
447
+ "declaration-unparseable",
448
+ "declaration-invalid",
449
+ "placement-invalid",
450
+ "reader-too-old",
451
+ "root-chant-required",
452
+ "not-a-git-repository",
453
+ "revision-unknown",
454
+ "kind-unreadable",
455
+ "kind-invalid",
456
+ "schema-unreadable",
457
+ "schema-id-mismatch",
458
+ "schema-invalid",
459
+ "location-missing",
460
+ "work-item-unknown"
461
+ ]
462
+ },
463
+ "message": {
464
+ "type": "string"
465
+ }
466
+ }
467
+ },
468
+ "paths": false
469
+ }
470
+ }
471
+ }
472
+ }