@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.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +20 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +14 -8
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +28 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +26 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +20 -21
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +3 -3
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +66 -36
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +9 -15
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/import/ir-utils.d.ts +1 -1
- package/dist/import/ir-utils.d.ts.map +1 -1
- package/dist/import/parser.d.ts +33 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +104 -14
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +71 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +89 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +84 -29
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +113 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +23 -7
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +184 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +30 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +79 -27
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/stack-output.d.ts +5 -0
- package/dist/stack-output.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +61 -17
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +91 -15
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +189 -11
- package/src/cli/commands/audit.ts +73 -27
- package/src/cli/commands/build.test.ts +292 -9
- package/src/cli/commands/build.ts +156 -24
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/import.ts +6 -0
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +48 -0
- package/src/cli/commands/lint.ts +123 -0
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +260 -55
- package/src/cli/handlers/run.test.ts +431 -1287
- package/src/cli/handlers/run.ts +365 -915
- package/src/cli/main.test.ts +23 -15
- package/src/cli/main.ts +88 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/registry.ts +26 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +3 -2
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +10 -5
- package/src/components/cli-support.ts +52 -44
- package/src/components/component.schema.json +2 -2
- package/src/components/component.ts +3 -3
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +92 -22
- package/src/components/driver.ts +193 -83
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.ts +11 -17
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +81 -1
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +2 -2
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/import/ir-utils.ts +11 -1
- package/src/import/parser.ts +35 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +120 -14
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +143 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +1 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +81 -0
- package/src/op/activities/reconcile.ts +187 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +123 -39
- package/src/op/composites/apply-op.ts +208 -0
- package/src/op/composites/composites.test.ts +366 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +107 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +26 -11
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +39 -6
- package/src/op/local-executor.test.ts +163 -34
- package/src/op/local-executor.ts +370 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +281 -0
- package/src/op/op-ir.ts +417 -0
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +26 -5
- package/src/op/operator.test.ts +175 -6
- package/src/op/operator.ts +63 -16
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +84 -24
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/stack-output.ts +6 -1
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
package/src/op/op-ir.ts
ADDED
|
@@ -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
|
+
}
|
package/src/op/op-verb-class.ts
CHANGED
|
@@ -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 (`
|
|
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 {
|
|
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
|
-
/**
|
|
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
|
-
|
|
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("
|
|
21
|
-
expect(op.entityType).toBe("
|
|
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
|
|
54
|
-
const op = Op({ name: "op", overview: "o", phases: [],
|
|
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.
|
|
77
|
+
expect(props.labels).toEqual({ Converge: "true", Env: "staging" });
|
|
57
78
|
});
|
|
58
79
|
});
|
|
59
80
|
|