@intentius/chant 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- 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/carve-bridge.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/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 +13 -0
- 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 +12 -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/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -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 +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- 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 +73 -37
- 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 +10 -22
- 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/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.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/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 +273 -16
- 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 +79 -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 +149 -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 +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -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-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- 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 +29 -9
- 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 +185 -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 +93 -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 +96 -29
- 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/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.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 +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- 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 +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- 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/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 +194 -1
- package/src/cli/commands/lint.ts +205 -7
- 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 +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -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/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -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 +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- 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 +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- 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/neo4j-fanout.pilot.ts +3 -3
- 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.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- 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/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- 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 +82 -2
- 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 +3 -3
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -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 +296 -16
- 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 +154 -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/pipeline-change-gate.test.ts +2 -2
- 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 +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -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 +161 -0
- package/src/op/activities/reconcile.ts +354 -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 +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -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 +110 -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 +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- 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 +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -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 +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- 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 +106 -26
- 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/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- 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/operator.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `chant operator` (#1485, epic #1487) —
|
|
3
|
-
*
|
|
2
|
+
* `chant operator` (#1485, epic #1487) — durable ticks with no service behind
|
|
3
|
+
* them. A deliberately small daemon: a timer, a lease
|
|
4
4
|
* (../lifecycle/lease.ts), and the existing local executor
|
|
5
5
|
* (./local-executor.ts) in a loop. No new service, no new state store — the
|
|
6
6
|
* lease lives on a git ref, tick state lives on the `chant/lifecycle`
|
|
7
7
|
* orphan branch via the same `convergeTick` activity `chant run <op>`
|
|
8
8
|
* already calls for a single one-shot tick.
|
|
9
9
|
*
|
|
10
|
-
* One round: discover every `ConvergeOp` (
|
|
10
|
+
* One round: discover every `ConvergeOp` (label `Converge:
|
|
11
11
|
* "true"`, optionally filtered to one env), and for each one, try to
|
|
12
12
|
* acquire (or renew) its lease. Win it — run one tick via `runOpLocally` on
|
|
13
13
|
* the Op's own Observe → Converge phases, the identical path `chant run
|
|
@@ -37,23 +37,34 @@
|
|
|
37
37
|
*/
|
|
38
38
|
import type { ActivityFn, ActivityProfile } from "./activity-registry";
|
|
39
39
|
import { discoverOps, type DiscoveredOp } from "./discover";
|
|
40
|
-
import { runOpLocally, OpRunFailure,
|
|
40
|
+
import { runOpLocally, OpRunFailure, type OpRunResult } from "./local-executor";
|
|
41
41
|
import { acquireLease, stillHoldsLease, currentHolderId, DEFAULT_LEASE_TTL_MS, type LeaseRecord, type AcquireLeaseResult } from "../lifecycle/lease";
|
|
42
42
|
import { StaleLockError } from "../lifecycle/git";
|
|
43
|
+
import { cronMatches, cronDueBetween } from "./cron";
|
|
44
|
+
import { createChangeSignalGate, DEFAULT_SIGNAL_FLOOR_MS, type WakeReason } from "./change-signal";
|
|
45
|
+
import type { ChangeSubscription } from "../lexicon";
|
|
43
46
|
|
|
44
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Poll interval between rounds — the operator's own cadence, and the fallback
|
|
49
|
+
* for an Op that declares none. Since #2120 an Op can carry its own
|
|
50
|
+
* `schedule.cron` (`./composites/converge-op.ts`), which this loop honours per
|
|
51
|
+
* Op: the round still wakes every `intervalMs`, but an Op with a cron is
|
|
52
|
+
* ticked only on the minutes that cron fires. Chosen short enough to converge
|
|
53
|
+
* promptly, long enough not to hammer `chant lifecycle plan --live` every few
|
|
54
|
+
* seconds — and short enough that a per-minute cron is not missed.
|
|
55
|
+
*/
|
|
45
56
|
export const DEFAULT_OPERATOR_INTERVAL_MS = 60_000;
|
|
46
57
|
|
|
47
|
-
/** One ConvergeOp's own `
|
|
58
|
+
/** One ConvergeOp's own `labels.Env` (`./composites/converge-op.ts` always sets it). `undefined` for a non-ConvergeOp or a hand-built one missing it — filtered out by `isConvergeOp` before this is trusted. */
|
|
48
59
|
function envOf(config: DiscoveredOp["config"]): string | undefined {
|
|
49
|
-
return config.
|
|
60
|
+
return config.labels?.Env;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
function isConvergeOp(config: DiscoveredOp["config"]): boolean {
|
|
53
|
-
return config.
|
|
64
|
+
return config.labels?.Converge === "true";
|
|
54
65
|
}
|
|
55
66
|
|
|
56
|
-
/** Discover every `ConvergeOp` in the project (`
|
|
67
|
+
/** Discover every `ConvergeOp` in the project (`labels.Converge === "true"`), optionally filtered to one environment. Ops that don't declare an `Env` label are excluded from an `--env`-filtered discovery (there's nothing to match), but included when no `env` filter is given. */
|
|
57
68
|
export async function discoverConvergeOps(
|
|
58
69
|
opts?: { cwd?: string; env?: string },
|
|
59
70
|
): Promise<{ ops: DiscoveredOp[]; errors: string[] }> {
|
|
@@ -67,6 +78,8 @@ export async function discoverConvergeOps(
|
|
|
67
78
|
export type OperatorTickEvent =
|
|
68
79
|
| { kind: "ticked"; op: string; env: string; result: OpRunResult }
|
|
69
80
|
| { kind: "skipped-lease-held"; op: string; env: string; heldBy?: string }
|
|
81
|
+
/** The Op declares its own `schedule.cron` (#2120) and this round did not land on a firing minute — the lease was never touched. An Op without a cron is never reported this way: it ticks every round, on `--interval`. */
|
|
82
|
+
| { kind: "skipped-not-due"; op: string; env: string; cron: string }
|
|
70
83
|
| { kind: "tick-failed"; op: string; env: string; error: string }
|
|
71
84
|
/** The lease was lost between acquiring it and the tick finishing (e.g. this process stalled past its TTL and another operator reclaimed it) — the tick's own ledger record (written inside `convergeTick`) still landed, since a converge tick is idempotent by design; this event exists purely so `chant operator`'s log and the ledger-independent test surface can see the fencing violation happened. Never a hard failure. */
|
|
72
85
|
| { kind: "fenced"; op: string; env: string }
|
|
@@ -96,6 +109,16 @@ export interface OperatorRoundOptions {
|
|
|
96
109
|
profiles: Record<string, ActivityProfile>;
|
|
97
110
|
now?: () => Date;
|
|
98
111
|
signal?: AbortSignal;
|
|
112
|
+
/**
|
|
113
|
+
* When each Op with its own `schedule.cron` was last considered (#2120) —
|
|
114
|
+
* the state a round needs to answer "has a firing minute passed since I
|
|
115
|
+
* last looked at this Op?". `runOperatorForever` owns one map across
|
|
116
|
+
* rounds; a bare `runOperatorRound` with none given falls back to "is this
|
|
117
|
+
* minute a firing minute", which is what a single round can know on its
|
|
118
|
+
* own. Every considered Op's entry is updated, ticked or not, so a late
|
|
119
|
+
* round makes up exactly one tick rather than a backlog.
|
|
120
|
+
*/
|
|
121
|
+
scheduleState?: Map<string, Date>;
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
/**
|
|
@@ -112,6 +135,24 @@ export async function runOperatorRound(opts: OperatorRoundOptions): Promise<Oper
|
|
|
112
135
|
for (const { config } of ops) {
|
|
113
136
|
const env = envOf(config) ?? "unknown";
|
|
114
137
|
|
|
138
|
+
// An Op that declares its own cadence (#2120) is ticked on that cron
|
|
139
|
+
// rather than on every round. Level-triggered: the question is whether a
|
|
140
|
+
// firing minute has passed since this Op was last looked at, so a round
|
|
141
|
+
// that arrives late still owes exactly one tick — a converge tick
|
|
142
|
+
// re-observes everything anyway, and several missed fires are one tick's
|
|
143
|
+
// worth of work.
|
|
144
|
+
const cron = config.schedule?.cron;
|
|
145
|
+
if (cron) {
|
|
146
|
+
const now = (opts.now ?? (() => new Date()))();
|
|
147
|
+
const lastSeen = opts.scheduleState?.get(config.name);
|
|
148
|
+
const due = lastSeen === undefined ? cronMatches(cron, now) : cronDueBetween(cron, lastSeen, now);
|
|
149
|
+
opts.scheduleState?.set(config.name, now);
|
|
150
|
+
if (!due) {
|
|
151
|
+
events.push({ kind: "skipped-not-due", op: config.name, env, cron });
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
115
156
|
let acquired: AcquireLeaseResult;
|
|
116
157
|
try {
|
|
117
158
|
acquired = await acquireLease(config.name, holder, {
|
|
@@ -137,18 +178,18 @@ export async function runOperatorRound(opts: OperatorRoundOptions): Promise<Oper
|
|
|
137
178
|
|
|
138
179
|
const lease = acquired.lease as LeaseRecord;
|
|
139
180
|
try {
|
|
140
|
-
const result = await runOpLocally(config, opts.activities, opts.profiles, opts.signal
|
|
181
|
+
const result = await runOpLocally(config, opts.activities, opts.profiles, opts.signal, {
|
|
182
|
+
ledger: { cwd: opts.cwd },
|
|
183
|
+
});
|
|
141
184
|
const held = await stillHoldsLease(config.name, holder, lease.token, { cwd: opts.cwd });
|
|
142
185
|
events.push(held ? { kind: "ticked", op: config.name, env, result } : { kind: "fenced", op: config.name, env });
|
|
143
186
|
} catch (err) {
|
|
144
187
|
const message =
|
|
145
188
|
err instanceof OpRunFailure
|
|
146
189
|
? `Op "${config.name}" failed — see its ledger record for step-level detail`
|
|
147
|
-
: err instanceof
|
|
190
|
+
: err instanceof Error
|
|
148
191
|
? err.message
|
|
149
|
-
: err
|
|
150
|
-
? err.message
|
|
151
|
-
: String(err);
|
|
192
|
+
: String(err);
|
|
152
193
|
events.push({ kind: "tick-failed", op: config.name, env, error: message });
|
|
153
194
|
}
|
|
154
195
|
}
|
|
@@ -172,11 +213,67 @@ function sleepAbortable(ms: number, signal?: AbortSignal): Promise<void> {
|
|
|
172
213
|
});
|
|
173
214
|
}
|
|
174
215
|
|
|
216
|
+
/**
|
|
217
|
+
* One lexicon's change-signal seam, already bound to an environment (#1981).
|
|
218
|
+
*
|
|
219
|
+
* The loop never sees a `LexiconPlugin`: core's operator does not import
|
|
220
|
+
* plugins, and binding happens where plugins are already loaded
|
|
221
|
+
* (`collectChangeSubscribers` in `../cli/plugins.ts`), the same extract-then-
|
|
222
|
+
* thread shape `collectBuildRootContributors` uses for build roots.
|
|
223
|
+
*/
|
|
224
|
+
export interface ChangeSubscriber {
|
|
225
|
+
/** Which lexicon supplies the signal. Log lines only; never a fact. */
|
|
226
|
+
lexicon: string;
|
|
227
|
+
subscribe(ctx: {
|
|
228
|
+
onChange: () => void;
|
|
229
|
+
onError: (message: string) => void;
|
|
230
|
+
signal: AbortSignal;
|
|
231
|
+
}): Promise<ChangeSubscription>;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* What the loop's change-signal machinery reports, alongside the per-op tick
|
|
236
|
+
* events. Separate from {@link OperatorTickEvent} on purpose: none of this is
|
|
237
|
+
* about an Op, and none of it is an observation.
|
|
238
|
+
*/
|
|
239
|
+
export type OperatorSignalEvent =
|
|
240
|
+
/** A lexicon's subscription is live and the loop may now wake early. */
|
|
241
|
+
| { kind: "subscribed"; lexicon: string }
|
|
242
|
+
/** Establishing it failed. The loop keeps its timer and retries next round. */
|
|
243
|
+
| { kind: "subscribe-failed"; lexicon: string; error: string }
|
|
244
|
+
/** A live subscription died. Reported once; the next round re-subscribes. */
|
|
245
|
+
| { kind: "subscription-lost"; lexicon: string; error: string }
|
|
246
|
+
/** A signal shortened the sleep. The round that follows is an ordinary round. */
|
|
247
|
+
| { kind: "woken"; afterMs: number };
|
|
248
|
+
|
|
249
|
+
/** Render one signal event as `chant operator`'s log line shape. */
|
|
250
|
+
export function formatSignalLine(event: OperatorSignalEvent): string {
|
|
251
|
+
switch (event.kind) {
|
|
252
|
+
case "subscribed":
|
|
253
|
+
return `operator: ${event.lexicon} change signal subscribed (the timer still runs)`;
|
|
254
|
+
case "subscribe-failed":
|
|
255
|
+
return `operator: ${event.lexicon} change signal unavailable, polling on the timer (${event.error})`;
|
|
256
|
+
case "subscription-lost":
|
|
257
|
+
return `operator: ${event.lexicon} change signal lost, polling on the timer until the next round re-subscribes (${event.error})`;
|
|
258
|
+
case "woken":
|
|
259
|
+
return `operator: woken by a change signal after ${event.afterMs}ms, running an ordinary round`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
175
263
|
export interface OperatorLoopOptions extends OperatorRoundOptions {
|
|
176
264
|
/** @default DEFAULT_OPERATOR_INTERVAL_MS */
|
|
177
265
|
intervalMs?: number;
|
|
178
266
|
/** Called after every round completes — the CLI's one-line-per-tick log lives here, not inside the loop itself, so a test can drive rounds without capturing stdout. */
|
|
179
267
|
onRound?: (events: OperatorTickEvent[]) => void;
|
|
268
|
+
/**
|
|
269
|
+
* Change-signal seams to keep subscribed for the life of the loop (#1981).
|
|
270
|
+
* Omitted, or empty, and the loop is exactly what it was: a timer.
|
|
271
|
+
*/
|
|
272
|
+
subscribers?: readonly ChangeSubscriber[];
|
|
273
|
+
/** @default DEFAULT_SIGNAL_FLOOR_MS. The shortest gap a signal may force between two rounds. */
|
|
274
|
+
signalFloorMs?: number;
|
|
275
|
+
/** Called for every subscription and wake event. The CLI logs one line each. */
|
|
276
|
+
onSignalEvent?: (event: OperatorSignalEvent) => void;
|
|
180
277
|
}
|
|
181
278
|
|
|
182
279
|
/**
|
|
@@ -185,14 +282,97 @@ export interface OperatorLoopOptions extends OperatorRoundOptions {
|
|
|
185
282
|
* (issue: "if it dies, nothing breaks and nothing is lost") — this function
|
|
186
283
|
* is exactly `while (!aborted) { round(); sleep(); }`, nothing durable lives
|
|
187
284
|
* in its own memory that a restart would need to recover.
|
|
285
|
+
*
|
|
286
|
+
* With `subscribers` (#1981) the sleep gains a second wake source, and only a
|
|
287
|
+
* wake source. A signal aborts the current sleep; the round that follows is
|
|
288
|
+
* the same round the timer would have run, deriving everything from a fresh
|
|
289
|
+
* observation. Nothing a subscription reports reaches a tick, because the
|
|
290
|
+
* seam has nowhere to put it: `onChange` takes no arguments.
|
|
188
291
|
*/
|
|
189
292
|
export async function runOperatorForever(opts: OperatorLoopOptions): Promise<void> {
|
|
190
293
|
const holder = opts.holder ?? currentHolderId();
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
294
|
+
// Per-op cron state (#2120) lives for the life of the loop. A restart starts
|
|
295
|
+
// it empty, which means the first round ticks a scheduled Op only if it
|
|
296
|
+
// lands on a firing minute — a fresh operator owes no catch-up for the ticks
|
|
297
|
+
// it was not running for.
|
|
298
|
+
const scheduleState = opts.scheduleState ?? new Map<string, Date>();
|
|
299
|
+
const intervalMs = opts.intervalMs ?? DEFAULT_OPERATOR_INTERVAL_MS;
|
|
300
|
+
const subscribers = opts.subscribers ?? [];
|
|
301
|
+
|
|
302
|
+
// Nothing to subscribe to: the loop below is byte for byte the loop that
|
|
303
|
+
// shipped before #1981, and takes none of the machinery's cost.
|
|
304
|
+
if (subscribers.length === 0) {
|
|
305
|
+
while (!opts.signal?.aborted) {
|
|
306
|
+
const events = await runOperatorRound({ ...opts, holder, scheduleState });
|
|
307
|
+
opts.onRound?.(events);
|
|
308
|
+
if (opts.signal?.aborted) break;
|
|
309
|
+
await sleepAbortable(intervalMs, opts.signal);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const gate = createChangeSignalGate({ floorMs: opts.signalFloorMs ?? DEFAULT_SIGNAL_FLOOR_MS });
|
|
315
|
+
// The subscriptions the loop currently holds, by lexicon. A lexicon absent
|
|
316
|
+
// from this map is one to (re-)subscribe on the next round, which is how a
|
|
317
|
+
// killed watch comes back without a special retry path.
|
|
318
|
+
const live = new Map<string, ChangeSubscription>();
|
|
319
|
+
// Stops every subscription at once when the loop ends, whatever ends it.
|
|
320
|
+
const subscriptionsAbort = new AbortController();
|
|
321
|
+
|
|
322
|
+
const closeAll = async (): Promise<void> => {
|
|
323
|
+
subscriptionsAbort.abort();
|
|
324
|
+
const open = [...live.values()];
|
|
325
|
+
live.clear();
|
|
326
|
+
// A close that throws must not mask why the loop is unwinding.
|
|
327
|
+
await Promise.allSettled(open.map((s) => s.close()));
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
const ensureSubscribed = async (): Promise<void> => {
|
|
331
|
+
for (const subscriber of subscribers) {
|
|
332
|
+
if (live.has(subscriber.lexicon) || subscriptionsAbort.signal.aborted) continue;
|
|
333
|
+
try {
|
|
334
|
+
const subscription = await subscriber.subscribe({
|
|
335
|
+
onChange: () => gate.signal(),
|
|
336
|
+
onError: (error) => {
|
|
337
|
+
// Reported once, then forgotten: dropping it from `live` is what
|
|
338
|
+
// makes the next round re-subscribe. The loop itself is untouched.
|
|
339
|
+
if (!live.delete(subscriber.lexicon)) return;
|
|
340
|
+
opts.onSignalEvent?.({ kind: "subscription-lost", lexicon: subscriber.lexicon, error });
|
|
341
|
+
},
|
|
342
|
+
signal: subscriptionsAbort.signal,
|
|
343
|
+
});
|
|
344
|
+
live.set(subscriber.lexicon, subscription);
|
|
345
|
+
opts.onSignalEvent?.({ kind: "subscribed", lexicon: subscriber.lexicon });
|
|
346
|
+
} catch (err) {
|
|
347
|
+
// A subscription that cannot be established is a slower loop, never a
|
|
348
|
+
// stopped one: report it and fall through to the timer.
|
|
349
|
+
opts.onSignalEvent?.({
|
|
350
|
+
kind: "subscribe-failed",
|
|
351
|
+
lexicon: subscriber.lexicon,
|
|
352
|
+
error: err instanceof Error ? err.message : String(err),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
while (!opts.signal?.aborted) {
|
|
360
|
+
gate.roundStarted();
|
|
361
|
+
const startedAt = Date.now();
|
|
362
|
+
const events = await runOperatorRound({ ...opts, holder, scheduleState });
|
|
363
|
+
opts.onRound?.(events);
|
|
364
|
+
if (opts.signal?.aborted) break;
|
|
365
|
+
|
|
366
|
+
await ensureSubscribed();
|
|
367
|
+
if (opts.signal?.aborted) break;
|
|
368
|
+
|
|
369
|
+
const reason: WakeReason = await gate.wait(intervalMs, opts.signal);
|
|
370
|
+
if (reason === "signal") {
|
|
371
|
+
opts.onSignalEvent?.({ kind: "woken", afterMs: Date.now() - startedAt });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
} finally {
|
|
375
|
+
await closeAll();
|
|
196
376
|
}
|
|
197
377
|
}
|
|
198
378
|
|
|
@@ -200,9 +380,12 @@ export async function runOperatorForever(opts: OperatorLoopOptions): Promise<voi
|
|
|
200
380
|
export function formatRoundLine(event: OperatorTickEvent): string {
|
|
201
381
|
switch (event.kind) {
|
|
202
382
|
case "ticked":
|
|
203
|
-
return `operator: ${event.op}@${event.env} ticked=1
|
|
383
|
+
return `operator: ${event.op}@${event.env} ticked=1 status=${event.result.status}` +
|
|
384
|
+
(event.result.gate ? ` gate="${event.result.gate.gate}"` : "");
|
|
204
385
|
case "skipped-lease-held":
|
|
205
386
|
return `operator: ${event.op}@${event.env} skipped=1(lease-held${event.heldBy ? `:${event.heldBy}` : ""})`;
|
|
387
|
+
case "skipped-not-due":
|
|
388
|
+
return `operator: ${event.op}@${event.env} skipped=1(not-due:${event.cron})`;
|
|
206
389
|
case "tick-failed":
|
|
207
390
|
return `operator: ${event.op}@${event.env} failed=1 error="${event.error}"`;
|
|
208
391
|
case "fenced":
|
package/src/op/receipt-store.ts
CHANGED
|
@@ -108,7 +108,7 @@ export interface ReceiptReadArgs extends ReceiptCheckInput {}
|
|
|
108
108
|
export interface ReceiptReadResult {
|
|
109
109
|
/** The receipt's live stored value, or null when absent. */
|
|
110
110
|
current: string | null;
|
|
111
|
-
/** The resolved expectation the
|
|
111
|
+
/** The resolved expectation the effect step compares and later writes. */
|
|
112
112
|
expectation: string;
|
|
113
113
|
/** Convenience: `current === expectation`. */
|
|
114
114
|
applied: boolean;
|
package/src/op/resource.ts
CHANGED
|
@@ -2,7 +2,25 @@ import { createResource } from "../runtime";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The Declarable resource backing an Op definition.
|
|
5
|
-
* entityType: "
|
|
5
|
+
* entityType: "Chant::Op", lexicon: "chant"
|
|
6
6
|
* Discovered automatically alongside infra files — no pipeline changes needed.
|
|
7
|
+
*
|
|
8
|
+
* An Op is chant's own verb, not a runtime's (#2118, epic #2114): the model,
|
|
9
|
+
* the executor and the ledger all live in core, and a lexicon that hosts runs
|
|
10
|
+
* is one runtime among several. The entity type says so.
|
|
7
11
|
*/
|
|
8
|
-
export const
|
|
12
|
+
export const OP_ENTITY_TYPE = "Chant::Op";
|
|
13
|
+
|
|
14
|
+
export const OpResource = createResource(OP_ENTITY_TYPE, "chant", {});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Is this entity an Op declaration?
|
|
18
|
+
*
|
|
19
|
+
* Duck-typed on `entityType` rather than `instanceof OpResource` for the same
|
|
20
|
+
* reason `../build.ts`'s dependency inference is: an entity can be built
|
|
21
|
+
* against a different copy of core (a linked lexicon, a child project) and
|
|
22
|
+
* still be the same declaration.
|
|
23
|
+
*/
|
|
24
|
+
export function isOpEntity(entity: unknown): boolean {
|
|
25
|
+
return (entity as { entityType?: string } | null)?.entityType === OP_ENTITY_TYPE;
|
|
26
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The op-runtime seam (#2121, epic #2114).
|
|
3
|
+
*
|
|
4
|
+
* An Op is a convergent verb; *where* it runs is a separate question from
|
|
5
|
+
* *what* it does. This module states that question once, as a provider
|
|
6
|
+
* contract, so `chant run` has one dispatch path instead of a branch per
|
|
7
|
+
* runtime. Core ships the `local` provider (./runtimes/local.ts) and never
|
|
8
|
+
* imports a hosting lexicon; a lexicon that hosts runs implements
|
|
9
|
+
* {@link OpRuntimeProvider} and hangs it off `LexiconPlugin.opRuntime`, where
|
|
10
|
+
* `chant run <op> --on <lexicon>` finds it.
|
|
11
|
+
*
|
|
12
|
+
* The record shapes below are the run ledger's (#2118): what a run wrote to
|
|
13
|
+
* `<env>/runs__<op>.jsonl` is what a provider's `status` and `log` read back,
|
|
14
|
+
* so a run's outcome survives the process that produced it. A provider with no
|
|
15
|
+
* ledger behind it (a hosting lexicon reporting a live run) fills the same
|
|
16
|
+
* shape from whatever it does know.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { OpConfig } from "./types";
|
|
20
|
+
import type { StepRecord, OpRunResult } from "./local-executor";
|
|
21
|
+
import type { GateResolutionRecord } from "../lifecycle/gate-ledger";
|
|
22
|
+
import type { RunComponentsOptions, RunComponentsResult } from "../components/cli-support";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* How a run ended, or that it has not. `gated` is the state a run reaches when
|
|
26
|
+
* a gate has no recorded resolution — a fact, not a wait (#2119).
|
|
27
|
+
*
|
|
28
|
+
* This is the coarse state a *runtime* reports. The ledger records the
|
|
29
|
+
* executor's own three-state outcome instead ({@link OpRunRecord.status}),
|
|
30
|
+
* which has no `running` or `cancelled`: a record is only written once a run
|
|
31
|
+
* has settled.
|
|
32
|
+
*/
|
|
33
|
+
export type OpRunState = "running" | "completed" | "failed" | "gated" | "cancelled";
|
|
34
|
+
|
|
35
|
+
/** Map a settled run's ledger status onto the coarser runtime state. */
|
|
36
|
+
export function runStateOf(status: OpRunRecord["status"]): OpRunState {
|
|
37
|
+
return status === "ok" ? "completed" : status === "gated" ? "gated" : "failed";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One step's outcome as the run ledger keeps it — `StepRecord` minus the fields only a live renderer needs. */
|
|
41
|
+
export interface OpRunStepRecord {
|
|
42
|
+
/** The activity function name, or `gate:<signal>` for a gate step. */
|
|
43
|
+
fn: string;
|
|
44
|
+
status: StepRecord["status"];
|
|
45
|
+
durationMs: number;
|
|
46
|
+
/** The step's `outcomeAttribute` capture, when it declared one. */
|
|
47
|
+
outcome?: { name: string; value: unknown };
|
|
48
|
+
/** Who cleared this gate step and when (#2119), for a gate the run passed. */
|
|
49
|
+
approval?: { gate: string; resolvedBy: string; timestamp: string; url?: string };
|
|
50
|
+
/** The failure message, for `status: "fail"`. */
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** One phase's steps and the verdict they add up to. */
|
|
55
|
+
export interface OpRunPhaseRecord {
|
|
56
|
+
name: string;
|
|
57
|
+
/** `fail` if any step failed, `skipped` if every step was skipped, else `ok`. */
|
|
58
|
+
status: "ok" | "fail" | "skipped";
|
|
59
|
+
steps: OpRunStepRecord[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A run's current state, as every runtime reports it.
|
|
64
|
+
*
|
|
65
|
+
* `records` and `result` are populated by a runtime that has the executor's
|
|
66
|
+
* own step records to hand (the local one does, for a run it just executed in
|
|
67
|
+
* this process); a runtime answering from the ledger alone omits them rather
|
|
68
|
+
* than inventing them.
|
|
69
|
+
*/
|
|
70
|
+
export interface OpRunStatus {
|
|
71
|
+
op: string;
|
|
72
|
+
runId: string;
|
|
73
|
+
state: OpRunState;
|
|
74
|
+
/** ISO-8601 instant the run started. */
|
|
75
|
+
startedAt: string;
|
|
76
|
+
/** ISO-8601 instant the run settled; absent while it is still running. */
|
|
77
|
+
endedAt?: string;
|
|
78
|
+
/** Per-step records, when the runtime has them. */
|
|
79
|
+
records?: StepRecord[];
|
|
80
|
+
/** The executor's own result, when the runtime is executing in this process. */
|
|
81
|
+
result?: OpRunResult;
|
|
82
|
+
/** The gate this run is waiting on, when `state` is `gated`. */
|
|
83
|
+
gate?: { name: string; since: string };
|
|
84
|
+
/** Free-text detail for a failed run. */
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One immutable, settled Op run — the run ledger's line
|
|
90
|
+
* (`../lifecycle/run-ledger.ts`), and what `chant run log <op>` prints a row
|
|
91
|
+
* per.
|
|
92
|
+
*
|
|
93
|
+
* This is where a run's outcome lives now that `OpConfig` no longer carries
|
|
94
|
+
* `searchAttributes` for the generated workflow to upsert (#2118). `labels` is
|
|
95
|
+
* copied off the declaration so a reader can filter runs the way it filters
|
|
96
|
+
* declarations; `outcomes` is every `outcomeAttribute` the run captured, later
|
|
97
|
+
* steps winning over earlier ones for a repeated name, exactly as an upsert
|
|
98
|
+
* would have.
|
|
99
|
+
*/
|
|
100
|
+
export interface OpRunRecord {
|
|
101
|
+
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
102
|
+
version: 1;
|
|
103
|
+
/** Stable run id — the same string a pending gate fact records for this run. */
|
|
104
|
+
id: string;
|
|
105
|
+
/** The Op's name (`OpConfig.name`). */
|
|
106
|
+
op: string;
|
|
107
|
+
/** The Op's `labels.Env`, or `local` when it declares none. */
|
|
108
|
+
env: string;
|
|
109
|
+
/** ISO-8601 instant the run started. */
|
|
110
|
+
started: string;
|
|
111
|
+
/** ISO-8601 instant the run settled. */
|
|
112
|
+
ended: string;
|
|
113
|
+
/**
|
|
114
|
+
* The executor's three-state outcome. `gated` is neither success nor
|
|
115
|
+
* failure: the run reached a gate nobody has approved, recorded the fact,
|
|
116
|
+
* and stopped (#2119).
|
|
117
|
+
*/
|
|
118
|
+
status: "ok" | "fail" | "gated";
|
|
119
|
+
/** The Op's own `labels`, copied at run time. */
|
|
120
|
+
labels: Record<string, string>;
|
|
121
|
+
/** Every `outcomeAttribute` the run captured, name → value. */
|
|
122
|
+
outcomes: Record<string, unknown>;
|
|
123
|
+
/** Per-phase, per-step status, in execution order. */
|
|
124
|
+
phases: OpRunPhaseRecord[];
|
|
125
|
+
/** The gate the run stopped on, for `status: "gated"`. */
|
|
126
|
+
gate?: { name: string; since: string };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** An {@link OpRunRecord} before the ledger stamps its version and mints an id. */
|
|
130
|
+
export type OpRunRecordInput = Omit<OpRunRecord, "version" | "id"> & { id?: string };
|
|
131
|
+
|
|
132
|
+
/** A started run. `result()` settles with the run's final status. */
|
|
133
|
+
export interface OpRunHandle {
|
|
134
|
+
op: string;
|
|
135
|
+
runId: string;
|
|
136
|
+
result(): Promise<OpRunStatus>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** What a caller hands a runtime when it starts a run. */
|
|
140
|
+
export interface OpRunStartOptions {
|
|
141
|
+
/** Build-time parameter bindings, when the caller resolved any. */
|
|
142
|
+
params?: Record<string, unknown>;
|
|
143
|
+
/** Target environment (`--env`). */
|
|
144
|
+
env?: string;
|
|
145
|
+
/**
|
|
146
|
+
* `-p, --profile <name>` (#2124, restored in #2192) — the named connection
|
|
147
|
+
* profile this runtime should target. Only a runtime that has profiles
|
|
148
|
+
* reads it; the local one ignores it, and a runtime that reads it decides
|
|
149
|
+
* for itself what an unknown name means (fountain refuses it rather than
|
|
150
|
+
* falling back to its default).
|
|
151
|
+
*/
|
|
152
|
+
profile?: string;
|
|
153
|
+
/** Called once per settled step, so `--progress-json` can stream. */
|
|
154
|
+
progress?: (record: StepRecord) => void;
|
|
155
|
+
/** Aborts in-flight work (Ctrl-C). */
|
|
156
|
+
signal?: AbortSignal;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The contract a runtime implements to host Op runs.
|
|
161
|
+
*
|
|
162
|
+
* `chant run` resolves exactly one provider per invocation — the named
|
|
163
|
+
* lexicon's for `--on <name>`, the built-in `local` one otherwise — and every
|
|
164
|
+
* subcommand calls it. A provider that cannot do something (cancel a
|
|
165
|
+
* foreground run, host components) says so by throwing a message the CLI
|
|
166
|
+
* prints verbatim, or by omitting the optional member.
|
|
167
|
+
*/
|
|
168
|
+
export interface OpRuntimeProvider {
|
|
169
|
+
/** How the CLI names this runtime in messages, and what `--on` matches. */
|
|
170
|
+
readonly name: string;
|
|
171
|
+
|
|
172
|
+
/** Start a run. Rejects with an actionable Error when it cannot. */
|
|
173
|
+
start(op: OpConfig, opts: OpRunStartOptions): Promise<OpRunHandle>;
|
|
174
|
+
|
|
175
|
+
/** The latest run's state, or `undefined` when this runtime has none recorded. */
|
|
176
|
+
status(op: string): Promise<OpRunStatus | undefined>;
|
|
177
|
+
|
|
178
|
+
/** Run history, newest first. Empty when nothing is recorded. */
|
|
179
|
+
log(op: string, opts?: { limit?: number }): Promise<OpRunRecord[]>;
|
|
180
|
+
|
|
181
|
+
/** Latest state for each of `ops`, keyed by op name. */
|
|
182
|
+
list(ops: OpConfig[]): Promise<Map<string, OpRunStatus | undefined>>;
|
|
183
|
+
|
|
184
|
+
/** Cancel the active run. `force` is the CLI's confirmation, already checked. */
|
|
185
|
+
cancel(op: string, opts: { force: boolean }): Promise<void>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Wake a run whose gate has just been resolved. The ledger write is the
|
|
189
|
+
* fact and `chant approve` owns it; this is the runtime's chance to act on
|
|
190
|
+
* it. Omit when a run re-reads the ledger on its own.
|
|
191
|
+
*/
|
|
192
|
+
resolveGate?(op: string, gate: string, resolution: GateResolutionRecord): Promise<void>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Host `chant run --components`. Optional: a runtime without it refuses the
|
|
196
|
+
* flag with one line naming itself.
|
|
197
|
+
*/
|
|
198
|
+
runComponents?(
|
|
199
|
+
projectPath: string,
|
|
200
|
+
selector: string,
|
|
201
|
+
options: RunComponentsOptions,
|
|
202
|
+
): Promise<RunComponentsResult>;
|
|
203
|
+
}
|