@intentius/chant 0.100.0 → 0.102.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 (608) hide show
  1. package/dist/agents/checks.d.ts.map +1 -1
  2. package/dist/attrref.d.ts.map +1 -1
  3. package/dist/audit/discover.d.ts.map +1 -1
  4. package/dist/audit/nginx.d.ts.map +1 -1
  5. package/dist/audit/prior-art.d.ts +48 -0
  6. package/dist/audit/prior-art.d.ts.map +1 -1
  7. package/dist/behaviour-kinds.d.ts.map +1 -1
  8. package/dist/build.d.ts +6 -0
  9. package/dist/build.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/cli/build-options.d.ts +2 -0
  12. package/dist/cli/build-options.d.ts.map +1 -1
  13. package/dist/cli/commands/build.d.ts.map +1 -1
  14. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  15. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  16. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  17. package/dist/cli/commands/import.d.ts +8 -0
  18. package/dist/cli/commands/import.d.ts.map +1 -1
  19. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  20. package/dist/cli/commands/init.d.ts +19 -0
  21. package/dist/cli/commands/init.d.ts.map +1 -1
  22. package/dist/cli/commands/onboard.d.ts +9 -0
  23. package/dist/cli/commands/onboard.d.ts.map +1 -1
  24. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  25. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  26. package/dist/cli/handlers/dev.d.ts.map +1 -1
  27. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  28. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  29. package/dist/cli/handlers/misc.d.ts.map +1 -1
  30. package/dist/cli/handlers/operator.d.ts +9 -0
  31. package/dist/cli/handlers/operator.d.ts.map +1 -1
  32. package/dist/cli/handlers/run.d.ts.map +1 -1
  33. package/dist/cli/lsp/server.d.ts.map +1 -1
  34. package/dist/cli/main.d.ts.map +1 -1
  35. package/dist/cli/mcp/server.d.ts.map +1 -1
  36. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  37. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  38. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  39. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  40. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  41. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  42. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  43. package/dist/cli/mcp/workspace-tools.d.ts +9 -1
  44. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  45. package/dist/cli/registry.d.ts +33 -2
  46. package/dist/cli/registry.d.ts.map +1 -1
  47. package/dist/codegen/fetch.d.ts.map +1 -1
  48. package/dist/codegen/naming.d.ts.map +1 -1
  49. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  50. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  51. package/dist/codegen/registry.d.ts.map +1 -1
  52. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  53. package/dist/components/capability.d.ts.map +1 -1
  54. package/dist/components/driver.d.ts.map +1 -1
  55. package/dist/components/fan-out.d.ts.map +1 -1
  56. package/dist/components/starter-plugin.d.ts.map +1 -1
  57. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  58. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  59. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  60. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  61. package/dist/components/verbs/sign.d.ts.map +1 -1
  62. package/dist/components/verbs/verify.d.ts.map +1 -1
  63. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  64. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  65. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  66. package/dist/composite.d.ts.map +1 -1
  67. package/dist/config.d.ts +30 -7
  68. package/dist/config.d.ts.map +1 -1
  69. package/dist/declarable.d.ts +16 -0
  70. package/dist/declarable.d.ts.map +1 -1
  71. package/dist/discovery/cache.d.ts.map +1 -1
  72. package/dist/discovery/fold-import.d.ts +15 -5
  73. package/dist/discovery/fold-import.d.ts.map +1 -1
  74. package/dist/discovery/param-deps.d.ts +16 -0
  75. package/dist/discovery/param-deps.d.ts.map +1 -1
  76. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  77. package/dist/discovery/specifier-resolve.d.ts +37 -0
  78. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  79. package/dist/errors.d.ts.map +1 -1
  80. package/dist/fold/fold.d.ts +3 -1
  81. package/dist/fold/fold.d.ts.map +1 -1
  82. package/dist/graph-detail.d.ts.map +1 -1
  83. package/dist/graph-ir.d.ts.map +1 -1
  84. package/dist/graph-layout.d.ts.map +1 -1
  85. package/dist/import/base-parser.d.ts.map +1 -1
  86. package/dist/import/embedded.d.ts +7 -0
  87. package/dist/import/embedded.d.ts.map +1 -1
  88. package/dist/import/parser-options.d.ts +14 -0
  89. package/dist/import/parser-options.d.ts.map +1 -0
  90. package/dist/import/parser.d.ts +17 -0
  91. package/dist/import/parser.d.ts.map +1 -1
  92. package/dist/kubectl-context.d.ts.map +1 -1
  93. package/dist/lexicon-output.d.ts.map +1 -1
  94. package/dist/lexicon-schema.d.ts +3 -3
  95. package/dist/lexicon.d.ts +78 -3
  96. package/dist/lexicon.d.ts.map +1 -1
  97. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  98. package/dist/lifecycle/gate-ledger.d.ts +15 -0
  99. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  100. package/dist/lifecycle/git.d.ts.map +1 -1
  101. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  102. package/dist/lifecycle/observe.d.ts.map +1 -1
  103. package/dist/lifecycle/plan-digest.d.ts +26 -5
  104. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  105. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  106. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  107. package/dist/lifecycle/scenario.d.ts.map +1 -1
  108. package/dist/lifecycle/status.d.ts.map +1 -1
  109. package/dist/lifecycle/work-lease.d.ts +61 -2
  110. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  111. package/dist/lint/config.d.ts +4 -4
  112. package/dist/lint/engine.d.ts +6 -0
  113. package/dist/lint/engine.d.ts.map +1 -1
  114. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  115. package/dist/op/activities/activity-contracts.d.ts +12 -11
  116. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  117. package/dist/op/activities/apply.d.ts +79 -9
  118. package/dist/op/activities/apply.d.ts.map +1 -1
  119. package/dist/op/activities/decide.d.ts.map +1 -1
  120. package/dist/op/activities/index.d.ts +1 -1
  121. package/dist/op/activities/index.d.ts.map +1 -1
  122. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  123. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  124. package/dist/op/activities/propose-upgrade.d.ts +2 -0
  125. package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
  126. package/dist/op/activity-contract.d.ts +1 -1
  127. package/dist/op/activity-failure.d.ts.map +1 -1
  128. package/dist/op/activity-profiles.d.ts.map +1 -1
  129. package/dist/op/builders.d.ts.map +1 -1
  130. package/dist/op/composites/apply-op.d.ts +12 -5
  131. package/dist/op/composites/apply-op.d.ts.map +1 -1
  132. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  133. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  134. package/dist/op/decide-backend.d.ts.map +1 -1
  135. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  136. package/dist/op/emulator-lifecycle.d.ts +21 -2
  137. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  138. package/dist/op/gate-approval.d.ts +5 -1
  139. package/dist/op/gate-approval.d.ts.map +1 -1
  140. package/dist/op/gate-wait.d.ts.map +1 -1
  141. package/dist/op/gate.d.ts +19 -3
  142. package/dist/op/gate.d.ts.map +1 -1
  143. package/dist/op/index.d.ts +3 -1
  144. package/dist/op/index.d.ts.map +1 -1
  145. package/dist/op/local-executor.d.ts +6 -0
  146. package/dist/op/local-executor.d.ts.map +1 -1
  147. package/dist/op/operator.d.ts.map +1 -1
  148. package/dist/op/run-context.d.ts +39 -0
  149. package/dist/op/run-context.d.ts.map +1 -0
  150. package/dist/op/run-live.d.ts.map +1 -1
  151. package/dist/op/runtimes/local.d.ts.map +1 -1
  152. package/dist/op/source-archive.d.ts.map +1 -1
  153. package/dist/op/steward-beside.d.ts.map +1 -1
  154. package/dist/op/steward-points.d.ts.map +1 -1
  155. package/dist/op/steward.d.ts.map +1 -1
  156. package/dist/op/types.d.ts +8 -3
  157. package/dist/op/types.d.ts.map +1 -1
  158. package/dist/op/work-lease-run.d.ts +24 -4
  159. package/dist/op/work-lease-run.d.ts.map +1 -1
  160. package/dist/project-root.d.ts.map +1 -1
  161. package/dist/provenance.d.ts +21 -0
  162. package/dist/provenance.d.ts.map +1 -1
  163. package/dist/pseudo-parameter.d.ts.map +1 -1
  164. package/dist/reconcile.d.ts.map +1 -1
  165. package/dist/secret-materialization.d.ts.map +1 -1
  166. package/dist/serializer.d.ts +8 -0
  167. package/dist/serializer.d.ts.map +1 -1
  168. package/dist/telemetry-attribution.d.ts +77 -0
  169. package/dist/telemetry-attribution.d.ts.map +1 -0
  170. package/dist/terraform/emit-source.d.ts.map +1 -1
  171. package/dist/terraform/parse.d.ts.map +1 -1
  172. package/dist/testing.d.ts.map +1 -1
  173. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  174. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  175. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  176. package/dist/workspace/agent-cli.d.ts +88 -0
  177. package/dist/workspace/agent-cli.d.ts.map +1 -0
  178. package/dist/workspace/box-factory.d.ts +73 -0
  179. package/dist/workspace/box-factory.d.ts.map +1 -0
  180. package/dist/workspace/changes-cli.d.ts.map +1 -1
  181. package/dist/workspace/changes.d.ts +8 -1
  182. package/dist/workspace/changes.d.ts.map +1 -1
  183. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  184. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  185. package/dist/workspace/checks/links.d.ts +1 -0
  186. package/dist/workspace/checks/links.d.ts.map +1 -1
  187. package/dist/workspace/checks/live.d.ts +40 -0
  188. package/dist/workspace/checks/live.d.ts.map +1 -0
  189. package/dist/workspace/checks.d.ts +26 -2
  190. package/dist/workspace/checks.d.ts.map +1 -1
  191. package/dist/workspace/compose-graph.d.ts +73 -0
  192. package/dist/workspace/compose-graph.d.ts.map +1 -1
  193. package/dist/workspace/conformance/index.d.ts +67 -6
  194. package/dist/workspace/conformance/index.d.ts.map +1 -1
  195. package/dist/workspace/conformance/vitest.d.ts +12 -3
  196. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  197. package/dist/workspace/conformance/writer.d.ts +368 -0
  198. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  199. package/dist/workspace/decide.d.ts +1 -1
  200. package/dist/workspace/decide.d.ts.map +1 -1
  201. package/dist/workspace/declaration.d.ts +119 -0
  202. package/dist/workspace/declaration.d.ts.map +1 -1
  203. package/dist/workspace/declaration.schema.json +368 -4
  204. package/dist/workspace/export-cli.d.ts +12 -0
  205. package/dist/workspace/export-cli.d.ts.map +1 -0
  206. package/dist/workspace/export.d.ts +145 -0
  207. package/dist/workspace/export.d.ts.map +1 -0
  208. package/dist/workspace/generated-files.d.ts.map +1 -1
  209. package/dist/workspace/graph-cache.d.ts.map +1 -1
  210. package/dist/workspace/graph-cli.d.ts +2 -0
  211. package/dist/workspace/graph-cli.d.ts.map +1 -1
  212. package/dist/workspace/identity.d.ts +111 -0
  213. package/dist/workspace/identity.d.ts.map +1 -0
  214. package/dist/workspace/import.d.ts +73 -0
  215. package/dist/workspace/import.d.ts.map +1 -0
  216. package/dist/workspace/intent-cli.d.ts +7 -4
  217. package/dist/workspace/intent-cli.d.ts.map +1 -1
  218. package/dist/workspace/intent-record.d.ts +8 -1
  219. package/dist/workspace/intent-record.d.ts.map +1 -1
  220. package/dist/workspace/intent.d.ts +149 -5
  221. package/dist/workspace/intent.d.ts.map +1 -1
  222. package/dist/workspace/kinds.d.ts +24 -6
  223. package/dist/workspace/kinds.d.ts.map +1 -1
  224. package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
  225. package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
  226. package/dist/workspace/lineage-adopt.d.ts +106 -0
  227. package/dist/workspace/lineage-adopt.d.ts.map +1 -0
  228. package/dist/workspace/lineage-check.d.ts +9 -2
  229. package/dist/workspace/lineage-check.d.ts.map +1 -1
  230. package/dist/workspace/lineage-cli.d.ts +6 -1
  231. package/dist/workspace/lineage-cli.d.ts.map +1 -1
  232. package/dist/workspace/lineage-hash-index.d.ts +110 -0
  233. package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
  234. package/dist/workspace/lineage-init.d.ts +10 -0
  235. package/dist/workspace/lineage-init.d.ts.map +1 -1
  236. package/dist/workspace/lineage-lock.d.ts +149 -2
  237. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  238. package/dist/workspace/lineage-migrations.d.ts +15 -3
  239. package/dist/workspace/lineage-migrations.d.ts.map +1 -1
  240. package/dist/workspace/lineage-provenance.d.ts +18 -0
  241. package/dist/workspace/lineage-provenance.d.ts.map +1 -0
  242. package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
  243. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
  244. package/dist/workspace/lineage-upgrade.d.ts +30 -1
  245. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  246. package/dist/workspace/lineage-versions.d.ts +116 -0
  247. package/dist/workspace/lineage-versions.d.ts.map +1 -0
  248. package/dist/workspace/links.d.ts +31 -5
  249. package/dist/workspace/links.d.ts.map +1 -1
  250. package/dist/workspace/ls-generated.d.ts +37 -0
  251. package/dist/workspace/ls-generated.d.ts.map +1 -0
  252. package/dist/workspace/ls.d.ts +4 -0
  253. package/dist/workspace/ls.d.ts.map +1 -1
  254. package/dist/workspace/member-commands.d.ts.map +1 -1
  255. package/dist/workspace/nested-graph.d.ts +56 -0
  256. package/dist/workspace/nested-graph.d.ts.map +1 -0
  257. package/dist/workspace/nesting.d.ts +21 -0
  258. package/dist/workspace/nesting.d.ts.map +1 -0
  259. package/dist/workspace/pin-cli.d.ts +10 -0
  260. package/dist/workspace/pin-cli.d.ts.map +1 -0
  261. package/dist/workspace/pin-integrity.d.ts +51 -0
  262. package/dist/workspace/pin-integrity.d.ts.map +1 -0
  263. package/dist/workspace/points.d.ts.map +1 -1
  264. package/dist/workspace/principal-classes.d.ts +114 -0
  265. package/dist/workspace/principal-classes.d.ts.map +1 -0
  266. package/dist/workspace/reason-codes.d.ts +47 -3
  267. package/dist/workspace/reason-codes.d.ts.map +1 -1
  268. package/dist/workspace/record-assets.d.ts.map +1 -1
  269. package/dist/workspace/record-sessions.d.ts +7 -11
  270. package/dist/workspace/record-sessions.d.ts.map +1 -1
  271. package/dist/workspace/records-checkout.d.ts +54 -0
  272. package/dist/workspace/records-checkout.d.ts.map +1 -0
  273. package/dist/workspace/records-cli.d.ts +57 -2
  274. package/dist/workspace/records-cli.d.ts.map +1 -1
  275. package/dist/workspace/records-close.d.ts +5 -2
  276. package/dist/workspace/records-close.d.ts.map +1 -1
  277. package/dist/workspace/records-since.d.ts.map +1 -1
  278. package/dist/workspace/records-write.d.ts +23 -4
  279. package/dist/workspace/records-write.d.ts.map +1 -1
  280. package/dist/workspace/records.d.ts +58 -5
  281. package/dist/workspace/records.d.ts.map +1 -1
  282. package/dist/workspace/returns.d.ts +129 -0
  283. package/dist/workspace/returns.d.ts.map +1 -0
  284. package/dist/workspace/runs-cli.d.ts +164 -0
  285. package/dist/workspace/runs-cli.d.ts.map +1 -0
  286. package/dist/workspace/runs.d.ts +423 -0
  287. package/dist/workspace/runs.d.ts.map +1 -0
  288. package/dist/workspace/source-block.d.ts +1 -1
  289. package/dist/workspace/source-block.d.ts.map +1 -1
  290. package/dist/workspace/status-gates.d.ts +15 -3
  291. package/dist/workspace/status-gates.d.ts.map +1 -1
  292. package/dist/workspace/status.d.ts +10 -0
  293. package/dist/workspace/status.d.ts.map +1 -1
  294. package/dist/workspace/symbols.d.ts +52 -0
  295. package/dist/workspace/symbols.d.ts.map +1 -0
  296. package/dist/workspace/template-manifest.d.ts +11 -3
  297. package/dist/workspace/template-manifest.d.ts.map +1 -1
  298. package/dist/workspace/trailer-joins.d.ts +46 -0
  299. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  300. package/dist/workspace/trailers.d.ts +89 -0
  301. package/dist/workspace/trailers.d.ts.map +1 -0
  302. package/dist/workspace/trust/attestor.d.ts +8 -0
  303. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  304. package/dist/workspace/trust/dsse.d.ts +58 -0
  305. package/dist/workspace/trust/dsse.d.ts.map +1 -0
  306. package/dist/workspace/trust/evidence-cli.d.ts +66 -0
  307. package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
  308. package/dist/workspace/trust/evidence.d.ts +93 -0
  309. package/dist/workspace/trust/evidence.d.ts.map +1 -0
  310. package/dist/workspace/trust/policy.d.ts +54 -1
  311. package/dist/workspace/trust/policy.d.ts.map +1 -1
  312. package/dist/workspace/trust/provenance.d.ts +21 -1
  313. package/dist/workspace/trust/provenance.d.ts.map +1 -1
  314. package/dist/workspace/trust/rotation.d.ts +132 -0
  315. package/dist/workspace/trust/rotation.d.ts.map +1 -0
  316. package/dist/workspace/trust/seal.d.ts +33 -0
  317. package/dist/workspace/trust/seal.d.ts.map +1 -1
  318. package/dist/workspace/trust/signers-cli.d.ts +49 -0
  319. package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
  320. package/dist/workspace/trust/ssh-commit.d.ts +12 -0
  321. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  322. package/dist/workspace/trust/test-repo.d.ts +13 -0
  323. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  324. package/dist/workspace/trust/verify.d.ts +15 -0
  325. package/dist/workspace/trust/verify.d.ts.map +1 -1
  326. package/dist/workspace/work-cli.d.ts +39 -3
  327. package/dist/workspace/work-cli.d.ts.map +1 -1
  328. package/dist/workspace/work-evidence.d.ts +1 -1
  329. package/dist/workspace/work-evidence.d.ts.map +1 -1
  330. package/dist/workspace/work.d.ts +26 -1
  331. package/dist/workspace/work.d.ts.map +1 -1
  332. package/dist/workspace/workspace-principals.schema.json +60 -0
  333. package/dist/workspace/write-scope.d.ts +259 -0
  334. package/dist/workspace/write-scope.d.ts.map +1 -0
  335. package/dist/yaml.d.ts +21 -39
  336. package/dist/yaml.d.ts.map +1 -1
  337. package/package.json +2 -2
  338. package/src/audit/prior-art.ts +15 -0
  339. package/src/build.ts +8 -0
  340. package/src/cli/build-options.ts +4 -1
  341. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  342. package/src/cli/commands/build.ts +2 -0
  343. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  344. package/src/cli/commands/carve-emit.ts +5 -19
  345. package/src/cli/commands/check-lexicon.test.ts +62 -1
  346. package/src/cli/commands/check-lexicon.ts +36 -6
  347. package/src/cli/commands/import-live.test.ts +87 -1
  348. package/src/cli/commands/import-parser-options.test.ts +133 -0
  349. package/src/cli/commands/import.ts +69 -25
  350. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  351. package/src/cli/commands/init.test.ts +8 -1
  352. package/src/cli/commands/init.ts +23 -8
  353. package/src/cli/commands/lint.test.ts +37 -0
  354. package/src/cli/commands/onboard.test.ts +53 -3
  355. package/src/cli/commands/onboard.ts +52 -4
  356. package/src/cli/commands/pinned-upgrade.ts +73 -33
  357. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  358. package/src/cli/handlers/components.ts +2 -2
  359. package/src/cli/handlers/dev.ts +8 -6
  360. package/src/cli/handlers/fan-out.test.ts +6 -6
  361. package/src/cli/handlers/fan-out.ts +2 -1
  362. package/src/cli/handlers/graph.test.ts +42 -0
  363. package/src/cli/handlers/graph.ts +22 -0
  364. package/src/cli/handlers/lifecycle.test.ts +67 -0
  365. package/src/cli/handlers/lifecycle.ts +6 -5
  366. package/src/cli/handlers/misc.ts +2 -0
  367. package/src/cli/handlers/operator.ts +88 -4
  368. package/src/cli/handlers/run.test.ts +111 -0
  369. package/src/cli/handlers/run.ts +85 -24
  370. package/src/cli/handlers/scenario.ts +2 -2
  371. package/src/cli/main.test.ts +33 -0
  372. package/src/cli/main.ts +168 -17
  373. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  374. package/src/cli/mcp/workspace-tools.ts +62 -4
  375. package/src/cli/registry.ts +33 -2
  376. package/src/cli/serve-mcp-workspace.test.ts +1 -1
  377. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  378. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  379. package/src/codegen/pinned-upgrade.test.ts +104 -0
  380. package/src/codegen/pinned-upgrade.ts +250 -56
  381. package/src/codegen/release-wiring.test.ts +5 -1
  382. package/src/codegen/testdata/postgres-tags.json +242 -0
  383. package/src/components/fan-out-output.test.ts +1 -1
  384. package/src/components/fan-out.test.ts +1 -1
  385. package/src/components/promote.test.ts +1 -1
  386. package/src/config.test.ts +21 -0
  387. package/src/config.ts +27 -0
  388. package/src/content-digest.test.ts +2 -2
  389. package/src/declarable.test.ts +21 -0
  390. package/src/declarable.ts +19 -0
  391. package/src/discovery/fold-composite.test.ts +41 -5
  392. package/src/discovery/fold-import.test.ts +129 -0
  393. package/src/discovery/fold-import.ts +643 -131
  394. package/src/discovery/fold-package-composite.test.ts +264 -0
  395. package/src/discovery/fold-specifiers.test.ts +191 -0
  396. package/src/discovery/param-deps.test.ts +66 -1
  397. package/src/discovery/param-deps.ts +45 -0
  398. package/src/discovery/specifier-resolve.ts +344 -0
  399. package/src/fold/fold.test.ts +39 -1
  400. package/src/fold/fold.ts +83 -9
  401. package/src/fold-provenance.test.ts +140 -0
  402. package/src/graph-ir.test.ts +83 -0
  403. package/src/graph-ir.ts +29 -0
  404. package/src/import/embedded.test.ts +20 -0
  405. package/src/import/embedded.ts +13 -0
  406. package/src/import/parser-options.ts +46 -0
  407. package/src/import/parser.ts +20 -0
  408. package/src/lexicon.ts +79 -3
  409. package/src/lifecycle/gate-ledger.test.ts +14 -0
  410. package/src/lifecycle/gate-ledger.ts +18 -1
  411. package/src/lifecycle/observe.test.ts +18 -0
  412. package/src/lifecycle/observe.ts +6 -4
  413. package/src/lifecycle/plan-digest.test.ts +54 -3
  414. package/src/lifecycle/plan-digest.ts +38 -8
  415. package/src/lifecycle/snapshot.ts +2 -2
  416. package/src/lifecycle/work-lease.test.ts +1 -1
  417. package/src/lifecycle/work-lease.ts +93 -2
  418. package/src/lint/engine.test.ts +55 -0
  419. package/src/lint/engine.ts +30 -4
  420. package/src/lint/output-docs.test.ts +59 -56
  421. package/src/op/activities/activity-contracts.ts +1 -0
  422. package/src/op/activities/apply.test.ts +189 -5
  423. package/src/op/activities/apply.ts +230 -8
  424. package/src/op/activities/index.ts +3 -0
  425. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  426. package/src/op/activities/lexicon-upgrade.ts +154 -51
  427. package/src/op/activities/propose-upgrade.ts +8 -5
  428. package/src/op/composites/apply-op.ts +12 -5
  429. package/src/op/composites/composites.test.ts +30 -3
  430. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  431. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  432. package/src/op/emulator-lifecycle.test.ts +23 -0
  433. package/src/op/emulator-lifecycle.ts +52 -14
  434. package/src/op/gate-approval.test.ts +91 -0
  435. package/src/op/gate-approval.ts +5 -1
  436. package/src/op/gate.ts +34 -8
  437. package/src/op/index.ts +3 -1
  438. package/src/op/local-executor.test.ts +15 -0
  439. package/src/op/local-executor.ts +40 -12
  440. package/src/op/local-output.ts +1 -1
  441. package/src/op/operator.ts +4 -0
  442. package/src/op/run-context.test.ts +141 -0
  443. package/src/op/run-context.ts +51 -0
  444. package/src/op/runtimes/local.test.ts +14 -0
  445. package/src/op/runtimes/local.ts +2 -0
  446. package/src/op/steward-beside.ts +2 -0
  447. package/src/op/types.ts +8 -3
  448. package/src/op/work-lease-run.test.ts +47 -0
  449. package/src/op/work-lease-run.ts +73 -11
  450. package/src/provenance.ts +35 -0
  451. package/src/serializer.ts +9 -0
  452. package/src/telemetry-attribution.test.ts +91 -0
  453. package/src/telemetry-attribution.ts +145 -0
  454. package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
  455. package/src/workspace/agent-cli.ts +138 -0
  456. package/src/workspace/agent.schema.json +378 -0
  457. package/src/workspace/behold-kinds.test.ts +1 -1
  458. package/src/workspace/box-factory.test.ts +320 -0
  459. package/src/workspace/box-factory.ts +103 -0
  460. package/src/workspace/changes-cli.ts +5 -0
  461. package/src/workspace/changes.schema.json +171 -1
  462. package/src/workspace/changes.ts +61 -4
  463. package/src/workspace/check-live.test.ts +192 -0
  464. package/src/workspace/check.schema.json +64 -0
  465. package/src/workspace/checks/boxes.test.ts +2 -0
  466. package/src/workspace/checks/links.ts +23 -2
  467. package/src/workspace/checks/live.ts +113 -0
  468. package/src/workspace/checks.test.ts +2 -2
  469. package/src/workspace/checks.ts +49 -8
  470. package/src/workspace/compose-graph.test.ts +47 -0
  471. package/src/workspace/compose-graph.ts +127 -3
  472. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
  473. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
  474. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
  475. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
  476. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
  477. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
  478. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
  479. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  480. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  481. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
  482. package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
  483. package/src/workspace/conformance/index.mjs +30 -3
  484. package/src/workspace/conformance/index.ts +103 -15
  485. package/src/workspace/conformance/vitest.ts +44 -2
  486. package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
  487. package/src/workspace/conformance/writer.test.ts +156 -0
  488. package/src/workspace/conformance/writer.ts +880 -0
  489. package/src/workspace/decide.ts +7 -1
  490. package/src/workspace/declaration.schema.json +368 -4
  491. package/src/workspace/declaration.ts +270 -1
  492. package/src/workspace/declared-kinds.test.ts +33 -0
  493. package/src/workspace/evidence.schema.json +279 -0
  494. package/src/workspace/export-cli.ts +180 -0
  495. package/src/workspace/export-import.test.ts +282 -0
  496. package/src/workspace/export.ts +486 -0
  497. package/src/workspace/graph-cli.ts +51 -2
  498. package/src/workspace/graph-contract.test.ts +89 -4
  499. package/src/workspace/graph.schema.json +453 -1
  500. package/src/workspace/identity.test.ts +196 -0
  501. package/src/workspace/identity.ts +186 -0
  502. package/src/workspace/import.ts +325 -0
  503. package/src/workspace/intent-cli.ts +64 -10
  504. package/src/workspace/intent-record.schema.json +208 -0
  505. package/src/workspace/intent-record.ts +35 -1
  506. package/src/workspace/intent-why.test.ts +274 -0
  507. package/src/workspace/intent.schema.json +718 -7
  508. package/src/workspace/intent.test.ts +11 -2
  509. package/src/workspace/intent.ts +495 -32
  510. package/src/workspace/kinds.test.ts +5 -5
  511. package/src/workspace/kinds.ts +62 -33
  512. package/src/workspace/lineage-adopt-cli.ts +103 -0
  513. package/src/workspace/lineage-adopt.test.ts +552 -0
  514. package/src/workspace/lineage-adopt.ts +452 -0
  515. package/src/workspace/lineage-check.ts +26 -5
  516. package/src/workspace/lineage-cli.ts +12 -2
  517. package/src/workspace/lineage-hash-index.ts +305 -0
  518. package/src/workspace/lineage-init.test.ts +9 -0
  519. package/src/workspace/lineage-init.ts +29 -9
  520. package/src/workspace/lineage-lock.ts +54 -0
  521. package/src/workspace/lineage-migrations.test.ts +27 -0
  522. package/src/workspace/lineage-migrations.ts +44 -14
  523. package/src/workspace/lineage-provenance.ts +40 -0
  524. package/src/workspace/lineage-upgrade-cli.ts +9 -5
  525. package/src/workspace/lineage-upgrade.test.ts +92 -1
  526. package/src/workspace/lineage-upgrade.ts +111 -16
  527. package/src/workspace/lineage-versions.ts +348 -0
  528. package/src/workspace/links.test.ts +121 -2
  529. package/src/workspace/links.ts +97 -6
  530. package/src/workspace/ls-contract.test.ts +84 -1
  531. package/src/workspace/ls-generated.ts +111 -0
  532. package/src/workspace/ls.schema.json +19 -0
  533. package/src/workspace/ls.ts +8 -1
  534. package/src/workspace/member-commands.ts +3 -1
  535. package/src/workspace/nested-graph.test.ts +176 -0
  536. package/src/workspace/nested-graph.ts +169 -0
  537. package/src/workspace/nesting.ts +37 -0
  538. package/src/workspace/pin-cli.test.ts +71 -0
  539. package/src/workspace/pin-cli.ts +57 -0
  540. package/src/workspace/pin-integrity.test.ts +121 -0
  541. package/src/workspace/pin-integrity.ts +104 -0
  542. package/src/workspace/points-write.schema.json +2 -0
  543. package/src/workspace/principal-classes.test.ts +175 -0
  544. package/src/workspace/principal-classes.ts +307 -0
  545. package/src/workspace/read-contract.test.ts +24 -0
  546. package/src/workspace/reason-codes.test.ts +20 -2
  547. package/src/workspace/reason-codes.ts +53 -3
  548. package/src/workspace/record-sessions.ts +12 -14
  549. package/src/workspace/records-amend.schema.json +6 -0
  550. package/src/workspace/records-checkout.ts +106 -0
  551. package/src/workspace/records-cli.ts +195 -22
  552. package/src/workspace/records-close.schema.json +7 -2
  553. package/src/workspace/records-close.ts +10 -2
  554. package/src/workspace/records-formats.test.ts +13 -5
  555. package/src/workspace/records-new.schema.json +6 -0
  556. package/src/workspace/records-review.schema.json +6 -0
  557. package/src/workspace/records-sessions.test.ts +23 -6
  558. package/src/workspace/records-uncommitted.test.ts +171 -0
  559. package/src/workspace/records-write.test.ts +65 -8
  560. package/src/workspace/records-write.ts +92 -6
  561. package/src/workspace/records.schema.json +127 -4
  562. package/src/workspace/records.ts +123 -5
  563. package/src/workspace/returns.ts +328 -0
  564. package/src/workspace/runs-cli.ts +381 -0
  565. package/src/workspace/runs-write.schema.json +583 -0
  566. package/src/workspace/runs.schema.json +810 -0
  567. package/src/workspace/runs.test.ts +242 -0
  568. package/src/workspace/runs.ts +709 -0
  569. package/src/workspace/signers.schema.json +206 -0
  570. package/src/workspace/status-contract.test.ts +5 -0
  571. package/src/workspace/status-gates.ts +24 -9
  572. package/src/workspace/status.schema.json +127 -2
  573. package/src/workspace/status.ts +21 -1
  574. package/src/workspace/symbols.ts +180 -0
  575. package/src/workspace/template-manifest.ts +22 -4
  576. package/src/workspace/trailer-joins.test.ts +171 -0
  577. package/src/workspace/trailer-joins.ts +82 -0
  578. package/src/workspace/trailers.ts +148 -0
  579. package/src/workspace/trust/attestor.ts +15 -0
  580. package/src/workspace/trust/dsse.ts +134 -0
  581. package/src/workspace/trust/evidence-cli.ts +195 -0
  582. package/src/workspace/trust/evidence.test.ts +241 -0
  583. package/src/workspace/trust/evidence.ts +207 -0
  584. package/src/workspace/trust/policy.ts +110 -3
  585. package/src/workspace/trust/provenance.ts +41 -4
  586. package/src/workspace/trust/record-seal.test.ts +1 -1
  587. package/src/workspace/trust/rotation.test.ts +258 -0
  588. package/src/workspace/trust/rotation.ts +336 -0
  589. package/src/workspace/trust/seal.ts +63 -1
  590. package/src/workspace/trust/signers-cli.ts +178 -0
  591. package/src/workspace/trust/ssh-commit.ts +53 -4
  592. package/src/workspace/trust/test-repo.ts +18 -0
  593. package/src/workspace/trust/trust.test.ts +8 -2
  594. package/src/workspace/trust/verify-cli.ts +1 -0
  595. package/src/workspace/trust/verify.ts +22 -0
  596. package/src/workspace/work-cli.e2e.test.ts +28 -1
  597. package/src/workspace/work-cli.ts +133 -8
  598. package/src/workspace/work-evidence.schema.json +6 -0
  599. package/src/workspace/work-history.schema.json +73 -1
  600. package/src/workspace/work-history.test.ts +48 -5
  601. package/src/workspace/work-kind-fields.test.ts +154 -0
  602. package/src/workspace/work-lease.schema.json +14 -1
  603. package/src/workspace/work.ts +82 -0
  604. package/src/workspace/workspace-principals.schema.json +60 -0
  605. package/src/workspace/write-scope.test.ts +466 -0
  606. package/src/workspace/write-scope.ts +573 -0
  607. package/src/yaml.test.ts +111 -1
  608. package/src/yaml.ts +141 -549
@@ -1,5 +1,7 @@
1
1
  import { describe, test, expect } from "vitest";
2
- import { computePlanDigest, isPlanDigest, describePlanDigest } from "./plan-digest";
2
+ import { canonicalJson } from "../effect-receipt";
3
+ import { contentDigest } from "../content-digest";
4
+ import { computePlanDigest, isPlanDigest, describePlanDigest, samePlanDigest, PLAN_DIGEST_PREFIX } from "./plan-digest";
3
5
 
4
6
  describe("computePlanDigest", () => {
5
7
  test("the same change set digests the same, whatever order its keys arrived in", () => {
@@ -23,19 +25,68 @@ describe("computePlanDigest", () => {
23
25
  );
24
26
  });
25
27
 
26
- test("it is a sha256 digest, in the shape isPlanDigest accepts", () => {
28
+ test("it is a versioned jcs1-sha256 digest, in the shape isPlanDigest accepts", () => {
27
29
  const digest = computePlanDigest("terraform-plan", {});
28
- expect(digest).toMatch(/^sha256:[0-9a-f]{64}$/);
30
+ expect(digest).toMatch(/^jcs1-sha256:[0-9a-f]{64}$/);
31
+ expect(digest.startsWith(PLAN_DIGEST_PREFIX)).toBe(true);
29
32
  expect(isPlanDigest(digest)).toBe(true);
30
33
  });
34
+
35
+ test("it hashes the same bytes the bare sha256: digest of chant before #2547 did", () => {
36
+ const subject = { b: [1, { y: 2, x: 1 }], a: "\u00e9" };
37
+ const legacy = contentDigest(canonicalJson({ kind: "k", subject }));
38
+ expect(computePlanDigest("k", subject)).toBe(`jcs1-${legacy}`);
39
+ });
40
+ });
41
+
42
+ describe("the canonical form is RFC 8785", () => {
43
+ test("it sorts keys by UTF-16 code unit, as RFC 8785 section 3.2.3 does", () => {
44
+ // The RFC's own example: these keys in this order.
45
+ const keys = ["\r", "1", "\u0080", "\u00f6", "\u20ac", "\ud83d\ude00", "\ufb33"];
46
+ const reversed = [...keys].reverse();
47
+ const value = Object.fromEntries(reversed.map((k) => [k, reversed.indexOf(k)]));
48
+ // Written out by hand because Object.keys puts "1" first, whatever order a key was added in.
49
+ expect(canonicalJson(value)).toBe(`{${keys.map((k) => `${JSON.stringify(k)}:${reversed.indexOf(k)}`).join(",")}}`);
50
+ });
51
+
52
+ test("it writes numbers as ECMAScript does, which is what RFC 8785 section 3.2.2 specifies", () => {
53
+ expect(canonicalJson([1e21, 1e-7, 0.000001, -0, 4.5, 333333333.33333329])).toBe("[1e+21,1e-7,0.000001,0,4.5,333333333.3333333]");
54
+ });
55
+ });
56
+
57
+ describe("samePlanDigest", () => {
58
+ const hex = "a".repeat(64);
59
+ test("a digest recorded under the bare prefix is the same plan as the jcs1 one", () => {
60
+ expect(samePlanDigest(`sha256:${hex}`, `jcs1-sha256:${hex}`)).toBe(true);
61
+ expect(samePlanDigest(`jcs1-sha256:${hex}`, `sha256:${hex}`)).toBe(true);
62
+ expect(samePlanDigest(`sha256:${hex}`, `sha256:${hex}`)).toBe(true);
63
+ });
64
+
65
+ test("a different hash is a different plan, in either prefix", () => {
66
+ expect(samePlanDigest(`sha256:${hex}`, `jcs1-sha256:${"b".repeat(64)}`)).toBe(false);
67
+ });
68
+
69
+ test("a value that is not a plan digest matches only itself", () => {
70
+ expect(samePlanDigest("anything", "anything")).toBe(true);
71
+ expect(samePlanDigest("anything", `sha256:${hex}`)).toBe(false);
72
+ expect(samePlanDigest(undefined, `sha256:${hex}`)).toBe(false);
73
+ expect(samePlanDigest(undefined, undefined)).toBe(true);
74
+ });
31
75
  });
32
76
 
33
77
  describe("isPlanDigest", () => {
78
+ test("accepts both prefixes, since gates recorded before #2547 carry the bare one", () => {
79
+ expect(isPlanDigest(`sha256:${"a".repeat(64)}`)).toBe(true);
80
+ expect(isPlanDigest(`jcs1-sha256:${"a".repeat(64)}`)).toBe(true);
81
+ });
82
+
34
83
  test("refuses everything a copy-paste or a path could be", () => {
35
84
  expect(isPlanDigest("chant.tfplan")).toBe(false);
36
85
  expect(isPlanDigest(`sha256:${"a".repeat(63)}`)).toBe(false);
37
86
  expect(isPlanDigest("a".repeat(64))).toBe(false);
38
87
  expect(isPlanDigest(`sha256:${"A".repeat(64)}`)).toBe(false);
88
+ expect(isPlanDigest(`jcs2-sha256:${"a".repeat(64)}`)).toBe(false);
89
+ expect(isPlanDigest(`jcs1-sha256:${"a".repeat(63)}`)).toBe(false);
39
90
  expect(isPlanDigest(undefined)).toBe(false);
40
91
  expect(isPlanDigest(12)).toBe(false);
41
92
  });
@@ -39,11 +39,22 @@
39
39
  import { canonicalJson } from "../effect-receipt";
40
40
  import { contentDigest } from "../content-digest";
41
41
 
42
- /** The hash a plan digest is taken with, and the prefix every digest carries. */
42
+ /** The hash a plan digest is taken with. */
43
43
  export const PLAN_DIGEST_ALGORITHM = "sha256";
44
44
 
45
- /** Shape of a well-formed digest: `sha256:` and 64 lowercase hex characters. */
46
- const PLAN_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
45
+ /**
46
+ * The version prefix a plan digest is written with since #2547: `jcs1` names
47
+ * the input form (the RFC 8785 canonical JSON of `{ kind, subject }`, see
48
+ * `canonicalJson` in ../effect-receipt.ts) and `sha256` the hash. A later
49
+ * input form gets a new prefix, so a digest always says how it was made.
50
+ */
51
+ export const PLAN_DIGEST_PREFIX = "jcs1-sha256:";
52
+
53
+ /** The bare prefix every digest written before #2547 carries. Still read, never written for a plan. */
54
+ export const LEGACY_PLAN_DIGEST_PREFIX = "sha256:";
55
+
56
+ /** Shape of a well-formed digest: either prefix, then 64 lowercase hex characters. */
57
+ const PLAN_DIGEST_PATTERN = /^(?:jcs1-)?sha256:([0-9a-f]{64})$/;
47
58
 
48
59
  /**
49
60
  * Hash a plan's change set into a stable identity.
@@ -60,21 +71,40 @@ const PLAN_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
60
71
  * versions, does not change the answer. It is the caller's job to
61
72
  * hand in a projection that already excludes the volatile fields this
62
73
  * module's doc comment lists.
74
+ *
75
+ * The result is `jcs1-sha256:<hex>` (#2547). Before that it was
76
+ * `sha256:<hex>` over the same bytes, so the hex is unchanged and
77
+ * {@link samePlanDigest} treats the two spellings as one digest: a gate
78
+ * recorded under the old prefix still matches the plan it was approved for.
63
79
  */
64
80
  export function computePlanDigest(kind: string, subject: unknown): string {
65
- return contentDigest(canonicalJson({ kind, subject }));
81
+ return PLAN_DIGEST_PREFIX + contentDigest(canonicalJson({ kind, subject })).slice(LEGACY_PLAN_DIGEST_PREFIX.length);
66
82
  }
67
83
 
68
84
  /**
69
- * Whether `raw` is a digest this code produced. Used at the `chant approve
70
- * --plan` boundary, so a typo, a truncated copy-paste or a plan *file* path
71
- * is refused before it is written into an immutable resolution that would
72
- * then never match anything.
85
+ * Whether `raw` is a digest this code produced, in either prefix. Used at the
86
+ * `chant approve --plan` boundary, so a typo, a truncated copy-paste or a plan
87
+ * *file* path is refused before it is written into an immutable resolution
88
+ * that would then never match anything.
73
89
  */
74
90
  export function isPlanDigest(raw: unknown): raw is string {
75
91
  return typeof raw === "string" && PLAN_DIGEST_PATTERN.test(raw);
76
92
  }
77
93
 
94
+ /**
95
+ * Whether two recorded or computed plan digests name the same plan. Two
96
+ * well-formed plan digests are the same when their hex is, whichever prefix
97
+ * each carries (read both, write new, #2547). Anything else, such as a
98
+ * release plan's own digest, is the same only when the strings are equal.
99
+ */
100
+ export function samePlanDigest(a: string | undefined, b: string | undefined): boolean {
101
+ if (a === b) return true;
102
+ if (a === undefined || b === undefined) return false;
103
+ const x = PLAN_DIGEST_PATTERN.exec(a);
104
+ const y = PLAN_DIGEST_PATTERN.exec(b);
105
+ return x !== null && y !== null && x[1] === y[1];
106
+ }
107
+
78
108
  /**
79
109
  * A digest as it reads in a message, and the one place that decides how an
80
110
  * absent one reads. Records written before #2300 carry no digest at all, and
@@ -18,7 +18,7 @@ import { formatUnobserved, normalizeObservation, unobservedAll, type UnobservedE
18
18
  // property tree is ever rendered or committed. Two lists would eventually
19
19
  // disagree about what counts as a secret.
20
20
  import { isSensitiveKey } from "../deep-observation";
21
- import { isResourceDeclarable } from "../declarable";
21
+ import { isObservableDeclarable } from "../declarable";
22
22
 
23
23
  /**
24
24
  * Check for potential sensitive data in resource attributes and return warnings.
@@ -128,7 +128,7 @@ export async function takeSnapshot(
128
128
  for (const [name, entity] of buildResult.entities) {
129
129
  // Resource declarables only — outputs, parameters and serializer
130
130
  // directives have no live counterpart (see lifecycle/observe.ts).
131
- if (entity.lexicon === plugin.name && isResourceDeclarable(entity)) {
131
+ if (entity.lexicon === plugin.name && isObservableDeclarable(entity)) {
132
132
  entityNames.push(name);
133
133
  entities.set(name, {
134
134
  entityType: entity.entityType,
@@ -107,7 +107,7 @@ describe("a work lease in one clone", () => {
107
107
 
108
108
  const again = await claimWorkLease("W-003", "carol", { cwd, ttlMs: 1_000, now: at(t0) });
109
109
  if (!again.ok) throw new Error(again.message);
110
- const closed = await releaseWorkLease("W-003", "dispatcher", { cwd, outcome: "expired", now: at("2026-09-25T11:00:00.000Z") });
110
+ const closed = await releaseWorkLease("W-003", "dispatcher", { cwd, outcome: "abandoned", now: at("2026-09-25T11:00:00.000Z") });
111
111
  expect(closed).toMatchObject({ ok: true, lease: { holder: "carol" } });
112
112
  });
113
113
 
@@ -100,6 +100,93 @@ export interface WorkLeaseState extends WorkLease {
100
100
  ref: string;
101
101
  }
102
102
 
103
+ /**
104
+ * How a work lease can end (#3147): the closed list of outcomes a release
105
+ * records. A new outcome is a contract change. Readers of an older history
106
+ * may still find free text from before the list was closed, which counts as
107
+ * an attempt (see {@link outcomeCountsAsAttempt}).
108
+ */
109
+ export const WORK_LEASE_OUTCOMES = [
110
+ /** The work was finished: built, checked and recorded. */
111
+ "done",
112
+ /** A build ran and did not finish, or the run failed. Counts as an attempt. */
113
+ "not_done",
114
+ /** An expired lease closed out by someone other than its holder: the worker went away. Counts as an attempt. */
115
+ "abandoned",
116
+ /** The run stopped at a gate, waiting for an approval. */
117
+ "gated",
118
+ /** The run stopped on a decision point's open question, waiting for a person. */
119
+ "waiting",
120
+ /** The item was dropped, such as by a refuse at the understand point. Nothing was built. */
121
+ "dropped",
122
+ /** The understand point answered redraft: the item goes back to its author. Nothing was built. */
123
+ "redraft",
124
+ /** The understand point answered ask: the item waits on a question to its author. Nothing was built. */
125
+ "ask",
126
+ ] as const;
127
+ export type WorkLeaseOutcome = (typeof WORK_LEASE_OUTCOMES)[number];
128
+
129
+ /** The outcomes that count toward an item's attempt limit. */
130
+ export const ATTEMPT_OUTCOMES: readonly WorkLeaseOutcome[] = ["not_done", "abandoned"];
131
+
132
+ /** Whether `value` is one of {@link WORK_LEASE_OUTCOMES}. */
133
+ export function isWorkLeaseOutcome(value: unknown): value is WorkLeaseOutcome {
134
+ return typeof value === "string" && (WORK_LEASE_OUTCOMES as readonly string[]).includes(value);
135
+ }
136
+
137
+ /**
138
+ * Whether a release with `outcome` counts toward the item's attempt limit:
139
+ * `not_done` and `abandoned` do, and so does a release that gave no outcome
140
+ * or one outside the closed list (free text written before #3147), since
141
+ * nothing says the work got anywhere.
142
+ */
143
+ export function outcomeCountsAsAttempt(outcome: string | null | undefined): boolean {
144
+ if (!isWorkLeaseOutcome(outcome)) return true;
145
+ return ATTEMPT_OUTCOMES.includes(outcome);
146
+ }
147
+
148
+ /** The ref prefix that keeps an unfinished attempt's work (#3147). */
149
+ export const KEPT_REF_PREFIX = "refs/chant/kept/";
150
+
151
+ /**
152
+ * Where the work of an attempt that ended `not_done` is kept: one ref per
153
+ * lease token, `refs/chant/kept/[<member>/...]<item>/<token>`, scoped by the
154
+ * members the way the work branch `chant/work/[<member>/]<item>` is.
155
+ */
156
+ export function keptAttemptRef(id: string, token: string, members: readonly string[] = []): string {
157
+ return `${keptAttemptPrefix(id, members)}${token}`;
158
+ }
159
+
160
+ /** The prefix under which every kept attempt of item `id` sits. */
161
+ export function keptAttemptPrefix(id: string, members: readonly string[] = []): string {
162
+ return `${KEPT_REF_PREFIX}${members.length ? `${members.join("/")}/` : ""}${id}/`;
163
+ }
164
+
165
+ /** One kept attempt, as `work history` lists it. */
166
+ export interface KeptAttempt {
167
+ /** The lease token the attempt ran under. */
168
+ token: string;
169
+ ref: string;
170
+ /** The commit the ref points at. */
171
+ commit: string;
172
+ }
173
+
174
+ /** Every kept attempt of item `id`, from the local refs, sorted by ref. Empty outside git. */
175
+ export async function listKeptAttempts(id: string, opts: { cwd: string; members?: readonly string[] }): Promise<KeptAttempt[]> {
176
+ const prefix = keptAttemptPrefix(id, opts.members ?? []);
177
+ const out = await getRuntime().spawn(["git", "for-each-ref", "--format=%(refname) %(objectname)", prefix], { cwd: opts.cwd });
178
+ if (out.exitCode !== 0) return [];
179
+ return out.stdout
180
+ .split("\n")
181
+ .filter(Boolean)
182
+ .map((line) => {
183
+ const [ref, commit] = line.split(" ");
184
+ return { token: ref.slice(prefix.length), ref, commit };
185
+ })
186
+ .filter((k) => k.token !== "" && !k.token.includes("/"))
187
+ .sort((a, b) => (a.ref < b.ref ? -1 : a.ref > b.ref ? 1 : 0));
188
+ }
189
+
103
190
  /** One line of `_leases/<id>.jsonl`. */
104
191
  export interface LeaseHistoryRecord {
105
192
  version: 1;
@@ -115,7 +202,7 @@ export interface LeaseHistoryRecord {
115
202
  expiresAt: string;
116
203
  /** When the event happened. */
117
204
  timestamp: string;
118
- /** How the work ended, on a release. Free text such as done, not_done or skipped. */
205
+ /** How the work ended, on a release: one of {@link WORK_LEASE_OUTCOMES}, or free text in a line written before #3147. */
119
206
  outcome?: string;
120
207
  note?: string;
121
208
  }
@@ -257,7 +344,8 @@ async function finish(
257
344
  /**
258
345
  * Give the lease on `id` back. The holder releases a live lease (with
259
346
  * `token`, only that one); anyone may release an expired one, which is how an
260
- * abandoned claim is closed out. `outcome` says how the work ended. Refused
347
+ * abandoned claim is closed out. `outcome` says how the work ended, from the
348
+ * closed list {@link WORK_LEASE_OUTCOMES}; any other value throws. Refused
261
349
  * with `lease-not-held` when there is no lease, and `lease-held` when someone
262
350
  * else holds it live.
263
351
  */
@@ -267,6 +355,9 @@ export async function releaseWorkLease(
267
355
  opts: WorkLeaseOptions & { token?: string; outcome?: string; note?: string },
268
356
  ): Promise<WorkLeaseResult> {
269
357
  checkId(id);
358
+ if (opts.outcome !== undefined && !isWorkLeaseOutcome(opts.outcome)) {
359
+ throw new Error(`${JSON.stringify(opts.outcome)} is not a work lease outcome: use one of ${WORK_LEASE_OUTCOMES.join(", ")}`);
360
+ }
270
361
  const key = workLeaseKey(id);
271
362
  const now = opts.now?.() ?? new Date();
272
363
  const { record } = await readLease(key, { cwd: opts.cwd });
@@ -6,6 +6,61 @@ import { writeFile } from "node:fs/promises";
6
6
  import { join } from "node:path";
7
7
 
8
8
  describe("runLint", () => {
9
+ // #2511
10
+ test("a rule that throws is an error for that file, and the other rules still run", async () => {
11
+ await withTestDir(async (testDir) => {
12
+ const testFile = join(testDir, "test.ts");
13
+ await writeFile(testFile, "const x = 1;");
14
+
15
+ const throwing: LintRule = {
16
+ id: "throws",
17
+ severity: "warning",
18
+ category: "correctness",
19
+ check: () => {
20
+ throw new Error("bad input");
21
+ },
22
+ };
23
+ const after: LintRule = {
24
+ id: "after",
25
+ severity: "warning",
26
+ category: "correctness",
27
+ check: (context: LintContext): LintDiagnostic[] => [
28
+ { file: context.filePath, line: 1, column: 1, ruleId: "after", severity: "warning", message: "ran" },
29
+ ],
30
+ };
31
+
32
+ const { diagnostics } = await runLint([testFile], [throwing, after]);
33
+
34
+ expect(diagnostics.map((d) => d.ruleId).sort()).toEqual(["after", "throws"]);
35
+ const threw = diagnostics.find((d) => d.ruleId === "throws")!;
36
+ expect(threw.severity).toBe("error");
37
+ expect(threw.file).toBe(testFile);
38
+ expect(threw.message).toBe(`Rule throws threw while checking ${testFile}: bad input`);
39
+ });
40
+ });
41
+
42
+ test("a disable comment does not suppress a rule's failure", async () => {
43
+ await withTestDir(async (testDir) => {
44
+ const testFile = join(testDir, "test.ts");
45
+ await writeFile(testFile, "// chant-disable\nconst x = 1;");
46
+
47
+ const throwing: LintRule = {
48
+ id: "throws",
49
+ severity: "warning",
50
+ category: "correctness",
51
+ check: () => {
52
+ throw "not an Error";
53
+ },
54
+ };
55
+
56
+ const { diagnostics, suppressed } = await runLint([testFile], [throwing]);
57
+
58
+ expect(suppressed).toHaveLength(0);
59
+ expect(diagnostics).toHaveLength(1);
60
+ expect(diagnostics[0].message).toContain("not an Error");
61
+ });
62
+ });
63
+
9
64
  test("executes rules and returns diagnostics", async () => {
10
65
  await withTestDir(async (testDir) => {
11
66
  const testFile = join(testDir, "test.ts");
@@ -189,6 +189,23 @@ function isDiagnosticDisabled(
189
189
  return { suppressed: false };
190
190
  }
191
191
 
192
+ /**
193
+ * The error reported when a rule throws while checking a file (#2511). It
194
+ * names the rule, the file and the thrown message, at error severity so
195
+ * `chant lint` exits non-zero.
196
+ */
197
+ export function ruleThrewDiagnostic(ruleId: string, filePath: string, error: unknown): LintDiagnostic {
198
+ const message = error instanceof Error ? error.message : String(error);
199
+ return {
200
+ file: filePath,
201
+ line: 1,
202
+ column: 1,
203
+ ruleId,
204
+ severity: "error",
205
+ message: `Rule ${ruleId} threw while checking ${filePath}: ${message}`,
206
+ };
207
+ }
208
+
192
209
  /**
193
210
  * Execute lint rules on a set of files
194
211
  * @param files - Array of file paths to lint
@@ -246,11 +263,17 @@ export async function runLint(
246
263
  propertyClasses,
247
264
  };
248
265
 
249
- // Execute each rule
266
+ // Execute each rule. A rule that throws is reported as an error for
267
+ // this file (#2511) and the remaining rules still run.
268
+ const ruleErrors: LintDiagnostic[] = [];
250
269
  for (const rule of rules) {
251
270
  const options = ruleOptions?.get(rule.id);
252
- const diagnostics = rule.check(context, options);
253
- allDiagnostics.push(...diagnostics);
271
+ try {
272
+ const diagnostics = rule.check(context, options);
273
+ allDiagnostics.push(...diagnostics);
274
+ } catch (error) {
275
+ ruleErrors.push(ruleThrewDiagnostic(rule.id, filePath, error));
276
+ }
254
277
  }
255
278
 
256
279
  // Partition file diagnostics into active and suppressed
@@ -269,7 +292,10 @@ export async function runLint(
269
292
 
270
293
  // Replace file diagnostics with filtered ones
271
294
  allDiagnostics.length = 0;
272
- allDiagnostics.push(...otherFileDiags, ...keptDiags);
295
+ // A rule's own failure is never suppressed by a disable comment: the
296
+ // comment is aimed at the rule's findings, and hiding the failure would
297
+ // make a rule that did not run look like a clean lint.
298
+ allDiagnostics.push(...otherFileDiags, ...keptDiags, ...ruleErrors);
273
299
  } catch (error) {
274
300
  // If parsing fails, skip this file and continue with others
275
301
  continue;
@@ -1,6 +1,7 @@
1
1
  import { describe, test, expect } from "vitest";
2
2
  import { parseOutputDocs, pick, get } from "./output-docs";
3
3
  import type { SerializerResult } from "../serializer";
4
+ import { load as jsYamlLoad } from "js-yaml";
4
5
 
5
6
  describe("parseOutputDocs", () => {
6
7
  test("parses a single JSON output as one document", () => {
@@ -156,65 +157,67 @@ describe("parseOutputDocs", () => {
156
157
  expect(bad.value).toBeUndefined();
157
158
  });
158
159
  });
159
- });
160
-
161
- describe("pick", () => {
162
- interface Widget {
163
- kind: string;
164
- name: string;
165
- extra: unknown;
166
- }
167
-
168
- test("returns only the named keys that are present", () => {
169
- const value = { kind: "Deployment", name: "web", other: "ignored" };
170
- expect(pick<Widget>(value, ["kind", "name"])).toEqual({ kind: "Deployment", name: "web" });
171
- });
172
-
173
- test("omits a named key that is absent — no invented default", () => {
174
- const value = { kind: "Deployment" };
175
- expect(pick<Widget>(value, ["kind", "name"])).toEqual({ kind: "Deployment" });
176
- });
177
-
178
- test("returns an empty object for a non-object value", () => {
179
- expect(pick<Widget>(null, ["kind"])).toEqual({});
180
- expect(pick<Widget>("a string", ["kind"])).toEqual({});
181
- expect(pick<Widget>(undefined, ["kind"])).toEqual({});
182
- });
183
-
184
- test("copies values through unvalidated, whatever their actual shape", () => {
185
- const value = { kind: 42 }; // wrong runtime type for `kind: string`
186
- expect(pick<Widget>(value, ["kind"])).toEqual({ kind: 42 });
187
- });
188
- });
189
-
190
- describe("get", () => {
191
- test("walks a dotted path through nested objects", () => {
192
- const value = { spec: { template: { spec: { containers: [] } } } };
193
- expect(get(value, "spec.template.spec")).toEqual({ containers: [] });
194
- });
195
-
196
- test("returns undefined as soon as a segment is missing", () => {
197
- const value = { spec: {} };
198
- expect(get(value, "spec.template.spec")).toBeUndefined();
199
- });
200
160
 
201
- test("returns undefined when an intermediate value is not indexable", () => {
202
- const value = { spec: "not-an-object" };
203
- expect(get(value, "spec.template")).toBeUndefined();
204
- });
161
+ // #2925: hand-written and third-party YAML (`chant audit`, test fixtures)
162
+ // uses flow collections and folded scalars. Each case is checked against
163
+ // js-yaml, so the expected value is what a full parser reads.
164
+ describe("YAML a hand-written manifest uses (#2925)", () => {
165
+ const docOf = (yaml: string): unknown => {
166
+ const docs = parseOutputDocs(new Map<string, string | SerializerResult>([["k8s", yaml]]));
167
+ expect(docs).toHaveLength(1);
168
+ expect(docs[0].error).toBeUndefined();
169
+ return docs[0].value;
170
+ };
205
171
 
206
- test("indexes into arrays with a numeric path segment", () => {
207
- const value = { items: [{ name: "first" }, { name: "second" }] };
208
- expect(get(value, "items.1.name")).toBe("second");
209
- });
172
+ test("flow mappings read as mappings, not strings", () => {
173
+ const yaml = [
174
+ "apiVersion: apps/v1",
175
+ "kind: Deployment",
176
+ "metadata: { name: gw, namespace: obs }",
177
+ "spec:",
178
+ " template:",
179
+ " spec:",
180
+ " volumes:",
181
+ " - name: conf",
182
+ " configMap: { name: gw-config }",
183
+ ].join("\n");
184
+ const value = docOf(yaml);
185
+ expect(value).toEqual(jsYamlLoad(yaml));
186
+ expect(get(value, "metadata.namespace")).toBe("obs");
187
+ expect(get(value, "spec.template.spec.volumes.0.configMap.name")).toBe("gw-config");
188
+ });
210
189
 
211
- test("returns the value itself for an empty path", () => {
212
- const value = { a: 1 };
213
- expect(get(value, "")).toBe(value);
214
- });
190
+ test("a flow sequence of flow mappings reads as a list of mappings", () => {
191
+ const yaml = [
192
+ "kind: Pod",
193
+ "spec:",
194
+ " containers:",
195
+ " - name: gw",
196
+ " volumeMounts: [{ name: conf, mountPath: /conf }, { name: data, mountPath: /data, readOnly: true }]",
197
+ " args: [--config, /conf/config.yaml]",
198
+ ].join("\n");
199
+ const value = docOf(yaml);
200
+ expect(value).toEqual(jsYamlLoad(yaml));
201
+ expect(get(value, "spec.containers.0.volumeMounts.1.readOnly")).toBe(true);
202
+ expect(get(value, "spec.containers.0.args")).toEqual(["--config", "/conf/config.yaml"]);
203
+ });
215
204
 
216
- test("does not throw on null/undefined input", () => {
217
- expect(get(null, "a.b")).toBeUndefined();
218
- expect(get(undefined, "a.b")).toBeUndefined();
205
+ test("a folded scalar keeps the line breaks of its more-indented lines", () => {
206
+ // js-yaml dumps a long ConfigMap value this way.
207
+ const yaml = [
208
+ "kind: ConfigMap",
209
+ "data:",
210
+ " config.yaml: >",
211
+ " receivers:",
212
+ " k8s_cluster:",
213
+ " auth_type: serviceAccount",
214
+ " exporters: {}",
215
+ ].join("\n");
216
+ const value = docOf(yaml);
217
+ expect(value).toEqual(jsYamlLoad(yaml));
218
+ expect((value as { data: Record<string, string> }).data["config.yaml"]).toBe(
219
+ "receivers:\n k8s_cluster:\n auth_type: serviceAccount\nexporters: {}\n",
220
+ );
221
+ });
219
222
  });
220
223
  });
@@ -153,6 +153,7 @@ export const proposeWorkspaceUpgradeContract = activityContract(
153
153
  base: z.string().optional(),
154
154
  remote: z.string().optional(),
155
155
  allowCode: z.boolean().optional(),
156
+ source: z.string().optional(),
156
157
  cwd: z.string().optional(),
157
158
  }),
158
159
  z.object({