@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,417 @@
1
+ /**
2
+ * op.json IR — chant #1289 ("An Op compiles only to TypeScript, so walk-away
3
+ * cost is zero everywhere except Ops").
4
+ *
5
+ * `OpConfig` is already inert data: every field is a string, number, boolean,
6
+ * or a nested object of those (no functions, no closures, no runtime
7
+ * references — see `./types.ts`). This module is the "second, simpler output
8
+ * from the same walk" the issue asks for: a deterministic
9
+ * `dist/ops/<name>/op.json`, so a foreign runtime (or a dashboard, a policy
10
+ * check, an agent) can read what an Op does without importing chant or
11
+ * parsing generated TypeScript.
12
+ *
13
+ * It lives in core, not in a hosting lexicon (#2118, epic #2114). The IR is a
14
+ * restatement of `OpConfig`, and `OpConfig` is core's — as is the profile
15
+ * table a step's `profile` key names, since #2117. What core does not own is
16
+ * the activity contracts that give a step's args a schema: those stay
17
+ * decentralized, so `buildOpIR` takes the registry as a parameter and defaults
18
+ * it to empty. A caller holding a lexicon's contracts passes them in, and the
19
+ * `activityContracts` section fills out without core ever importing that
20
+ * lexicon.
21
+ *
22
+ * Two things beyond a literal restatement of `OpConfig` earn their place:
23
+ *
24
+ * - Every step's `profile` / gate `timeout` is resolved to its effective
25
+ * value (chant's own default when omitted), and every referenced profile's
26
+ * actual retry/timeout policy rides along out of `ACTIVITY_PROFILES`.
27
+ * Without it a foreign runtime would have to read chant's TypeScript to
28
+ * know what "fastIdempotent" means.
29
+ * - Every step whose `fn` has a registered {@link ActivityContract} in the
30
+ * contract registry the caller passes (chant #1288 Stage 1) gets its args/
31
+ * returns zod schema embedded as JSON Schema (via zod 4's built-in
32
+ * `z.toJSONSchema`), keyed by activity name. This is exactly the payoff
33
+ * the Stage 1 decision comment named: "#1289 (op.json IR) ... build on
34
+ * these [Stage 1] contracts." Ownership stays decentralized — only
35
+ * activities the passed registry knows are covered; a step calling an
36
+ * activity from a lexicon outside it (or one with no registered contract
37
+ * yet) simply has no entry here.
38
+ * - Every step whose contract declares entity-identifying args
39
+ * (`ActivityContract.entities`, chant #2022) gets those args' literal
40
+ * string values resolved into `entities` — the estate join a renderer
41
+ * otherwise had to invent off scope fields like `stackName`. The contract
42
+ * entry echoes the declared key list, so a consumer can resolve values
43
+ * this serialization could not (a step-output ref) itself.
44
+ * JSON-Schema-incompatible contracts (schemas containing transforms or
45
+ * custom types that zod cannot serialize) are skipped gracefully: the
46
+ * activity appears in the Op's step graph but has no entry in
47
+ * activityContracts, consistent with the decentralized and partial
48
+ * coverage philosophy.
49
+ *
50
+ * Resolving defaults loses nothing: parsing `op.json` back into an
51
+ * `OpConfig`-shaped object (`opConfigFromIR`) and re-serializing it produces
52
+ * a byte-identical `op.json`, and a lexicon serializer fed the reconstruction
53
+ * emits byte-identical code (verified by the round-trip tests here) — the
54
+ * issue's own verification criterion.
55
+ *
56
+ * ## Step-output references (chant #1290, #1288 Stage 2 follow-up)
57
+ *
58
+ * A step's `args` may hold a {@link StepOutputRef} (`./step-output-ref.ts`)
59
+ * anywhere in its structure — a placeholder for a
60
+ * prior step's declared return value, which the executor substitutes for at
61
+ * run time from the producing step's record. This module does not
62
+ * special-case it: `irActivityStep` copies `step.args` through as-is (same as
63
+ * every other value), and `JSON.stringify` — both the literal one in
64
+ * `serializeOpIR` and the structural-equality one `z.toJSONSchema`-adjacent
65
+ * consumers would use — drops a `StepOutputRef`'s brand (a `Symbol.for(...)`
66
+ * key; JSON has no symbols) while keeping its three own enumerable string
67
+ * properties. The result is a plain, first-class IR value at exactly the
68
+ * position the reference sat in `args`:
69
+ *
70
+ * ```json
71
+ * { "kind": "step-output-ref", "step": "build-step", "path": "manifestPath" }
72
+ * ```
73
+ *
74
+ * (`path` omitted when the reference is to the whole return value.) This is
75
+ * deliberate, not an accident of `JSON.stringify`'s symbol-dropping — a
76
+ * foreign consumer of op.json can match on `args.<field>.kind ===
77
+ * "step-output-ref"` to recognize a placeholder and resolve it against
78
+ * `steps[].id`/`activityContracts[fn].returns` itself, without ever loading
79
+ * chant's TypeScript. `op-ir.test.ts` asserts the shape directly so a future
80
+ * change to `StepOutputRef`'s own fields (`./step-output-ref.ts`) that would
81
+ * silently change this JSON shape gets caught here.
82
+ */
83
+
84
+ import { z } from "zod";
85
+ import type {
86
+ OutcomeAttribute,
87
+ OpConfig,
88
+ OpSchedule,
89
+ PhaseDefinition,
90
+ StepDefinition,
91
+ ActivityStep,
92
+ GateStep,
93
+ EffectStep,
94
+ } from "./types";
95
+ import type { EffectReceiptRef } from "./receipt-store";
96
+ import type { ActivityContract } from "./activity-contract";
97
+ import { ACTIVITY_PROFILES, type ActivityProfile } from "./activity-profiles";
98
+
99
+ /**
100
+ * The op.json IR schema version. Bumped on a breaking change to this
101
+ * module's output shape — additive fields (a new optional key) do not
102
+ * require a bump.
103
+ *
104
+ * `2.0` (#2118): `taskQueue` and `namespace` are gone and `searchAttributes`
105
+ * is replaced by `labels`. Those three were the fields only a workflow engine
106
+ * read; an op.json now states what the Op does, not where it runs.
107
+ */
108
+ export const OP_IR_FORMAT_VERSION = "2.0";
109
+
110
+ // ── IR shape ──────────────────────────────────────────────────────────────────
111
+
112
+ export interface OpIRActivityStep {
113
+ kind: "activity";
114
+ fn: string;
115
+ /** Always present (defaulted to `{}`) — unlike `ActivityStep.args`, which omits an empty bag. */
116
+ args: Record<string, unknown>;
117
+ /** Resolved to its effective value — `ActivityStep.profile ?? "fastIdempotent"`. */
118
+ profile: string;
119
+ /**
120
+ * What this step's effect touches in the estate (#2022): the string values
121
+ * of the args its contract declares as entity-identifying
122
+ * (`ActivityContract.entities`), resolved per step at serialization the
123
+ * same way `profile` is. Absent when the activity has no contract, the
124
+ * contract declares no entity args, or none of them holds a literal string
125
+ * in this step (a step-output ref resolves at run time, not here).
126
+ */
127
+ entities?: string[];
128
+ /** One run outcome, or several published off the same result (#2105). */
129
+ outcomeAttribute?: OutcomeAttribute | OutcomeAttribute[];
130
+ }
131
+
132
+ export interface OpIRGateStep {
133
+ kind: "gate";
134
+ signalName: string;
135
+ /** Resolved to its effective value — `GateStep.timeout ?? "48h"`. */
136
+ timeout: string;
137
+ description?: string;
138
+ }
139
+
140
+ export interface OpIREffectStep {
141
+ kind: "effect";
142
+ receipt: EffectReceiptRef;
143
+ expectation?: string;
144
+ steps: Array<OpIRActivityStep | OpIRGateStep>;
145
+ description?: string;
146
+ }
147
+
148
+ export type OpIRStep = OpIRActivityStep | OpIRGateStep | OpIREffectStep;
149
+
150
+ export interface OpIRPhase {
151
+ name: string;
152
+ parallel: boolean;
153
+ steps: OpIRStep[];
154
+ }
155
+
156
+ /** A registered activity contract's args/returns, restated as JSON Schema. */
157
+ export interface OpIRActivityContract {
158
+ args: Record<string, unknown>;
159
+ returns?: Record<string, unknown>;
160
+ /** Names of args the contract declares as entity-identifying (#2022) — the key a consumer uses to resolve entities out of any step's `args` itself, including values this serialization could not (a step-output ref). */
161
+ entities?: string[];
162
+ }
163
+
164
+ export interface OpIR {
165
+ formatVersion: string;
166
+ name: string;
167
+ overview: string;
168
+ depends: string[];
169
+ /** The Op's discovery keys (#2118) — `OpConfig.labels` verbatim, `{}` when it declares none. */
170
+ labels: Record<string, string>;
171
+ /**
172
+ * The Op's cadence (#2120) — `OpConfig.schedule` verbatim, absent when it
173
+ * declares none. Op data, not runtime data: the cron says how often this Op
174
+ * should run, and which scheduler honours it is the reader's business, the
175
+ * same way `profile` states a retry policy without naming a retrier. An
176
+ * additive optional key, so it needs no `formatVersion` bump.
177
+ */
178
+ schedule?: OpSchedule;
179
+ phases: OpIRPhase[];
180
+ onFailure: OpIRPhase[];
181
+ /** Every activity profile referenced by a step in this Op, keyed by profile name — from the registry passed to {@link buildOpIR}, empty when none was. */
182
+ activityProfiles: Record<string, ActivityProfile>;
183
+ /**
184
+ * JSON Schema for every referenced activity that has a registered contract
185
+ * in the passed registry (chant #1288 Stage 1). Decentralized and partial
186
+ * by design — see the module doc.
187
+ */
188
+ activityContracts: Record<string, OpIRActivityContract>;
189
+ }
190
+
191
+ // ── Step helpers ──────────────────────────────────────────────────────────────
192
+
193
+ function effectiveProfile(step: ActivityStep): string {
194
+ return step.profile ?? "fastIdempotent";
195
+ }
196
+
197
+ /**
198
+ * The step's entity-identifying arg values (#2022): the literal strings at
199
+ * the arg names its contract declares in `entities`. A non-string there (a
200
+ * step-output ref placeholder, a structured value) is skipped — the IR only
201
+ * states joins it can resolve at serialization; a consumer holding the
202
+ * contract's own `entities` key list can resolve the rest itself.
203
+ */
204
+ function stepEntities(step: ActivityStep, contracts: ReadonlyMap<string, ActivityContract>): string[] | undefined {
205
+ const declared = contracts.get(step.fn)?.entities;
206
+ if (!declared || declared.length === 0) return undefined;
207
+ const values: string[] = [];
208
+ for (const key of declared) {
209
+ const value = (step.args ?? {})[key];
210
+ if (typeof value === "string") values.push(value);
211
+ }
212
+ return values.length > 0 ? values : undefined;
213
+ }
214
+
215
+ function irActivityStep(step: ActivityStep, contracts: ReadonlyMap<string, ActivityContract>): OpIRActivityStep {
216
+ const entities = stepEntities(step, contracts);
217
+ return {
218
+ kind: "activity",
219
+ fn: step.fn,
220
+ args: step.args ?? {},
221
+ profile: effectiveProfile(step),
222
+ ...(entities ? { entities } : {}),
223
+ ...(step.outcomeAttribute ? { outcomeAttribute: step.outcomeAttribute } : {}),
224
+ };
225
+ }
226
+
227
+ function irGateStep(step: GateStep): OpIRGateStep {
228
+ return {
229
+ kind: "gate",
230
+ signalName: step.signalName,
231
+ timeout: step.timeout ?? "48h",
232
+ ...(step.description ? { description: step.description } : {}),
233
+ };
234
+ }
235
+
236
+ function irEffectStep(step: EffectStep, contracts: ReadonlyMap<string, ActivityContract>): OpIREffectStep {
237
+ return {
238
+ kind: "effect",
239
+ receipt: step.receipt,
240
+ ...(step.expectation !== undefined ? { expectation: step.expectation } : {}),
241
+ steps: step.steps.map((s) => (s.kind === "activity" ? irActivityStep(s, contracts) : irGateStep(s))),
242
+ ...(step.description ? { description: step.description } : {}),
243
+ };
244
+ }
245
+
246
+ function irStep(step: StepDefinition, contracts: ReadonlyMap<string, ActivityContract>): OpIRStep {
247
+ if (step.kind === "activity") return irActivityStep(step, contracts);
248
+ if (step.kind === "gate") return irGateStep(step);
249
+ return irEffectStep(step, contracts);
250
+ }
251
+
252
+ function irPhase(phase: PhaseDefinition, contracts: ReadonlyMap<string, ActivityContract>): OpIRPhase {
253
+ return {
254
+ name: phase.name,
255
+ parallel: phase.parallel ?? false,
256
+ steps: phase.steps.map((s) => irStep(s, contracts)),
257
+ };
258
+ }
259
+
260
+ // ── Referenced-activity collection ─────────────────────────────────────────────
261
+
262
+ /** Every `ActivityStep` reachable from a phase list, including ones nested inside an `EffectStep`. */
263
+ function activityStepsOf(phases: PhaseDefinition[]): ActivityStep[] {
264
+ const out: ActivityStep[] = [];
265
+ for (const phase of phases) {
266
+ for (const step of phase.steps) {
267
+ if (step.kind === "activity") out.push(step);
268
+ else if (step.kind === "effect") {
269
+ for (const nested of step.steps) if (nested.kind === "activity") out.push(nested);
270
+ }
271
+ }
272
+ }
273
+ return out;
274
+ }
275
+
276
+ /** No contracts unless a caller supplies them — core does not own that registry. See the module doc. */
277
+ const NO_CONTRACTS: ReadonlyMap<string, ActivityContract> = new Map();
278
+
279
+ /** Sort object keys for a set-like dictionary without a meaningful authored order (profiles/contracts, keyed by name). */
280
+ function sortedEntries<T>(map: Map<string, T>): Record<string, T> {
281
+ const out: Record<string, T> = {};
282
+ for (const key of [...map.keys()].sort()) out[key] = map.get(key)!;
283
+ return out;
284
+ }
285
+
286
+ // ── Public API ────────────────────────────────────────────────────────────────
287
+
288
+ /**
289
+ * Build the deterministic op.json IR for one Op's config.
290
+ *
291
+ * `contractRegistry` is the one thing core does not own (see the module doc):
292
+ * a caller holding a lexicon's activity contracts passes them in and
293
+ * `activityContracts` fills out. Omitted, that section is empty — the step
294
+ * graph, the labels and every step's resolved `profile` name are unaffected
295
+ * either way. `profileRegistry` defaults to core's own `ACTIVITY_PROFILES`;
296
+ * a test overrides it.
297
+ */
298
+ export function buildOpIR(
299
+ config: OpConfig,
300
+ contractRegistry: ReadonlyMap<string, ActivityContract> = NO_CONTRACTS,
301
+ profileRegistry: Readonly<Record<string, ActivityProfile>> = ACTIVITY_PROFILES,
302
+ ): OpIR {
303
+ const allSteps = [...activityStepsOf(config.phases), ...activityStepsOf(config.onFailure ?? [])];
304
+
305
+ const profiles = new Map<string, ActivityProfile>();
306
+ const contracts = new Map<string, OpIRActivityContract>();
307
+ for (const step of allSteps) {
308
+ const prof = effectiveProfile(step);
309
+ if (!profiles.has(prof) && prof in profileRegistry) {
310
+ profiles.set(prof, profileRegistry[prof]);
311
+ }
312
+ if (!contracts.has(step.fn)) {
313
+ const contract = contractRegistry.get(step.fn);
314
+ if (contract) {
315
+ try {
316
+ const args = z.toJSONSchema(contract.args) as Record<string, unknown>;
317
+ const returns = contract.returns ? (z.toJSONSchema(contract.returns) as Record<string, unknown>) : undefined;
318
+ contracts.set(step.fn, {
319
+ args,
320
+ ...(returns ? { returns } : {}),
321
+ ...(contract.entities && contract.entities.length > 0 ? { entities: contract.entities } : {}),
322
+ });
323
+ } catch {
324
+ // zod 4's toJSONSchema throws on schemas containing transforms or custom types.
325
+ // Gracefully skip this contract — the activity remains in the step graph but
326
+ // has no entry in activityContracts. Consistent with the decentralized and
327
+ // partial coverage philosophy.
328
+ }
329
+ }
330
+ }
331
+ }
332
+
333
+ return {
334
+ formatVersion: OP_IR_FORMAT_VERSION,
335
+ name: config.name,
336
+ overview: config.overview,
337
+ depends: config.depends ?? [],
338
+ labels: config.labels ?? {},
339
+ ...(config.schedule ? { schedule: config.schedule } : {}),
340
+ phases: config.phases.map((p) => irPhase(p, contractRegistry)),
341
+ onFailure: (config.onFailure ?? []).map((p) => irPhase(p, contractRegistry)),
342
+ activityProfiles: sortedEntries(profiles),
343
+ activityContracts: sortedEntries(contracts),
344
+ };
345
+ }
346
+
347
+ /** Serialize one Op's op.json IR to a deterministic JSON string (stable key order, 2-space indent, trailing newline). Takes the same two optional registries as {@link buildOpIR}. */
348
+ export function serializeOpIR(
349
+ config: OpConfig,
350
+ contractRegistry?: ReadonlyMap<string, ActivityContract>,
351
+ profileRegistry?: Readonly<Record<string, ActivityProfile>>,
352
+ ): string {
353
+ return JSON.stringify(buildOpIR(config, contractRegistry, profileRegistry), null, 2) + "\n";
354
+ }
355
+
356
+ // ── Round trip (op.json → OpConfig) ────────────────────────────────────────────
357
+ //
358
+ // The inverse of `buildOpIR`. Exists primarily to prove the IR's own
359
+ // verification criterion (chant #1289): parsing `op.json` back into an
360
+ // `OpConfig`-shaped object and re-serializing it round-trips byte-identically,
361
+ // and a lexicon serializer fed the reconstruction emits identical code. Also
362
+ // the mechanical shape a foreign consumer would use to drive its own executor
363
+ // off the IR rather than the generated TypeScript.
364
+
365
+ function opStepFromIR(step: OpIRStep): StepDefinition {
366
+ if (step.kind === "activity") {
367
+ return {
368
+ kind: "activity",
369
+ fn: step.fn,
370
+ args: step.args,
371
+ profile: step.profile as ActivityStep["profile"],
372
+ ...(step.outcomeAttribute ? { outcomeAttribute: step.outcomeAttribute } : {}),
373
+ };
374
+ }
375
+ if (step.kind === "gate") {
376
+ return {
377
+ kind: "gate",
378
+ signalName: step.signalName,
379
+ timeout: step.timeout,
380
+ ...(step.description ? { description: step.description } : {}),
381
+ };
382
+ }
383
+ return {
384
+ kind: "effect",
385
+ receipt: step.receipt,
386
+ ...(step.expectation !== undefined ? { expectation: step.expectation } : {}),
387
+ steps: step.steps.map((s) => opStepFromIR(s) as ActivityStep | GateStep),
388
+ ...(step.description ? { description: step.description } : {}),
389
+ };
390
+ }
391
+
392
+ function opPhaseFromIR(phase: OpIRPhase): PhaseDefinition {
393
+ return {
394
+ name: phase.name,
395
+ steps: phase.steps.map(opStepFromIR),
396
+ ...(phase.parallel ? { parallel: true } : {}),
397
+ };
398
+ }
399
+
400
+ /** Reconstruct an `OpConfig` from its op.json IR. */
401
+ export function opConfigFromIR(ir: OpIR): OpConfig {
402
+ if (ir.formatVersion !== OP_IR_FORMAT_VERSION) {
403
+ throw new Error(
404
+ `op.json IR format mismatch: expected "${OP_IR_FORMAT_VERSION}", got "${ir.formatVersion}". ` +
405
+ `This op.json may be stale or from a newer chant version.`,
406
+ );
407
+ }
408
+ return {
409
+ name: ir.name,
410
+ overview: ir.overview,
411
+ phases: ir.phases.map(opPhaseFromIR),
412
+ ...(ir.depends.length > 0 ? { depends: ir.depends } : {}),
413
+ ...(ir.onFailure.length > 0 ? { onFailure: ir.onFailure.map(opPhaseFromIR) } : {}),
414
+ ...(Object.keys(ir.labels).length > 0 ? { labels: ir.labels } : {}),
415
+ ...(ir.schedule ? { schedule: ir.schedule } : {}),
416
+ };
417
+ }
@@ -8,7 +8,7 @@
8
8
  * just the pre-built composites — so classification walks `OpConfig`'s
9
9
  * steps rather than trusting a self-reported tag.
10
10
  *
11
- * There is no existing per-Op verb-class field (`searchAttributes` is a free
11
+ * There is no existing per-Op verb-class field (`labels` is a free
12
12
  * `Record<string,string>` an author may or may not set — `ApplyOp` tags
13
13
  * `{ Apply: "true" }` but nothing requires it, and it carries no verb-class
14
14
  * semantics on its own) and no existing "which activity names are
@@ -27,8 +27,7 @@
27
27
  * list.
28
28
  */
29
29
 
30
- import { findGate } from "./local-executor";
31
- import type { ActivityStep, EffectStep, OpConfig, StepDefinition } from "./types";
30
+ import type { ActivityStep, EffectStep, GateStep, OpConfig, StepDefinition } from "./types";
32
31
 
33
32
  export type OpVerbClass = "read-only" | "mutating" | "destructive";
34
33
 
@@ -109,7 +108,22 @@ export function classifyOpVerbClass(config: Pick<OpConfig, "phases" | "onFailure
109
108
  return sawMutating ? "mutating" : "read-only";
110
109
  }
111
110
 
112
- /** Does this Op have its own approval gate anywhere in its phases (main or `onFailure`)? Thin re-export of `findGate` under the name this module's callers reach for. */
111
+ /**
112
+ * Does this Op have its own approval gate anywhere in its phases (main or
113
+ * `onFailure`), including one nested inside an effect step?
114
+ *
115
+ * A declaration-time question, not a run-time one: a gate is a fact the
116
+ * executor decides against the ledger when it reaches one (#2119,
117
+ * `./gate.ts`), so this says "this op can stop for a human", never "this op
118
+ * will stop". `OPS014`'s dispatch refusals are the caller that needs it.
119
+ */
113
120
  export function isGated(config: Pick<OpConfig, "phases" | "onFailure">): boolean {
114
- return findGate(config as OpConfig) !== undefined;
121
+ const isGate = (s: StepDefinition): s is GateStep => s.kind === "gate";
122
+ for (const phase of [...config.phases, ...(config.onFailure ?? [])]) {
123
+ for (const step of phase.steps) {
124
+ if (isGate(step)) return true;
125
+ if (step.kind === "effect" && step.steps.some(isGate)) return true;
126
+ }
127
+ }
128
+ return false;
115
129
  }
package/src/op/op.test.ts CHANGED
@@ -17,8 +17,8 @@ describe("Op()", () => {
17
17
  it("returns a Declarable with correct lexicon and entityType", () => {
18
18
  const op = Op({ name: "my-op", overview: "Test op", phases: [] });
19
19
  expect(op[DECLARABLE_MARKER]).toBe(true);
20
- expect(op.lexicon).toBe("temporal");
21
- expect(op.entityType).toBe("Temporal::Op");
20
+ expect(op.lexicon).toBe("chant");
21
+ expect(op.entityType).toBe("Chant::Op");
22
22
  expect(op.kind).toBe("resource");
23
23
  });
24
24
 
@@ -43,6 +43,27 @@ describe("Op()", () => {
43
43
  expect(props.depends).toEqual(["first-op"]);
44
44
  });
45
45
 
46
+ it("stores an optional schedule in props (#2120)", () => {
47
+ const op = Op({ name: "op", overview: "o", phases: [], schedule: { cron: "*/10 * * * *" } });
48
+ expect(opProps(op).schedule).toEqual({ cron: "*/10 * * * *" });
49
+ });
50
+
51
+ it("accepts the only overlap policy there is", () => {
52
+ const op = Op({ name: "op", overview: "o", phases: [], schedule: { cron: "0 6 * * *", overlap: "skip" } });
53
+ expect(opProps(op).schedule).toEqual({ cron: "0 6 * * *", overlap: "skip" });
54
+ });
55
+
56
+ it("refuses an invalid cron at construction, with cronSyntaxMessage's wording (#2120)", () => {
57
+ expect(() => Op({ name: "nightly", overview: "o", phases: [], schedule: { cron: "0 6 * *" } })).toThrow(
58
+ 'Op "nightly": cron expression "0 6 * *" does not look like valid 5- or 6-field cron syntax',
59
+ );
60
+ });
61
+
62
+ it("an Op with no schedule is unchanged — nothing is validated and nothing is added", () => {
63
+ const op = Op({ name: "op", overview: "o", phases: [] });
64
+ expect(opProps(op).schedule).toBeUndefined();
65
+ });
66
+
46
67
  it("stores optional onFailure in props", () => {
47
68
  const compensation = phase("Rollback", [shell("echo rollback")]);
48
69
  const op = Op({ name: "op", overview: "o", phases: [], onFailure: [compensation] });
@@ -50,10 +71,10 @@ describe("Op()", () => {
50
71
  expect(Array.isArray(props.onFailure)).toBe(true);
51
72
  });
52
73
 
53
- it("stores optional taskQueue in props", () => {
54
- const op = Op({ name: "op", overview: "o", phases: [], taskQueue: "custom-queue" });
74
+ it("stores optional labels in props", () => {
75
+ const op = Op({ name: "op", overview: "o", phases: [], labels: { Converge: "true", Env: "staging" } });
55
76
  const props = opProps(op);
56
- expect(props.taskQueue).toBe("custom-queue");
77
+ expect(props.labels).toEqual({ Converge: "true", Env: "staging" });
57
78
  });
58
79
  });
59
80