@intentius/chant 0.57.0 → 0.59.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 (558) 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 +36 -1
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts +26 -9
  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/carve-bridge.d.ts.map +1 -1
  34. package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
  35. package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
  36. package/dist/cli/commands/check-lexicon-examples.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 +13 -0
  44. package/dist/cli/commands/lint.d.ts.map +1 -1
  45. package/dist/cli/commands/onboard.d.ts +2 -0
  46. package/dist/cli/commands/onboard.d.ts.map +1 -1
  47. package/dist/cli/handlers/build.d.ts.map +1 -1
  48. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  49. package/dist/cli/handlers/operator.d.ts +82 -16
  50. package/dist/cli/handlers/operator.d.ts.map +1 -1
  51. package/dist/cli/handlers/run.d.ts +49 -42
  52. package/dist/cli/handlers/run.d.ts.map +1 -1
  53. package/dist/cli/main.d.ts +12 -1
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/mcp/op-tools.d.ts +16 -1
  56. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  58. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  59. package/dist/cli/plugins.d.ts +22 -0
  60. package/dist/cli/plugins.d.ts.map +1 -1
  61. package/dist/cli/registry.d.ts +40 -9
  62. package/dist/cli/registry.d.ts.map +1 -1
  63. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  64. package/dist/components/auto-release.d.ts +10 -20
  65. package/dist/components/auto-release.d.ts.map +1 -1
  66. package/dist/components/capability.d.ts +4 -4
  67. package/dist/components/cli-support.d.ts +24 -22
  68. package/dist/components/cli-support.d.ts.map +1 -1
  69. package/dist/components/component.d.ts +21 -6
  70. package/dist/components/component.d.ts.map +1 -1
  71. package/dist/components/driver-output.d.ts.map +1 -1
  72. package/dist/components/driver.d.ts +73 -37
  73. package/dist/components/driver.d.ts.map +1 -1
  74. package/dist/components/index.d.ts +1 -2
  75. package/dist/components/index.d.ts.map +1 -1
  76. package/dist/components/manifest-persistence.d.ts +1 -9
  77. package/dist/components/manifest-persistence.d.ts.map +1 -1
  78. package/dist/components/run-progress.d.ts +6 -6
  79. package/dist/components/run-progress.d.ts.map +1 -1
  80. package/dist/components/verbs/run-agent.d.ts +10 -22
  81. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  82. package/dist/components/verbs/verify.d.ts +2 -2
  83. package/dist/deep-observation.d.ts +17 -0
  84. package/dist/deep-observation.d.ts.map +1 -1
  85. package/dist/detectLexicon.d.ts +13 -0
  86. package/dist/detectLexicon.d.ts.map +1 -1
  87. package/dist/discovery/files.d.ts +4 -4
  88. package/dist/discovery/fold-import.d.ts.map +1 -1
  89. package/dist/discovery/param-deps.d.ts +33 -0
  90. package/dist/discovery/param-deps.d.ts.map +1 -1
  91. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  92. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  93. package/dist/fold/foldable-helpers.d.ts +5 -1
  94. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  95. package/dist/fold-provenance.d.ts +236 -0
  96. package/dist/fold-provenance.d.ts.map +1 -0
  97. package/dist/graph-ops.d.ts +1 -1
  98. package/dist/held-elsewhere.d.ts +85 -0
  99. package/dist/held-elsewhere.d.ts.map +1 -0
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/kubectl-context.d.ts +3 -3
  103. package/dist/lexicon-config.d.ts +4 -4
  104. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  105. package/dist/lexicon.d.ts +273 -16
  106. package/dist/lexicon.d.ts.map +1 -1
  107. package/dist/lifecycle/change-set.d.ts +13 -0
  108. package/dist/lifecycle/change-set.d.ts.map +1 -1
  109. package/dist/lifecycle/deep-diff.d.ts +133 -6
  110. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  111. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  112. package/dist/lifecycle/gate-ledger.d.ts +79 -3
  113. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  114. package/dist/lifecycle/index.d.ts +1 -0
  115. package/dist/lifecycle/index.d.ts.map +1 -1
  116. package/dist/lifecycle/release-ledger.d.ts +2 -2
  117. package/dist/lifecycle/run-ledger.d.ts +53 -0
  118. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  119. package/dist/lifecycle/symptoms.d.ts +3 -3
  120. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  121. package/dist/lint/config.d.ts +81 -2
  122. package/dist/lint/config.d.ts.map +1 -1
  123. package/dist/lint/post-synth.d.ts +55 -2
  124. package/dist/lint/post-synth.d.ts.map +1 -1
  125. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  126. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  127. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  128. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  129. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  130. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  131. package/dist/lint/rules/comp/index.d.ts +1 -1
  132. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  133. package/dist/lint/rules/op/index.d.ts +16 -0
  134. package/dist/lint/rules/op/index.d.ts.map +1 -0
  135. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  136. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  137. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  138. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  139. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  140. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  141. package/dist/lint/rules/op/support.d.ts +12 -0
  142. package/dist/lint/rules/op/support.d.ts.map +1 -0
  143. package/dist/lint/suppressions.d.ts +108 -0
  144. package/dist/lint/suppressions.d.ts.map +1 -0
  145. package/dist/live-endpoint.d.ts +1 -1
  146. package/dist/op/activities/activity-contracts.d.ts +54 -0
  147. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  148. package/dist/op/activities/apply.d.ts +262 -0
  149. package/dist/op/activities/apply.d.ts.map +1 -0
  150. package/dist/op/activities/build.d.ts +13 -0
  151. package/dist/op/activities/build.d.ts.map +1 -0
  152. package/dist/op/activities/converge.d.ts +110 -0
  153. package/dist/op/activities/converge.d.ts.map +1 -0
  154. package/dist/op/activities/env-teardown.d.ts +76 -0
  155. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  156. package/dist/op/activities/guard-validate.d.ts +64 -0
  157. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  158. package/dist/op/activities/http-check.d.ts +34 -0
  159. package/dist/op/activities/http-check.d.ts.map +1 -0
  160. package/dist/op/activities/index.d.ts +31 -0
  161. package/dist/op/activities/index.d.ts.map +1 -0
  162. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  163. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  164. package/dist/op/activities/lifecycle.d.ts +42 -0
  165. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  166. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  167. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  168. package/dist/op/activities/policy.d.ts +17 -0
  169. package/dist/op/activities/policy.d.ts.map +1 -0
  170. package/dist/op/activities/reconcile.d.ts +149 -0
  171. package/dist/op/activities/reconcile.d.ts.map +1 -0
  172. package/dist/op/activities/shell.d.ts +13 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -0
  174. package/dist/op/activities/teardown.d.ts +10 -0
  175. package/dist/op/activities/teardown.d.ts.map +1 -0
  176. package/dist/op/activities/util.d.ts +7 -0
  177. package/dist/op/activities/util.d.ts.map +1 -0
  178. package/dist/op/activities/wait.d.ts +28 -0
  179. package/dist/op/activities/wait.d.ts.map +1 -0
  180. package/dist/op/activities/workflow-audit.d.ts +92 -0
  181. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  182. package/dist/op/activity-contract-registry.d.ts +76 -0
  183. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  184. package/dist/op/activity-contract.d.ts +25 -18
  185. package/dist/op/activity-contract.d.ts.map +1 -1
  186. package/dist/op/activity-failure.d.ts +28 -0
  187. package/dist/op/activity-failure.d.ts.map +1 -0
  188. package/dist/op/activity-profiles.d.ts +118 -0
  189. package/dist/op/activity-profiles.d.ts.map +1 -0
  190. package/dist/op/activity-registry.d.ts +22 -38
  191. package/dist/op/activity-registry.d.ts.map +1 -1
  192. package/dist/op/activity-runtime.d.ts +3 -14
  193. package/dist/op/activity-runtime.d.ts.map +1 -1
  194. package/dist/op/builders.d.ts +85 -30
  195. package/dist/op/builders.d.ts.map +1 -1
  196. package/dist/op/change-signal.d.ts +91 -0
  197. package/dist/op/change-signal.d.ts.map +1 -0
  198. package/dist/op/composites/apply-op.d.ts +118 -0
  199. package/dist/op/composites/apply-op.d.ts.map +1 -0
  200. package/dist/op/composites/converge-op.d.ts +120 -0
  201. package/dist/op/composites/converge-op.d.ts.map +1 -0
  202. package/dist/op/composites/index.d.ts +26 -0
  203. package/dist/op/composites/index.d.ts.map +1 -0
  204. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  205. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  206. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  207. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  208. package/dist/op/composites/reconcile-op.d.ts +57 -0
  209. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  210. package/dist/op/composites/watch-op.d.ts +60 -0
  211. package/dist/op/composites/watch-op.d.ts.map +1 -0
  212. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  213. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  214. package/dist/op/converge-rule.d.ts +12 -10
  215. package/dist/op/converge-rule.d.ts.map +1 -1
  216. package/dist/op/cron.d.ts +51 -0
  217. package/dist/op/cron.d.ts.map +1 -0
  218. package/dist/op/discover.d.ts +9 -0
  219. package/dist/op/discover.d.ts.map +1 -1
  220. package/dist/op/duration.d.ts +11 -0
  221. package/dist/op/duration.d.ts.map +1 -0
  222. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  223. package/dist/op/gate-name.d.ts +40 -0
  224. package/dist/op/gate-name.d.ts.map +1 -0
  225. package/dist/op/gate-summary.d.ts +43 -0
  226. package/dist/op/gate-summary.d.ts.map +1 -0
  227. package/dist/op/gate.d.ts +90 -0
  228. package/dist/op/gate.d.ts.map +1 -0
  229. package/dist/op/generate-pipeline.d.ts +9 -0
  230. package/dist/op/generate-pipeline.d.ts.map +1 -1
  231. package/dist/op/index.d.ts +29 -9
  232. package/dist/op/index.d.ts.map +1 -1
  233. package/dist/op/local-executor.d.ts +114 -28
  234. package/dist/op/local-executor.d.ts.map +1 -1
  235. package/dist/op/local-output.d.ts +11 -1
  236. package/dist/op/local-output.d.ts.map +1 -1
  237. package/dist/op/op-ir.d.ts +185 -0
  238. package/dist/op/op-ir.d.ts.map +1 -0
  239. package/dist/op/op-verb-class.d.ts +10 -2
  240. package/dist/op/op-verb-class.d.ts.map +1 -1
  241. package/dist/op/operator.d.ts +93 -5
  242. package/dist/op/operator.d.ts.map +1 -1
  243. package/dist/op/receipt-store.d.ts +1 -1
  244. package/dist/op/receipt-store.d.ts.map +1 -1
  245. package/dist/op/resource.d.ts +15 -1
  246. package/dist/op/resource.d.ts.map +1 -1
  247. package/dist/op/runtime.d.ts +200 -0
  248. package/dist/op/runtime.d.ts.map +1 -0
  249. package/dist/op/runtimes/local.d.ts +29 -0
  250. package/dist/op/runtimes/local.d.ts.map +1 -0
  251. package/dist/op/step-output-ref.d.ts +15 -13
  252. package/dist/op/step-output-ref.d.ts.map +1 -1
  253. package/dist/op/types.d.ts +96 -29
  254. package/dist/op/types.d.ts.map +1 -1
  255. package/dist/ownership.d.ts +1 -1
  256. package/dist/provenance.d.ts +21 -0
  257. package/dist/provenance.d.ts.map +1 -1
  258. package/dist/serializer-walker.d.ts.map +1 -1
  259. package/dist/terraform/bridge.d.ts +26 -7
  260. package/dist/terraform/bridge.d.ts.map +1 -1
  261. package/dist/terraform/carve-provider.d.ts +28 -2
  262. package/dist/terraform/carve-provider.d.ts.map +1 -1
  263. package/dist/terraform/data-source-shape.d.ts +77 -0
  264. package/dist/terraform/data-source-shape.d.ts.map +1 -0
  265. package/dist/terraform/graph.d.ts.map +1 -1
  266. package/dist/terraform/providers/kubernetes.d.ts +5 -0
  267. package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
  268. package/dist/terraform/tier-map.d.ts +16 -4
  269. package/dist/terraform/tier-map.d.ts.map +1 -1
  270. package/dist/terraform/types.d.ts +8 -0
  271. package/dist/terraform/types.d.ts.map +1 -1
  272. package/package.json +6 -1
  273. package/src/audit/catalog.test.ts +79 -3
  274. package/src/audit/catalog.ts +111 -13
  275. package/src/audit/core.test.ts +26 -0
  276. package/src/audit/core.ts +84 -18
  277. package/src/audit/discover.test.ts +39 -0
  278. package/src/audit/discover.ts +202 -18
  279. package/src/audit/lineage.ts +100 -0
  280. package/src/audit/prior-art.ts +153 -0
  281. package/src/audit/proof.test.ts +67 -0
  282. package/src/audit/proof.ts +70 -0
  283. package/src/audit/report-html.ts +9 -4
  284. package/src/audit/report-model.ts +16 -2
  285. package/src/audit/report.test.ts +33 -0
  286. package/src/audit/report.ts +5 -3
  287. package/src/audit/rules-doc.test.ts +34 -2
  288. package/src/audit/rules-doc.ts +82 -9
  289. package/src/audit/secrets.ts +15 -3
  290. package/src/audit/terraform-state.test.ts +144 -0
  291. package/src/audit/terraform-state.ts +131 -0
  292. package/src/build.ts +31 -1
  293. package/src/claimed-fields.test.ts +145 -0
  294. package/src/claimed-fields.ts +208 -0
  295. package/src/cli/build-params-cli.ts +2 -2
  296. package/src/cli/command-group.ts +14 -0
  297. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  298. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  299. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  300. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  301. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  302. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  303. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  304. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  305. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  306. package/src/cli/commands/audit.test.ts +191 -11
  307. package/src/cli/commands/audit.ts +78 -28
  308. package/src/cli/commands/build.test.ts +330 -9
  309. package/src/cli/commands/build.ts +170 -24
  310. package/src/cli/commands/carve-bridge.test.ts +237 -14
  311. package/src/cli/commands/carve-bridge.ts +21 -17
  312. package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
  313. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  314. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  315. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  316. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  317. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  318. package/src/cli/commands/init-lexicon.test.ts +97 -2
  319. package/src/cli/commands/init-lexicon.ts +4 -2
  320. package/src/cli/commands/init.test.ts +35 -1
  321. package/src/cli/commands/init.ts +14 -3
  322. package/src/cli/commands/lint.test.ts +194 -1
  323. package/src/cli/commands/lint.ts +205 -7
  324. package/src/cli/commands/onboard.test.ts +75 -0
  325. package/src/cli/commands/onboard.ts +54 -23
  326. package/src/cli/handlers/build.test.ts +81 -1
  327. package/src/cli/handlers/build.ts +15 -1
  328. package/src/cli/handlers/graph.test.ts +3 -3
  329. package/src/cli/handlers/lifecycle.test.ts +195 -12
  330. package/src/cli/handlers/lifecycle.ts +123 -6
  331. package/src/cli/handlers/misc.ts +1 -1
  332. package/src/cli/handlers/operator.test.ts +183 -11
  333. package/src/cli/handlers/operator.ts +341 -55
  334. package/src/cli/handlers/run.test.ts +568 -1295
  335. package/src/cli/handlers/run.ts +446 -912
  336. package/src/cli/main.test.ts +22 -16
  337. package/src/cli/main.ts +66 -33
  338. package/src/cli/mcp/op-tools.ts +147 -88
  339. package/src/cli/mcp/resource-handlers.ts +10 -37
  340. package/src/cli/mcp/resources/context.ts +11 -12
  341. package/src/cli/mcp/server.test.ts +25 -27
  342. package/src/cli/mcp/server.ts +2 -2
  343. package/src/cli/plugins.test.ts +68 -2
  344. package/src/cli/plugins.ts +39 -0
  345. package/src/cli/registry.ts +40 -9
  346. package/src/codegen/docs.ts +1 -1
  347. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  348. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  349. package/src/components/README.md +4 -3
  350. package/src/components/__fixtures__/neo4j-fanout.json +1 -1
  351. package/src/components/auto-release.test.ts +4 -20
  352. package/src/components/auto-release.ts +17 -42
  353. package/src/components/capability.ts +4 -4
  354. package/src/components/cli-support.test.ts +28 -12
  355. package/src/components/cli-support.ts +60 -47
  356. package/src/components/component-schema.test.ts +18 -2
  357. package/src/components/component.schema.json +18 -5
  358. package/src/components/component.test.ts +2 -2
  359. package/src/components/component.ts +27 -7
  360. package/src/components/config-defaults.test.ts +2 -2
  361. package/src/components/driver-output.ts +14 -2
  362. package/src/components/driver.test.ts +109 -20
  363. package/src/components/driver.ts +201 -84
  364. package/src/components/index.ts +1 -6
  365. package/src/components/manifest-persistence.test.ts +2 -20
  366. package/src/components/manifest-persistence.ts +4 -24
  367. package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
  368. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  369. package/src/components/run-progress.ts +6 -6
  370. package/src/components/verbs/run-agent.test.ts +19 -0
  371. package/src/components/verbs/run-agent.ts +12 -24
  372. package/src/components/verbs/verify.ts +2 -2
  373. package/src/deep-observation.test.ts +75 -0
  374. package/src/deep-observation.ts +48 -0
  375. package/src/detectLexicon.ts +18 -1
  376. package/src/discovery/collect.test.ts +3 -3
  377. package/src/discovery/files.ts +4 -4
  378. package/src/discovery/fold-import.test.ts +1 -1
  379. package/src/discovery/fold-import.ts +105 -2
  380. package/src/discovery/param-deps.test.ts +112 -1
  381. package/src/discovery/param-deps.ts +193 -0
  382. package/src/discovery/sandbox/bundle.ts +15 -1
  383. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  384. package/src/discovery/sandbox/config-wire.ts +2 -2
  385. package/src/fold/fold.test.ts +56 -0
  386. package/src/fold/foldable-helpers.ts +82 -2
  387. package/src/fold-provenance-exclusion.test.ts +186 -0
  388. package/src/fold-provenance.test.ts +495 -0
  389. package/src/fold-provenance.ts +441 -0
  390. package/src/graph-ops.test.ts +3 -3
  391. package/src/graph-ops.ts +1 -1
  392. package/src/held-elsewhere.test.ts +102 -0
  393. package/src/held-elsewhere.ts +114 -0
  394. package/src/index.ts +3 -0
  395. package/src/kubectl-context.ts +3 -3
  396. package/src/lexicon-config.test.ts +5 -5
  397. package/src/lexicon-config.ts +4 -4
  398. package/src/lexicon-plugin-helpers.ts +1 -1
  399. package/src/lexicon.ts +296 -16
  400. package/src/lifecycle/change-set.test.ts +49 -0
  401. package/src/lifecycle/change-set.ts +67 -0
  402. package/src/lifecycle/converge-ledger.ts +1 -1
  403. package/src/lifecycle/deep-diff.test.ts +267 -14
  404. package/src/lifecycle/deep-diff.ts +217 -14
  405. package/src/lifecycle/deep-observe.test.ts +3 -1
  406. package/src/lifecycle/deep-observe.ts +16 -6
  407. package/src/lifecycle/gate-ledger.test.ts +74 -2
  408. package/src/lifecycle/gate-ledger.ts +154 -36
  409. package/src/lifecycle/index.ts +1 -0
  410. package/src/lifecycle/release-ledger.ts +2 -2
  411. package/src/lifecycle/run-ledger.test.ts +268 -0
  412. package/src/lifecycle/run-ledger.ts +201 -0
  413. package/src/lifecycle/symptoms.ts +3 -3
  414. package/src/lint/config.test.ts +82 -1
  415. package/src/lint/config.ts +112 -3
  416. package/src/lint/pipeline-change-gate.test.ts +2 -2
  417. package/src/lint/policy.test.ts +1 -1
  418. package/src/lint/post-synth.test.ts +31 -0
  419. package/src/lint/post-synth.ts +54 -1
  420. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  421. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  422. package/src/lint/rules/comp/comp.test.ts +27 -1
  423. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
  424. package/src/lint/rules/comp/index.ts +3 -3
  425. package/src/lint/rules/op/index.ts +23 -0
  426. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  427. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  428. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  429. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  430. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  431. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  432. package/src/lint/rules/op/support.ts +11 -0
  433. package/src/lint/suppressions.test.ts +163 -0
  434. package/src/lint/suppressions.ts +204 -0
  435. package/src/live-endpoint.ts +1 -1
  436. package/src/op/activities/activity-contracts.ts +66 -0
  437. package/src/op/activities/apply.test.ts +567 -0
  438. package/src/op/activities/apply.ts +662 -0
  439. package/src/op/activities/build.ts +26 -0
  440. package/src/op/activities/converge.test.ts +330 -0
  441. package/src/op/activities/converge.ts +449 -0
  442. package/src/op/activities/env-teardown.test.ts +187 -0
  443. package/src/op/activities/env-teardown.ts +171 -0
  444. package/src/op/activities/guard-validate.test.ts +139 -0
  445. package/src/op/activities/guard-validate.ts +223 -0
  446. package/src/op/activities/http-check.test.ts +48 -0
  447. package/src/op/activities/http-check.ts +55 -0
  448. package/src/op/activities/index.ts +119 -0
  449. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  450. package/src/op/activities/lexicon-upgrade.ts +673 -0
  451. package/src/op/activities/lifecycle.ts +85 -0
  452. package/src/op/activities/pipeline-audit.test.ts +67 -0
  453. package/src/op/activities/pipeline-audit.ts +201 -0
  454. package/src/op/activities/policy.test.ts +19 -0
  455. package/src/op/activities/policy.ts +37 -0
  456. package/src/op/activities/reconcile.test.ts +161 -0
  457. package/src/op/activities/reconcile.ts +354 -0
  458. package/src/op/activities/shell.ts +26 -0
  459. package/src/op/activities/teardown.ts +22 -0
  460. package/src/op/activities/util.ts +6 -0
  461. package/src/op/activities/wait.ts +69 -0
  462. package/src/op/activities/workflow-audit.test.ts +90 -0
  463. package/src/op/activities/workflow-audit.ts +203 -0
  464. package/src/op/activity-contract-registry.test.ts +98 -0
  465. package/src/op/activity-contract-registry.ts +114 -0
  466. package/src/op/activity-contract.test.ts +1 -1
  467. package/src/op/activity-contract.ts +37 -33
  468. package/src/op/activity-failure.ts +34 -0
  469. package/src/op/activity-profiles.test.ts +56 -0
  470. package/src/op/activity-profiles.ts +116 -0
  471. package/src/op/activity-registry.test.ts +37 -28
  472. package/src/op/activity-registry.ts +27 -56
  473. package/src/op/activity-runtime.ts +3 -47
  474. package/src/op/builders-exports.test.ts +0 -49
  475. package/src/op/builders-typed.test.ts +164 -0
  476. package/src/op/builders.ts +125 -41
  477. package/src/op/change-signal.test.ts +117 -0
  478. package/src/op/change-signal.ts +169 -0
  479. package/src/op/composites/apply-op.ts +218 -0
  480. package/src/op/composites/composites.test.ts +379 -0
  481. package/src/op/composites/converge-op.test.ts +168 -0
  482. package/src/op/composites/converge-op.ts +214 -0
  483. package/src/op/composites/index.ts +26 -0
  484. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  485. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  486. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  487. package/src/op/composites/pipeline-audit-op.ts +78 -0
  488. package/src/op/composites/reconcile-op.test.ts +51 -0
  489. package/src/op/composites/reconcile-op.ts +110 -0
  490. package/src/op/composites/watch-op.ts +108 -0
  491. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  492. package/src/op/composites/workflow-audit-op.ts +88 -0
  493. package/src/op/converge-rule.ts +12 -10
  494. package/src/op/cron.test.ts +128 -0
  495. package/src/op/cron.ts +149 -0
  496. package/src/op/discover-root.test.ts +105 -1
  497. package/src/op/discover.test.ts +6 -2
  498. package/src/op/discover.ts +84 -16
  499. package/src/op/duration.ts +21 -0
  500. package/src/op/effect-step.test.ts +29 -14
  501. package/src/op/emulator-lifecycle.ts +1 -2
  502. package/src/op/gate-name.test.ts +65 -0
  503. package/src/op/gate-name.ts +60 -0
  504. package/src/op/gate-summary.ts +84 -0
  505. package/src/op/gate.ts +155 -0
  506. package/src/op/generate-pipeline.test.ts +65 -3
  507. package/src/op/generate-pipeline.ts +19 -2
  508. package/src/op/index.ts +48 -8
  509. package/src/op/local-executor.test.ts +178 -34
  510. package/src/op/local-executor.ts +371 -102
  511. package/src/op/local-output.test.ts +95 -11
  512. package/src/op/local-output.ts +33 -4
  513. package/src/op/op-ir.test.ts +292 -0
  514. package/src/op/op-ir.ts +419 -0
  515. package/src/op/op-verb-class.test.ts +2 -2
  516. package/src/op/op-verb-class.ts +19 -5
  517. package/src/op/op.test.ts +28 -7
  518. package/src/op/operator.test.ts +543 -6
  519. package/src/op/operator.ts +203 -20
  520. package/src/op/receipt-store.ts +1 -1
  521. package/src/op/resource.ts +20 -2
  522. package/src/op/runtime.ts +203 -0
  523. package/src/op/runtimes/local.test.ts +181 -0
  524. package/src/op/runtimes/local.ts +212 -0
  525. package/src/op/step-output-ref.ts +15 -13
  526. package/src/op/types.ts +106 -26
  527. package/src/ownership.ts +1 -1
  528. package/src/provenance.test.ts +6 -0
  529. package/src/provenance.ts +21 -1
  530. package/src/serializer-walker.test.ts +42 -0
  531. package/src/serializer-walker.ts +21 -2
  532. package/src/terraform/aws-resources.test.ts +13 -4
  533. package/src/terraform/bridge.test.ts +22 -9
  534. package/src/terraform/bridge.ts +89 -28
  535. package/src/terraform/carve-provider.ts +38 -2
  536. package/src/terraform/data-source-shape.ts +95 -0
  537. package/src/terraform/graph.ts +35 -7
  538. package/src/terraform/providers/kubernetes.ts +48 -2
  539. package/src/terraform/tier-map.ts +21 -6
  540. package/src/terraform/types.ts +8 -0
  541. package/dist/cli/handlers/op-progress.d.ts +0 -90
  542. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  543. package/dist/cli/handlers/run-client.d.ts +0 -127
  544. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  545. package/dist/cli/handlers/run-report.d.ts +0 -5
  546. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  547. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  548. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  549. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  550. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  551. package/src/cli/handlers/op-progress.test.ts +0 -268
  552. package/src/cli/handlers/op-progress.ts +0 -248
  553. package/src/cli/handlers/run-client.test.ts +0 -82
  554. package/src/cli/handlers/run-client.ts +0 -219
  555. package/src/cli/handlers/run-report.test.ts +0 -62
  556. package/src/cli/handlers/run-report.ts +0 -122
  557. package/src/components/temporal-codegen-loader.ts +0 -41
  558. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -950,19 +950,21 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
950
950
  });
951
951
  });
952
952
 
953
- test("op worker files go to <project>/dist/ops even with no --output (#878)", async () => {
954
- // The generated Op worker must land where `chant run <op> --temporal` reads it
955
- // (`<project>/dist/ops/<name>/worker.ts`) even when the build has no --output
956
- // (a Temporal Op project often has no primary resource manifest to route).
953
+ test("serializer files under ops/ go to <project>/dist/ops even with no --output (#878)", async () => {
954
+ // Whatever a serializer emits under `ops/` must land in
955
+ // `<project>/dist/ops/<name>/`, beside the `op.json` core writes there,
956
+ // even when the build has no --output (an Op-only project often has no
957
+ // primary resource manifest to route). The routing is on the `ops/`
958
+ // prefix alone — it does not know or care what the files are.
957
959
  const opSerializer: Serializer = {
958
960
  name: "multi",
959
961
  rulePrefix: "MULTI",
960
962
  serialize: () => ({
961
963
  primary: "{}",
962
964
  files: {
963
- "ops/durable-hello/workflow.ts": "// workflow\n",
964
- "ops/durable-hello/worker.ts": "// worker\n",
965
- "ops/durable-hello/activities.ts": "// activities\n",
965
+ "ops/nightly-report/steps.json": "{}\n",
966
+ "ops/nightly-report/notes.md": "# notes\n",
967
+ "ops/nightly-report/nested/extra.txt": "extra\n",
966
968
  },
967
969
  }),
968
970
  };
@@ -979,8 +981,31 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
979
981
  } as BuildOptions);
980
982
 
981
983
  expect(result.errors).toEqual([]);
982
- expect(existsSync(join(testDir, "dist", "ops", "durable-hello", "worker.ts"))).toBe(true);
983
- expect(existsSync(join(testDir, "dist", "ops", "durable-hello", "workflow.ts"))).toBe(true);
984
+ expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "steps.json"))).toBe(true);
985
+ expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "notes.md"))).toBe(true);
986
+ expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "nested", "extra.txt"))).toBe(true);
987
+ });
988
+
989
+ test("an Op entity emits dist/ops/<name>/op.json from core, with no serializer involved (#2118)", async () => {
990
+ await writeFile(
991
+ join(testDir, "deploy.op.ts"),
992
+ `export default { [Symbol.for("chant.declarable")]: true, entityType: "Chant::Op", lexicon: "chant", kind: "resource", attributes: {},` +
993
+ ` props: { name: "deploy", overview: "Deploy the thing", labels: { Env: "staging" },` +
994
+ ` phases: [{ name: "Apply", steps: [{ kind: "activity", fn: "shellCmd", args: { cmd: "true" } }] }] } };`,
995
+ );
996
+
997
+ const result = await buildCommand({ path: testDir, format: "json", serializers: [] } as BuildOptions);
998
+
999
+ expect(result.errors).toEqual([]);
1000
+ const ir = JSON.parse(readFileSync(join(testDir, "dist", "ops", "deploy", "op.json"), "utf-8"));
1001
+ expect(ir.formatVersion).toBe("2.0");
1002
+ expect(ir.name).toBe("deploy");
1003
+ expect(ir.labels).toEqual({ Env: "staging" });
1004
+ expect(ir).not.toHaveProperty("taskQueue");
1005
+ expect(ir.phases[0].steps[0]).toMatchObject({ kind: "activity", fn: "shellCmd", profile: "fastIdempotent" });
1006
+ // Ops are held out of `partitionByLexicon` (they have no serializer and
1007
+ // need none), so core's own `chant` lexicon never trips the warning.
1008
+ expect(result.warnings.filter((w) => w.includes("No serializer"))).toEqual([]);
984
1009
  });
985
1010
 
986
1011
  // ── #284 bug 2: array-of-objects must serialize to valid YAML ──────────
@@ -1219,6 +1244,302 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
1219
1244
  30_000,
1220
1245
  );
1221
1246
  });
1247
+
1248
+ describe("post-synth findings honor inline chant-ignore comments (chant #2111)", () => {
1249
+ /**
1250
+ * A discovered entity carrying a `suppressions` directive by hand, the
1251
+ * generic, duck-typed field `applyInlineSuppressions` reads (see
1252
+ * `../../lint/suppressions.ts`'s module doc). The terraform lexicon
1253
+ * populates this from real `# chant-ignore*` HCL comments
1254
+ * (`lexicons/terraform/src/hcl/suppressions.ts`); this test proves the
1255
+ * core wiring, that `chant build` applies it to ANY lexicon's entities,
1256
+ * without needing a real HCL parse.
1257
+ */
1258
+ async function writeSuppressibleEntity(ids: string): Promise<void> {
1259
+ await writeFile(
1260
+ join(testDir, "main.ts"),
1261
+ `export const e = {\n` +
1262
+ ` lexicon: "test",\n` +
1263
+ ` entityType: "TestEntity",\n` +
1264
+ ` [Symbol.for("chant.declarable")]: true,\n` +
1265
+ ` suppressions: [{ form: "chant-ignore", ids: new Set(${JSON.stringify(ids.split(","))}), file: "main.ts", line: 1, key: "main.ts:1:chant-ignore" }],\n` +
1266
+ `};\n`,
1267
+ );
1268
+ }
1269
+
1270
+ /** Same shape as `fakePostSynthPlugin` above, except its check attaches `entity` to whatever entity the build discovered, so a suppression directive on that entity has something to match against. */
1271
+ function fakeEntitySuppressionPlugin(checkId: string, severity: "error" | "warning" | "info"): LexiconPlugin {
1272
+ return {
1273
+ name: "fake",
1274
+ serializer: { name: "fake", rulePrefix: "FAKE", serialize: () => "{}" },
1275
+ generate: async () => {},
1276
+ validate: async () => {},
1277
+ coverage: async () => {},
1278
+ package: async () => {},
1279
+ postSynthChecks: () => [
1280
+ {
1281
+ id: checkId,
1282
+ description: "test check",
1283
+ check: (ctx) => {
1284
+ const [key] = [...ctx.entities.keys()];
1285
+ return key ? [{ checkId, severity, message: `${checkId} triggered`, entity: key }] : [];
1286
+ },
1287
+ },
1288
+ ],
1289
+ };
1290
+ }
1291
+
1292
+ test("an inline chant-ignore naming the finding's checkId suppresses it and reports a suppressed count", async () => {
1293
+ await writeSuppressibleEntity("FAKE005");
1294
+ await writeFile(join(testDir, "chant.config.ts"), `export default {};\n`);
1295
+
1296
+ const result = await buildCommand({
1297
+ path: testDir,
1298
+ format: "json",
1299
+ serializers: [mockSerializer],
1300
+ plugins: [fakeEntitySuppressionPlugin("FAKE005", "error")],
1301
+ });
1302
+
1303
+ expect(result.success).toBe(true);
1304
+ expect(result.errors).toEqual([]);
1305
+ expect(result.warnings.some((w) => w.includes("1 post-synth finding(s) suppressed via inline chant-ignore comments"))).toBe(true);
1306
+ });
1307
+
1308
+ test("an inline chant-ignore naming a different id has no effect", async () => {
1309
+ await writeSuppressibleEntity("FAKE006");
1310
+ await writeFile(join(testDir, "chant.config.ts"), `export default {};\n`);
1311
+
1312
+ const result = await buildCommand({
1313
+ path: testDir,
1314
+ format: "json",
1315
+ serializers: [mockSerializer],
1316
+ plugins: [fakeEntitySuppressionPlugin("FAKE007", "error")],
1317
+ });
1318
+
1319
+ expect(result.success).toBe(false);
1320
+ expect(result.errors.some((e) => e.includes("FAKE007 triggered"))).toBe(true);
1321
+ expect(result.warnings.some((w) => w.includes("suppressed"))).toBe(false);
1322
+ });
1323
+
1324
+ test("ignorable: false in lint.rules denies the ignore and reports the attempt, keeping the finding active", async () => {
1325
+ await writeSuppressibleEntity("FAKE008");
1326
+ await writeFile(
1327
+ join(testDir, "chant.config.ts"),
1328
+ `export default { lint: { rules: { "FAKE008": ["error", { ignorable: false }] } } };\n`,
1329
+ );
1330
+
1331
+ const result = await buildCommand({
1332
+ path: testDir,
1333
+ format: "json",
1334
+ serializers: [mockSerializer],
1335
+ plugins: [fakeEntitySuppressionPlugin("FAKE008", "error")],
1336
+ });
1337
+
1338
+ expect(result.success).toBe(false);
1339
+ expect(result.errors.some((e) => e.includes("FAKE008 triggered"))).toBe(true);
1340
+ expect(result.warnings.some((w) => w.includes("SUPP003") && w.includes("ignorable: false"))).toBe(true);
1341
+ });
1342
+ });
1343
+
1344
+ /**
1345
+ * chant #2113: `lint.presets` filters WHICH post-synth check ids are
1346
+ * reported at all, ahead of `lint.rules`' severity overrides (proven
1347
+ * above). A plugin with no `lintPresets()` is unaffected (the common case
1348
+ * today); one that ships presets defaults to `recommended` and is
1349
+ * overridden per-lexicon via `lint.presets: { <name>: "<preset>" }`.
1350
+ */
1351
+ describe("post-synth findings honor lint.presets (chant #2113)", () => {
1352
+ async function writeTrivialEntity(): Promise<void> {
1353
+ await writeFile(
1354
+ join(testDir, "main.ts"),
1355
+ `export const e = { lexicon: "test", entityType: "TestEntity", [Symbol.for("chant.declarable")]: true };\n`,
1356
+ );
1357
+ }
1358
+
1359
+ /** A `LexiconPlugin` whose one post-synth check always fires, with `recommended`/`all` presets. `recommended` excludes the check's own id, `all` includes it. */
1360
+ function fakePresetPlugin(): LexiconPlugin {
1361
+ return {
1362
+ name: "fakepreset",
1363
+ serializer: { name: "fakepreset", rulePrefix: "FP", serialize: () => "{}" },
1364
+ generate: async () => {},
1365
+ validate: async () => {},
1366
+ coverage: async () => {},
1367
+ package: async () => {},
1368
+ postSynthChecks: () => [
1369
+ {
1370
+ id: "FP001",
1371
+ description: "a report-only check, always fires",
1372
+ check: () => [{ checkId: "FP001", severity: "warning" as const, message: "FP001 triggered" }],
1373
+ },
1374
+ ],
1375
+ lintPresets: () => ({ recommended: [], all: ["FP001"] }),
1376
+ };
1377
+ }
1378
+
1379
+ test("with no lint.presets config, the default preset (recommended) excludes the finding", async () => {
1380
+ await writeTrivialEntity();
1381
+ const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
1382
+ expect(result.warnings.join("\n")).not.toContain("FP001 triggered");
1383
+ expect(result.warnings.some((w) => w.includes("not reported: excluded by the active lint.presets preset"))).toBe(true);
1384
+ });
1385
+
1386
+ test('lint.presets: { fakepreset: "all" } includes the finding', async () => {
1387
+ await writeTrivialEntity();
1388
+ await writeFile(
1389
+ join(testDir, "chant.config.ts"),
1390
+ `export default { lint: { presets: { fakepreset: "all" } } };\n`,
1391
+ );
1392
+ const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
1393
+ expect(result.warnings.join("\n")).toContain("FP001 triggered");
1394
+ });
1395
+
1396
+ test("an explicit lint.rules entry re-enables the rule even under the excluding (recommended) preset", async () => {
1397
+ await writeTrivialEntity();
1398
+ await writeFile(
1399
+ join(testDir, "chant.config.ts"),
1400
+ `export default { lint: { rules: { "FP001": "warning" } } };\n`,
1401
+ );
1402
+ const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
1403
+ expect(result.warnings.join("\n")).toContain("FP001 triggered");
1404
+ });
1405
+ });
1406
+ });
1407
+
1408
+ // #2122 (epic #2114 sub-issue 6) — OPS012/OPS013/OPS014 are core-owned
1409
+ // post-synth checks over the Op model, run unscoped by `coreOpChecks()`
1410
+ // regardless of which plugins/lexicons are configured. This is the
1411
+ // end-to-end path acceptance criterion 3 needs: `chant build` over a real
1412
+ // ConvergeOp-shaped fixture with a destructive gated dispatch rule fails
1413
+ // with the OPS014 refusal, with zero plugins/lexicons loaded.
1414
+ describe("buildCommand — OPS014 (op-model post-synth checks, #2122)", () => {
1415
+ let testDir: string;
1416
+
1417
+ const mockSerializer: Serializer = {
1418
+ name: "test",
1419
+ rulePrefix: "TEST",
1420
+ serialize: (entities) => JSON.stringify({ resources: [...entities.keys()] }, null, 2),
1421
+ };
1422
+
1423
+ beforeEach(async () => {
1424
+ testDir = join(tmpdir(), `chant-ops014-test-${Date.now()}-${Math.random()}`);
1425
+ await mkdir(testDir, { recursive: true });
1426
+ });
1427
+
1428
+ afterEach(async () => {
1429
+ await rm(testDir, { recursive: true, force: true });
1430
+ });
1431
+
1432
+ test("fails build with the OPS014 refusal on a ConvergeOp dispatching a destructive, gated op", async () => {
1433
+ // The destructive dispatch target: a gated `nativeApply` with
1434
+ // `deleteMode: "gated"` — classified destructive by
1435
+ // `../../op/op-verb-class.ts`, gate or not.
1436
+ await writeFile(
1437
+ join(testDir, "prune-staging.op.ts"),
1438
+ `
1439
+ export const pruneStaging = {
1440
+ [Symbol.for("chant.declarable")]: true,
1441
+ entityType: "Chant::Op",
1442
+ lexicon: "chant",
1443
+ kind: "resource",
1444
+ props: {
1445
+ name: "prune-staging",
1446
+ overview: "test",
1447
+ phases: [
1448
+ { name: "Approve", steps: [{ kind: "gate", gate: "approve-x" }] },
1449
+ { name: "Apply", steps: [
1450
+ { kind: "activity", fn: "nativeApply", args: { target: "kubectl", env: "staging", output: "dist", deleteMode: "gated" } },
1451
+ ] },
1452
+ ],
1453
+ },
1454
+ };
1455
+ `,
1456
+ );
1457
+
1458
+ // The ConvergeOp-shaped Op: dial "apply", one rule dispatching the
1459
+ // destructive target above.
1460
+ await writeFile(
1461
+ join(testDir, "converge.op.ts"),
1462
+ `
1463
+ export const converge = {
1464
+ [Symbol.for("chant.declarable")]: true,
1465
+ entityType: "Chant::Op",
1466
+ lexicon: "chant",
1467
+ kind: "resource",
1468
+ props: {
1469
+ name: "converge",
1470
+ overview: "test",
1471
+ labels: { Converge: "true", Env: "staging", Dial: "apply" },
1472
+ phases: [
1473
+ { name: "Observe", steps: [{ kind: "activity", fn: "lifecycleDiff", args: { env: "staging" }, id: "diff" }] },
1474
+ { name: "Converge", steps: [{ kind: "activity", fn: "convergeTick", args: { rules: [
1475
+ {
1476
+ id: "drift-prune",
1477
+ when: { kind: "field-comparison", field: "status", op: "eq", value: "drifted" },
1478
+ then: { kind: "run", op: "prune-staging" },
1479
+ why: "Prune drifted resources.",
1480
+ },
1481
+ ] } }] },
1482
+ ],
1483
+ },
1484
+ };
1485
+ `,
1486
+ );
1487
+
1488
+ const result = await buildCommand({
1489
+ path: testDir,
1490
+ format: "json",
1491
+ serializers: [mockSerializer],
1492
+ plugins: [],
1493
+ });
1494
+
1495
+ expect(result.success).toBe(false);
1496
+ // build.ts's plain error strings carry the diagnostic's message text, not
1497
+ // its checkId — OPS014's own message names what it refused and why (see
1498
+ // ../../lint/rules/op/ops014-converge-rule-refusals.ts).
1499
+ expect(
1500
+ result.errors.some(
1501
+ (e) => e.includes("destructive") && e.includes("prune-staging") && e.includes("refused in v1"),
1502
+ ),
1503
+ ).toBe(true);
1504
+ });
1505
+
1506
+ // #2202: a gate step spelling its name `signalName` still builds, and the
1507
+ // build says so once, naming the Ops involved rather than each gate step.
1508
+ test("warns once, naming the Ops, when a gate step still uses the deprecated `signalName` key", async () => {
1509
+ const opFile = (name: string): string => `
1510
+ export const ${name.replace(/-/g, "")} = {
1511
+ [Symbol.for("chant.declarable")]: true,
1512
+ entityType: "Chant::Op",
1513
+ lexicon: "chant",
1514
+ kind: "resource",
1515
+ props: {
1516
+ name: "${name}",
1517
+ overview: "test",
1518
+ phases: [{ name: "Approve", steps: [{ kind: "gate", signalName: "approve-x" }] }],
1519
+ },
1520
+ };
1521
+ `;
1522
+ await writeFile(join(testDir, "old-a.op.ts"), opFile("old-a"));
1523
+ await writeFile(join(testDir, "old-b.op.ts"), opFile("old-b"));
1524
+ await writeFile(
1525
+ join(testDir, "new-c.op.ts"),
1526
+ opFile("new-c").replace("signalName", "gate"),
1527
+ );
1528
+
1529
+ const result = await buildCommand({
1530
+ path: testDir,
1531
+ format: "json",
1532
+ serializers: [mockSerializer],
1533
+ plugins: [],
1534
+ });
1535
+
1536
+ const deprecation = result.warnings.filter((w) => w.includes("signalName"));
1537
+ expect(deprecation).toHaveLength(1);
1538
+ expect(deprecation[0]).toContain("old-a");
1539
+ expect(deprecation[0]).toContain("old-b");
1540
+ expect(deprecation[0]).not.toContain("new-c");
1541
+ expect(deprecation[0]).toContain("0.60.0");
1542
+ });
1222
1543
  });
1223
1544
 
1224
1545
  // ── #284 bug 1: -o extension drives format when --format is absent ────────
@@ -14,11 +14,19 @@ import type { OwnershipMarker } from "../../ownership";
14
14
  import { resolveCliBuildParams } from "../build-params-cli";
15
15
  import type { Serializer, SerializerResult } from "../../serializer";
16
16
  import type { LexiconPlugin } from "../../lexicon";
17
- import { runPostSynthChecks } from "../../lint/post-synth";
17
+ import { runPostSynthChecks, type PostSynthDiagnostic } from "../../lint/post-synth";
18
+ import { loadActivityContracts } from "../../op/activity-contract-registry";
19
+ import { isOpEntity } from "../../op/resource";
20
+ import { serializeOpIR } from "../../op/op-ir";
21
+ import { opUsesDeprecatedGateKey, DEPRECATED_GATE_KEY_WARNING } from "../../op/gate-name";
22
+ import type { OpConfig } from "../../op/types";
18
23
  import { coreReceiptChecks } from "../../lint/receipt-checks";
19
24
  import { coreOutputChecks } from "../../lint/output-checks";
20
25
  import { coreKnowledgeChecks } from "../../lint/knowledge-checks";
21
- import { applyConfiguredSeverity } from "../../lint/config";
26
+ import { applyConfiguredSeverity, applyConfiguredPreset, resolvePresetIds } from "../../lint/config";
27
+ import { applyInlineSuppressions, type SuppressionMetaFinding } from "../../lint/suppressions";
28
+ import type { Declarable } from "../../declarable";
29
+ import { coreOpChecks } from "../../lint/rules/op";
22
30
  import { loadPolicyChecks } from "../../lint/policy";
23
31
  import { armSandboxPolicyExecution, runProjectPolicies } from "../../lint/policy-sandbox";
24
32
  import { sortedJsonReplacer } from "../../utils";
@@ -392,7 +400,46 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
392
400
  // rule id — so `lint.rules: { WAW019: "off" }` suppresses a post-synth
393
401
  // finding just as it suppresses a pre-synth one. A finding it suppresses is
394
402
  // counted, not dropped silently — see `suppressedPostSynthCount` below.
403
+ //
404
+ // chant #2111: every batch also goes through `applyInlineSuppressions`
405
+ // right after, so a `# chant-ignore` comment on an entity (terraform's HCL
406
+ // blocks today; any lexicon that attaches `suppressions` to its own
407
+ // entities tomorrow) suppresses identically regardless of which phase
408
+ // produced the diagnostic. Same counted-not-dropped contract, in its own
409
+ // `inlineSuppressedCount`, plus `suppressionMeta` for directives that are
410
+ // themselves worth a finding (expired, misplaced, denied by `ignorable: false`).
395
411
  let suppressedPostSynthCount = 0;
412
+ let inlineSuppressedCount = 0;
413
+ const suppressionMeta: SuppressionMetaFinding[] = [];
414
+ // A rule a `lint.presets` preset excludes (chant #2113) is a distinct
415
+ // reason a finding doesn't reach the errors/warnings lists. The preset
416
+ // decided the rule shouldn't run at all under this project's configured
417
+ // tier, not that `lint.rules` downgraded it to "off", so it gets its own
418
+ // counter and its own summary line rather than folding into the one above.
419
+ let suppressedPresetCount = 0;
420
+
421
+ /**
422
+ * Apply every suppression/filtering surface to one batch, in order:
423
+ * `lint.presets` (chant #2113, which check ids are enabled at all; a
424
+ * no-op when `presetIds` is undefined, the case for every call site below
425
+ * except the per-plugin loop, which is the only one with a lexicon a
426
+ * preset could apply to), then `lint.rules` severity overrides (chant
427
+ * #1138), then inline `# chant-ignore` comments (chant #2111).
428
+ */
429
+ const resolvePostSynth = (
430
+ diags: PostSynthDiagnostic[],
431
+ entities: Map<string, Declarable>,
432
+ presetIds?: Set<string>,
433
+ ): PostSynthDiagnostic[] => {
434
+ const { diagnostics: afterPreset, suppressed: presetSuppressed } = applyConfiguredPreset(diags, presetIds, config.lint?.rules);
435
+ suppressedPresetCount += presetSuppressed.length;
436
+ const { diagnostics: afterConfig, suppressed: configSuppressed } = applyConfiguredSeverity(afterPreset, config.lint?.rules);
437
+ suppressedPostSynthCount += configSuppressed.length;
438
+ const { diagnostics: active, suppressed: inlineSuppressed, meta } = applyInlineSuppressions(afterConfig, entities, config.lint?.rules);
439
+ inlineSuppressedCount += inlineSuppressed.length;
440
+ suppressionMeta.push(...meta);
441
+ return active;
442
+ };
396
443
 
397
444
  // Core-owned post-synth checks over effect receipts (#1833). Receipts are
398
445
  // recognized by marker, lexicon-independently, so this set runs over the
@@ -400,9 +447,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
400
447
  // Same severity-resolution funnel as every other post-synth finding.
401
448
  if (result.errors.length === 0) {
402
449
  const receiptDiags = runPostSynthChecks(coreReceiptChecks(), result, env);
403
- const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(receiptDiags, config.lint?.rules);
404
- suppressedPostSynthCount += suppressed.length;
405
- for (const diag of activeDiags) {
450
+ for (const diag of resolvePostSynth(receiptDiags, result.entities)) {
406
451
  const prefix = diag.entity ? `[${diag.entity}] ` : "";
407
452
  const lexiconSuffix = diag.lexicon ? ` (${diag.lexicon})` : "";
408
453
  if (diag.severity === "error") {
@@ -419,9 +464,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
419
464
  // the FULL build result the same way the receipt checks above do.
420
465
  if (result.errors.length === 0) {
421
466
  const outputDiags = runPostSynthChecks(coreOutputChecks(), result, env);
422
- const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(outputDiags, config.lint?.rules);
423
- suppressedPostSynthCount += suppressed.length;
424
- for (const diag of activeDiags) {
467
+ for (const diag of resolvePostSynth(outputDiags, result.entities)) {
425
468
  const prefix = diag.entity ? `[${diag.entity}] ` : "";
426
469
  const lexiconSuffix = diag.lexicon ? ` (${diag.lexicon})` : "";
427
470
  if (diag.severity === "error") {
@@ -440,7 +483,36 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
440
483
  if (result.errors.length === 0) {
441
484
  const bundle = await loadOkfBundle(resolveKnowledgeDir(config, configDir));
442
485
  const knowledgeDiags = runPostSynthChecks(coreKnowledgeChecks(bundle), result, env);
443
- const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(knowledgeDiags, config.lint?.rules);
486
+ for (const diag of resolvePostSynth(knowledgeDiags, result.entities)) {
487
+ const prefix = diag.entity ? `[${diag.entity}] ` : "";
488
+ const lexiconSuffix = diag.lexicon ? ` (${diag.lexicon})` : "";
489
+ if (diag.severity === "error") {
490
+ errors.push(formatError({ message: `${prefix}${diag.message}${lexiconSuffix}` }));
491
+ } else {
492
+ warnings.push(formatWarning({ message: `${prefix}${diag.message}${lexiconSuffix}` }));
493
+ }
494
+ }
495
+ }
496
+
497
+ // Activity contracts across every loaded lexicon (chant #2101): core's own
498
+ // plus each lexicon's, by the same `@intentius/chant-lexicon-<name>/op/...`
499
+ // convention `loadActivities` resolves implementations with. OPS012/OPS013
500
+ // and a plugin's own checks merge this over their own tables, so a step
501
+ // calling a lexicon's activity is validated against that lexicon's contract
502
+ // instead of failing for the absence of one. Resolved once, for both check
503
+ // passes below.
504
+ const activityContracts =
505
+ result.errors.length === 0 ? await loadActivityContracts(options.plugins ?? []) : undefined;
506
+
507
+ // Core-owned post-synth checks over the Op model (#2122, epic #2114
508
+ // sub-issue 6) — OPS012/OPS013/OPS014, ported from a hosting lexicon's
509
+ // own TMP012/TMP013/TMP014. An Op is recognized by entity type
510
+ // (`OpResource`), not by which lexicon declared it, so this runs over the
511
+ // FULL build result regardless of which plugins loaded — same as the
512
+ // receipt/output/knowledge checks above.
513
+ if (result.errors.length === 0) {
514
+ const opDiags = runPostSynthChecks(coreOpChecks(), result, env, { activityContracts });
515
+ const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(opDiags, config.lint?.rules);
444
516
  suppressedPostSynthCount += suppressed.length;
445
517
  for (const diag of activeDiags) {
446
518
  const prefix = diag.entity ? `[${diag.entity}] ` : "";
@@ -471,10 +543,16 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
471
543
  }
472
544
 
473
545
  const scopedResult = { ...result, outputs: scopedOutputs };
474
- const postDiags = runPostSynthChecks(checks, scopedResult, env);
475
- const { diagnostics: activeDiags, suppressed } = applyConfiguredSeverity(postDiags, config.lint?.rules);
476
- suppressedPostSynthCount += suppressed.length;
477
- for (const diag of activeDiags) {
546
+ const postDiags = runPostSynthChecks(checks, scopedResult, env, { activityContracts });
547
+ // `lint.presets` (chant #2113) filters WHICH check ids are reported at
548
+ // all, before `lint.rules`/inline suppression act on the reported
549
+ // ones. It's a no-op for a lexicon that ships no `lintPresets()` (the
550
+ // common case today), since `resolvePresetIds` returns `undefined`
551
+ // for one. This is the only `resolvePostSynth` call site with a
552
+ // lexicon a preset could apply to; every other call below passes no
553
+ // `presetIds` at all.
554
+ const presetIds = resolvePresetIds(plugin.lintPresets?.(), config.lint?.presets?.[plugin.name] ?? "recommended");
555
+ for (const diag of resolvePostSynth(postDiags, result.entities, presetIds)) {
478
556
  const prefix = diag.entity ? `[${diag.entity}] ` : "";
479
557
  const lexiconSuffix = diag.lexicon ? ` (${diag.lexicon})` : "";
480
558
  if (diag.severity === "error") {
@@ -511,9 +589,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
511
589
  env,
512
590
  preloaded: preloadedPolicyChecks,
513
591
  });
514
- const { diagnostics: activePolicyDiags, suppressed } = applyConfiguredSeverity(policyDiags, config.lint?.rules);
515
- suppressedPostSynthCount += suppressed.length;
516
- for (const diag of activePolicyDiags) {
592
+ for (const diag of resolvePostSynth(policyDiags, result.entities)) {
517
593
  const prefix = diag.entity ? `[${diag.entity}] ` : "";
518
594
  const where = diag.lexicon ? ` (${diag.lexicon})` : "";
519
595
  const msg = `[policy:${diag.checkId}] ${prefix}${diag.message}${where}`;
@@ -529,15 +605,58 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
529
605
  }),
530
606
  );
531
607
  }
608
+
609
+ if (suppressedPresetCount > 0) {
610
+ warnings.push(
611
+ formatWarning({
612
+ message: `${suppressedPresetCount} post-synth finding(s) not reported: excluded by the active lint.presets preset`,
613
+ }),
614
+ );
615
+ }
616
+
617
+ if (inlineSuppressedCount > 0) {
618
+ warnings.push(
619
+ formatWarning({
620
+ message: `${inlineSuppressedCount} post-synth finding(s) suppressed via inline chant-ignore comments`,
621
+ }),
622
+ );
623
+ }
624
+
625
+ // Directives that are themselves worth a finding (expired, misplaced, or
626
+ // naming a rule id configured `ignorable: false`) are reported once
627
+ // each, never silently (chant #2111).
628
+ for (const m of suppressionMeta) {
629
+ warnings.push(formatWarning({ message: `[${m.checkId}] ${m.file}:${m.line} ${m.message}` }));
630
+ }
532
631
  }
533
632
 
534
633
  // Empty-output guard: source files were discovered but no lexicon produced
535
634
  // any output. Almost always indicates broken imports resolving to undefined
536
635
  // (e.g. missing root re-exports from a lexicon) or modules that exported no
537
636
  // Declarables. Without this guard, chant writes "{}" and exits 0.
637
+ //
638
+ // An Op declaration is the honest exception (#2118): it belongs to no
639
+ // lexicon partition and its build output is the `op.json` written below,
640
+ // not a resource manifest, so an Ops-only project legitimately produces no
641
+ // serializer output and must not be reported as a broken import.
642
+ const declaredOps = [...result.entities.values()].filter(isOpEntity);
643
+
644
+ // The gate step's name key was renamed from `signalName` to `gate` in #2202.
645
+ // The old key is still read; a build that finds an Op still using it says so
646
+ // once, naming every Op involved, rather than once per gate step.
647
+ const opsOnOldGateKey = declaredOps
648
+ .map((entity) => (entity as unknown as { props?: OpConfig }).props)
649
+ .filter((config): config is OpConfig => Boolean(config?.name) && opUsesDeprecatedGateKey(config as OpConfig))
650
+ .map((config) => config.name);
651
+ if (opsOnOldGateKey.length > 0) {
652
+ warnings.push(
653
+ formatWarning({ message: `${DEPRECATED_GATE_KEY_WARNING} Ops: ${opsOnOldGateKey.join(", ")}.` }),
654
+ );
655
+ }
538
656
  if (
539
657
  result.sourceFileCount > 0 &&
540
658
  result.outputs.size === 0 &&
659
+ declaredOps.length === 0 &&
541
660
  result.errors.length === 0 &&
542
661
  errors.length === 0
543
662
  ) {
@@ -658,12 +777,12 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
658
777
  }
659
778
  }
660
779
 
661
- // Op worker artifacts (`ops/<name>/{workflow,worker,activities}.ts`) always
662
- // go to `<project>/dist/ops/` — the fixed location `chant run <op> --temporal`
663
- // reads (`join(projectPath, "dist", "ops", ...)`) — independent of `--output`,
664
- // which routes the primary resource manifest. Without this, a bare `chant build`
665
- // only printed them to stderr and `--output foo.yaml` scattered them next to
666
- // `foo.yaml`, so the durable-run worker was never where `run --temporal` looks.
780
+ // Anything a serializer emits under `ops/` always goes to
781
+ // `<project>/dist/ops/` — the fixed place an Op's build output is read
782
+ // from, alongside the `op.json` core writes below — independent of
783
+ // `--output`, which routes the primary resource manifest. Without this, a
784
+ // bare `chant build` only printed them to stderr and `--output foo.yaml`
785
+ // scattered them next to `foo.yaml`.
667
786
  const projectDist = resolve(options.path ?? ".", "dist");
668
787
  let opsWritten = 0;
669
788
  for (const [filename, entry] of [...additionalFiles]) {
@@ -677,13 +796,40 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
677
796
  } catch (err) {
678
797
  errors.push(
679
798
  formatError({
680
- message: `Failed to write Op worker file ${filename}: ${err instanceof Error ? err.message : String(err)}`,
799
+ message: `Failed to write Op output file ${filename}: ${err instanceof Error ? err.message : String(err)}`,
681
800
  }),
682
801
  );
683
802
  }
684
803
  }
685
804
  if (opsWritten > 0) {
686
- console.error(formatInfo(`Wrote ${opsWritten} Op worker file(s) under ${join(options.path ?? ".", "dist", "ops")}/`));
805
+ console.error(formatInfo(`Wrote ${opsWritten} Op output file(s) under ${join(options.path ?? ".", "dist", "ops")}/`));
806
+ }
807
+
808
+ // `dist/ops/<name>/op.json` — the Op IR (#1289), written here by core
809
+ // rather than emitted by a lexicon serializer (#2118). An Op declaration
810
+ // is core's own entity now (`Chant::Op`, lexicon `chant`) and is held out
811
+ // of `partitionByLexicon` entirely, so this is the one place its build
812
+ // output is produced: a deterministic, engine-neutral restatement of the
813
+ // step graph that anything can read without importing chant.
814
+ let irWritten = 0;
815
+ for (const entity of declaredOps) {
816
+ const config = (entity as unknown as { props?: OpConfig }).props;
817
+ if (!config?.name) continue;
818
+ try {
819
+ const targetPath = join(projectDist, "ops", config.name, "op.json");
820
+ mkdirSync(dirname(targetPath), { recursive: true });
821
+ writeFileSync(targetPath, serializeOpIR(config));
822
+ irWritten += 1;
823
+ } catch (err) {
824
+ errors.push(
825
+ formatError({
826
+ message: `Failed to write op.json for Op "${config.name}": ${err instanceof Error ? err.message : String(err)}`,
827
+ }),
828
+ );
829
+ }
830
+ }
831
+ if (irWritten > 0) {
832
+ console.error(formatInfo(`Wrote ${irWritten} op.json file(s) under ${join(options.path ?? ".", "dist", "ops")}/`));
687
833
  }
688
834
 
689
835
  if (options.output) {