@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
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* `loadProfiles` from the project's configured lexicons).
|
|
8
8
|
*/
|
|
9
9
|
import { loadChantConfig } from "../../config";
|
|
10
|
+
import { build } from "../../build";
|
|
11
|
+
import { isResourceDeclarable } from "../../declarable";
|
|
12
|
+
import { collectBuildRootContributors, collectChangeSubscribers } from "../plugins";
|
|
10
13
|
import { discoverOps } from "../../op/discover";
|
|
11
14
|
import { loadActivities, loadProfiles } from "../../op/activity-registry";
|
|
12
15
|
import { parseDuration } from "../../op/local-executor";
|
|
@@ -15,18 +18,27 @@ import {
|
|
|
15
18
|
runOperatorRound,
|
|
16
19
|
runOperatorForever,
|
|
17
20
|
formatRoundLine,
|
|
21
|
+
formatSignalLine,
|
|
18
22
|
DEFAULT_OPERATOR_INTERVAL_MS,
|
|
23
|
+
type ChangeSubscriber,
|
|
24
|
+
type OperatorSignalEvent,
|
|
19
25
|
type OperatorTickEvent,
|
|
20
26
|
} from "../../op/operator";
|
|
21
27
|
import { readLease, DEFAULT_LEASE_TTL_MS } from "../../lifecycle/lease";
|
|
22
28
|
import { readConvergeLedger, type ConvergeTickRecord } from "../../lifecycle/converge-ledger";
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
29
|
+
import { readRunLedger } from "../../lifecycle/run-ledger";
|
|
30
|
+
import type { OpRunRecord } from "../../op/runtime";
|
|
31
|
+
import type { GateResolutionRecord, PendingGateRecord } from "../../lifecycle/gate-ledger";
|
|
32
|
+
import {
|
|
33
|
+
appendGateResolution, appendPendingGate, readGateResolutions, readGateLedger,
|
|
34
|
+
latestResolutionSince, latestPendingGate, isPendingGateExpired,
|
|
35
|
+
resolveApprovalUrl, isApprovalUrl,
|
|
36
|
+
} from "../../lifecycle/gate-ledger";
|
|
25
37
|
import { pushLifecycle } from "../../lifecycle/git";
|
|
26
38
|
import { formatError, formatWarning, formatSuccess, formatBold, formatInfo } from "../format";
|
|
27
39
|
import type { CommandContext } from "../registry";
|
|
28
40
|
|
|
29
|
-
/** Load the activities a local tick needs, the same way
|
|
41
|
+
/** Load the activities a local tick needs, the same way a local run does: core's base activities plus whatever the project's configured lexicons contribute. Best-effort on the lexicon list — an unreadable `chant.config.ts` falls back to base activities only. */
|
|
30
42
|
async function loadOperatorActivities() {
|
|
31
43
|
let lexicons: string[] = [];
|
|
32
44
|
try {
|
|
@@ -37,12 +49,82 @@ async function loadOperatorActivities() {
|
|
|
37
49
|
return Promise.all([loadActivities(lexicons), loadProfiles()]);
|
|
38
50
|
}
|
|
39
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Bind the change-signal seams (#1981) the daemon will keep subscribed, or an
|
|
54
|
+
* empty list.
|
|
55
|
+
*
|
|
56
|
+
* Three gates, in cost order, so a project that gains nothing from this pays
|
|
57
|
+
* nothing for it:
|
|
58
|
+
*
|
|
59
|
+
* 1. No configured lexicon implements `subscribeChanges`. Return immediately,
|
|
60
|
+
* without loading config or building anything. This is every project today.
|
|
61
|
+
* 2. No `--env`. A subscription resolves the same cluster binding a read
|
|
62
|
+
* does, and there is no binding to resolve without an environment. Said out
|
|
63
|
+
* loud rather than silently skipped, because "why did it not wake" is
|
|
64
|
+
* otherwise unanswerable.
|
|
65
|
+
* 3. The build that supplies the declared entities failed. Warn and fall back
|
|
66
|
+
* to the timer. A subscription is an optimization; a build error here must
|
|
67
|
+
* not stop the operator, which has its own per-tick build inside the tick.
|
|
68
|
+
*/
|
|
69
|
+
async function collectOperatorSubscribers(
|
|
70
|
+
ctx: CommandContext,
|
|
71
|
+
env: string | undefined,
|
|
72
|
+
): Promise<ChangeSubscriber[]> {
|
|
73
|
+
if (!ctx.plugins.some((p) => typeof p.subscribeChanges === "function")) return [];
|
|
74
|
+
|
|
75
|
+
if (!env) {
|
|
76
|
+
console.error(formatWarning({
|
|
77
|
+
message: "a change signal needs an environment to resolve its binding, so this runs on the timer alone",
|
|
78
|
+
hint: "pass --env <env> to let a lexicon's subscribeChanges wake a tick early",
|
|
79
|
+
}));
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const cwd = process.cwd();
|
|
84
|
+
try {
|
|
85
|
+
const { config } = await loadChantConfig(cwd);
|
|
86
|
+
const buildRoots = collectBuildRootContributors(
|
|
87
|
+
ctx.plugins,
|
|
88
|
+
config as unknown as Record<string, unknown>,
|
|
89
|
+
cwd,
|
|
90
|
+
);
|
|
91
|
+
const buildResult = await build(config.sourceDir ?? ".", ctx.serializers, undefined, { buildRoots });
|
|
92
|
+
if (buildResult.errors.length > 0) {
|
|
93
|
+
console.error(formatWarning({
|
|
94
|
+
message: "build failed while scoping the change signal, so this runs on the timer alone",
|
|
95
|
+
}));
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The declared estate, sliced per lexicon: the same slice
|
|
100
|
+
// `takeSnapshot` hands `describeResources`, and the bound on what any
|
|
101
|
+
// subscription may watch.
|
|
102
|
+
const entities = new Map<string, Map<string, { entityType: string; props: Record<string, unknown> }>>();
|
|
103
|
+
for (const [name, entity] of buildResult.entities) {
|
|
104
|
+
if (!isResourceDeclarable(entity)) continue;
|
|
105
|
+
let perLexicon = entities.get(entity.lexicon);
|
|
106
|
+
if (!perLexicon) entities.set(entity.lexicon, (perLexicon = new Map()));
|
|
107
|
+
perLexicon.set(name, {
|
|
108
|
+
entityType: entity.entityType,
|
|
109
|
+
props: (entity.props != null ? entity.props : {}) as Record<string, unknown>,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return collectChangeSubscribers(ctx.plugins, { environment: env, cwd, entities });
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.error(formatWarning({
|
|
116
|
+
message: `could not scope the change signal, so this runs on the timer alone (${err instanceof Error ? err.message : String(err)})`,
|
|
117
|
+
}));
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
40
122
|
// ── chant operator ──────────────────────────────────────────────────────────
|
|
41
123
|
|
|
42
124
|
/**
|
|
43
125
|
* `chant operator [--env <env>] [--interval <duration>] [--lease-ttl
|
|
44
126
|
* <duration>] [--once]` — run scheduled ticks for this project's discovered
|
|
45
|
-
* ConvergeOps, locally, with no
|
|
127
|
+
* ConvergeOps, locally, with no service to install (issue's own worked
|
|
46
128
|
* example). `--once` runs a single round and exits (also the offline test
|
|
47
129
|
* story, and what a cron/systemd-timer/k8s-CronJob invoker uses instead of
|
|
48
130
|
* leaving the daemon running); omitted, the daemon loops until Ctrl-C.
|
|
@@ -92,6 +174,9 @@ export async function runOperator(ctx: CommandContext): Promise<number> {
|
|
|
92
174
|
console.error(formatInfo(
|
|
93
175
|
`chant operator: watching ${ops.length} ConvergeOp(s) every ${intervalMs}ms (Ctrl-C to stop)`,
|
|
94
176
|
));
|
|
177
|
+
// A change signal (#1981) only ever shortens the sleep above. Every round
|
|
178
|
+
// it wakes is the round the timer would have run.
|
|
179
|
+
const subscribers = await collectOperatorSubscribers(ctx, ctx.args.env);
|
|
95
180
|
await runOperatorForever({
|
|
96
181
|
env: ctx.args.env,
|
|
97
182
|
intervalMs,
|
|
@@ -100,6 +185,8 @@ export async function runOperator(ctx: CommandContext): Promise<number> {
|
|
|
100
185
|
profiles,
|
|
101
186
|
signal: controller.signal,
|
|
102
187
|
onRound: printRound,
|
|
188
|
+
subscribers,
|
|
189
|
+
onSignalEvent: (event: OperatorSignalEvent) => console.error(formatInfo(formatSignalLine(event))),
|
|
103
190
|
});
|
|
104
191
|
return 0;
|
|
105
192
|
} finally {
|
|
@@ -113,11 +200,37 @@ interface OpStatusLine {
|
|
|
113
200
|
op: string;
|
|
114
201
|
env: string;
|
|
115
202
|
lastTick?: ConvergeTickRecord;
|
|
116
|
-
/** `url` (#2028) is the gate's approval surface, when
|
|
117
|
-
pendingGates: { rule
|
|
203
|
+
/** `url` (#2028) is the gate's approval surface, when whatever recorded it knew one — what a renderer points its approve affordance at instead of a shell command. `rule` is present only for a gate a converge rule's dispatch reached; a gate an ordinary `chant run` stopped at has none. */
|
|
204
|
+
pendingGates: { rule?: string; op?: string; gate: string; url?: string; expiresAt?: string; description?: string }[];
|
|
118
205
|
lease?: { holder: string; expiresAt: string };
|
|
119
206
|
}
|
|
120
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Every gate an op is currently standing at, read from its own gate ledger
|
|
210
|
+
* (#2119) — a live (unexpired) pending fact with no resolution newer than it.
|
|
211
|
+
*
|
|
212
|
+
* Ledger-first, so `chant operator status` sees a gate any run recorded, not
|
|
213
|
+
* only one a converge tick's dispatch reached. Before this, a plain `chant run
|
|
214
|
+
* <op>` could not produce a pending gate at all (the executor refused the op
|
|
215
|
+
* outright), so reading the converge ledger's `gated` outcomes was the whole
|
|
216
|
+
* story; now it is one source among the ops' own.
|
|
217
|
+
*/
|
|
218
|
+
export async function pendingGatesFor(
|
|
219
|
+
opName: string,
|
|
220
|
+
opts: { cwd?: string; now?: string } = {},
|
|
221
|
+
): Promise<PendingGateRecord[]> {
|
|
222
|
+
const now = opts.now ?? new Date().toISOString();
|
|
223
|
+
const { resolutions, pending } = await readGateLedger(opName, { cwd: opts.cwd });
|
|
224
|
+
const standing: PendingGateRecord[] = [];
|
|
225
|
+
for (const gate of new Set(pending.map((p) => p.gate))) {
|
|
226
|
+
const latest = latestPendingGate(pending, gate);
|
|
227
|
+
if (!latest || isPendingGateExpired(latest, now)) continue;
|
|
228
|
+
if (latestResolutionSince(resolutions, gate, latest.timestamp)) continue;
|
|
229
|
+
standing.push(latest);
|
|
230
|
+
}
|
|
231
|
+
return standing.sort((a, b) => a.gate.localeCompare(b.gate));
|
|
232
|
+
}
|
|
233
|
+
|
|
121
234
|
async function statusFor(opName: string, env: string, cwd?: string): Promise<OpStatusLine> {
|
|
122
235
|
const [{ records }, { record: lease }] = await Promise.all([
|
|
123
236
|
readConvergeLedger(env, { cwd }),
|
|
@@ -127,19 +240,47 @@ async function statusFor(opName: string, env: string, cwd?: string): Promise<OpS
|
|
|
127
240
|
const lastTick = ownRecords.at(-1);
|
|
128
241
|
|
|
129
242
|
const pendingGates: OpStatusLine["pendingGates"] = [];
|
|
243
|
+
const seen = new Set<string>();
|
|
244
|
+
|
|
245
|
+
// The dispatched ops this ConvergeOp's last tick recorded as gated, plus the
|
|
246
|
+
// ConvergeOp itself — a gate can sit on either.
|
|
247
|
+
const gateOps = new Set<string>([opName]);
|
|
248
|
+
const ruleFor = new Map<string, string>();
|
|
249
|
+
for (const outcome of lastTick?.outcomes ?? []) {
|
|
250
|
+
if (outcome.action !== "gated" || !outcome.gateName || !outcome.op) continue;
|
|
251
|
+
gateOps.add(outcome.op);
|
|
252
|
+
ruleFor.set(`${outcome.op}\0${outcome.gateName}`, outcome.ruleId);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (const gateOp of [...gateOps].sort()) {
|
|
256
|
+
for (const record of await pendingGatesFor(gateOp, { cwd })) {
|
|
257
|
+
seen.add(`${gateOp}\0${record.gate}`);
|
|
258
|
+
pendingGates.push({
|
|
259
|
+
op: gateOp,
|
|
260
|
+
gate: record.gate,
|
|
261
|
+
expiresAt: record.expiresAt,
|
|
262
|
+
...(ruleFor.get(`${gateOp}\0${record.gate}`) ? { rule: ruleFor.get(`${gateOp}\0${record.gate}`) } : {}),
|
|
263
|
+
...(record.description ? { description: record.description } : {}),
|
|
264
|
+
...(record.url ? { url: record.url } : {}),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// A tick that recorded a `gated` outcome before the executor started writing
|
|
270
|
+
// pending facts (#2119) still has nothing in `_gates` to read; fall back to
|
|
271
|
+
// the outcome itself so an in-flight gate isn't dropped on upgrade.
|
|
130
272
|
if (lastTick) {
|
|
131
273
|
for (const outcome of lastTick.outcomes) {
|
|
132
274
|
if (outcome.action !== "gated" || !outcome.gateName || !outcome.op) continue;
|
|
275
|
+
if (seen.has(`${outcome.op}\0${outcome.gateName}`)) continue;
|
|
133
276
|
const { records: resolutions } = await readGateResolutions(outcome.op, { cwd });
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
}
|
|
277
|
+
if (latestResolutionSince(resolutions, outcome.gateName, lastTick.timestamp)) continue;
|
|
278
|
+
pendingGates.push({
|
|
279
|
+
rule: outcome.ruleId,
|
|
280
|
+
op: outcome.op,
|
|
281
|
+
gate: outcome.gateName,
|
|
282
|
+
...(outcome.url ? { url: outcome.url } : {}),
|
|
283
|
+
});
|
|
143
284
|
}
|
|
144
285
|
}
|
|
145
286
|
|
|
@@ -152,6 +293,15 @@ async function statusFor(opName: string, env: string, cwd?: string): Promise<OpS
|
|
|
152
293
|
};
|
|
153
294
|
}
|
|
154
295
|
|
|
296
|
+
/** One op standing at a gate that no ConvergeOp row above already reported (#2119) — an ordinary `chant run <op>` records these now, so they belong on this page even where no converge tick was ever involved. */
|
|
297
|
+
export interface StandaloneGateLine {
|
|
298
|
+
op: string;
|
|
299
|
+
gate: string;
|
|
300
|
+
description?: string;
|
|
301
|
+
expiresAt: string;
|
|
302
|
+
url?: string;
|
|
303
|
+
}
|
|
304
|
+
|
|
155
305
|
/**
|
|
156
306
|
* `chant operator status [--env <env>] [--json]` — last tick, outcome
|
|
157
307
|
* counts, and pending gates, read from the `chant/lifecycle` orphan branch
|
|
@@ -159,22 +309,46 @@ async function statusFor(opName: string, env: string, cwd?: string): Promise<OpS
|
|
|
159
309
|
* running: everything here was already durably recorded by whichever
|
|
160
310
|
* process (this operator, a bare `chant run <op>`, or another machine's
|
|
161
311
|
* operator) ran the last tick.
|
|
312
|
+
*
|
|
313
|
+
* Pending gates are read from every discovered op's own gate ledger, not only
|
|
314
|
+
* from a converge tick's `gated` outcomes (#2119) — a gate an ordinary `chant
|
|
315
|
+
* run <op>` stopped at is the same standing fact and shows up the same way,
|
|
316
|
+
* under "pending gates" for ops with no converge tick behind them.
|
|
162
317
|
*/
|
|
163
318
|
export async function runOperatorStatus(ctx: CommandContext): Promise<number> {
|
|
164
319
|
const { ops, errors } = await discoverConvergeOps({ env: ctx.args.env });
|
|
165
320
|
for (const err of errors) console.error(formatWarning({ message: err }));
|
|
166
321
|
|
|
167
|
-
|
|
322
|
+
const rows = await Promise.all(
|
|
323
|
+
ops.map((d) => statusFor(d.config.name, d.config.labels?.Env ?? "unknown")),
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
// Every other discovered op that is standing at a gate. `discoverOps` sees
|
|
327
|
+
// the whole project, so an ApplyOp someone ran by hand this morning is here
|
|
328
|
+
// even though no ConvergeOp ever dispatched it.
|
|
329
|
+
const covered = new Set(rows.flatMap((r) => r.pendingGates.map((g) => `${g.op ?? r.op} ${g.gate}`)));
|
|
330
|
+
const { ops: allOps } = await discoverOps();
|
|
331
|
+
const standalone: StandaloneGateLine[] = [];
|
|
332
|
+
for (const opName of [...allOps.keys()].sort()) {
|
|
333
|
+
for (const record of await pendingGatesFor(opName)) {
|
|
334
|
+
if (covered.has(`${opName} ${record.gate}`)) continue;
|
|
335
|
+
standalone.push({
|
|
336
|
+
op: opName,
|
|
337
|
+
gate: record.gate,
|
|
338
|
+
expiresAt: record.expiresAt,
|
|
339
|
+
...(record.description ? { description: record.description } : {}),
|
|
340
|
+
...(record.url ? { url: record.url } : {}),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (ops.length === 0 && standalone.length === 0) {
|
|
168
346
|
console.error(formatWarning({ message: "No ConvergeOp declarations found" }));
|
|
169
347
|
return 0;
|
|
170
348
|
}
|
|
171
349
|
|
|
172
|
-
const rows = await Promise.all(
|
|
173
|
-
ops.map((d) => statusFor(d.config.name, d.config.searchAttributes?.Env ?? "unknown")),
|
|
174
|
-
);
|
|
175
|
-
|
|
176
350
|
if (ctx.args.json) {
|
|
177
|
-
console.log(JSON.stringify(rows, null, 2));
|
|
351
|
+
console.log(JSON.stringify(standalone.length > 0 ? { rows, pendingGates: standalone } : rows, null, 2));
|
|
178
352
|
return 0;
|
|
179
353
|
}
|
|
180
354
|
|
|
@@ -190,13 +364,28 @@ export async function runOperatorStatus(ctx: CommandContext): Promise<number> {
|
|
|
190
364
|
if (row.pendingGates.length > 0) {
|
|
191
365
|
console.log(` pending gates:`);
|
|
192
366
|
for (const g of row.pendingGates) {
|
|
193
|
-
|
|
367
|
+
const op = g.op ?? row.op;
|
|
368
|
+
console.log(
|
|
369
|
+
` - ${op} gate "${g.gate}"${g.rule ? ` (rule ${g.rule})` : ""} — resolve: chant approve ${op} ${g.gate}`,
|
|
370
|
+
);
|
|
371
|
+
if (g.expiresAt) console.log(` expires: ${g.expiresAt}`);
|
|
194
372
|
if (g.url) console.log(` approve at: ${g.url}`);
|
|
195
373
|
}
|
|
196
374
|
}
|
|
197
375
|
console.log("");
|
|
198
376
|
}
|
|
199
377
|
|
|
378
|
+
if (standalone.length > 0) {
|
|
379
|
+
console.log(formatBold("pending gates (no converge tick)"));
|
|
380
|
+
for (const g of standalone) {
|
|
381
|
+
console.log(` - ${g.op} gate "${g.gate}" — resolve: chant approve ${g.op} ${g.gate}`);
|
|
382
|
+
if (g.description) console.log(` ${g.description}`);
|
|
383
|
+
console.log(` expires: ${g.expiresAt}`);
|
|
384
|
+
if (g.url) console.log(` approve at: ${g.url}`);
|
|
385
|
+
}
|
|
386
|
+
console.log("");
|
|
387
|
+
}
|
|
388
|
+
|
|
200
389
|
return 0;
|
|
201
390
|
}
|
|
202
391
|
|
|
@@ -205,17 +394,20 @@ export async function runOperatorStatus(ctx: CommandContext): Promise<number> {
|
|
|
205
394
|
/** One entry of the merged tick/gate timeline `chant operator log` prints. */
|
|
206
395
|
export type OperatorLogEntry =
|
|
207
396
|
| { kind: "tick"; timestamp: string; record: ConvergeTickRecord }
|
|
208
|
-
| { kind: "gate-resolution"; timestamp: string; record: GateResolutionRecord }
|
|
397
|
+
| { kind: "gate-resolution"; timestamp: string; record: GateResolutionRecord }
|
|
398
|
+
/** One Op run (#2118), timestamped at the instant it ended — the tick that dispatched it precedes it. */
|
|
399
|
+
| { kind: "run"; timestamp: string; record: OpRunRecord };
|
|
209
400
|
|
|
210
401
|
export interface OperatorLogResult {
|
|
211
402
|
entries: OperatorLogEntry[];
|
|
212
403
|
/**
|
|
213
|
-
* Unreadable lines behind this answer, per ledger. `readConvergeLedger
|
|
214
|
-
* `readGateResolutions`
|
|
215
|
-
* throwing, so a corrupted ledger renders a shorter
|
|
216
|
-
* consumer could not tell that from a genuinely
|
|
404
|
+
* Unreadable lines behind this answer, per ledger. `readConvergeLedger`,
|
|
405
|
+
* `readGateResolutions` and `readRunLedger` all skip a malformed line and
|
|
406
|
+
* count it rather than throwing, so a corrupted ledger renders a shorter
|
|
407
|
+
* timeline; without this a consumer could not tell that from a genuinely
|
|
408
|
+
* quiet environment.
|
|
217
409
|
*/
|
|
218
|
-
malformed: { converge: number; gates: number };
|
|
410
|
+
malformed: { converge: number; gates: number; runs: number };
|
|
219
411
|
}
|
|
220
412
|
|
|
221
413
|
/**
|
|
@@ -234,7 +426,7 @@ export async function collectOperatorLog(
|
|
|
234
426
|
const sinceMs = opts.since ? new Date(opts.since).getTime() : undefined;
|
|
235
427
|
|
|
236
428
|
const entries: OperatorLogEntry[] = [];
|
|
237
|
-
const malformed = { converge: 0, gates: 0 };
|
|
429
|
+
const malformed = { converge: 0, gates: 0, runs: 0 };
|
|
238
430
|
|
|
239
431
|
// One read per distinct environment — several ConvergeOps can share one
|
|
240
432
|
// `<env>/converge.jsonl`, and re-reading it per op would both cost more and
|
|
@@ -263,11 +455,23 @@ export async function collectOperatorLog(
|
|
|
263
455
|
}
|
|
264
456
|
}
|
|
265
457
|
|
|
458
|
+
// The runs each discovered Op recorded (#2118). Keyed `<env>/runs__<op>`,
|
|
459
|
+
// so unlike the converge ledger this is one read per (env, op) pair rather
|
|
460
|
+
// than per env — a ConvergeOp's own ticks and its own runs interleave here.
|
|
461
|
+
for (const { name, env } of wanted) {
|
|
462
|
+
const { records, malformed: bad } = await readRunLedger(env, name, { cwd: opts.cwd });
|
|
463
|
+
malformed.runs += bad;
|
|
464
|
+
for (const record of records) {
|
|
465
|
+
entries.push({ kind: "run", timestamp: record.ended, record });
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Within one instant: the tick first (it is what dispatched anything else),
|
|
470
|
+
// then the run it dispatched, then the gate resolution against that run.
|
|
471
|
+
const rank: Record<OperatorLogEntry["kind"], number> = { tick: 0, run: 1, "gate-resolution": 2 };
|
|
266
472
|
let merged = entries.sort((a, b) => {
|
|
267
473
|
const delta = new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime();
|
|
268
|
-
|
|
269
|
-
// the tick is what made the gate pending in the first place.
|
|
270
|
-
return delta !== 0 ? delta : (a.kind === b.kind ? 0 : a.kind === "tick" ? -1 : 1);
|
|
474
|
+
return delta !== 0 ? delta : rank[a.kind] - rank[b.kind];
|
|
271
475
|
});
|
|
272
476
|
if (sinceMs !== undefined) merged = merged.filter((e) => new Date(e.timestamp).getTime() >= sinceMs);
|
|
273
477
|
if (opts.limit !== undefined && merged.length > opts.limit) merged = merged.slice(-opts.limit);
|
|
@@ -276,6 +480,17 @@ export async function collectOperatorLog(
|
|
|
276
480
|
}
|
|
277
481
|
|
|
278
482
|
function renderLogEntry(entry: OperatorLogEntry): string[] {
|
|
483
|
+
if (entry.kind === "run") {
|
|
484
|
+
const { record } = entry;
|
|
485
|
+
const id = `[${record.id.slice(0, 8)}]`;
|
|
486
|
+
const outcomes = Object.entries(record.outcomes).map(([k, v]) => `${k}=${String(v)}`).join(" ");
|
|
487
|
+
const steps = record.phases.reduce((n, p) => n + p.steps.length, 0);
|
|
488
|
+
return [
|
|
489
|
+
`${record.ended} ${record.op}@${record.env} ${id} run ${record.status} ` +
|
|
490
|
+
`phases=${record.phases.length} steps=${steps}${outcomes ? ` ${outcomes}` : ""}`,
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
|
|
279
494
|
if (entry.kind === "gate-resolution") {
|
|
280
495
|
const { record } = entry;
|
|
281
496
|
return [
|
|
@@ -335,7 +550,7 @@ export async function runOperatorLog(ctx: CommandContext): Promise<number> {
|
|
|
335
550
|
}
|
|
336
551
|
|
|
337
552
|
const { entries, malformed } = await collectOperatorLog(
|
|
338
|
-
ops.map((d) => ({ name: d.config.name, env: d.config.
|
|
553
|
+
ops.map((d) => ({ name: d.config.name, env: d.config.labels?.Env ?? "unknown" })),
|
|
339
554
|
{ op: ctx.args.op, since: ctx.args.since, limit: ctx.args.limit },
|
|
340
555
|
);
|
|
341
556
|
|
|
@@ -344,16 +559,16 @@ export async function runOperatorLog(ctx: CommandContext): Promise<number> {
|
|
|
344
559
|
return 0;
|
|
345
560
|
}
|
|
346
561
|
|
|
347
|
-
const unreadable = malformed.converge + malformed.gates;
|
|
562
|
+
const unreadable = malformed.converge + malformed.gates + malformed.runs;
|
|
348
563
|
if (unreadable > 0) {
|
|
349
564
|
console.error(formatWarning({
|
|
350
565
|
message: `${unreadable} ledger line(s) were unreadable and are missing from this timeline ` +
|
|
351
|
-
`(converge: ${malformed.converge}, gates: ${malformed.gates})`,
|
|
566
|
+
`(converge: ${malformed.converge}, gates: ${malformed.gates}, runs: ${malformed.runs})`,
|
|
352
567
|
}));
|
|
353
568
|
}
|
|
354
569
|
|
|
355
570
|
if (entries.length === 0) {
|
|
356
|
-
console.error(formatWarning({ message: "No converge ticks recorded yet" }));
|
|
571
|
+
console.error(formatWarning({ message: "No converge ticks or Op runs recorded yet" }));
|
|
357
572
|
return 0;
|
|
358
573
|
}
|
|
359
574
|
|
|
@@ -366,16 +581,22 @@ export async function runOperatorLog(ctx: CommandContext): Promise<number> {
|
|
|
366
581
|
// ── chant approve <op> <gate> ───────────────────────────────────────────────
|
|
367
582
|
|
|
368
583
|
/**
|
|
369
|
-
* `chant approve <op> <gate> [--actor <name>] [--note <text>] [--url <url>]
|
|
370
|
-
* — record the
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
584
|
+
* `chant approve <op> <gate> [--actor <name>] [--note <text>] [--url <url>]
|
|
585
|
+
* [--expire]` — record the out-of-band resolution fact for a gate a run
|
|
586
|
+
* stopped at (issue #1485: "resolution is an out-of-band act that writes the
|
|
587
|
+
* counterpart fact"). Per that issue's leaning on open question 3 ("local
|
|
588
|
+
* trust in v1"), this performs no authorization check beyond "you can run
|
|
589
|
+
* `chant approve` locally".
|
|
590
|
+
*
|
|
591
|
+
* Since #2119 this closes the loop rather than just narrating it: the next
|
|
592
|
+
* `chant run <op>` reads the resolution, finds it newer than the gate's
|
|
593
|
+
* pending fact, and walks through.
|
|
594
|
+
*
|
|
595
|
+
* `--expire` is the other half — clear a standing pending fact *without*
|
|
596
|
+
* approving anything, for a gate that was recorded against a run nobody
|
|
597
|
+
* intends to finish. It writes no resolution; it appends a pending fact that
|
|
598
|
+
* is already expired, which supersedes the standing one on an append-only
|
|
599
|
+
* ledger, so the next run decides the gate from scratch.
|
|
379
600
|
*/
|
|
380
601
|
export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
381
602
|
const opName = ctx.args.path;
|
|
@@ -385,6 +606,75 @@ export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
|
385
606
|
return 1;
|
|
386
607
|
}
|
|
387
608
|
|
|
609
|
+
if (ctx.args.expire) {
|
|
610
|
+
const now = new Date().toISOString();
|
|
611
|
+
const standing = latestPendingGate((await readGateLedger(opName)).pending, gate);
|
|
612
|
+
if (!standing || isPendingGateExpired(standing, now)) {
|
|
613
|
+
console.error(formatWarning({
|
|
614
|
+
message: `Gate "${gate}" on "${opName}" has no standing pending fact — nothing to expire`,
|
|
615
|
+
}));
|
|
616
|
+
return 0;
|
|
617
|
+
}
|
|
618
|
+
await appendPendingGate({
|
|
619
|
+
op: opName,
|
|
620
|
+
gate,
|
|
621
|
+
timestamp: now,
|
|
622
|
+
expiresAt: now,
|
|
623
|
+
...(standing.description ? { description: standing.description } : {}),
|
|
624
|
+
});
|
|
625
|
+
await pushLifecycle().catch(() => undefined);
|
|
626
|
+
console.error(formatSuccess(`Gate "${gate}" on "${opName}" expired at ${now} — not approved`));
|
|
627
|
+
console.error(formatInfo(
|
|
628
|
+
`The next \`chant run ${opName}\` decides this gate from scratch and records a fresh pending fact.`,
|
|
629
|
+
));
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// `--approver` wins over `--actor`, the same precedence `chant run approve`
|
|
634
|
+
// has applied since #2126 (`../handlers/run.ts`'s `runOpApprove`). Reading
|
|
635
|
+
// only `--actor` here meant every README that teaches `--approver you`
|
|
636
|
+
// recorded the shell user instead (#2192).
|
|
637
|
+
const outcome = await recordGateApproval(opName, gate, {
|
|
638
|
+
actor: ctx.args.approver ?? ctx.args.actor,
|
|
639
|
+
note: ctx.args.note,
|
|
640
|
+
url: ctx.args.url,
|
|
641
|
+
});
|
|
642
|
+
if (!outcome.ok) return 1;
|
|
643
|
+
|
|
644
|
+
console.error(formatInfo(
|
|
645
|
+
`This records the resolution as a fact; it does not itself re-run anything. ` +
|
|
646
|
+
`Run \`chant run ${opName}\` and it walks through gate "${gate}".`,
|
|
647
|
+
));
|
|
648
|
+
return 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/** What a caller supplies alongside the op and gate names. */
|
|
652
|
+
export interface GateApprovalOptions {
|
|
653
|
+
/** `--actor`/`--approver`; falls back to the CI or shell identity. */
|
|
654
|
+
actor?: string;
|
|
655
|
+
/** `--note` — free-text prose. */
|
|
656
|
+
note?: string;
|
|
657
|
+
/** `--url` — the approval surface, validated as absolute http/https. */
|
|
658
|
+
url?: string;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
export type GateApprovalOutcome =
|
|
662
|
+
| { ok: true; record: GateResolutionRecord }
|
|
663
|
+
| { ok: false };
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* The ledger write behind `chant approve` — extracted so `chant run approve`
|
|
667
|
+
* (#2121) records the identical fact before waking the runtime that hosts the
|
|
668
|
+
* gated run, instead of growing a second, drifting writer.
|
|
669
|
+
*
|
|
670
|
+
* Prints the same warning for an undiscovered op and the same success line as
|
|
671
|
+
* `chant approve` always did; the caller adds whatever it does next.
|
|
672
|
+
*/
|
|
673
|
+
export async function recordGateApproval(
|
|
674
|
+
opName: string,
|
|
675
|
+
gate: string,
|
|
676
|
+
opts: GateApprovalOptions,
|
|
677
|
+
): Promise<GateApprovalOutcome> {
|
|
388
678
|
const { ops } = await discoverOps();
|
|
389
679
|
if (!ops.has(opName)) {
|
|
390
680
|
console.error(formatWarning({
|
|
@@ -392,18 +682,18 @@ export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
|
392
682
|
}));
|
|
393
683
|
}
|
|
394
684
|
|
|
395
|
-
const resolvedBy =
|
|
685
|
+
const resolvedBy = opts.actor ?? process.env.GITHUB_ACTOR ?? process.env.GITLAB_USER_LOGIN ?? process.env.USER ?? "unknown";
|
|
396
686
|
|
|
397
687
|
// #2028: the resolution's link is typed. `--url` wins; otherwise, running
|
|
398
688
|
// inside the PR/MR job that carries the change is itself the address, the
|
|
399
689
|
// same env fallback `--actor` uses. `--note` stays free-text prose.
|
|
400
|
-
const url =
|
|
690
|
+
const url = opts.url ?? resolveApprovalUrl();
|
|
401
691
|
if (url && !isApprovalUrl(url)) {
|
|
402
692
|
console.error(formatError({
|
|
403
693
|
message: `--url must be an absolute http/https URL (got "${url}")`,
|
|
404
694
|
hint: "Pass the PR/MR link, or omit --url and put prose in --note.",
|
|
405
695
|
}));
|
|
406
|
-
return
|
|
696
|
+
return { ok: false };
|
|
407
697
|
}
|
|
408
698
|
|
|
409
699
|
const { record } = await appendGateResolution({
|
|
@@ -411,7 +701,7 @@ export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
|
411
701
|
gate,
|
|
412
702
|
resolvedBy,
|
|
413
703
|
timestamp: new Date().toISOString(),
|
|
414
|
-
...(
|
|
704
|
+
...(opts.note ? { note: opts.note } : {}),
|
|
415
705
|
...(url ? { url } : {}),
|
|
416
706
|
});
|
|
417
707
|
await pushLifecycle().catch(() => undefined);
|
|
@@ -420,9 +710,5 @@ export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
|
420
710
|
`Gate "${gate}" on "${opName}" resolved by ${record.resolvedBy} at ${record.timestamp}` +
|
|
421
711
|
(record.url ? ` (${record.url})` : ""),
|
|
422
712
|
));
|
|
423
|
-
|
|
424
|
-
"This records the resolution as a fact; it does not itself re-run the gated dispatch — " +
|
|
425
|
-
"the local executor still refuses any op with a gate. Re-run it with --temporal, or via the PR that carries the change.",
|
|
426
|
-
));
|
|
427
|
-
return 0;
|
|
713
|
+
return { ok: true, record };
|
|
428
714
|
}
|