@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/builders.ts
CHANGED
|
@@ -2,7 +2,17 @@ import { OpResource } from "./resource";
|
|
|
2
2
|
import type { OpConfig, PhaseDefinition, StepDefinition, ActivityStep, GateStep, EffectStep } from "./types";
|
|
3
3
|
import { isEffectReceipt, type EffectReceiptDeclaration } from "../effect-receipt";
|
|
4
4
|
import { receiptCheckInput } from "./receipt-store";
|
|
5
|
-
import { makeOutProxy, type StepOutputRef } from "./step-output-ref";
|
|
5
|
+
import { makeOutProxy, type StepOutputRef, type WithStepRefs } from "./step-output-ref";
|
|
6
|
+
import type { ChantBuildArgs } from "./activities/build";
|
|
7
|
+
import type { ShellCmdArgs } from "./activities/shell";
|
|
8
|
+
import type { WaitForStackArgs } from "./activities/wait";
|
|
9
|
+
import type { LifecycleSnapshotArgs } from "./activities/lifecycle";
|
|
10
|
+
import type { ChantTeardownArgs } from "./activities/teardown";
|
|
11
|
+
import type { EnvTeardownArgs } from "./activities/env-teardown";
|
|
12
|
+
import type { HttpCheckArgs } from "./activities/http-check";
|
|
13
|
+
import type { PolicyGateArgs } from "./activities/policy";
|
|
14
|
+
import type { GuardValidateArgs } from "./activities/guard-validate";
|
|
15
|
+
import { isValidCronExpression, cronSyntaxMessage } from "./cron";
|
|
6
16
|
|
|
7
17
|
/** An `activity()` result — the plain `ActivityStep` shape plus the `.out` reference sugar (#1290). */
|
|
8
18
|
export interface NamedActivityStep extends ActivityStep {
|
|
@@ -18,7 +28,7 @@ export interface NamedActivityStep extends ActivityStep {
|
|
|
18
28
|
// ── Core builders ─────────────────────────────────────────────────────────────
|
|
19
29
|
|
|
20
30
|
/**
|
|
21
|
-
* Declare a named, phased
|
|
31
|
+
* Declare a named, phased Op.
|
|
22
32
|
*
|
|
23
33
|
* @example
|
|
24
34
|
* ```ts
|
|
@@ -31,8 +41,15 @@ export interface NamedActivityStep extends ActivityStep {
|
|
|
31
41
|
* ],
|
|
32
42
|
* });
|
|
33
43
|
* ```
|
|
44
|
+
*
|
|
45
|
+
* A `schedule` may be supplied for an Op that runs on a cadence (#2120); its
|
|
46
|
+
* cron is validated here, at construction, so a typo fails on `chant build`
|
|
47
|
+
* rather than becoming a schedule that silently never fires.
|
|
34
48
|
*/
|
|
35
49
|
export function Op(config: OpConfig): InstanceType<typeof OpResource> {
|
|
50
|
+
if (config.schedule && !isValidCronExpression(config.schedule.cron)) {
|
|
51
|
+
throw new Error(`Op "${config.name}": ${cronSyntaxMessage(config.schedule.cron)}`);
|
|
52
|
+
}
|
|
36
53
|
return new OpResource(config as unknown as Record<string, unknown>);
|
|
37
54
|
}
|
|
38
55
|
|
|
@@ -85,14 +102,19 @@ export function activity(
|
|
|
85
102
|
return step;
|
|
86
103
|
}
|
|
87
104
|
|
|
88
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Insert a human gate. A gate is a fact on the gate ledger, not a wait: a run
|
|
107
|
+
* that reaches this step with no resolution newer than its pending fact
|
|
108
|
+
* records the pending fact and ends `gated`. `chant approve <op> <gate>`
|
|
109
|
+
* writes the resolution, and the next run walks through carrying the approver.
|
|
110
|
+
*/
|
|
89
111
|
export function gate(
|
|
90
|
-
|
|
112
|
+
name: string,
|
|
91
113
|
opts?: { timeout?: string; description?: string },
|
|
92
114
|
): GateStep {
|
|
93
115
|
return {
|
|
94
116
|
kind: "gate",
|
|
95
|
-
|
|
117
|
+
gate: name,
|
|
96
118
|
...(opts?.timeout ? { timeout: opts.timeout } : {}),
|
|
97
119
|
...(opts?.description ? { description: opts.description } : {}),
|
|
98
120
|
};
|
|
@@ -113,9 +135,10 @@ export function gate(
|
|
|
113
135
|
* would sever the step from the declaration that lint, plan, and the lexicon
|
|
114
136
|
* row all key on.
|
|
115
137
|
*
|
|
116
|
-
* A gate authored inside `steps`
|
|
117
|
-
* matched path never reaches it). The receipt-store activities
|
|
118
|
-
* `receiptWrite`) are provided by the receipt row's lexicon
|
|
138
|
+
* A gate authored inside `steps` is reached only when the effect will fire
|
|
139
|
+
* (the matched path never reaches it). The receipt-store activities
|
|
140
|
+
* (`receiptRead`, `receiptWrite`) are provided by the receipt row's lexicon
|
|
141
|
+
* (#1835, aws).
|
|
119
142
|
*
|
|
120
143
|
* @example
|
|
121
144
|
* ```ts
|
|
@@ -190,10 +213,25 @@ export function takeProfileAndId(
|
|
|
190
213
|
return { args, profile, id };
|
|
191
214
|
}
|
|
192
215
|
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Extra opts every typed base-activity wrapper below accepts alongside its
|
|
218
|
+
* activity's own fields: the step's `profile` override and its `id` (which
|
|
219
|
+
* routes to the step, never into args, so `.out` works — chant #1290).
|
|
220
|
+
*/
|
|
221
|
+
type StepOpts = { profile?: ActivityStep["profile"]; id?: string };
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Run an npm build script in the given project directory. `opts` is
|
|
225
|
+
* {@link ChantBuildArgs} itself, minus the positional `path` — `script`
|
|
226
|
+
* selects the npm script (default `build`, e.g. `build:aws`), `env` adds
|
|
227
|
+
* env vars.
|
|
228
|
+
*/
|
|
229
|
+
export const build = (
|
|
230
|
+
path: string,
|
|
231
|
+
opts?: WithStepRefs<Omit<ChantBuildArgs, "path">> & StepOpts,
|
|
232
|
+
): NamedActivityStep => {
|
|
233
|
+
const { args, profile, id } = takeProfileAndId(opts as Record<string, unknown> | undefined);
|
|
234
|
+
return activity("chantBuild", { path, ...args }, { ...(profile ? { profile } : {}), ...(id ? { id } : {}) });
|
|
197
235
|
};
|
|
198
236
|
|
|
199
237
|
/** Run `kubectl apply -f <manifest>`. Defaults to the `longInfra` profile (override via `opts.profile`). */
|
|
@@ -228,10 +266,17 @@ export const helmInstallPinned = (
|
|
|
228
266
|
return activity("helmInstall", { name, contentDigest, ...args }, profile ?? "longInfra");
|
|
229
267
|
};
|
|
230
268
|
|
|
231
|
-
/**
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Poll until a Kubernetes Deployment/StatefulSet is fully rolled out. `opts` is
|
|
271
|
+
* {@link WaitForStackArgs} itself, minus the positional `name`. Defaults to the
|
|
272
|
+
* `k8sWait` profile (override via `opts.profile`).
|
|
273
|
+
*/
|
|
274
|
+
export const waitForStack = (
|
|
275
|
+
name: string,
|
|
276
|
+
opts?: WithStepRefs<Omit<WaitForStackArgs, "name">> & StepOpts,
|
|
277
|
+
): NamedActivityStep => {
|
|
278
|
+
const { args, profile, id } = takeProfileAndId(opts as Record<string, unknown> | undefined);
|
|
279
|
+
return activity("waitForStack", { name, ...args }, { profile: profile ?? "k8sWait", ...(id ? { id } : {}) });
|
|
235
280
|
};
|
|
236
281
|
|
|
237
282
|
/** Poll any operator-backed Kubernetes resource until it reports ready, driven by a data-only readiness spec (CRD-aware; #365). Defaults to the `k8sWait` profile (override via `opts.profile`). */
|
|
@@ -246,20 +291,26 @@ export const gitlabPipeline = (name: string, opts?: Record<string, unknown>): Ac
|
|
|
246
291
|
return activity("gitlabPipeline", { name, ...args }, profile ?? "longInfra");
|
|
247
292
|
};
|
|
248
293
|
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Take a chant lifecycle snapshot for the given environment.
|
|
296
|
+
* {@link LifecycleSnapshotArgs} has only `env`, which is positional here, so
|
|
297
|
+
* `opts` carries nothing but the step's `id` (for `.out`).
|
|
298
|
+
*/
|
|
299
|
+
export const lifecycleSnapshot = (env: string, opts?: { id?: string }): NamedActivityStep =>
|
|
300
|
+
activity("lifecycleSnapshot", { env } satisfies LifecycleSnapshotArgs, opts?.id ? { id: opts.id } : undefined);
|
|
252
301
|
|
|
253
302
|
/**
|
|
254
303
|
* Run an arbitrary shell command. Tag long-running commands with a `profile`
|
|
255
304
|
* (e.g. `longInfra` for a multi-GB image push) so they get the right
|
|
256
|
-
* start-to-close timeout
|
|
305
|
+
* start-to-close timeout on whichever runtime hosts the run.
|
|
257
306
|
*/
|
|
258
307
|
export const shell = (
|
|
259
308
|
cmd: string,
|
|
260
|
-
opts?:
|
|
261
|
-
):
|
|
262
|
-
|
|
309
|
+
opts?: WithStepRefs<Omit<ShellCmdArgs, "cmd">> & StepOpts,
|
|
310
|
+
): NamedActivityStep => {
|
|
311
|
+
const { args, profile, id } = takeProfileAndId(opts as Record<string, unknown> | undefined);
|
|
312
|
+
return activity("shellCmd", { cmd, ...args }, { ...(profile ? { profile } : {}), ...(id ? { id } : {}) });
|
|
313
|
+
};
|
|
263
314
|
|
|
264
315
|
/**
|
|
265
316
|
* Ensure a `generated-once` secret exists in the target store (#1829, epic
|
|
@@ -283,9 +334,17 @@ export const ensureSecret = (
|
|
|
283
334
|
return activity("ensureSecret", { name, keys, ...args }, profile);
|
|
284
335
|
};
|
|
285
336
|
|
|
286
|
-
/**
|
|
287
|
-
|
|
288
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Run `chant teardown` in the given project directory. Fixed `longInfra`
|
|
339
|
+
* profile (not overridable). {@link ChantTeardownArgs} has only `path`
|
|
340
|
+
* (positional), so `opts` is just the step's `id` (for `.out`).
|
|
341
|
+
*/
|
|
342
|
+
export const teardown = (path: string, opts?: { id?: string }): NamedActivityStep =>
|
|
343
|
+
activity(
|
|
344
|
+
"chantTeardown",
|
|
345
|
+
{ path } satisfies ChantTeardownArgs,
|
|
346
|
+
{ profile: "longInfra", ...(opts?.id ? { id: opts.id } : {}) },
|
|
347
|
+
);
|
|
289
348
|
|
|
290
349
|
/**
|
|
291
350
|
* Tear down one environment's marker-owned resources — the durable form of
|
|
@@ -309,13 +368,16 @@ export const teardown = (path: string): ActivityStep =>
|
|
|
309
368
|
* ]),
|
|
310
369
|
* ```
|
|
311
370
|
*
|
|
312
|
-
* `opts` also accepts `path` (the chant project directory, default the
|
|
313
|
-
*
|
|
371
|
+
* `opts` also accepts `path` (the chant project directory, default the chant
|
|
372
|
+
* process's cwd). Defaults to the `longInfra` profile (override via
|
|
314
373
|
* `opts.profile`).
|
|
315
374
|
*/
|
|
316
|
-
export const envTeardown = (
|
|
317
|
-
|
|
318
|
-
|
|
375
|
+
export const envTeardown = (
|
|
376
|
+
env: string,
|
|
377
|
+
opts?: WithStepRefs<Omit<EnvTeardownArgs, "env">> & StepOpts,
|
|
378
|
+
): NamedActivityStep => {
|
|
379
|
+
const { args, profile, id } = takeProfileAndId(opts as Record<string, unknown> | undefined);
|
|
380
|
+
return activity("envTeardown", { env, ...args }, { profile: profile ?? "longInfra", ...(id ? { id } : {}) });
|
|
319
381
|
};
|
|
320
382
|
|
|
321
383
|
/**
|
|
@@ -455,9 +517,12 @@ export const flociGcpDown = (opts?: Record<string, unknown>): ActivityStep => {
|
|
|
455
517
|
* Defaults to the `fastIdempotent` profile. `opts` accepts `method`, `status`
|
|
456
518
|
* (default any 2xx), `contains` (body substring), `retries`, `intervalMs`.
|
|
457
519
|
*/
|
|
458
|
-
export const httpCheck = (
|
|
459
|
-
|
|
460
|
-
|
|
520
|
+
export const httpCheck = (
|
|
521
|
+
url: string,
|
|
522
|
+
opts?: WithStepRefs<Omit<HttpCheckArgs, "url">> & StepOpts,
|
|
523
|
+
): NamedActivityStep => {
|
|
524
|
+
const { args, profile, id } = takeProfileAndId(opts as Record<string, unknown> | undefined);
|
|
525
|
+
return activity("httpCheck", { url, ...args }, { profile: profile ?? "fastIdempotent", ...(id ? { id } : {}) });
|
|
461
526
|
};
|
|
462
527
|
|
|
463
528
|
/**
|
|
@@ -546,7 +611,7 @@ export const gcpDelete = (manifestPath: string, opts?: Record<string, unknown>):
|
|
|
546
611
|
// The builder and the executor-side activity function share a name (e.g.
|
|
547
612
|
// `spriteCreate`), and that is intentional: the builder here returns an
|
|
548
613
|
// `activity("spriteCreate", ...)` step; `loadActivities` loads the function of
|
|
549
|
-
// the same name from the
|
|
614
|
+
// the same name from the fly lexicon to run the HTTP. They live in
|
|
550
615
|
// different modules and are both exported — exactly how `flapsUp`/`flapsDown`
|
|
551
616
|
// already work. Op files import these builders; the executor resolves the
|
|
552
617
|
// function by name. Endpoint override + bearer are read by the activity from
|
|
@@ -806,14 +871,33 @@ export const spritesDown = (args: {
|
|
|
806
871
|
|
|
807
872
|
/**
|
|
808
873
|
* Gate an apply on organizational policy: build the project and run its
|
|
809
|
-
* `lint.policies` over the resolved resources,
|
|
810
|
-
* violation. Place it before the apply phase. `env` (or `ownership.env`) lets a
|
|
874
|
+
* `lint.policies` over the resolved resources, failing the step on any
|
|
875
|
+
* violation so no later phase runs. Place it before the apply phase. `env` (or `ownership.env`) lets a
|
|
811
876
|
* policy branch on environment. Single-attempt (`policyCheck` profile) — a
|
|
812
877
|
* deterministic violation is not retried.
|
|
813
878
|
*/
|
|
814
|
-
export const policyGate = (opts?:
|
|
815
|
-
|
|
879
|
+
export const policyGate = (opts?: WithStepRefs<PolicyGateArgs> & { id?: string }): NamedActivityStep => {
|
|
880
|
+
const path = (opts?.path as PolicyGateArgs["path"] | undefined) ?? ".";
|
|
881
|
+
const env = opts?.env;
|
|
882
|
+
return activity(
|
|
816
883
|
"policyGate",
|
|
817
|
-
{ path
|
|
818
|
-
"policyCheck",
|
|
884
|
+
{ path, ...(env !== undefined ? { env } : {}) },
|
|
885
|
+
{ profile: "policyCheck", ...(opts?.id ? { id: opts.id } : {}) },
|
|
819
886
|
);
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Run an external CloudFormation Guard rules pack against the project's built
|
|
891
|
+
* CloudFormation template (chant #522). `opts` is {@link GuardValidateArgs}
|
|
892
|
+
* itself, minus the positional `rules`; `template` defaults (inside the
|
|
893
|
+
* activity) to `<path>/template.json`. Fixed `policyCheck` profile — same
|
|
894
|
+
* reasoning as {@link policyGate}: a deterministic policy check is
|
|
895
|
+
* single-attempt — and not overridable.
|
|
896
|
+
*/
|
|
897
|
+
export const guardValidate = (
|
|
898
|
+
rules: string,
|
|
899
|
+
opts?: WithStepRefs<Omit<GuardValidateArgs, "rules">> & { id?: string },
|
|
900
|
+
): NamedActivityStep => {
|
|
901
|
+
const { id, ...rest } = (opts ?? {}) as Omit<GuardValidateArgs, "rules"> & { id?: string };
|
|
902
|
+
return activity("guardValidate", { rules, ...rest }, { profile: "policyCheck", ...(id ? { id } : {}) });
|
|
903
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wake gate (#1981): coalescing, the floor, and abort.
|
|
3
|
+
*
|
|
4
|
+
* Real timers with small floors rather than fake ones: the gate is nothing but
|
|
5
|
+
* two `setTimeout`s racing, and a fake-timer test of that asserts the mock
|
|
6
|
+
* rather than the behaviour.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, test, expect } from "vitest";
|
|
9
|
+
import { createChangeSignalGate, DEFAULT_SIGNAL_FLOOR_MS } from "./change-signal";
|
|
10
|
+
|
|
11
|
+
describe("createChangeSignalGate", () => {
|
|
12
|
+
test("no signal: the wait runs the full interval and reports the timer", async () => {
|
|
13
|
+
const gate = createChangeSignalGate({ floorMs: 10 });
|
|
14
|
+
gate.roundStarted();
|
|
15
|
+
const started = Date.now();
|
|
16
|
+
expect(await gate.wait(60)).toBe("timer");
|
|
17
|
+
expect(Date.now() - started).toBeGreaterThanOrEqual(45);
|
|
18
|
+
expect(gate.wakeCount).toBe(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("a signal past the floor wakes the sleep early", async () => {
|
|
22
|
+
const gate = createChangeSignalGate({ floorMs: 0 });
|
|
23
|
+
gate.roundStarted();
|
|
24
|
+
const started = Date.now();
|
|
25
|
+
const waiting = gate.wait(5_000);
|
|
26
|
+
setTimeout(() => gate.signal(), 10);
|
|
27
|
+
expect(await waiting).toBe("signal");
|
|
28
|
+
expect(Date.now() - started).toBeLessThan(2_000);
|
|
29
|
+
expect(gate.wakeCount).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("a signal inside the floor waits the floor out rather than waking at once", async () => {
|
|
33
|
+
const gate = createChangeSignalGate({ floorMs: 120 });
|
|
34
|
+
gate.roundStarted();
|
|
35
|
+
const started = Date.now();
|
|
36
|
+
const waiting = gate.wait(5_000);
|
|
37
|
+
gate.signal();
|
|
38
|
+
expect(await waiting).toBe("signal");
|
|
39
|
+
// Woken by the signal, but not before the floor had passed.
|
|
40
|
+
expect(Date.now() - started).toBeGreaterThanOrEqual(100);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("a storm of signals inside one floor window costs exactly one wake", async () => {
|
|
44
|
+
const gate = createChangeSignalGate({ floorMs: 60 });
|
|
45
|
+
gate.roundStarted();
|
|
46
|
+
const waiting = gate.wait(5_000);
|
|
47
|
+
for (let i = 0; i < 500; i++) gate.signal();
|
|
48
|
+
expect(await waiting).toBe("signal");
|
|
49
|
+
expect(gate.signalCount).toBe(500);
|
|
50
|
+
expect(gate.wakeCount).toBe(1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("the floor is measured from the round, so a steady stream cannot starve the tick", async () => {
|
|
54
|
+
const gate = createChangeSignalGate({ floorMs: 80 });
|
|
55
|
+
gate.roundStarted();
|
|
56
|
+
const started = Date.now();
|
|
57
|
+
const waiting = gate.wait(5_000);
|
|
58
|
+
// A signal every 10ms. A debounce would push the deadline out forever.
|
|
59
|
+
const drip = setInterval(() => gate.signal(), 10);
|
|
60
|
+
const reason = await waiting;
|
|
61
|
+
clearInterval(drip);
|
|
62
|
+
expect(reason).toBe("signal");
|
|
63
|
+
expect(Date.now() - started).toBeLessThan(1_000);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("a signal arriving between rounds is honoured by the next wait, not lost", async () => {
|
|
67
|
+
const gate = createChangeSignalGate({ floorMs: 0 });
|
|
68
|
+
gate.roundStarted();
|
|
69
|
+
gate.signal(); // nothing is sleeping yet
|
|
70
|
+
expect(await gate.wait(5_000)).toBe("signal");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("roundStarted clears the pending flag, so one signal never wakes two rounds", async () => {
|
|
74
|
+
const gate = createChangeSignalGate({ floorMs: 0 });
|
|
75
|
+
gate.roundStarted();
|
|
76
|
+
gate.signal();
|
|
77
|
+
expect(await gate.wait(5_000)).toBe("signal");
|
|
78
|
+
gate.roundStarted();
|
|
79
|
+
expect(await gate.wait(40)).toBe("timer");
|
|
80
|
+
expect(gate.wakeCount).toBe(1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("abort resolves rather than throwing, before and during a wait", async () => {
|
|
84
|
+
const gate = createChangeSignalGate({ floorMs: 0 });
|
|
85
|
+
const already = new AbortController();
|
|
86
|
+
already.abort();
|
|
87
|
+
expect(await gate.wait(5_000, already.signal)).toBe("aborted");
|
|
88
|
+
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
const waiting = gate.wait(5_000, controller.signal);
|
|
91
|
+
setTimeout(() => controller.abort(), 10);
|
|
92
|
+
expect(await waiting).toBe("aborted");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("a signal after abort does nothing", async () => {
|
|
96
|
+
const gate = createChangeSignalGate({ floorMs: 0 });
|
|
97
|
+
const controller = new AbortController();
|
|
98
|
+
const waiting = gate.wait(5_000, controller.signal);
|
|
99
|
+
controller.abort();
|
|
100
|
+
expect(await waiting).toBe("aborted");
|
|
101
|
+
gate.signal();
|
|
102
|
+
expect(gate.wakeCount).toBe(0);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("signal() carries no payload: the type has no argument and the call ignores one", () => {
|
|
106
|
+
const gate = createChangeSignalGate();
|
|
107
|
+
expect(gate.signal.length).toBe(0);
|
|
108
|
+
// A caller that fabricates an event has nowhere to put it: the extra
|
|
109
|
+
// argument is dropped, and the gate's only state is a boolean.
|
|
110
|
+
(gate.signal as (...args: unknown[]) => void)({ kind: "Deployment", name: "fabricated" });
|
|
111
|
+
expect(gate.signalCount).toBe(1);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("the documented floor is a real, positive default", () => {
|
|
115
|
+
expect(DEFAULT_SIGNAL_FLOOR_MS).toBe(5_000);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wake gate between a substrate's change signal and `chant operator`'s
|
|
3
|
+
* sleep (#1981, epic #1487).
|
|
4
|
+
*
|
|
5
|
+
* A lexicon that implements `subscribeChanges` (`../lexicon.ts`) can say
|
|
6
|
+
* "something moved". This module is everything the loop does with that: it
|
|
7
|
+
* shortens the current sleep, at most once per floor. It is deliberately the
|
|
8
|
+
* only place a signal touches, so the rule that a signal is a trigger and
|
|
9
|
+
* never a fact is a property of the code rather than a convention. Nothing
|
|
10
|
+
* here has a parameter, a return value or a field that could carry what
|
|
11
|
+
* changed.
|
|
12
|
+
*
|
|
13
|
+
* ## Backpressure: the floor
|
|
14
|
+
*
|
|
15
|
+
* A watch on a busy namespace is not a trickle. A rollout, a Job sweep or a
|
|
16
|
+
* controller resyncing its whole world produces hundreds of events in a
|
|
17
|
+
* second, and each one is a truthful "something moved". Waking a tick per
|
|
18
|
+
* event would turn a convergence loop into a load generator pointed at the
|
|
19
|
+
* cluster it is meant to be watching.
|
|
20
|
+
*
|
|
21
|
+
* So the gate coalesces. Signals are collapsed into a single pending flag, and
|
|
22
|
+
* a pending flag wakes the sleep no earlier than {@link
|
|
23
|
+
* ChangeSignalGateOptions.floorMs} after the last round *started*. A storm of
|
|
24
|
+
* a thousand signals inside one floor window costs exactly one early wake, and
|
|
25
|
+
* a substrate that never stops sending settles into ticking on the floor
|
|
26
|
+
* rather than on the interval, which is the fastest the loop is ever allowed
|
|
27
|
+
* to run.
|
|
28
|
+
*
|
|
29
|
+
* The floor is measured from the start of the last round, not from the last
|
|
30
|
+
* signal, so a steady stream can never push the wake further out (that would
|
|
31
|
+
* be a debounce, and a debounce starves: the busier the cluster, the later the
|
|
32
|
+
* tick). Measuring from the round start makes the guarantee a rate limit,
|
|
33
|
+
* never more than one signal-driven tick per floor, which is the property the
|
|
34
|
+
* loop actually needs.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The shortest gap between two rounds a change signal may produce. Signals
|
|
39
|
+
* arriving inside this window of the last round's start are coalesced into one
|
|
40
|
+
* wake at the end of it.
|
|
41
|
+
*
|
|
42
|
+
* Five seconds: long enough that a rollout's event storm costs one tick rather
|
|
43
|
+
* than dozens, short enough that "wakes within a second or so of a change"
|
|
44
|
+
* holds for the quiet case a signal exists for. The timer
|
|
45
|
+
* (`DEFAULT_OPERATOR_INTERVAL_MS`, 60s) is unchanged and remains the ceiling.
|
|
46
|
+
*/
|
|
47
|
+
export const DEFAULT_SIGNAL_FLOOR_MS = 5_000;
|
|
48
|
+
|
|
49
|
+
/** Why {@link ChangeSignalGate.wait} returned. */
|
|
50
|
+
export type WakeReason =
|
|
51
|
+
/** The full interval elapsed. An ordinary timer-driven round. */
|
|
52
|
+
| "timer"
|
|
53
|
+
/** A substrate signalled and the floor had passed. An early round. */
|
|
54
|
+
| "signal"
|
|
55
|
+
/** The operator is stopping. */
|
|
56
|
+
| "aborted";
|
|
57
|
+
|
|
58
|
+
export interface ChangeSignalGateOptions {
|
|
59
|
+
/** @default DEFAULT_SIGNAL_FLOOR_MS */
|
|
60
|
+
floorMs?: number;
|
|
61
|
+
/** Injectable clock, for tests. @default Date.now */
|
|
62
|
+
now?: () => number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* One operator loop's wake gate. Not reusable across loops: it carries the
|
|
67
|
+
* time the current loop last started a round, which is what the floor is
|
|
68
|
+
* measured from.
|
|
69
|
+
*/
|
|
70
|
+
export interface ChangeSignalGate {
|
|
71
|
+
/**
|
|
72
|
+
* A substrate said something moved. Takes nothing and returns nothing, and
|
|
73
|
+
* that is the enforcement of "a trigger, never a fact": there is no
|
|
74
|
+
* argument for a watch event to ride in on.
|
|
75
|
+
*
|
|
76
|
+
* Safe to call at any time, including while no `wait` is in flight (the flag
|
|
77
|
+
* is remembered and honoured by the next one) and after the loop has
|
|
78
|
+
* stopped (it does nothing).
|
|
79
|
+
*/
|
|
80
|
+
signal(): void;
|
|
81
|
+
/** The loop is starting a round now. Resets the pending flag and the floor. */
|
|
82
|
+
roundStarted(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Sleep up to `intervalMs`, resolving early when a signal has passed the
|
|
85
|
+
* floor. Resolves rather than throws on abort, like the timer-only sleep it
|
|
86
|
+
* replaces, so Ctrl-C never surfaces as a loop failure.
|
|
87
|
+
*/
|
|
88
|
+
wait(intervalMs: number, abortSignal?: AbortSignal): Promise<WakeReason>;
|
|
89
|
+
/** How many signals have arrived, coalesced or not. Diagnostics and tests. */
|
|
90
|
+
readonly signalCount: number;
|
|
91
|
+
/** How many of those actually shortened a sleep. Diagnostics and tests. */
|
|
92
|
+
readonly wakeCount: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createChangeSignalGate(options: ChangeSignalGateOptions = {}): ChangeSignalGate {
|
|
96
|
+
const floorMs = options.floorMs ?? DEFAULT_SIGNAL_FLOOR_MS;
|
|
97
|
+
const now = options.now ?? (() => Date.now());
|
|
98
|
+
|
|
99
|
+
let pending = false;
|
|
100
|
+
let lastRoundAt = now();
|
|
101
|
+
let signalCount = 0;
|
|
102
|
+
let wakeCount = 0;
|
|
103
|
+
/** Set only while a `wait` is in flight. */
|
|
104
|
+
let arm: (() => void) | undefined;
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
get signalCount() {
|
|
108
|
+
return signalCount;
|
|
109
|
+
},
|
|
110
|
+
get wakeCount() {
|
|
111
|
+
return wakeCount;
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
signal() {
|
|
115
|
+
signalCount++;
|
|
116
|
+
pending = true;
|
|
117
|
+
arm?.();
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
roundStarted() {
|
|
121
|
+
lastRoundAt = now();
|
|
122
|
+
pending = false;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
wait(intervalMs: number, abortSignal?: AbortSignal): Promise<WakeReason> {
|
|
126
|
+
return new Promise<WakeReason>((resolve) => {
|
|
127
|
+
if (abortSignal?.aborted) return resolve("aborted");
|
|
128
|
+
|
|
129
|
+
let settled = false;
|
|
130
|
+
let floorTimer: ReturnType<typeof setTimeout> | undefined;
|
|
131
|
+
|
|
132
|
+
const finish = (reason: WakeReason) => {
|
|
133
|
+
if (settled) return;
|
|
134
|
+
settled = true;
|
|
135
|
+
clearTimeout(intervalTimer);
|
|
136
|
+
if (floorTimer) clearTimeout(floorTimer);
|
|
137
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
138
|
+
arm = undefined;
|
|
139
|
+
if (reason === "signal") wakeCount++;
|
|
140
|
+
resolve(reason);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const intervalTimer = setTimeout(() => finish("timer"), intervalMs);
|
|
144
|
+
const onAbort = () => finish("aborted");
|
|
145
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
146
|
+
|
|
147
|
+
// A pending signal wakes the sleep the moment the floor has passed,
|
|
148
|
+
// and not one moment earlier. `remaining` is measured from the last
|
|
149
|
+
// round's start, so repeated signals inside the window collapse onto
|
|
150
|
+
// the same deadline instead of pushing it out.
|
|
151
|
+
const consider = () => {
|
|
152
|
+
if (settled || !pending) return;
|
|
153
|
+
const remaining = lastRoundAt + floorMs - now();
|
|
154
|
+
if (remaining <= 0) return finish("signal");
|
|
155
|
+
if (floorTimer) return; // already waiting out this window
|
|
156
|
+
floorTimer = setTimeout(() => {
|
|
157
|
+
floorTimer = undefined;
|
|
158
|
+
consider();
|
|
159
|
+
}, remaining);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
arm = consider;
|
|
163
|
+
// A signal that arrived between rounds, while nothing was sleeping,
|
|
164
|
+
// is honoured here rather than lost.
|
|
165
|
+
consider();
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|