@intentius/chant 0.56.0 → 0.58.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 (515) hide show
  1. package/dist/audit/catalog.d.ts +51 -1
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +20 -1
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts +14 -8
  6. package/dist/audit/discover.d.ts.map +1 -1
  7. package/dist/audit/lineage.d.ts +10 -0
  8. package/dist/audit/lineage.d.ts.map +1 -0
  9. package/dist/audit/prior-art.d.ts +385 -0
  10. package/dist/audit/prior-art.d.ts.map +1 -0
  11. package/dist/audit/proof.d.ts +16 -0
  12. package/dist/audit/proof.d.ts.map +1 -1
  13. package/dist/audit/report-html.d.ts.map +1 -1
  14. package/dist/audit/report-model.d.ts +8 -1
  15. package/dist/audit/report-model.d.ts.map +1 -1
  16. package/dist/audit/report.d.ts.map +1 -1
  17. package/dist/audit/rules-doc.d.ts +3 -0
  18. package/dist/audit/rules-doc.d.ts.map +1 -1
  19. package/dist/audit/secrets.d.ts +15 -0
  20. package/dist/audit/secrets.d.ts.map +1 -1
  21. package/dist/audit/terraform-state.d.ts +46 -0
  22. package/dist/audit/terraform-state.d.ts.map +1 -0
  23. package/dist/build.d.ts +17 -1
  24. package/dist/build.d.ts.map +1 -1
  25. package/dist/claimed-fields.d.ts +161 -0
  26. package/dist/claimed-fields.d.ts.map +1 -0
  27. package/dist/cli/build-params-cli.d.ts +2 -2
  28. package/dist/cli/command-group.d.ts +14 -0
  29. package/dist/cli/command-group.d.ts.map +1 -1
  30. package/dist/cli/commands/audit.d.ts +17 -1
  31. package/dist/cli/commands/audit.d.ts.map +1 -1
  32. package/dist/cli/commands/build.d.ts.map +1 -1
  33. package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
  34. package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
  35. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
  36. package/dist/cli/commands/import.d.ts.map +1 -1
  37. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
  38. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
  39. package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
  40. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  41. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  42. package/dist/cli/commands/init.d.ts.map +1 -1
  43. package/dist/cli/commands/lint.d.ts.map +1 -1
  44. package/dist/cli/commands/onboard.d.ts +2 -0
  45. package/dist/cli/commands/onboard.d.ts.map +1 -1
  46. package/dist/cli/handlers/build.d.ts.map +1 -1
  47. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  48. package/dist/cli/handlers/operator.d.ts +82 -16
  49. package/dist/cli/handlers/operator.d.ts.map +1 -1
  50. package/dist/cli/handlers/run.d.ts +49 -42
  51. package/dist/cli/handlers/run.d.ts.map +1 -1
  52. package/dist/cli/main.d.ts +28 -1
  53. package/dist/cli/main.d.ts.map +1 -1
  54. package/dist/cli/mcp/op-tools.d.ts +16 -1
  55. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  56. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  57. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  58. package/dist/cli/registry.d.ts +26 -9
  59. package/dist/cli/registry.d.ts.map +1 -1
  60. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  61. package/dist/components/auto-release.d.ts +10 -20
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability.d.ts +4 -4
  64. package/dist/components/cli-support.d.ts +20 -21
  65. package/dist/components/cli-support.d.ts.map +1 -1
  66. package/dist/components/component.d.ts +3 -3
  67. package/dist/components/component.d.ts.map +1 -1
  68. package/dist/components/driver-output.d.ts.map +1 -1
  69. package/dist/components/driver.d.ts +66 -36
  70. package/dist/components/driver.d.ts.map +1 -1
  71. package/dist/components/index.d.ts +1 -2
  72. package/dist/components/index.d.ts.map +1 -1
  73. package/dist/components/manifest-persistence.d.ts +1 -9
  74. package/dist/components/manifest-persistence.d.ts.map +1 -1
  75. package/dist/components/run-progress.d.ts +6 -6
  76. package/dist/components/run-progress.d.ts.map +1 -1
  77. package/dist/components/verbs/run-agent.d.ts +9 -15
  78. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  79. package/dist/components/verbs/verify.d.ts +2 -2
  80. package/dist/deep-observation.d.ts +17 -0
  81. package/dist/deep-observation.d.ts.map +1 -1
  82. package/dist/discovery/files.d.ts +4 -4
  83. package/dist/discovery/fold-import.d.ts.map +1 -1
  84. package/dist/discovery/param-deps.d.ts +33 -0
  85. package/dist/discovery/param-deps.d.ts.map +1 -1
  86. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  87. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  88. package/dist/fold/foldable-helpers.d.ts +5 -1
  89. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  90. package/dist/fold-provenance.d.ts +236 -0
  91. package/dist/fold-provenance.d.ts.map +1 -0
  92. package/dist/graph-ops.d.ts +1 -1
  93. package/dist/held-elsewhere.d.ts +85 -0
  94. package/dist/held-elsewhere.d.ts.map +1 -0
  95. package/dist/import/ir-utils.d.ts +1 -1
  96. package/dist/import/ir-utils.d.ts.map +1 -1
  97. package/dist/import/parser.d.ts +33 -0
  98. package/dist/import/parser.d.ts.map +1 -1
  99. package/dist/index.d.ts +3 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/kubectl-context.d.ts +3 -3
  102. package/dist/lexicon-config.d.ts +4 -4
  103. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  104. package/dist/lexicon.d.ts +104 -14
  105. package/dist/lexicon.d.ts.map +1 -1
  106. package/dist/lifecycle/change-set.d.ts +13 -0
  107. package/dist/lifecycle/change-set.d.ts.map +1 -1
  108. package/dist/lifecycle/deep-diff.d.ts +133 -6
  109. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  110. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  111. package/dist/lifecycle/gate-ledger.d.ts +71 -3
  112. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  113. package/dist/lifecycle/index.d.ts +1 -0
  114. package/dist/lifecycle/index.d.ts.map +1 -1
  115. package/dist/lifecycle/release-ledger.d.ts +2 -2
  116. package/dist/lifecycle/run-ledger.d.ts +53 -0
  117. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  118. package/dist/lifecycle/symptoms.d.ts +3 -3
  119. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  120. package/dist/lint/config.d.ts +81 -2
  121. package/dist/lint/config.d.ts.map +1 -1
  122. package/dist/lint/post-synth.d.ts +55 -2
  123. package/dist/lint/post-synth.d.ts.map +1 -1
  124. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  125. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  126. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  127. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  128. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  129. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  130. package/dist/lint/rules/comp/index.d.ts +1 -1
  131. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  132. package/dist/lint/rules/op/index.d.ts +16 -0
  133. package/dist/lint/rules/op/index.d.ts.map +1 -0
  134. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  135. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  136. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  137. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  138. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  139. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  140. package/dist/lint/rules/op/support.d.ts +12 -0
  141. package/dist/lint/rules/op/support.d.ts.map +1 -0
  142. package/dist/lint/suppressions.d.ts +108 -0
  143. package/dist/lint/suppressions.d.ts.map +1 -0
  144. package/dist/live-endpoint.d.ts +1 -1
  145. package/dist/op/activities/activity-contracts.d.ts +54 -0
  146. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  147. package/dist/op/activities/apply.d.ts +262 -0
  148. package/dist/op/activities/apply.d.ts.map +1 -0
  149. package/dist/op/activities/build.d.ts +13 -0
  150. package/dist/op/activities/build.d.ts.map +1 -0
  151. package/dist/op/activities/converge.d.ts +110 -0
  152. package/dist/op/activities/converge.d.ts.map +1 -0
  153. package/dist/op/activities/env-teardown.d.ts +76 -0
  154. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  155. package/dist/op/activities/guard-validate.d.ts +64 -0
  156. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  157. package/dist/op/activities/http-check.d.ts +34 -0
  158. package/dist/op/activities/http-check.d.ts.map +1 -0
  159. package/dist/op/activities/index.d.ts +31 -0
  160. package/dist/op/activities/index.d.ts.map +1 -0
  161. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  162. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  163. package/dist/op/activities/lifecycle.d.ts +42 -0
  164. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  165. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  166. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  167. package/dist/op/activities/policy.d.ts +17 -0
  168. package/dist/op/activities/policy.d.ts.map +1 -0
  169. package/dist/op/activities/reconcile.d.ts +89 -0
  170. package/dist/op/activities/reconcile.d.ts.map +1 -0
  171. package/dist/op/activities/shell.d.ts +13 -0
  172. package/dist/op/activities/shell.d.ts.map +1 -0
  173. package/dist/op/activities/teardown.d.ts +10 -0
  174. package/dist/op/activities/teardown.d.ts.map +1 -0
  175. package/dist/op/activities/util.d.ts +7 -0
  176. package/dist/op/activities/util.d.ts.map +1 -0
  177. package/dist/op/activities/wait.d.ts +28 -0
  178. package/dist/op/activities/wait.d.ts.map +1 -0
  179. package/dist/op/activities/workflow-audit.d.ts +92 -0
  180. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  181. package/dist/op/activity-contract-registry.d.ts +76 -0
  182. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  183. package/dist/op/activity-contract.d.ts +25 -18
  184. package/dist/op/activity-contract.d.ts.map +1 -1
  185. package/dist/op/activity-failure.d.ts +28 -0
  186. package/dist/op/activity-failure.d.ts.map +1 -0
  187. package/dist/op/activity-profiles.d.ts +118 -0
  188. package/dist/op/activity-profiles.d.ts.map +1 -0
  189. package/dist/op/activity-registry.d.ts +22 -38
  190. package/dist/op/activity-registry.d.ts.map +1 -1
  191. package/dist/op/activity-runtime.d.ts +3 -14
  192. package/dist/op/activity-runtime.d.ts.map +1 -1
  193. package/dist/op/builders.d.ts +84 -29
  194. package/dist/op/builders.d.ts.map +1 -1
  195. package/dist/op/composites/apply-op.d.ts +113 -0
  196. package/dist/op/composites/apply-op.d.ts.map +1 -0
  197. package/dist/op/composites/converge-op.d.ts +120 -0
  198. package/dist/op/composites/converge-op.d.ts.map +1 -0
  199. package/dist/op/composites/index.d.ts +26 -0
  200. package/dist/op/composites/index.d.ts.map +1 -0
  201. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  202. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  203. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  204. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  205. package/dist/op/composites/reconcile-op.d.ts +57 -0
  206. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  207. package/dist/op/composites/watch-op.d.ts +60 -0
  208. package/dist/op/composites/watch-op.d.ts.map +1 -0
  209. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  210. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  211. package/dist/op/converge-rule.d.ts +12 -10
  212. package/dist/op/converge-rule.d.ts.map +1 -1
  213. package/dist/op/cron.d.ts +51 -0
  214. package/dist/op/cron.d.ts.map +1 -0
  215. package/dist/op/discover.d.ts +9 -0
  216. package/dist/op/discover.d.ts.map +1 -1
  217. package/dist/op/duration.d.ts +11 -0
  218. package/dist/op/duration.d.ts.map +1 -0
  219. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  220. package/dist/op/gate.d.ts +90 -0
  221. package/dist/op/gate.d.ts.map +1 -0
  222. package/dist/op/generate-pipeline.d.ts +9 -0
  223. package/dist/op/generate-pipeline.d.ts.map +1 -1
  224. package/dist/op/index.d.ts +23 -7
  225. package/dist/op/index.d.ts.map +1 -1
  226. package/dist/op/local-executor.d.ts +114 -28
  227. package/dist/op/local-executor.d.ts.map +1 -1
  228. package/dist/op/local-output.d.ts +11 -1
  229. package/dist/op/local-output.d.ts.map +1 -1
  230. package/dist/op/op-ir.d.ts +184 -0
  231. package/dist/op/op-ir.d.ts.map +1 -0
  232. package/dist/op/op-verb-class.d.ts +10 -2
  233. package/dist/op/op-verb-class.d.ts.map +1 -1
  234. package/dist/op/operator.d.ts +30 -5
  235. package/dist/op/operator.d.ts.map +1 -1
  236. package/dist/op/receipt-store.d.ts +1 -1
  237. package/dist/op/receipt-store.d.ts.map +1 -1
  238. package/dist/op/resource.d.ts +15 -1
  239. package/dist/op/resource.d.ts.map +1 -1
  240. package/dist/op/runtime.d.ts +200 -0
  241. package/dist/op/runtime.d.ts.map +1 -0
  242. package/dist/op/runtimes/local.d.ts +29 -0
  243. package/dist/op/runtimes/local.d.ts.map +1 -0
  244. package/dist/op/step-output-ref.d.ts +15 -13
  245. package/dist/op/step-output-ref.d.ts.map +1 -1
  246. package/dist/op/types.d.ts +79 -27
  247. package/dist/op/types.d.ts.map +1 -1
  248. package/dist/ownership.d.ts +1 -1
  249. package/dist/provenance.d.ts +21 -0
  250. package/dist/provenance.d.ts.map +1 -1
  251. package/dist/serializer-walker.d.ts.map +1 -1
  252. package/dist/stack-output.d.ts +5 -0
  253. package/dist/stack-output.d.ts.map +1 -1
  254. package/package.json +6 -1
  255. package/src/audit/catalog.test.ts +79 -3
  256. package/src/audit/catalog.ts +111 -13
  257. package/src/audit/core.test.ts +26 -0
  258. package/src/audit/core.ts +61 -17
  259. package/src/audit/discover.test.ts +39 -0
  260. package/src/audit/discover.ts +91 -15
  261. package/src/audit/lineage.ts +100 -0
  262. package/src/audit/prior-art.ts +153 -0
  263. package/src/audit/proof.test.ts +67 -0
  264. package/src/audit/proof.ts +70 -0
  265. package/src/audit/report-html.ts +9 -4
  266. package/src/audit/report-model.ts +16 -2
  267. package/src/audit/report.test.ts +33 -0
  268. package/src/audit/report.ts +5 -3
  269. package/src/audit/rules-doc.test.ts +34 -2
  270. package/src/audit/rules-doc.ts +82 -9
  271. package/src/audit/secrets.ts +15 -3
  272. package/src/audit/terraform-state.test.ts +144 -0
  273. package/src/audit/terraform-state.ts +131 -0
  274. package/src/build.ts +31 -1
  275. package/src/claimed-fields.test.ts +145 -0
  276. package/src/claimed-fields.ts +208 -0
  277. package/src/cli/build-params-cli.ts +2 -2
  278. package/src/cli/command-group.ts +14 -0
  279. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  280. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  281. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  282. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  283. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  284. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  285. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  286. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  287. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  288. package/src/cli/commands/audit.test.ts +189 -11
  289. package/src/cli/commands/audit.ts +73 -27
  290. package/src/cli/commands/build.test.ts +292 -9
  291. package/src/cli/commands/build.ts +156 -24
  292. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  293. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  294. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  295. package/src/cli/commands/import.ts +6 -0
  296. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  297. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  298. package/src/cli/commands/init-lexicon.test.ts +97 -2
  299. package/src/cli/commands/init-lexicon.ts +4 -2
  300. package/src/cli/commands/init.test.ts +35 -1
  301. package/src/cli/commands/init.ts +14 -3
  302. package/src/cli/commands/lint.test.ts +48 -0
  303. package/src/cli/commands/lint.ts +123 -0
  304. package/src/cli/commands/onboard.test.ts +75 -0
  305. package/src/cli/commands/onboard.ts +54 -23
  306. package/src/cli/handlers/build.test.ts +81 -1
  307. package/src/cli/handlers/build.ts +15 -1
  308. package/src/cli/handlers/graph.test.ts +3 -3
  309. package/src/cli/handlers/lifecycle.test.ts +195 -12
  310. package/src/cli/handlers/lifecycle.ts +123 -6
  311. package/src/cli/handlers/misc.ts +1 -1
  312. package/src/cli/handlers/operator.test.ts +183 -11
  313. package/src/cli/handlers/operator.ts +260 -55
  314. package/src/cli/handlers/run.test.ts +431 -1287
  315. package/src/cli/handlers/run.ts +365 -915
  316. package/src/cli/main.test.ts +23 -15
  317. package/src/cli/main.ts +88 -33
  318. package/src/cli/mcp/op-tools.ts +147 -88
  319. package/src/cli/mcp/resource-handlers.ts +10 -37
  320. package/src/cli/mcp/resources/context.ts +11 -12
  321. package/src/cli/mcp/server.test.ts +25 -27
  322. package/src/cli/mcp/server.ts +2 -2
  323. package/src/cli/registry.ts +26 -9
  324. package/src/codegen/docs.ts +1 -1
  325. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  326. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  327. package/src/components/README.md +3 -2
  328. package/src/components/auto-release.test.ts +4 -20
  329. package/src/components/auto-release.ts +17 -42
  330. package/src/components/capability.ts +4 -4
  331. package/src/components/cli-support.test.ts +10 -5
  332. package/src/components/cli-support.ts +52 -44
  333. package/src/components/component.schema.json +2 -2
  334. package/src/components/component.ts +3 -3
  335. package/src/components/driver-output.ts +14 -2
  336. package/src/components/driver.test.ts +92 -22
  337. package/src/components/driver.ts +193 -83
  338. package/src/components/index.ts +1 -6
  339. package/src/components/manifest-persistence.test.ts +2 -20
  340. package/src/components/manifest-persistence.ts +4 -24
  341. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  342. package/src/components/run-progress.ts +6 -6
  343. package/src/components/verbs/run-agent.ts +11 -17
  344. package/src/components/verbs/verify.ts +2 -2
  345. package/src/deep-observation.test.ts +75 -0
  346. package/src/deep-observation.ts +48 -0
  347. package/src/discovery/collect.test.ts +3 -3
  348. package/src/discovery/files.ts +4 -4
  349. package/src/discovery/fold-import.ts +105 -2
  350. package/src/discovery/param-deps.test.ts +112 -1
  351. package/src/discovery/param-deps.ts +193 -0
  352. package/src/discovery/sandbox/bundle.ts +15 -1
  353. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  354. package/src/discovery/sandbox/config-wire.ts +2 -2
  355. package/src/fold/fold.test.ts +56 -0
  356. package/src/fold/foldable-helpers.ts +81 -1
  357. package/src/fold-provenance-exclusion.test.ts +186 -0
  358. package/src/fold-provenance.test.ts +495 -0
  359. package/src/fold-provenance.ts +441 -0
  360. package/src/graph-ops.test.ts +2 -2
  361. package/src/graph-ops.ts +1 -1
  362. package/src/held-elsewhere.test.ts +102 -0
  363. package/src/held-elsewhere.ts +114 -0
  364. package/src/import/ir-utils.ts +11 -1
  365. package/src/import/parser.ts +35 -0
  366. package/src/index.ts +3 -0
  367. package/src/kubectl-context.ts +3 -3
  368. package/src/lexicon-config.test.ts +5 -5
  369. package/src/lexicon-config.ts +4 -4
  370. package/src/lexicon-plugin-helpers.ts +1 -1
  371. package/src/lexicon.ts +120 -14
  372. package/src/lifecycle/change-set.test.ts +49 -0
  373. package/src/lifecycle/change-set.ts +67 -0
  374. package/src/lifecycle/converge-ledger.ts +1 -1
  375. package/src/lifecycle/deep-diff.test.ts +267 -14
  376. package/src/lifecycle/deep-diff.ts +217 -14
  377. package/src/lifecycle/deep-observe.test.ts +3 -1
  378. package/src/lifecycle/deep-observe.ts +16 -6
  379. package/src/lifecycle/gate-ledger.test.ts +74 -2
  380. package/src/lifecycle/gate-ledger.ts +143 -36
  381. package/src/lifecycle/index.ts +1 -0
  382. package/src/lifecycle/release-ledger.ts +2 -2
  383. package/src/lifecycle/run-ledger.test.ts +268 -0
  384. package/src/lifecycle/run-ledger.ts +201 -0
  385. package/src/lifecycle/symptoms.ts +3 -3
  386. package/src/lint/config.test.ts +82 -1
  387. package/src/lint/config.ts +112 -3
  388. package/src/lint/policy.test.ts +1 -1
  389. package/src/lint/post-synth.test.ts +31 -0
  390. package/src/lint/post-synth.ts +54 -1
  391. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  392. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  393. package/src/lint/rules/comp/comp.test.ts +1 -1
  394. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
  395. package/src/lint/rules/comp/index.ts +3 -3
  396. package/src/lint/rules/op/index.ts +23 -0
  397. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  398. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  399. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  400. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  401. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  402. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  403. package/src/lint/rules/op/support.ts +11 -0
  404. package/src/lint/suppressions.test.ts +163 -0
  405. package/src/lint/suppressions.ts +204 -0
  406. package/src/live-endpoint.ts +1 -1
  407. package/src/op/activities/activity-contracts.ts +66 -0
  408. package/src/op/activities/apply.test.ts +567 -0
  409. package/src/op/activities/apply.ts +662 -0
  410. package/src/op/activities/build.ts +26 -0
  411. package/src/op/activities/converge.test.ts +330 -0
  412. package/src/op/activities/converge.ts +449 -0
  413. package/src/op/activities/env-teardown.test.ts +187 -0
  414. package/src/op/activities/env-teardown.ts +171 -0
  415. package/src/op/activities/guard-validate.test.ts +139 -0
  416. package/src/op/activities/guard-validate.ts +223 -0
  417. package/src/op/activities/http-check.test.ts +48 -0
  418. package/src/op/activities/http-check.ts +55 -0
  419. package/src/op/activities/index.ts +119 -0
  420. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  421. package/src/op/activities/lexicon-upgrade.ts +673 -0
  422. package/src/op/activities/lifecycle.ts +85 -0
  423. package/src/op/activities/pipeline-audit.test.ts +67 -0
  424. package/src/op/activities/pipeline-audit.ts +201 -0
  425. package/src/op/activities/policy.test.ts +19 -0
  426. package/src/op/activities/policy.ts +37 -0
  427. package/src/op/activities/reconcile.test.ts +81 -0
  428. package/src/op/activities/reconcile.ts +187 -0
  429. package/src/op/activities/shell.ts +26 -0
  430. package/src/op/activities/teardown.ts +22 -0
  431. package/src/op/activities/util.ts +6 -0
  432. package/src/op/activities/wait.ts +69 -0
  433. package/src/op/activities/workflow-audit.test.ts +90 -0
  434. package/src/op/activities/workflow-audit.ts +203 -0
  435. package/src/op/activity-contract-registry.test.ts +98 -0
  436. package/src/op/activity-contract-registry.ts +114 -0
  437. package/src/op/activity-contract.test.ts +1 -1
  438. package/src/op/activity-contract.ts +37 -33
  439. package/src/op/activity-failure.ts +34 -0
  440. package/src/op/activity-profiles.test.ts +56 -0
  441. package/src/op/activity-profiles.ts +116 -0
  442. package/src/op/activity-registry.test.ts +37 -28
  443. package/src/op/activity-registry.ts +27 -56
  444. package/src/op/activity-runtime.ts +3 -47
  445. package/src/op/builders-exports.test.ts +0 -49
  446. package/src/op/builders-typed.test.ts +164 -0
  447. package/src/op/builders.ts +123 -39
  448. package/src/op/composites/apply-op.ts +208 -0
  449. package/src/op/composites/composites.test.ts +366 -0
  450. package/src/op/composites/converge-op.test.ts +168 -0
  451. package/src/op/composites/converge-op.ts +214 -0
  452. package/src/op/composites/index.ts +26 -0
  453. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  454. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  455. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  456. package/src/op/composites/pipeline-audit-op.ts +78 -0
  457. package/src/op/composites/reconcile-op.test.ts +51 -0
  458. package/src/op/composites/reconcile-op.ts +107 -0
  459. package/src/op/composites/watch-op.ts +108 -0
  460. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  461. package/src/op/composites/workflow-audit-op.ts +88 -0
  462. package/src/op/converge-rule.ts +12 -10
  463. package/src/op/cron.test.ts +128 -0
  464. package/src/op/cron.ts +149 -0
  465. package/src/op/discover-root.test.ts +105 -1
  466. package/src/op/discover.test.ts +6 -2
  467. package/src/op/discover.ts +84 -16
  468. package/src/op/duration.ts +21 -0
  469. package/src/op/effect-step.test.ts +26 -11
  470. package/src/op/emulator-lifecycle.ts +1 -2
  471. package/src/op/gate.ts +155 -0
  472. package/src/op/generate-pipeline.test.ts +65 -3
  473. package/src/op/generate-pipeline.ts +19 -2
  474. package/src/op/index.ts +39 -6
  475. package/src/op/local-executor.test.ts +163 -34
  476. package/src/op/local-executor.ts +370 -102
  477. package/src/op/local-output.test.ts +95 -11
  478. package/src/op/local-output.ts +33 -4
  479. package/src/op/op-ir.test.ts +281 -0
  480. package/src/op/op-ir.ts +417 -0
  481. package/src/op/op-verb-class.ts +19 -5
  482. package/src/op/op.test.ts +26 -5
  483. package/src/op/operator.test.ts +175 -6
  484. package/src/op/operator.ts +63 -16
  485. package/src/op/receipt-store.ts +1 -1
  486. package/src/op/resource.ts +20 -2
  487. package/src/op/runtime.ts +203 -0
  488. package/src/op/runtimes/local.test.ts +181 -0
  489. package/src/op/runtimes/local.ts +212 -0
  490. package/src/op/step-output-ref.ts +15 -13
  491. package/src/op/types.ts +84 -24
  492. package/src/ownership.ts +1 -1
  493. package/src/provenance.test.ts +6 -0
  494. package/src/provenance.ts +21 -1
  495. package/src/serializer-walker.test.ts +42 -0
  496. package/src/serializer-walker.ts +21 -2
  497. package/src/stack-output.ts +6 -1
  498. package/dist/cli/handlers/op-progress.d.ts +0 -90
  499. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  500. package/dist/cli/handlers/run-client.d.ts +0 -127
  501. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  502. package/dist/cli/handlers/run-report.d.ts +0 -5
  503. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  504. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  505. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  506. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  507. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  508. package/src/cli/handlers/op-progress.test.ts +0 -268
  509. package/src/cli/handlers/op-progress.ts +0 -248
  510. package/src/cli/handlers/run-client.test.ts +0 -82
  511. package/src/cli/handlers/run-client.ts +0 -219
  512. package/src/cli/handlers/run-report.test.ts +0 -62
  513. package/src/cli/handlers/run-report.ts +0 -122
  514. package/src/components/temporal-codegen-loader.ts +0 -41
  515. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -0,0 +1,208 @@
1
+ /**
2
+ * The claimed-field set (#2160) — which properties this declaration ever set.
3
+ *
4
+ * chant's ownership question has always been answered per resource, from a
5
+ * marker: is this thing mine. The finer question was never asked. A live
6
+ * property tree carries fields nobody declared — an autoscaler's replica count,
7
+ * a controller's annotation, a value a person typed into a console — and the
8
+ * deep diff (./lifecycle/deep-diff.ts) reported every one of them as a
9
+ * difference, because a difference is all a two-way comparison can produce.
10
+ *
11
+ * Every lexicon has been paying for that in hand-written knowledge.
12
+ * `DeepNormalizationHooks.prune` is where the noise goes, and three of the four
13
+ * hooks exist because the live tree holds fields the declaration never
14
+ * mentions. Kubernetes is the one substrate that escapes it: the API server
15
+ * records a field manager per field (`metadata.managedFields`), so a foreign
16
+ * write is a fact about the object rather than a rule somebody maintains.
17
+ * `lexicons/gcp/src/deep-observe.ts` says why nobody else can do that — "a REST
18
+ * payload carries no field ownership" — and answers with a static per-kind
19
+ * table instead.
20
+ *
21
+ * The declaration is the table they are missing. A `ResourceDeclarable`'s
22
+ * `props` are exactly the fields chant set, they are available on every
23
+ * substrate, and they come from the same build that produced the entity.
24
+ * Nothing has to come back from the provider.
25
+ *
26
+ * ## The grammar is the diff's grammar
27
+ *
28
+ * A claim is a set of property paths in the form `flattenDeepProperties`
29
+ * produces: `spec.replicas`, `Tags[#env].Value`, `ingress[0].fromPort`. Same
30
+ * hooks, same normalization, same flattening — so a path in the claim and a
31
+ * path in the diff are the same string or they are different fields. Deriving
32
+ * the claim any other way (walking raw props, say) would give a set that agrees
33
+ * with the diff for most trees and disagrees for exactly the ones the hooks
34
+ * were written for.
35
+ *
36
+ * ## Membership is exact, deliberately
37
+ *
38
+ * A claimed path is matched exactly, never by its index-erased pattern
39
+ * (`Tags[].Value`). The pattern is the right test for
40
+ * {@link import("./deep-observation").DeepNode.counterpart}, which asks a
41
+ * shape question ("did source declare tag values at all") before array order is
42
+ * canonical. Classification asks a value question, and it pairs a declared
43
+ * value with a live one at the same path. A pattern match would answer
44
+ * "declared" for a path that has no declared value to compare against, which is
45
+ * neither of the two declared classifications and would quietly become a third
46
+ * meaning of "drift".
47
+ *
48
+ * ## What the claim does not decide
49
+ *
50
+ * It does not prune. A field chant never declared still reaches the diff, still
51
+ * appears in the report, and still carries its live value — it is reported as
52
+ * unclaimed rather than dropped, because chant #1191 already lost a
53
+ * console-added label by pruning what it could not attribute. What the claim
54
+ * changes is the verdict: unclaimed is not drift, and drift is the only thing
55
+ * that may become an update.
56
+ */
57
+
58
+ import {
59
+ deepValueEqual,
60
+ flattenDeepProperties,
61
+ normalizeDeepProperties,
62
+ type DeepNormalizationHooks,
63
+ } from "./deep-observation";
64
+
65
+ /**
66
+ * The set of property paths one declaration claims — every path its `props`
67
+ * flatten to, in the diff's own grammar.
68
+ *
69
+ * Opaque on purpose: {@link isClaimed} is the only membership test, so a
70
+ * consumer cannot accidentally invent a looser one (see the module doc on
71
+ * pattern matching).
72
+ */
73
+ export interface ClaimedFieldSet {
74
+ /** Flattened property paths, exactly as the diff addresses them. */
75
+ readonly paths: ReadonlySet<string>;
76
+ }
77
+
78
+ /**
79
+ * How one LIVE value relates to the claim. Three answers where a two-way diff
80
+ * had two:
81
+ *
82
+ * - `declared-equal` — chant set this field and the cloud agrees. Nothing to say.
83
+ * - `declared-changed` — chant set this field and the cloud holds something
84
+ * else. This is drift, and it is the only classification that may become an
85
+ * update.
86
+ * - `undeclared` — the field has a value and chant never set it. Somebody else
87
+ * holds it. Reported, never proposed, never counted as drift.
88
+ *
89
+ * A declared path with no live value at all is not in this enumeration: there
90
+ * is no live value to classify. The diff keeps reporting that case as `absent`.
91
+ */
92
+ export type FieldClaim = "declared-equal" | "declared-changed" | "undeclared";
93
+
94
+ /** Which source answered "who holds this field". */
95
+ export type FieldClaimSource =
96
+ /**
97
+ * The substrate named the manager. Kubernetes' `metadata.managedFields`, and
98
+ * nowhere else today — strictly better than the claim, because it says who.
99
+ */
100
+ | "field-manager"
101
+ /**
102
+ * The declaration answered: the path is not in the claimed-field set, so
103
+ * chant never set it. Says that it is somebody else's without saying whose,
104
+ * which is the best any substrate without ownership metadata can do.
105
+ */
106
+ | "claimed-fields";
107
+
108
+ /** An empty claim — a declaration with no props, and the safe default. */
109
+ export const NO_CLAIMED_FIELDS: ClaimedFieldSet = { paths: new Set<string>() };
110
+
111
+ /**
112
+ * Build a claim from an already-normalized declared property tree.
113
+ *
114
+ * `options` must be the same {@link FlattenDeepOptions} the diff flattens the
115
+ * declared side with, or the two disagree about keyed list segments.
116
+ */
117
+ export function claimedFieldsOfTree(
118
+ declared: Record<string, unknown>,
119
+ options: { entityType: string; hooks?: DeepNormalizationHooks },
120
+ ): ClaimedFieldSet {
121
+ const flat = flattenDeepProperties(declared, {
122
+ entityType: options.entityType,
123
+ side: "declared",
124
+ ...(options.hooks ? { hooks: options.hooks } : {}),
125
+ });
126
+ return { paths: new Set(flat.keys()) };
127
+ }
128
+
129
+ /**
130
+ * Build a claim straight from a declaration's raw `props` — the entry point for
131
+ * a consumer that has an entity and no diff.
132
+ *
133
+ * Normalizes with the lexicon's own hooks first, exactly as the diff does, so
134
+ * pruned and masked paths land the same way on both routes. `livePaths` is the
135
+ * counterpart set (`deepPathSet` over the live tree) where the caller has one:
136
+ * without it the pass runs one-sided and any hook gated on
137
+ * {@link import("./deep-observation").DeepNode.counterpart} sees `"unknown"`,
138
+ * which is the honest answer and prunes nothing default-related.
139
+ */
140
+ export function claimedFieldsOfProps(
141
+ props: Record<string, unknown>,
142
+ options: {
143
+ entityType: string;
144
+ hooks?: DeepNormalizationHooks;
145
+ livePaths?: ReadonlySet<string>;
146
+ },
147
+ ): ClaimedFieldSet {
148
+ const normalized = normalizeDeepProperties(props, {
149
+ entityType: options.entityType,
150
+ side: "declared",
151
+ ...(options.hooks ? { hooks: options.hooks } : {}),
152
+ ...(options.livePaths ? { counterpartPaths: options.livePaths } : {}),
153
+ });
154
+ return claimedFieldsOfTree(normalized, options);
155
+ }
156
+
157
+ /** True when this declaration set the property at `path`. */
158
+ export function isClaimed(claimed: ClaimedFieldSet | undefined, path: string): boolean {
159
+ return claimed !== undefined && claimed.paths.has(path);
160
+ }
161
+
162
+ /**
163
+ * The claim as a sorted array — the wire form, for
164
+ * {@link import("./deep-observation").DeepResourceObservation.claimedFields}
165
+ * and for anything serializing a result to JSON.
166
+ */
167
+ export function claimedFieldPaths(claimed: ClaimedFieldSet): string[] {
168
+ return [...claimed.paths].sort();
169
+ }
170
+
171
+ /** Rebuild a claim from its wire form. */
172
+ export function claimedFieldsFromPaths(paths: Iterable<string>): ClaimedFieldSet {
173
+ return { paths: new Set(paths) };
174
+ }
175
+
176
+ /**
177
+ * Classify one live value against the claim.
178
+ *
179
+ * `declaredValue` is only read when the path is claimed; pass whatever the
180
+ * declared tree holds there (including `undefined`, which is a legal declared
181
+ * value on a claimed path only in the sense that the flattener never emits it).
182
+ */
183
+ export function classifyLiveField(input: {
184
+ claimed: ClaimedFieldSet | undefined;
185
+ path: string;
186
+ declaredValue: unknown;
187
+ liveValue: unknown;
188
+ }): FieldClaim {
189
+ if (!isClaimed(input.claimed, input.path)) return "undeclared";
190
+ return deepValueEqual(input.declaredValue, input.liveValue) ? "declared-equal" : "declared-changed";
191
+ }
192
+
193
+ /**
194
+ * Who holds an undeclared live field, and which source said so.
195
+ *
196
+ * The manager wins where the substrate records one: "owned by `hpa-controller`"
197
+ * and "chant never set it" are the same verdict with very different amounts of
198
+ * information in them, and an operator can act on the first. The claim is the
199
+ * fallback, and it answers on every substrate.
200
+ */
201
+ export function heldBy(fieldOwners: Record<string, string> | undefined, path: string): {
202
+ holder?: string;
203
+ source: FieldClaimSource;
204
+ } {
205
+ const manager = fieldOwners?.[path];
206
+ if (manager) return { holder: manager, source: "field-manager" };
207
+ return { source: "claimed-fields" };
208
+ }
@@ -9,8 +9,8 @@ import { formatError, formatInfo } from "./format";
9
9
  * out (chant #1108) so every command that discovers project source before
10
10
  * running it resolves `chant.config.ts`'s declared `buildParams` the exact
11
11
  * same way: `chant build` (`../commands/build.ts`'s `buildCommand`), the
12
- * component deploy driver (`./handlers/run.ts`'s `chant run --components`
13
- * local + `--temporal` paths), and generate mode (`./handlers/build.ts`'s
12
+ * component deploy driver (`./handlers/run.ts`'s `chant run --components`),
13
+ * and generate mode (`./handlers/build.ts`'s
14
14
  * `chant build --components --generate <lexicon>`).
15
15
  *
16
16
  * Before #1108, only `buildCommand` ran this sequence — `chant run
@@ -57,6 +57,20 @@ export interface CommandGroup {
57
57
  description: string;
58
58
  /** Verbs in this group. */
59
59
  commands: CommandGroupCommand[];
60
+ /**
61
+ * The verb to run when the group name is given on its own — `chant acp`
62
+ * rather than `chant acp serve` (#2125). Named here rather than assumed to
63
+ * be the first verb, because a group whose bare form should be a usage
64
+ * error (`chant kube`) must stay one: omitting this field is how a group
65
+ * says it has no default.
66
+ *
67
+ * The token after the group name decides which reading applies, and that
68
+ * decision belongs to the caller that still holds the raw argv
69
+ * (`../cli/main.ts`'s `tryPluginCommand`): with a default verb, `chant acp
70
+ * --durable-requests` has no verb token to consume, so the flag is the
71
+ * default verb's argument rather than a verb it does not have.
72
+ */
73
+ defaultVerb?: string;
60
74
  }
61
75
 
62
76
  /**
@@ -0,0 +1 @@
1
+ resource "null_resource" "root" {}
@@ -0,0 +1 @@
1
+ resource "null_resource" "foo" {}
@@ -0,0 +1,3 @@
1
+ variable "region" {
2
+ type = string
3
+ }
@@ -8,8 +8,16 @@
8
8
  "dist/"
9
9
  ],
10
10
  "exports": {
11
- ".": "./src/index.ts",
12
- "./*": "./src/*",
11
+ ".": {
12
+ "development": "./src/index.ts",
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./src/index.ts"
15
+ },
16
+ "./*": {
17
+ "development": "./src/*.ts",
18
+ "types": "./dist/*.d.ts",
19
+ "default": "./src/*.ts"
20
+ },
13
21
  "./manifest": "./dist/manifest.json",
14
22
  "./meta": "./dist/meta.json",
15
23
  "./types": "./dist/types/index.d.ts"
@@ -18,8 +26,9 @@
18
26
  "generate": "npx tsx src/codegen/generate-cli.ts",
19
27
  "validate": "npx tsx src/validate-cli.ts",
20
28
  "docs": "npx tsx src/codegen/docs-cli.ts",
21
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
22
- "prepack": "npm run generate && npm run validate && npm run build"
29
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete",
30
+ "prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
31
+ "bundle": "tsx src/package-cli.ts"
23
32
  },
24
33
  "devDependencies": {
25
34
  "@intentius/chant": "*",
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env tsx
2
+ import { generateDocs } from "./docs";
3
+
4
+ await generateDocs({ verbose: true });
@@ -15,6 +15,7 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
15
15
  buildManifest: (genResult) => ({
16
16
  name: "fixture",
17
17
  version: "0.0.1",
18
+ chantVersion: ">=0.1.0",
18
19
  }),
19
20
  srcDir,
20
21
  collectSkills: () => new Map(),
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env tsx
2
+ import { generate, writeGeneratedFiles } from "./codegen/generate";
3
+ import { packageLexicon } from "./codegen/package";
4
+ import { writeBundleSpec } from "@intentius/chant/codegen/package";
5
+ import { join, dirname } from "path";
6
+ import { fileURLToPath } from "url";
7
+
8
+ const srcDir = dirname(fileURLToPath(import.meta.url));
9
+
10
+ // 1. Generate src/generated/ files (writeGeneratedFiles resolves its own target)
11
+ const genResult = await generate({ verbose: true });
12
+ writeGeneratedFiles(genResult);
13
+
14
+ // 2. Run package pipeline and write dist/
15
+ const { spec, stats } = await packageLexicon({ verbose: true });
16
+
17
+ const distDir = join(dirname(srcDir), "dist");
18
+ writeBundleSpec(spec, distDir);
19
+
20
+ console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
21
+ console.error(`dist/ written to ${distDir}`);
@@ -97,6 +97,7 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
97
97
  buildManifest: (genResult) => ({
98
98
  name: "fixture",
99
99
  version: "0.0.1",
100
+ chantVersion: ">=0.1.0",
100
101
  }),
101
102
  srcDir,
102
103
  collectSkills: () => new Map(),
@@ -221,6 +221,35 @@ describe("auditCommand", () => {
221
221
  expect(none.exitCode).toBe(0);
222
222
  });
223
223
 
224
+ test("--fail-on error is a severity floor, decoupled from tier: a warning-severity finding does not fail it, an error-severity one does (chant #2113)", async () => {
225
+ const onlyWarning = await auditCommand({
226
+ path: REPO,
227
+ failOn: "error",
228
+ checksProvider: async () => [
229
+ {
230
+ id: "TEST900",
231
+ description: "always fires a warning, for the --fail-on error floor test",
232
+ check: () => [{ checkId: "TEST900", severity: "warning" as const, message: "a new rule shipped at warning" }],
233
+ },
234
+ ],
235
+ });
236
+ expect(onlyWarning.findings.some((f) => f.checkId === "TEST900")).toBe(true);
237
+ expect(onlyWarning.exitCode).toBe(0);
238
+
239
+ const withAnError = await auditCommand({
240
+ path: REPO,
241
+ failOn: "error",
242
+ checksProvider: async () => [
243
+ {
244
+ id: "TEST901",
245
+ description: "always fires an error, for the --fail-on error floor test",
246
+ check: () => [{ checkId: "TEST901", severity: "error" as const, message: "an actual error" }],
247
+ },
248
+ ],
249
+ });
250
+ expect(withAnError.exitCode).toBe(1);
251
+ });
252
+
224
253
  test("--tier merge-worthy filters out report-only findings", async () => {
225
254
  const all = await auditCommand({ path: REPO, tier: "all" });
226
255
  const mw = await auditCommand({ path: REPO, tier: "merge-worthy" });
@@ -267,12 +296,11 @@ describe("auditCommand", () => {
267
296
  expect(result.output).toContain("k8s/deploy.yaml -> k8s");
268
297
  expect(result.output).toContain("infra/stack.json -> aws");
269
298
  expect(result.output).toContain("Dockerfile -> docker");
270
- expect(result.output).toContain("infra/main.tf -> terraform (not audited; see chant carve)");
271
- // The install line names only the lexicons the files wanted, never terraform.
299
+ expect(result.output).toContain("infra/main.tf -> terraform");
300
+ // The install line names every lexicon the files wanted, terraform included.
272
301
  expect(result.output).toContain(
273
- `npx -p @intentius/chant -p @intentius/chant-lexicon-github -p @intentius/chant-lexicon-docker -p @intentius/chant-lexicon-aws -p @intentius/chant-lexicon-k8s chant audit ${MIXED}`,
302
+ `npx -p @intentius/chant -p @intentius/chant-lexicon-github -p @intentius/chant-lexicon-docker -p @intentius/chant-lexicon-terraform -p @intentius/chant-lexicon-aws -p @intentius/chant-lexicon-k8s chant audit ${MIXED}`,
274
303
  );
275
- expect(result.output).not.toContain("chant-lexicon-terraform");
276
304
  });
277
305
 
278
306
  test("zero lexicons with --json: status no-lexicons plus the unclaimed list and install line", async () => {
@@ -282,7 +310,7 @@ describe("auditCommand", () => {
282
310
  const json = JSON.parse(result.output);
283
311
  expect(json.status).toBe("no-lexicons");
284
312
  expect(json.findings).toEqual([]);
285
- expect(json.missingLexicons).toEqual(["github", "docker", "aws", "k8s"]);
313
+ expect(json.missingLexicons).toEqual(["github", "docker", "terraform", "aws", "k8s"]);
286
314
  expect(json.unclaimed).toContainEqual({ path: "k8s/deploy.yaml", lexicon: "k8s" });
287
315
  expect(json.unclaimed).toContainEqual({ path: "infra/main.tf", lexicon: "terraform" });
288
316
  expect(json.install).toMatch(/^npx -p @intentius\/chant /);
@@ -307,9 +335,9 @@ describe("auditCommand", () => {
307
335
  expect(result.status).toBe("ok");
308
336
  expect(result.exitCode).toBe(0);
309
337
  expect(result.scanned).toEqual([".github/workflows/ci.yml"]);
310
- expect(result.output).toMatch(/^Note: 3 files look like docker\/aws\/k8s but those lexicons are not installed, so they were skipped \(npm i @intentius\/chant-lexicon-docker @intentius\/chant-lexicon-aws @intentius\/chant-lexicon-k8s\)\./);
311
- expect(result.output).toContain("1 Terraform file skipped; the audit does not read HCL (see chant carve).");
338
+ expect(result.output).toMatch(/^Note: 4 files look like docker\/terraform\/aws\/k8s but those lexicons are not installed, so they were skipped \(npm i @intentius\/chant-lexicon-docker @intentius\/chant-lexicon-terraform @intentius\/chant-lexicon-aws @intentius\/chant-lexicon-k8s\)\./);
312
339
  expect(result.unclaimed).toContainEqual({ path: "k8s/deploy.yaml", lexicon: "k8s" });
340
+ expect(result.unclaimed).toContainEqual({ path: "infra/main.tf", lexicon: "terraform" });
313
341
  });
314
342
 
315
343
  test("partial with --json: status ok and the unclaimed files ride along", async () => {
@@ -320,12 +348,13 @@ describe("auditCommand", () => {
320
348
  expect(json.unclaimed.map((u: { lexicon: string }) => u.lexicon).sort()).toEqual(["aws", "docker", "k8s", "terraform"]);
321
349
  });
322
350
 
323
- test("all lexicons loaded: no coverage note, no unclaimed (terraform aside)", async () => {
351
+ test("every installable lexicon loaded: nothing is unclaimed, and the terraform root is scanned as one bundle (#2083)", async () => {
324
352
  const result = await auditCommand({ path: MIXED, plugins: await loadAuditPlugins() });
325
353
  expect(result.status).toBe("ok");
326
- expect(result.unclaimed).toEqual([{ path: "infra/main.tf", lexicon: "terraform" }]);
327
- expect(result.output).not.toContain("not installed");
328
- expect(result.scanned.sort()).toEqual([".github/workflows/ci.yml", "Dockerfile", "infra/stack.json", "k8s/deploy.yaml"]);
354
+ expect(result.unclaimed).toEqual([]);
355
+ expect(result.output).not.toContain("looks like terraform");
356
+ // `infra` is the terraform root-module bundle (one input per directory of `.tf` files).
357
+ expect(result.scanned.sort()).toEqual([".github/workflows/ci.yml", "Dockerfile", "infra", "infra/stack.json", "k8s/deploy.yaml"]);
329
358
  });
330
359
 
331
360
  test("installLine puts every lexicon on the same npx -p path", () => {
@@ -441,6 +470,51 @@ describe("auditCommand", () => {
441
470
  expect(valid).toBe(true);
442
471
  });
443
472
 
473
+ describe("TF001's missing-resource shape renders in all three reporters (chant #2113)", () => {
474
+ const dir = join(tmpdir(), `chant-audit-tf-missing-${process.pid}`);
475
+
476
+ function setup(): void {
477
+ mkdirSync(join(dir, "infra"), { recursive: true });
478
+ writeFileSync(join(dir, "infra/main.tf"), 'terraform {\n required_version = ">= 1.5.0"\n}\n');
479
+ }
480
+ function teardown(): void {
481
+ rmSync(dir, { recursive: true, force: true });
482
+ }
483
+
484
+ test("stylish names the missing kind and scope instead of falling back to entity", async () => {
485
+ setup();
486
+ const result = await auditCommand({ path: dir, format: "stylish" });
487
+ expect(result.output).toContain("(missing backend in audit-root)");
488
+ teardown();
489
+ });
490
+
491
+ test("json carries `missing` on the finding", async () => {
492
+ setup();
493
+ const result = await auditCommand({ path: dir, format: "json" });
494
+ const doc = JSON.parse(result.output) as { findings: Array<{ checkId: string; missing?: { kind: string; scope: string } }> };
495
+ const tf001 = doc.findings.find((f) => f.checkId === "TF001");
496
+ expect(tf001?.missing).toEqual({ kind: "backend", scope: "audit-root" });
497
+ teardown();
498
+ });
499
+
500
+ test("sarif carries `missing` in the result's properties, and still validates against the SARIF schema", async () => {
501
+ setup();
502
+ const result = await auditCommand({ path: dir, format: "sarif" });
503
+ const doc = JSON.parse(result.output) as {
504
+ runs: Array<{ results: Array<{ ruleId: string; properties?: { missing?: { kind: string; scope: string } } }> }>;
505
+ };
506
+ const tf001 = doc.runs[0].results.find((r) => r.ruleId === "TF001");
507
+ expect(tf001?.properties?.missing).toEqual({ kind: "backend", scope: "audit-root" });
508
+
509
+ const ajv = new Ajv({ strict: false, allErrors: true });
510
+ const validate = ajv.compile(loadSarifSchema() as object);
511
+ const valid = validate(doc);
512
+ if (!valid) throw new Error(ajv.errorsText(validate.errors));
513
+ expect(valid).toBe(true);
514
+ teardown();
515
+ });
516
+ });
517
+
444
518
  test("sarif schema validation also holds for the empty-result case (no findings)", async () => {
445
519
  const repo = fileURLToPath(new URL("./__fixtures__/audit-fountain-clean", import.meta.url));
446
520
  const result = await auditCommand({ path: repo, format: "sarif" });
@@ -555,6 +629,82 @@ describe("secrets detection (#443)", () => {
555
629
  });
556
630
  });
557
631
 
632
+ describe("Terraform HCL suppression (chant #2111)", () => {
633
+ function tmpRepo(): string {
634
+ const dir = join(tmpdir(), `chant-audit-tf-suppress-${process.pid}-${Math.random().toString(36).slice(2)}`);
635
+ mkdirSync(dir, { recursive: true });
636
+ mkdirSync(join(dir, "infra"), { recursive: true });
637
+ return dir;
638
+ }
639
+
640
+ const BACKENDLESS = 'terraform {\n required_version = ">= 1.5.0"\n}\n';
641
+
642
+ async function auditTerraform(dir: string): Promise<Awaited<ReturnType<typeof auditCommand>>> {
643
+ const all = await loadAuditPlugins();
644
+ return auditCommand({ path: dir, plugins: all.filter((p) => p.name === "terraform"), format: "json" });
645
+ }
646
+
647
+ test("chant-ignore-block suppresses TF001 through chant audit", async () => {
648
+ const dir = tmpRepo();
649
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001\n${BACKENDLESS}`);
650
+ const result = await auditTerraform(dir);
651
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
652
+ expect(result.suppressedCount).toBe(1);
653
+ rmSync(dir, { recursive: true, force: true });
654
+ });
655
+
656
+ test("a plain chant-ignore on the same block also suppresses TF001 through chant audit", async () => {
657
+ const dir = tmpRepo();
658
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore: TF001\n${BACKENDLESS}`);
659
+ const result = await auditTerraform(dir);
660
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
661
+ expect(result.suppressedCount).toBe(1);
662
+ rmSync(dir, { recursive: true, force: true });
663
+ });
664
+
665
+ test('"all" suppresses TF001 through chant audit', async () => {
666
+ const dir = tmpRepo();
667
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: all\n${BACKENDLESS}`);
668
+ const result = await auditTerraform(dir);
669
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
670
+ rmSync(dir, { recursive: true, force: true });
671
+ });
672
+
673
+ test("chant-ignore-file at the top of the file suppresses TF001 through chant audit", async () => {
674
+ const dir = tmpRepo();
675
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-file: TF001\n${BACKENDLESS}`);
676
+ const result = await auditTerraform(dir);
677
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
678
+ rmSync(dir, { recursive: true, force: true });
679
+ });
680
+
681
+ test("a chant-ignore-file NOT at the top has no effect and is reported through chant audit", async () => {
682
+ const dir = tmpRepo();
683
+ writeFileSync(join(dir, "infra", "main.tf"), `# a header\n# chant-ignore-file: TF001\n${BACKENDLESS}`);
684
+ const result = await auditTerraform(dir);
685
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires
686
+ expect(result.findings.map((f) => f.checkId)).toContain("SUPP002");
687
+ rmSync(dir, { recursive: true, force: true });
688
+ });
689
+
690
+ test("a directive naming a different rule id does not suppress TF001 through chant audit", async () => {
691
+ const dir = tmpRepo();
692
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF010\n${BACKENDLESS}`);
693
+ const result = await auditTerraform(dir);
694
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001");
695
+ rmSync(dir, { recursive: true, force: true });
696
+ });
697
+
698
+ test("an already-expired suppression no longer suppresses TF001 and is reported through chant audit", async () => {
699
+ const dir = tmpRepo();
700
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001 exp:2020-01-01\n${BACKENDLESS}`);
701
+ const result = await auditTerraform(dir);
702
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires: expired
703
+ expect(result.findings.map((f) => f.checkId)).toContain("SUPP001");
704
+ rmSync(dir, { recursive: true, force: true });
705
+ });
706
+ });
707
+
558
708
  describe("Wrangler config audit (#446)", () => {
559
709
  function tmpRepo(): string {
560
710
  const dir = join(tmpdir(), `chant-audit-wrangler-${process.pid}-${Math.random().toString(36).slice(2)}`);
@@ -649,3 +799,31 @@ describe("nginx config audit (#1979)", () => {
649
799
  rmSync(dir, { recursive: true, force: true });
650
800
  });
651
801
  });
802
+
803
+ describe("committed Terraform state (TF023, #2110)", () => {
804
+ function tmpRepo(): string {
805
+ const dir = join(tmpdir(), `chant-audit-tfstate-${process.pid}-${Math.random().toString(36).slice(2)}`);
806
+ mkdirSync(dir, { recursive: true });
807
+ return dir;
808
+ }
809
+
810
+ test("fires end to end on a directory with a tracked state file, with no lexicon installed", async () => {
811
+ const dir = tmpRepo();
812
+ writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
813
+ writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
814
+ const result = await auditCommand({ path: dir, plugins: [] });
815
+ expect(result.findings.map((f) => f.checkId)).toContain("TF023");
816
+ rmSync(dir, { recursive: true, force: true });
817
+ });
818
+
819
+ test("says nothing when the state is ignored rather than committed", async () => {
820
+ const dir = tmpRepo();
821
+ writeFileSync(join(dir, ".gitignore"), "*.tfstate\n.terraform/\n");
822
+ writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
823
+ writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
824
+ mkdirSync(join(dir, ".terraform"), { recursive: true });
825
+ const result = await auditCommand({ path: dir, plugins: [] });
826
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF023");
827
+ rmSync(dir, { recursive: true, force: true });
828
+ });
829
+ });