@intentius/chant 0.102.0 → 0.104.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 (464) hide show
  1. package/dist/audit/core.d.ts +2 -0
  2. package/dist/audit/core.d.ts.map +1 -1
  3. package/dist/audit/discover.d.ts.map +1 -1
  4. package/dist/change-set.d.ts +232 -0
  5. package/dist/change-set.d.ts.map +1 -0
  6. package/dist/cli/commands/audit.d.ts +7 -0
  7. package/dist/cli/commands/audit.d.ts.map +1 -1
  8. package/dist/cli/commands/build.d.ts.map +1 -1
  9. package/dist/cli/handlers/build.d.ts.map +1 -1
  10. package/dist/cli/handlers/change-set.d.ts +11 -0
  11. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  12. package/dist/cli/handlers/fan-out.d.ts +33 -0
  13. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  14. package/dist/cli/handlers/operator.d.ts +7 -0
  15. package/dist/cli/handlers/operator.d.ts.map +1 -1
  16. package/dist/cli/handlers/pr.d.ts +31 -0
  17. package/dist/cli/handlers/pr.d.ts.map +1 -0
  18. package/dist/cli/handlers/run.d.ts.map +1 -1
  19. package/dist/cli/main.d.ts.map +1 -1
  20. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  21. package/dist/cli/mcp/workspace-tools.d.ts +3 -2
  22. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  23. package/dist/cli/registry.d.ts +63 -1
  24. package/dist/cli/registry.d.ts.map +1 -1
  25. package/dist/components/auto-release.d.ts +16 -0
  26. package/dist/components/auto-release.d.ts.map +1 -1
  27. package/dist/components/capability.d.ts +53 -0
  28. package/dist/components/capability.d.ts.map +1 -1
  29. package/dist/components/changed-files.d.ts +31 -0
  30. package/dist/components/changed-files.d.ts.map +1 -0
  31. package/dist/components/cli-support.d.ts +9 -1
  32. package/dist/components/cli-support.d.ts.map +1 -1
  33. package/dist/components/component.d.ts +24 -0
  34. package/dist/components/component.d.ts.map +1 -1
  35. package/dist/components/deploy-units.d.ts.map +1 -1
  36. package/dist/components/driver.d.ts +13 -0
  37. package/dist/components/driver.d.ts.map +1 -1
  38. package/dist/components/fan-out-output.d.ts +6 -0
  39. package/dist/components/fan-out-output.d.ts.map +1 -1
  40. package/dist/components/fan-out-record.d.ts +41 -0
  41. package/dist/components/fan-out-record.d.ts.map +1 -0
  42. package/dist/components/fan-out-run.d.ts +65 -0
  43. package/dist/components/fan-out-run.d.ts.map +1 -1
  44. package/dist/components/fan-out-support.d.ts +2 -0
  45. package/dist/components/fan-out-support.d.ts.map +1 -1
  46. package/dist/components/fan-out.d.ts +6 -0
  47. package/dist/components/fan-out.d.ts.map +1 -1
  48. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  49. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  50. package/dist/components/index.d.ts +1 -1
  51. package/dist/components/index.d.ts.map +1 -1
  52. package/dist/components/layers.d.ts +25 -0
  53. package/dist/components/layers.d.ts.map +1 -0
  54. package/dist/components/pr-pipeline.d.ts +61 -0
  55. package/dist/components/pr-pipeline.d.ts.map +1 -0
  56. package/dist/components/pr-run.d.ts +119 -0
  57. package/dist/components/pr-run.d.ts.map +1 -0
  58. package/dist/components/promote.d.ts.map +1 -1
  59. package/dist/components/verbs/shell.d.ts.map +1 -1
  60. package/dist/components/wave-plan.d.ts +49 -0
  61. package/dist/components/wave-plan.d.ts.map +1 -0
  62. package/dist/gated-waves.d.ts +147 -0
  63. package/dist/gated-waves.d.ts.map +1 -0
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/lexicon.d.ts +48 -0
  67. package/dist/lexicon.d.ts.map +1 -1
  68. package/dist/lifecycle/gate-ledger.d.ts +7 -0
  69. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  70. package/dist/lifecycle/git.d.ts +46 -1
  71. package/dist/lifecycle/git.d.ts.map +1 -1
  72. package/dist/lint/post-synth.d.ts +18 -0
  73. package/dist/lint/post-synth.d.ts.map +1 -1
  74. package/dist/op/activities/activity-contracts.d.ts +126 -0
  75. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  76. package/dist/op/activities/change-set.d.ts +62 -0
  77. package/dist/op/activities/change-set.d.ts.map +1 -0
  78. package/dist/op/activities/decide.d.ts +2 -0
  79. package/dist/op/activities/decide.d.ts.map +1 -1
  80. package/dist/op/activities/factory.d.ts +137 -0
  81. package/dist/op/activities/factory.d.ts.map +1 -0
  82. package/dist/op/activities/index.d.ts +4 -0
  83. package/dist/op/activities/index.d.ts.map +1 -1
  84. package/dist/op/activity-contract.d.ts.map +1 -1
  85. package/dist/op/builders.d.ts +11 -0
  86. package/dist/op/builders.d.ts.map +1 -1
  87. package/dist/op/decide-backend.d.ts +5 -1
  88. package/dist/op/decide-backend.d.ts.map +1 -1
  89. package/dist/op/decide-read-inputs.d.ts +4 -2
  90. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  91. package/dist/op/factory.d.ts +83 -0
  92. package/dist/op/factory.d.ts.map +1 -0
  93. package/dist/op/index.d.ts +4 -1
  94. package/dist/op/index.d.ts.map +1 -1
  95. package/dist/op/op-ir.d.ts +2 -0
  96. package/dist/op/op-ir.d.ts.map +1 -1
  97. package/dist/op/op-verb-class.d.ts.map +1 -1
  98. package/dist/op/types.d.ts +8 -0
  99. package/dist/op/types.d.ts.map +1 -1
  100. package/dist/op/work-lease-run.d.ts.map +1 -1
  101. package/dist/plan-summary.d.ts +207 -0
  102. package/dist/plan-summary.d.ts.map +1 -0
  103. package/dist/pr-forge.d.ts +105 -0
  104. package/dist/pr-forge.d.ts.map +1 -0
  105. package/dist/pr-loop.d.ts +178 -0
  106. package/dist/pr-loop.d.ts.map +1 -0
  107. package/dist/telemetry-attribution.d.ts +31 -0
  108. package/dist/telemetry-attribution.d.ts.map +1 -1
  109. package/dist/terraform/hcl2json.d.ts +45 -0
  110. package/dist/terraform/hcl2json.d.ts.map +1 -0
  111. package/dist/terraform/parse.d.ts +4 -40
  112. package/dist/terraform/parse.d.ts.map +1 -1
  113. package/dist/workspace/box-cli.d.ts +12 -0
  114. package/dist/workspace/box-cli.d.ts.map +1 -0
  115. package/dist/workspace/box-factory.d.ts +27 -3
  116. package/dist/workspace/box-factory.d.ts.map +1 -1
  117. package/dist/workspace/box-listing.d.ts +85 -0
  118. package/dist/workspace/box-listing.d.ts.map +1 -0
  119. package/dist/workspace/box-publish.d.ts +147 -0
  120. package/dist/workspace/box-publish.d.ts.map +1 -0
  121. package/dist/workspace/broker-protocol.d.ts +190 -0
  122. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  123. package/dist/workspace/checks.d.ts.map +1 -1
  124. package/dist/workspace/composites.d.ts +2 -2
  125. package/dist/workspace/composites.d.ts.map +1 -1
  126. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  127. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  128. package/dist/workspace/conformance/broker.d.ts +202 -0
  129. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  130. package/dist/workspace/conformance/index.d.ts +2 -1
  131. package/dist/workspace/conformance/index.d.ts.map +1 -1
  132. package/dist/workspace/conformance/vitest.d.ts +9 -2
  133. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  134. package/dist/workspace/conformance/writer.d.ts +108 -14
  135. package/dist/workspace/conformance/writer.d.ts.map +1 -1
  136. package/dist/workspace/decide.d.ts +126 -12
  137. package/dist/workspace/decide.d.ts.map +1 -1
  138. package/dist/workspace/decision-points.schema.json +11 -4
  139. package/dist/workspace/declaration.d.ts +65 -0
  140. package/dist/workspace/declaration.d.ts.map +1 -1
  141. package/dist/workspace/declaration.schema.json +153 -4
  142. package/dist/workspace/environments.d.ts +36 -10
  143. package/dist/workspace/environments.d.ts.map +1 -1
  144. package/dist/workspace/factory-rules.d.ts +180 -0
  145. package/dist/workspace/factory-rules.d.ts.map +1 -0
  146. package/dist/workspace/init.d.ts +21 -0
  147. package/dist/workspace/init.d.ts.map +1 -1
  148. package/dist/workspace/intent-cli.d.ts +1 -1
  149. package/dist/workspace/intent-cli.d.ts.map +1 -1
  150. package/dist/workspace/intent-record.d.ts +28 -1
  151. package/dist/workspace/intent-record.d.ts.map +1 -1
  152. package/dist/workspace/intent.d.ts +102 -5
  153. package/dist/workspace/intent.d.ts.map +1 -1
  154. package/dist/workspace/json-edit.d.ts +24 -0
  155. package/dist/workspace/json-edit.d.ts.map +1 -0
  156. package/dist/workspace/jsonc.d.ts +11 -0
  157. package/dist/workspace/jsonc.d.ts.map +1 -1
  158. package/dist/workspace/kinds.d.ts +48 -0
  159. package/dist/workspace/kinds.d.ts.map +1 -1
  160. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  161. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  162. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  163. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  164. package/dist/workspace/point-answer.schema.json +42 -2
  165. package/dist/workspace/points-cli.d.ts +10 -3
  166. package/dist/workspace/points-cli.d.ts.map +1 -1
  167. package/dist/workspace/points.d.ts +66 -5
  168. package/dist/workspace/points.d.ts.map +1 -1
  169. package/dist/workspace/reason-codes.d.ts +33 -4
  170. package/dist/workspace/reason-codes.d.ts.map +1 -1
  171. package/dist/workspace/record-sessions.d.ts +5 -7
  172. package/dist/workspace/record-sessions.d.ts.map +1 -1
  173. package/dist/workspace/records-cli.d.ts +7 -0
  174. package/dist/workspace/records-cli.d.ts.map +1 -1
  175. package/dist/workspace/records-close.d.ts +7 -3
  176. package/dist/workspace/records-close.d.ts.map +1 -1
  177. package/dist/workspace/records-write.d.ts +66 -6
  178. package/dist/workspace/records-write.d.ts.map +1 -1
  179. package/dist/workspace/records.d.ts +28 -9
  180. package/dist/workspace/records.d.ts.map +1 -1
  181. package/dist/workspace/runs-cli.d.ts +138 -6
  182. package/dist/workspace/runs-cli.d.ts.map +1 -1
  183. package/dist/workspace/runs.d.ts +132 -11
  184. package/dist/workspace/runs.d.ts.map +1 -1
  185. package/dist/workspace/session-kinds.d.ts +1 -1
  186. package/dist/workspace/session-kinds.d.ts.map +1 -1
  187. package/dist/workspace/squash.d.ts +80 -0
  188. package/dist/workspace/squash.d.ts.map +1 -0
  189. package/dist/workspace/status-gates.d.ts +2 -0
  190. package/dist/workspace/status-gates.d.ts.map +1 -1
  191. package/dist/workspace/status.d.ts +54 -0
  192. package/dist/workspace/status.d.ts.map +1 -1
  193. package/dist/workspace/symbols.d.ts +16 -5
  194. package/dist/workspace/symbols.d.ts.map +1 -1
  195. package/dist/workspace/trust/run-commits.d.ts +46 -0
  196. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  197. package/dist/workspace/trust/run-statement.d.ts +128 -0
  198. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  199. package/dist/workspace/trust/seal.d.ts +6 -1
  200. package/dist/workspace/trust/seal.d.ts.map +1 -1
  201. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  202. package/dist/workspace/trust/verify.d.ts +16 -2
  203. package/dist/workspace/trust/verify.d.ts.map +1 -1
  204. package/dist/workspace/wip-cli.d.ts +21 -0
  205. package/dist/workspace/wip-cli.d.ts.map +1 -0
  206. package/dist/workspace/wip.d.ts +268 -0
  207. package/dist/workspace/wip.d.ts.map +1 -0
  208. package/dist/workspace/work-cli.d.ts.map +1 -1
  209. package/dist/workspace/work-evidence.d.ts +1 -1
  210. package/dist/workspace/work-evidence.d.ts.map +1 -1
  211. package/dist/workspace/work-size.d.ts +55 -0
  212. package/dist/workspace/work-size.d.ts.map +1 -0
  213. package/dist/workspace/workspace-kinds.schema.json +122 -0
  214. package/dist/workspace/write-lock-cli.d.ts +60 -0
  215. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  216. package/dist/workspace/write-lock.d.ts +152 -0
  217. package/dist/workspace/write-lock.d.ts.map +1 -0
  218. package/dist/workspace/write-scope.d.ts +6 -2
  219. package/dist/workspace/write-scope.d.ts.map +1 -1
  220. package/package.json +6 -1
  221. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  222. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  223. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  224. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  225. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  226. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  227. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  228. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  229. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  230. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  231. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  232. package/src/audit/core.test.ts +15 -0
  233. package/src/audit/core.ts +8 -2
  234. package/src/audit/discover.test.ts +11 -0
  235. package/src/audit/discover.ts +7 -2
  236. package/src/change-set-bundle.test.ts +57 -0
  237. package/src/change-set.test.ts +215 -0
  238. package/src/change-set.ts +445 -0
  239. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  240. package/src/cli/commands/audit.ts +29 -2
  241. package/src/cli/commands/build.test.ts +19 -0
  242. package/src/cli/commands/build.ts +3 -2
  243. package/src/cli/handlers/build.ts +13 -1
  244. package/src/cli/handlers/change-set.test.ts +56 -0
  245. package/src/cli/handlers/change-set.ts +44 -0
  246. package/src/cli/handlers/fan-out.test.ts +221 -2
  247. package/src/cli/handlers/fan-out.ts +165 -75
  248. package/src/cli/handlers/graph.ts +3 -0
  249. package/src/cli/handlers/operator.test.ts +21 -0
  250. package/src/cli/handlers/operator.ts +34 -3
  251. package/src/cli/handlers/pr.ts +373 -0
  252. package/src/cli/handlers/run.ts +1 -0
  253. package/src/cli/main.test.ts +20 -0
  254. package/src/cli/main.ts +185 -23
  255. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  256. package/src/cli/mcp/op-tools.ts +24 -2
  257. package/src/cli/mcp/workspace-tools.test.ts +1 -1
  258. package/src/cli/mcp/workspace-tools.ts +34 -6
  259. package/src/cli/registry.ts +63 -1
  260. package/src/components/auto-release.ts +1 -1
  261. package/src/components/capability.ts +55 -0
  262. package/src/components/changed-files.ts +66 -0
  263. package/src/components/cli-support.ts +28 -5
  264. package/src/components/component.schema.json +17 -0
  265. package/src/components/component.ts +25 -0
  266. package/src/components/deploy-units.ts +3 -0
  267. package/src/components/driver.test.ts +52 -0
  268. package/src/components/driver.ts +31 -13
  269. package/src/components/fan-out-output.ts +42 -1
  270. package/src/components/fan-out-record.ts +69 -0
  271. package/src/components/fan-out-run.test.ts +17 -0
  272. package/src/components/fan-out-run.ts +304 -1
  273. package/src/components/fan-out-support.ts +3 -0
  274. package/src/components/fan-out-waves.test.ts +375 -0
  275. package/src/components/fan-out.ts +18 -17
  276. package/src/components/gated-wave-pipeline.ts +82 -0
  277. package/src/components/index.ts +1 -0
  278. package/src/components/layers.ts +30 -0
  279. package/src/components/pr-pipeline.ts +91 -0
  280. package/src/components/pr-run.test.ts +205 -0
  281. package/src/components/pr-run.ts +280 -0
  282. package/src/components/promote.ts +5 -0
  283. package/src/components/verbs/shell.test.ts +11 -0
  284. package/src/components/verbs/shell.ts +7 -3
  285. package/src/components/wave-plan.ts +124 -0
  286. package/src/discovery/sandbox/bundle.ts +1 -1
  287. package/src/gated-waves-bundle.test.ts +62 -0
  288. package/src/gated-waves.test.ts +118 -0
  289. package/src/gated-waves.ts +240 -0
  290. package/src/index.ts +1 -0
  291. package/src/lexicon.ts +51 -0
  292. package/src/lifecycle/gate-ledger.ts +7 -0
  293. package/src/lifecycle/git.ts +102 -16
  294. package/src/lint/post-synth.test.ts +19 -0
  295. package/src/lint/post-synth.ts +19 -1
  296. package/src/meta/declared-imports.test.ts +1 -1
  297. package/src/op/activities/activity-contracts.ts +84 -0
  298. package/src/op/activities/change-set.ts +114 -0
  299. package/src/op/activities/decide.ts +3 -0
  300. package/src/op/activities/factory.ts +675 -0
  301. package/src/op/activities/index.ts +6 -0
  302. package/src/op/activity-contract.test.ts +21 -1
  303. package/src/op/activity-contract.ts +19 -9
  304. package/src/op/builders.ts +23 -0
  305. package/src/op/decide-backend.ts +5 -1
  306. package/src/op/decide-read-inputs.ts +33 -5
  307. package/src/op/factory.e2e.test.ts +232 -0
  308. package/src/op/factory.ts +118 -0
  309. package/src/op/index.ts +9 -1
  310. package/src/op/op-ir.test.ts +9 -0
  311. package/src/op/op-ir.ts +4 -0
  312. package/src/op/op-verb-class.ts +3 -0
  313. package/src/op/types.ts +8 -0
  314. package/src/op/work-lease-run.ts +3 -0
  315. package/src/plan-summary.test.ts +263 -0
  316. package/src/plan-summary.ts +845 -0
  317. package/src/pr-forge.test.ts +237 -0
  318. package/src/pr-forge.ts +332 -0
  319. package/src/pr-loop-bundle.test.ts +46 -0
  320. package/src/pr-loop.test.ts +171 -0
  321. package/src/pr-loop.ts +324 -0
  322. package/src/telemetry-attribution.test.ts +23 -1
  323. package/src/telemetry-attribution.ts +51 -0
  324. package/src/terraform/hcl2json.test.ts +21 -0
  325. package/src/terraform/hcl2json.ts +81 -0
  326. package/src/terraform/parse.ts +11 -74
  327. package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
  328. package/src/workspace/app-kind.test.ts +196 -0
  329. package/src/workspace/box-cli.ts +113 -0
  330. package/src/workspace/box-factory.test.ts +4 -1
  331. package/src/workspace/box-factory.ts +37 -4
  332. package/src/workspace/box-listing-write.schema.json +204 -0
  333. package/src/workspace/box-listing.test.ts +234 -0
  334. package/src/workspace/box-listing.ts +324 -0
  335. package/src/workspace/box-publish.schema.json +498 -0
  336. package/src/workspace/box-publish.test.ts +204 -0
  337. package/src/workspace/box-publish.ts +420 -0
  338. package/src/workspace/box-ship.test.ts +96 -0
  339. package/src/workspace/broker-protocol.schema.json +186 -0
  340. package/src/workspace/broker-protocol.test.ts +122 -0
  341. package/src/workspace/broker-protocol.ts +317 -0
  342. package/src/workspace/builder-tiers.test.ts +146 -0
  343. package/src/workspace/change-set.schema.json +460 -0
  344. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  345. package/src/workspace/checks/boxes.test.ts +3 -0
  346. package/src/workspace/checks.ts +10 -3
  347. package/src/workspace/component-environments.test.ts +105 -0
  348. package/src/workspace/composites.schema.json +23 -4
  349. package/src/workspace/composites.test.ts +8 -8
  350. package/src/workspace/composites.ts +13 -2
  351. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  352. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  353. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +7 -2
  354. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +42 -2
  355. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  356. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  357. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +96 -0
  358. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  359. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  360. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +14 -8
  361. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +187 -6
  362. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +25 -0
  363. package/src/workspace/conformance/broker.test.ts +122 -0
  364. package/src/workspace/conformance/broker.ts +792 -0
  365. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  366. package/src/workspace/conformance/index.mjs +22 -1
  367. package/src/workspace/conformance/index.ts +5 -1
  368. package/src/workspace/conformance/vitest.ts +33 -1
  369. package/src/workspace/conformance/writer-conformance.e2e.test.ts +49 -3
  370. package/src/workspace/conformance/writer.test.ts +32 -2
  371. package/src/workspace/conformance/writer.ts +339 -28
  372. package/src/workspace/decide.test.ts +208 -4
  373. package/src/workspace/decide.ts +427 -73
  374. package/src/workspace/decision-points.schema.json +11 -4
  375. package/src/workspace/declaration.schema.json +153 -4
  376. package/src/workspace/declaration.ts +141 -0
  377. package/src/workspace/environments.ts +66 -14
  378. package/src/workspace/factory-rules.test.ts +62 -0
  379. package/src/workspace/factory-rules.ts +218 -0
  380. package/src/workspace/graph-cli.ts +2 -2
  381. package/src/workspace/graph.schema.json +67 -0
  382. package/src/workspace/identity.test.ts +23 -0
  383. package/src/workspace/init.ts +82 -2
  384. package/src/workspace/intent-cli.ts +26 -9
  385. package/src/workspace/intent-patch-id.test.ts +162 -0
  386. package/src/workspace/intent-record.schema.json +130 -3
  387. package/src/workspace/intent-record.ts +74 -28
  388. package/src/workspace/intent-reviews.test.ts +76 -0
  389. package/src/workspace/intent-squash.test.ts +213 -0
  390. package/src/workspace/intent-why.test.ts +5 -5
  391. package/src/workspace/intent.schema.json +234 -4
  392. package/src/workspace/intent.ts +260 -66
  393. package/src/workspace/json-edit.test.ts +121 -0
  394. package/src/workspace/json-edit.ts +142 -0
  395. package/src/workspace/jsonc.ts +20 -0
  396. package/src/workspace/kinds.ts +157 -2
  397. package/src/workspace/lexicon-symbols.test.ts +148 -0
  398. package/src/workspace/lexicon-symbols.ts +125 -0
  399. package/src/workspace/lineage-upgrade.test.ts +63 -0
  400. package/src/workspace/lineage-upgrade.ts +146 -5
  401. package/src/workspace/plan-summary.schema.json +155 -0
  402. package/src/workspace/point-answer.schema.json +42 -2
  403. package/src/workspace/points-cli.ts +42 -16
  404. package/src/workspace/points-write.schema.json +162 -4
  405. package/src/workspace/points.schema.json +157 -2
  406. package/src/workspace/points.test.ts +13 -1
  407. package/src/workspace/points.ts +118 -12
  408. package/src/workspace/pr-report.schema.json +95 -0
  409. package/src/workspace/profiles.test.ts +159 -0
  410. package/src/workspace/read-contract.test.ts +2 -2
  411. package/src/workspace/reason-codes.test.ts +13 -1
  412. package/src/workspace/reason-codes.ts +38 -4
  413. package/src/workspace/record-sessions.ts +9 -8
  414. package/src/workspace/records-amend.schema.json +78 -0
  415. package/src/workspace/records-cli.ts +20 -6
  416. package/src/workspace/records-close.schema.json +78 -0
  417. package/src/workspace/records-close.ts +31 -7
  418. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  419. package/src/workspace/records-concurrent.test.ts +145 -0
  420. package/src/workspace/records-formats.test.ts +46 -10
  421. package/src/workspace/records-new.schema.json +7 -0
  422. package/src/workspace/records-review.schema.json +78 -0
  423. package/src/workspace/records-sessions-write.test.ts +69 -0
  424. package/src/workspace/records-sessions.test.ts +22 -0
  425. package/src/workspace/records-write.ts +192 -25
  426. package/src/workspace/records.schema.json +16 -0
  427. package/src/workspace/records.ts +50 -9
  428. package/src/workspace/reference-kinds/app/package.json +10 -0
  429. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  430. package/src/workspace/run-statement.schema.json +622 -0
  431. package/src/workspace/runs-cli.ts +343 -14
  432. package/src/workspace/runs-statement.test.ts +239 -0
  433. package/src/workspace/runs-write.schema.json +416 -5
  434. package/src/workspace/runs.schema.json +451 -4
  435. package/src/workspace/runs.test.ts +39 -0
  436. package/src/workspace/runs.ts +296 -35
  437. package/src/workspace/session-kinds.ts +3 -3
  438. package/src/workspace/squash.ts +198 -0
  439. package/src/workspace/status-contract.test.ts +5 -2
  440. package/src/workspace/status-gates.ts +3 -1
  441. package/src/workspace/status.schema.json +126 -3
  442. package/src/workspace/status.ts +90 -1
  443. package/src/workspace/symbols.ts +20 -9
  444. package/src/workspace/trust/run-commits.ts +115 -0
  445. package/src/workspace/trust/run-statement.ts +226 -0
  446. package/src/workspace/trust/seal.ts +8 -2
  447. package/src/workspace/trust/verify-cli.ts +6 -5
  448. package/src/workspace/trust/verify.ts +39 -6
  449. package/src/workspace/wip-cli.ts +97 -0
  450. package/src/workspace/wip-write.schema.json +504 -0
  451. package/src/workspace/wip.schema.json +334 -0
  452. package/src/workspace/wip.test.ts +294 -0
  453. package/src/workspace/wip.ts +753 -0
  454. package/src/workspace/work-cli.ts +3 -0
  455. package/src/workspace/work-evidence.schema.json +3 -0
  456. package/src/workspace/work-size.test.ts +77 -0
  457. package/src/workspace/work-size.ts +93 -0
  458. package/src/workspace/workspace-kinds.schema.json +122 -0
  459. package/src/workspace/write-lock-cli.ts +131 -0
  460. package/src/workspace/write-lock.schema.json +172 -0
  461. package/src/workspace/write-lock.test.ts +189 -0
  462. package/src/workspace/write-lock.ts +474 -0
  463. package/src/workspace/write-scope.test.ts +16 -1
  464. package/src/workspace/write-scope.ts +33 -11
@@ -11,7 +11,8 @@
11
11
  * can see it. With `--open`, only open questions are listed. It never writes
12
12
  * and never calls a model.
13
13
  *
14
- * `points ask` and `points answer` are the writes, in `decide.ts`.
14
+ * `points ask`, `points answer` and `points retract` are the writes, in
15
+ * `decide.ts`.
15
16
  */
16
17
 
17
18
  import { readFileSync } from "node:fs";
@@ -20,7 +21,7 @@ import { formatError } from "../cli/format";
20
21
  import type { CommandContext } from "../cli/registry";
21
22
  import { declaredRecordKinds, readDeclaration, readerVersion, WorkspaceReadError, type ErrorLocation, type WorkspaceErrorCode } from "./declaration";
22
23
  import { declaredKindFile } from "./declared-kinds";
23
- import { answerPoint, askPoint, questionView, POINTS_WRITE_CONTRACT_VERSION, POINTS_WRITE_SCHEMA_ID, type PointsWriteDocument, type QuestionView } from "./decide";
24
+ import { answerPoint, askPoint, questionView, retractAnswer, POINTS_WRITE_CONTRACT_VERSION, POINTS_WRITE_SCHEMA_ID, type PointsWriteDocument, type PointsWriteVerb, type QuestionView } from "./decide";
24
25
  import { candidates, inputOutput, pointsFileOf, pointVersion, quorumOf, readPointsThrough, type Decider, type ModelAsk, type WireAnswer } from "./points";
25
26
  import type { ReasonCode } from "./reason-codes";
26
27
  import { gitRevisionSource, workingTreeSource } from "./record-source";
@@ -71,8 +72,14 @@ export interface PointView {
71
72
  questionType: string;
72
73
  instructions: string;
73
74
  candidates: (string | boolean)[];
74
- /** What each candidate means, as the points file declares it: an object of strings for noul and choice, an array for score. */
75
+ /**
76
+ * What each candidate means, as the points file declares it: an object of
77
+ * strings for noul and choice, an array for score. Empty for an ad-hoc point,
78
+ * whose candidates come with each ask (#3403).
79
+ */
75
80
  criteria: Record<string, string> | string[];
81
+ /** The question's text and candidates come with each ask (#3403): each question lists them as `asked`. */
82
+ adhoc: boolean;
76
83
  /** Each input: its name, the read-contract output it names, and its description. */
77
84
  inputs: { name: string; output: string; description: string }[];
78
85
  deciders: Decider[];
@@ -164,8 +171,9 @@ export async function workspacePoints(query: PointsQuery): Promise<PointsDocumen
164
171
  version: pointVersion(p),
165
172
  questionType: p.question.type,
166
173
  instructions: p.question.instructions,
167
- candidates: candidates(p.question),
168
- criteria: p.question.criteria,
174
+ candidates: p.adhoc ? [] : candidates(p.question),
175
+ criteria: p.question.criteria ?? (p.question.type === "score" ? [] : {}),
176
+ adhoc: !!p.adhoc,
169
177
  inputs: Object.entries(p.inputs).map(([n, description]) => ({ name: n, output: inputOutput(n), description })),
170
178
  deciders: p.deciders,
171
179
  quorum: quorumOf(p),
@@ -215,7 +223,7 @@ export async function readQuestionStates(cwd: string): Promise<Map<string, Quest
215
223
  export function formatPoints(doc: Extract<PointsDocument, { points: unknown }>): string {
216
224
  const lines: string[] = [];
217
225
  for (const s of doc.sources) if (s.reason) lines.push(`${s.kind}: ${s.reason.code}: ${s.reason.message}`);
218
- for (const p of doc.points) lines.push(`${p.name} ${p.questionType} ${p.title} (${p.deciders.map((d) => d.kind).join(", ")})`);
226
+ for (const p of doc.points) lines.push(`${p.name} ${p.questionType}${p.adhoc ? ", ad hoc" : ""} ${p.title} (${p.deciders.map((d) => d.kind).join(", ")})`);
219
227
  if (doc.points.length === 0) lines.push("no decision points are declared");
220
228
  lines.push("");
221
229
  for (const q of doc.questions) {
@@ -241,18 +249,23 @@ export function responseAsk(response: unknown): ModelAsk {
241
249
 
242
250
  const USAGE = [
243
251
  "chant workspace points [--open] [--kind <kind file>] [--at <rev>] [--json]",
244
- "chant workspace points ask <point> --inputs <file|-> [--response <file>] [--subject <id>] [--kind <kind file>] [--dry-run]",
245
- "chant workspace points answer <id> --answer <value> --by <name> [--by <name>...] [--kind <kind file>] [--dry-run]",
252
+ "chant workspace points ask <point> --inputs <file|-|json> [--candidates <file|-|json>] [--response <file>] [--subject <id>] [--kind <kind file>] [--dry-run]",
253
+ "chant workspace points answer <id> --answer <value> --by <name> [--by <name>...] [--note <text>] [--relayed-by <principal>] [--kind <kind file>] [--dry-run]",
254
+ "chant workspace points retract <id> --by <name> [--by <name>...] [--note <text>] [--kind <kind file>] [--dry-run]",
246
255
  ].join("\n");
247
256
 
248
- function usage(verb: "ask" | "answer", message: string): PointsWriteDocument {
257
+ function usage(verb: PointsWriteVerb, message: string): PointsWriteDocument {
249
258
  return { $schema: POINTS_WRITE_SCHEMA_ID, contract: POINTS_WRITE_CONTRACT_VERSION, verb, error: { code: "write-usage-invalid", message } };
250
259
  }
251
260
 
252
- function readJson(verb: "ask" | "answer", flag: string, value: string, cwd: string): { value: unknown } | PointsWriteDocument {
261
+ /** Whether a flag's value is the JSON itself rather than a file: it starts with { or [ (#3403). */
262
+ const inlineJson = (value: string): boolean => /^\s*[[{]/.test(value);
263
+
264
+ /** A flag's JSON: from standard input (-), the value itself when it starts with { or [, or a file. */
265
+ function readJson(verb: PointsWriteVerb, flag: string, value: string, cwd: string): { value: unknown } | PointsWriteDocument {
253
266
  let text: string;
254
267
  try {
255
- text = readFileSync(value === "-" ? 0 : resolve(cwd, value), "utf-8");
268
+ text = inlineJson(value) ? value : readFileSync(value === "-" ? 0 : resolve(cwd, value), "utf-8");
256
269
  } catch (err) {
257
270
  return { $schema: POINTS_WRITE_SCHEMA_ID, contract: POINTS_WRITE_CONTRACT_VERSION, verb, error: { code: "write-input-invalid", message: `${flag} ${value} could not be read: ${err instanceof Error ? err.message : String(err)}` } };
258
271
  }
@@ -263,7 +276,7 @@ function readJson(verb: "ask" | "answer", flag: string, value: string, cwd: stri
263
276
  }
264
277
  }
265
278
 
266
- /** `chant workspace points`, and its `ask` and `answer` verbs. */
279
+ /** `chant workspace points`, and its `ask`, `answer` and `retract` verbs. */
267
280
  export async function runWorkspacePoints(ctx: CommandContext): Promise<number> {
268
281
  const { args } = ctx;
269
282
  const cwd = process.cwd();
@@ -275,26 +288,39 @@ export async function runWorkspacePoints(ctx: CommandContext): Promise<number> {
275
288
  if (verb === "ask") {
276
289
  const point = args.extraPositional2;
277
290
  if (!point) return print(usage("ask", "ask needs the point's name"));
278
- if (args.inputs === undefined) return print(usage("ask", "--inputs <file|-> is required"));
291
+ if (args.inputs === undefined) return print(usage("ask", "--inputs <file|-|json> is required"));
292
+ if (args.inputs === "-" && args.candidates === "-") return print(usage("ask", "--inputs and --candidates can't both read standard input: give one as a file or as JSON"));
279
293
  const inputs = readJson("ask", "--inputs", args.inputs, cwd);
280
294
  if (!("value" in inputs)) return print(inputs);
295
+ let given: unknown;
296
+ if (args.candidates !== undefined) {
297
+ const read = readJson("ask", "--candidates", args.candidates, cwd);
298
+ if (!("value" in read)) return print(read);
299
+ given = read.value;
300
+ }
281
301
  let ask: ModelAsk | undefined;
282
302
  if (args.response !== undefined) {
283
303
  const response = readJson("ask", "--response", args.response, cwd);
284
304
  if (!("value" in response)) return print(response);
285
305
  ask = responseAsk(response.value);
286
306
  }
287
- return print(await askPoint({ cwd, point, inputs: inputs.value, subject: args.subject, kind: args.kind, ask, dryRun: args.dryRun }));
307
+ return print(await askPoint({ cwd, point, inputs: inputs.value, candidates: given, subject: args.subject, kind: args.kind, ask, dryRun: args.dryRun }));
288
308
  }
289
309
  if (verb === "answer") {
290
310
  const id = args.extraPositional2;
291
311
  if (!id) return print(usage("answer", "answer needs the question's id"));
292
312
  if (args.answer === undefined) return print(usage("answer", "--answer <value> is required"));
293
313
  if (!args.bys || args.bys.length === 0) return print(usage("answer", "--by <name> is required, once for each person who answered"));
294
- return print(await answerPoint({ cwd, id, answer: args.answer, by: args.bys, kind: args.kind, dryRun: args.dryRun }));
314
+ return print(await answerPoint({ cwd, id, answer: args.answer, by: args.bys, note: args.note, relayedBy: args.relayedBy, kind: args.kind, dryRun: args.dryRun }));
315
+ }
316
+ if (verb === "retract") {
317
+ const id = args.extraPositional2;
318
+ if (!id) return print(usage("retract", "retract needs the question's id"));
319
+ if (!args.bys || args.bys.length === 0) return print(usage("retract", "--by <name> is required, once for each person who takes the answer back"));
320
+ return print(await retractAnswer({ cwd, id, by: args.bys, note: args.note, kind: args.kind, dryRun: args.dryRun }));
295
321
  }
296
322
  if (verb !== undefined) {
297
- console.error(formatError({ message: `chant workspace points takes no argument but ask or answer (got ${verb})`, hint: USAGE }));
323
+ console.error(formatError({ message: `chant workspace points takes no argument but ask, answer or retract (got ${verb})`, hint: USAGE }));
298
324
  return 1;
299
325
  }
300
326
  const doc = await workspacePoints({ cwd, at: args.at, open: args.open, kind: args.kind });
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://intentius.io/chant/schemas/workspace/points-write/v1/points-write.schema.json",
4
- "title": "chant workspace points ask and answer output",
5
- "description": "What `chant workspace points ask` and `points answer` print (ws-058, #2739): the answer record asked for or written, as `points --json` lists a question. ask returns the record that is there when the same point, declaration and inputs were answered or proposed before (reused), and otherwise writes one: answered from a table, proposed from a model at or above its threshold, escalated to people below it. answer records people's answer to an open question once the point's quorum is met. Nothing is committed to the working branch, and nothing is written on a refusal or with --dry-run. In a steward's turn a new record goes on the lifecycle ledger instead of the working tree (#2786), as a commit on chant/lifecycle, and a record already held there is rewritten there. The error codes are a closed list, each in the one closed list of `reason-codes.ts`. Written at contract version 1 of the write documents.",
4
+ "title": "chant workspace points ask, answer and retract output",
5
+ "description": "What `chant workspace points ask`, `points answer` and `points retract` print (ws-058, #2739, #3351): the answer record asked for or written, as `points --json` lists a question. ask returns the record that is there when the same point, declaration and inputs were answered or proposed before (reused), and otherwise writes one: answered from a table, proposed from a model at or above its threshold, escalated to people below it. answer records people's answer to an open question once the point's quorum is met, with their note. retract takes an answer back once the quorum is met: the question is escalated to people again and the answer moves into its retractions (ws-084). Nothing is committed to the working branch, and nothing is written on a refusal or with --dry-run. In a steward's turn a new record goes on the lifecycle ledger instead of the working tree (#2786), as a commit on chant/lifecycle, and a record already held there is rewritten there. The error codes are a closed list, each in the one closed list of `reason-codes.ts`. Written at contract version 1 of the write documents.",
6
6
  "oneOf": [
7
7
  {
8
8
  "$ref": "#/$defs/result"
@@ -37,7 +37,8 @@
37
37
  "verb": {
38
38
  "enum": [
39
39
  "ask",
40
- "answer"
40
+ "answer",
41
+ "retract"
41
42
  ]
42
43
  },
43
44
  "kind": {
@@ -235,6 +236,13 @@
235
236
  }
236
237
  ]
237
238
  },
239
+ "reason": {
240
+ "type": [
241
+ "string",
242
+ "null"
243
+ ],
244
+ "description": "The model's own explanation of the recorded answer, a proposal or a confirmed proposal, when the backend gave one (#3345). null otherwise, and from a chant before it."
245
+ },
238
246
  "model": {
239
247
  "description": "Any model answer: the proposal (observed), or the last answer below a model decider's threshold (not observed). null when no model answered.",
240
248
  "oneOf": [
@@ -303,6 +311,13 @@
303
311
  },
304
312
  "observed": {
305
313
  "type": "boolean"
314
+ },
315
+ "reason": {
316
+ "type": [
317
+ "string",
318
+ "null"
319
+ ],
320
+ "description": "The model's explanation of this answer, when the backend gave one (#3345)."
306
321
  }
307
322
  }
308
323
  }
@@ -362,6 +377,10 @@
362
377
  "type": "number",
363
378
  "minimum": 0,
364
379
  "maximum": 1
380
+ },
381
+ "model_reason": {
382
+ "type": "string",
383
+ "description": "A model decider's own explanation of the answer it gave, when the backend gave one (#3345). reason is why the decider did not answer."
365
384
  }
366
385
  }
367
386
  }
@@ -391,6 +410,139 @@
391
410
  "null"
392
411
  ]
393
412
  },
413
+ "note": {
414
+ "type": [
415
+ "string",
416
+ "null"
417
+ ],
418
+ "description": "What the people who answered wrote with their answer (points answer --note, #3351). null when they wrote nothing, and from a chant before it."
419
+ },
420
+ "relayedBy": {
421
+ "type": [
422
+ "string",
423
+ "null"
424
+ ],
425
+ "description": "Who relayed the answer to chant for the people who gave it (points answer --relayed-by, #3402), such as a follower relaying a person's answer through hud. null when nobody did, and from a chant before it."
426
+ },
427
+ "retractions": {
428
+ "type": "array",
429
+ "description": "Answers people took back, oldest first (points retract, #3351): each answer as it was and who retracted it, when and why. A retracted question is escalated to people again. Empty when none was, and absent from a chant before it.",
430
+ "items": {
431
+ "type": "object",
432
+ "required": [
433
+ "answer",
434
+ "decider",
435
+ "answeredBy",
436
+ "answeredOn",
437
+ "answerNote",
438
+ "answerRelayedBy",
439
+ "by",
440
+ "on",
441
+ "note"
442
+ ],
443
+ "properties": {
444
+ "answer": {
445
+ "oneOf": [
446
+ {
447
+ "type": "string"
448
+ },
449
+ {
450
+ "type": "boolean"
451
+ },
452
+ {
453
+ "type": "null"
454
+ }
455
+ ]
456
+ },
457
+ "decider": {
458
+ "type": "object",
459
+ "description": "Who gave the answer: the record's decider as it was."
460
+ },
461
+ "answeredBy": {
462
+ "type": "array",
463
+ "items": {
464
+ "type": "string"
465
+ }
466
+ },
467
+ "answeredOn": {
468
+ "type": [
469
+ "string",
470
+ "null"
471
+ ]
472
+ },
473
+ "answerNote": {
474
+ "type": [
475
+ "string",
476
+ "null"
477
+ ],
478
+ "description": "The note the answer carried."
479
+ },
480
+ "answerRelayedBy": {
481
+ "type": [
482
+ "string",
483
+ "null"
484
+ ],
485
+ "description": "Who relayed the answer (#3402)."
486
+ },
487
+ "by": {
488
+ "type": "array",
489
+ "items": {
490
+ "type": "string"
491
+ },
492
+ "description": "Who retracted it."
493
+ },
494
+ "on": {
495
+ "type": [
496
+ "string",
497
+ "null"
498
+ ]
499
+ },
500
+ "note": {
501
+ "type": [
502
+ "string",
503
+ "null"
504
+ ],
505
+ "description": "Why it was retracted (points retract --note)."
506
+ }
507
+ }
508
+ }
509
+ },
510
+ "asked": {
511
+ "description": "An ad-hoc point's question as its ask gave it (points ask --candidates, #3403): the question's text, and its criteria, what each candidate means, in the point's question type's shape. People's answer is one of the candidates. null for a declared point's question, and absent from a chant before it.",
512
+ "oneOf": [
513
+ {
514
+ "type": "null"
515
+ },
516
+ {
517
+ "type": "object",
518
+ "required": [
519
+ "question",
520
+ "criteria"
521
+ ],
522
+ "properties": {
523
+ "question": {
524
+ "type": "string"
525
+ },
526
+ "criteria": {
527
+ "oneOf": [
528
+ {
529
+ "type": "object",
530
+ "additionalProperties": {
531
+ "type": "string"
532
+ }
533
+ },
534
+ {
535
+ "type": "array",
536
+ "items": {
537
+ "type": "string"
538
+ }
539
+ }
540
+ ]
541
+ }
542
+ }
543
+ }
544
+ ]
545
+ },
394
546
  "valid": {
395
547
  "type": "boolean"
396
548
  },
@@ -445,7 +597,8 @@
445
597
  "verb": {
446
598
  "enum": [
447
599
  "ask",
448
- "answer"
600
+ "answer",
601
+ "retract"
449
602
  ]
450
603
  },
451
604
  "error": {
@@ -474,6 +627,11 @@
474
627
  "quorum-not-met",
475
628
  "answer-in-steward-turn",
476
629
  "principal-unidentified",
630
+ "answer-not-answered",
631
+ "answer-field-unsupported",
632
+ "point-candidates-invalid",
633
+ "write-lock-timeout",
634
+ "write-lock-not-held",
477
635
  "record-not-found",
478
636
  "record-closed",
479
637
  "record-id-taken",
@@ -238,7 +238,7 @@
238
238
  }
239
239
  },
240
240
  "criteria": {
241
- "description": "What each candidate means, as the points file declares it: noul and choice give an object of strings keyed by candidate, score an array of ordered level descriptions.",
241
+ "description": "What each candidate means, as the points file declares it: noul and choice give an object of strings keyed by candidate, score an array of ordered level descriptions. Empty for an ad-hoc point (#3403).",
242
242
  "oneOf": [
243
243
  {
244
244
  "type": "object",
@@ -254,6 +254,10 @@
254
254
  }
255
255
  ]
256
256
  },
257
+ "adhoc": {
258
+ "type": "boolean",
259
+ "description": "An ad-hoc point (#3403): the question's text and candidates come with each ask, and each question lists them as asked. Its candidates are empty and its criteria an empty object, or an empty array for a score. Absent from a chant before it."
260
+ },
257
261
  "inputs": {
258
262
  "type": "array",
259
263
  "items": {
@@ -269,7 +273,7 @@
269
273
  },
270
274
  "output": {
271
275
  "type": "string",
272
- "description": "The read-contract output the input names: record, decision, work-item, finding, region, commit, member, gate, release, environment or component."
276
+ "description": "The read-contract output the input names: record, decision, work-item, finding, region, commit, node, member, gate, release, environment, component or ask."
273
277
  },
274
278
  "description": {
275
279
  "type": "string"
@@ -464,6 +468,13 @@
464
468
  }
465
469
  ]
466
470
  },
471
+ "reason": {
472
+ "type": [
473
+ "string",
474
+ "null"
475
+ ],
476
+ "description": "The model's own explanation of the recorded answer, a proposal or a confirmed proposal, when the backend gave one (#3345). null otherwise, and from a chant before it."
477
+ },
467
478
  "model": {
468
479
  "description": "Any model answer: the proposal (observed), or the last answer below a model decider's threshold (not observed). null when no model answered.",
469
480
  "oneOf": [
@@ -532,6 +543,13 @@
532
543
  },
533
544
  "observed": {
534
545
  "type": "boolean"
546
+ },
547
+ "reason": {
548
+ "type": [
549
+ "string",
550
+ "null"
551
+ ],
552
+ "description": "The model's explanation of this answer, when the backend gave one (#3345)."
535
553
  }
536
554
  }
537
555
  }
@@ -591,6 +609,10 @@
591
609
  "type": "number",
592
610
  "minimum": 0,
593
611
  "maximum": 1
612
+ },
613
+ "model_reason": {
614
+ "type": "string",
615
+ "description": "A model decider's own explanation of the answer it gave, when the backend gave one (#3345). reason is why the decider did not answer."
594
616
  }
595
617
  }
596
618
  }
@@ -646,6 +668,139 @@
646
668
  "null"
647
669
  ]
648
670
  },
671
+ "note": {
672
+ "type": [
673
+ "string",
674
+ "null"
675
+ ],
676
+ "description": "What the people who answered wrote with their answer (points answer --note, #3351). null when they wrote nothing, and from a chant before it."
677
+ },
678
+ "relayedBy": {
679
+ "type": [
680
+ "string",
681
+ "null"
682
+ ],
683
+ "description": "Who relayed the answer to chant for the people who gave it (points answer --relayed-by, #3402), such as a follower relaying a person's answer through hud. null when nobody did, and from a chant before it."
684
+ },
685
+ "retractions": {
686
+ "type": "array",
687
+ "description": "Answers people took back, oldest first (points retract, #3351): each answer as it was and who retracted it, when and why. A retracted question is escalated to people again. Empty when none was, and absent from a chant before it.",
688
+ "items": {
689
+ "type": "object",
690
+ "required": [
691
+ "answer",
692
+ "decider",
693
+ "answeredBy",
694
+ "answeredOn",
695
+ "answerNote",
696
+ "answerRelayedBy",
697
+ "by",
698
+ "on",
699
+ "note"
700
+ ],
701
+ "properties": {
702
+ "answer": {
703
+ "oneOf": [
704
+ {
705
+ "type": "string"
706
+ },
707
+ {
708
+ "type": "boolean"
709
+ },
710
+ {
711
+ "type": "null"
712
+ }
713
+ ]
714
+ },
715
+ "decider": {
716
+ "type": "object",
717
+ "description": "Who gave the answer: the record's decider as it was."
718
+ },
719
+ "answeredBy": {
720
+ "type": "array",
721
+ "items": {
722
+ "type": "string"
723
+ }
724
+ },
725
+ "answeredOn": {
726
+ "type": [
727
+ "string",
728
+ "null"
729
+ ]
730
+ },
731
+ "answerNote": {
732
+ "type": [
733
+ "string",
734
+ "null"
735
+ ],
736
+ "description": "The note the answer carried."
737
+ },
738
+ "answerRelayedBy": {
739
+ "type": [
740
+ "string",
741
+ "null"
742
+ ],
743
+ "description": "Who relayed the answer (#3402)."
744
+ },
745
+ "by": {
746
+ "type": "array",
747
+ "items": {
748
+ "type": "string"
749
+ },
750
+ "description": "Who retracted it."
751
+ },
752
+ "on": {
753
+ "type": [
754
+ "string",
755
+ "null"
756
+ ]
757
+ },
758
+ "note": {
759
+ "type": [
760
+ "string",
761
+ "null"
762
+ ],
763
+ "description": "Why it was retracted (points retract --note)."
764
+ }
765
+ }
766
+ }
767
+ },
768
+ "asked": {
769
+ "description": "An ad-hoc point's question as its ask gave it (points ask --candidates, #3403): the question's text, and its criteria, what each candidate means, in the point's question type's shape. People's answer is one of the candidates. null for a declared point's question, and absent from a chant before it.",
770
+ "oneOf": [
771
+ {
772
+ "type": "null"
773
+ },
774
+ {
775
+ "type": "object",
776
+ "required": [
777
+ "question",
778
+ "criteria"
779
+ ],
780
+ "properties": {
781
+ "question": {
782
+ "type": "string"
783
+ },
784
+ "criteria": {
785
+ "oneOf": [
786
+ {
787
+ "type": "object",
788
+ "additionalProperties": {
789
+ "type": "string"
790
+ }
791
+ },
792
+ {
793
+ "type": "array",
794
+ "items": {
795
+ "type": "string"
796
+ }
797
+ }
798
+ ]
799
+ }
800
+ }
801
+ }
802
+ ]
803
+ },
649
804
  "valid": {
650
805
  "type": "boolean"
651
806
  },
@@ -143,7 +143,7 @@ describe("the decision points schema (#2738)", () => {
143
143
 
144
144
  test("the reference workspace's points validate", () => {
145
145
  const points = parsePoints(readFileSync(join(REPO, "reference-workspace", "decisions", "points.json"), "utf-8"), "decisions/points.json");
146
- expect(Object.keys(points)).toEqual(["slice-tier", "ship-skip", "finding-triage", "needs-a-decision"]);
146
+ expect(Object.keys(points)).toEqual(["slice-tier", "understand", "ship-skip", "finding-triage", "needs-a-decision", "intent-origin", "intent-judgment", "intent-disposition", "agent-question"]);
147
147
  });
148
148
 
149
149
  test("a point whose chain does not end in a quorum is refused", () => {
@@ -232,6 +232,18 @@ describe("the decider chain (#2739)", () => {
232
232
  expect(r.escalations[1]).toMatchObject({ kind: "model", answer: "medium", confidence: 0.25, threshold: 0.8, reason: "not observed: confidence 0.25 is below the threshold 0.8" });
233
233
  });
234
234
 
235
+ test("the model's reason is kept with a proposal, and in the escalation of an answer below the threshold (#3345)", async () => {
236
+ const proposed = await runChain("slice-tier", SLICE, big, stub({ type: "choice", choice: "large", probabilities: { large: 0.9 }, confidence: 0.9, reason: " Nine criteria across three services.\n" }));
237
+ expect(proposed).toMatchObject({ status: "proposed", reason: "Nine criteria across three services." });
238
+ const low = await runChain("n", NOUL, {}, stub({ type: "noul", noul: 0.6, reason: "Probably, but the diff is small." }));
239
+ expect(low.escalations[0]).toMatchObject({ kind: "model", answer: true, reason: "not observed: confidence 0.6 is below the threshold 0.8", model_reason: "Probably, but the diff is small." });
240
+ // A blank or non-string reason is no reason.
241
+ const blank = await runChain("slice-tier", SLICE, big, stub({ type: "choice", choice: "large", confidence: 0.9, reason: " " }));
242
+ expect(blank).not.toHaveProperty("reason");
243
+ const odd = await runChain("slice-tier", SLICE, big, stub({ type: "choice", choice: "large", confidence: 0.9, reason: 3 } as unknown as WireAnswer));
244
+ expect(odd).not.toHaveProperty("reason");
245
+ });
246
+
235
247
  test("without a backend, or with an unpinned model answering, the model is not asked or not observed", async () => {
236
248
  expect((await runChain("slice-tier", SLICE, big)).escalations[1].reason).toBe("not asked: no model backend was given to this ask");
237
249
  const r = await runChain("slice-tier", SLICE, big, stub({ type: "choice", choice: "large", confidence: 0.99 }, "bosun-latest"));