@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
|
@@ -15,26 +15,24 @@
|
|
|
15
15
|
* second non-env top-level directory.
|
|
16
16
|
*
|
|
17
17
|
* `chant approve <op> <gate>` (`../cli/handlers/operator.ts`) is what
|
|
18
|
-
* appends
|
|
19
|
-
* writes the counterpart fact". Per
|
|
18
|
+
* appends a resolution — issue #1485's "resolution is an out-of-band act
|
|
19
|
+
* that writes the counterpart fact". Per that issue's leaning on open
|
|
20
20
|
* question 3 ("local trust in v1, signature as an additive follow-up"),
|
|
21
21
|
* this record is *not* itself an authorization check — anyone who can run
|
|
22
22
|
* `chant approve` locally can write one, the same trust boundary a local
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* "this gate is cleared" that a human (or a future auto-resume path) reads;
|
|
37
|
-
* it is not itself the unblock.
|
|
23
|
+
* commit already has.
|
|
24
|
+
*
|
|
25
|
+
* Since #2119 the file carries both halves of the loop. A `gate` step the
|
|
26
|
+
* local executor reaches (`../op/local-executor.ts`) appends a
|
|
27
|
+
* {@link PendingGateRecord} and ends that run with status `gated`; `chant
|
|
28
|
+
* approve` appends the {@link GateResolutionRecord} that answers it; the next
|
|
29
|
+
* run reads both, finds a resolution newer than the pending fact, and walks
|
|
30
|
+
* through the gate carrying the approver. A resolution older than the newest
|
|
31
|
+
* pending fact is not an answer to it — {@link latestResolutionSince} applies
|
|
32
|
+
* that rule for the executor and for `chant operator status` alike. Both kinds
|
|
33
|
+
* of line share one file, told apart by {@link GateLedgerRecord}'s `kind`
|
|
34
|
+
* (absent on the resolution lines written before #2119, which is why
|
|
35
|
+
* `"resolution"` is the default reading).
|
|
38
36
|
*/
|
|
39
37
|
import { sortedJsonReplacer } from "../utils";
|
|
40
38
|
import { readBlobFromPath, readPathSha, readBlobBySha, writeBlobToPath, RefCASConflictError } from "./git";
|
|
@@ -98,11 +96,13 @@ export function isApprovalUrl(raw: string): boolean {
|
|
|
98
96
|
export interface GateResolutionRecord {
|
|
99
97
|
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
100
98
|
version: 1;
|
|
99
|
+
/** Discriminator against {@link PendingGateRecord}, which shares this file. Absent on every line written before #2119, so a reader must treat "no kind" as `"resolution"`. */
|
|
100
|
+
kind?: "resolution";
|
|
101
101
|
/** The dispatched op the gate belongs to. */
|
|
102
102
|
op: string;
|
|
103
103
|
/** The gate's signal name (matches `ConvergeRuleOutcome.gateName`). */
|
|
104
104
|
gate: string;
|
|
105
|
-
/** Who resolved it — an actor name, the same convention `components release --actor` and `run
|
|
105
|
+
/** Who resolved it — an actor name, the same convention `components release --actor` and `run approve --approver` use. */
|
|
106
106
|
resolvedBy: string;
|
|
107
107
|
/** ISO-8601 timestamp, caller-supplied (library code never calls `Date.now()` internally). */
|
|
108
108
|
timestamp: string;
|
|
@@ -121,18 +121,99 @@ export interface GateResolutionRecord {
|
|
|
121
121
|
url?: string;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
export type GateResolutionInput = Omit<GateResolutionRecord, "version">;
|
|
124
|
+
export type GateResolutionInput = Omit<GateResolutionRecord, "version" | "kind">;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One immutable pending-gate record (#2119) — what an executor writes when a
|
|
128
|
+
* run reaches a `gate` step with no resolution standing against it. The run
|
|
129
|
+
* ends here with status `gated`; this line is the durable trace of that, and
|
|
130
|
+
* the anchor a later {@link GateResolutionRecord} has to be newer than to
|
|
131
|
+
* count as its answer.
|
|
132
|
+
*
|
|
133
|
+
* Idempotent by design: a run that finds a live (unexpired) pending fact for
|
|
134
|
+
* the same gate reuses it rather than appending a second one, so a converge
|
|
135
|
+
* loop ticking every minute against an unapproved gate does not grow the
|
|
136
|
+
* ledger by a line a minute. Once `expiresAt` passes, the fact is stale and
|
|
137
|
+
* the next run records a fresh one.
|
|
138
|
+
*/
|
|
139
|
+
export interface PendingGateRecord {
|
|
140
|
+
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
141
|
+
version: 1;
|
|
142
|
+
kind: "pending";
|
|
143
|
+
/** The op (or, on the component driver, the component) the gate belongs to. */
|
|
144
|
+
op: string;
|
|
145
|
+
/** The gate's name (matches `GateStep.gate`). */
|
|
146
|
+
gate: string;
|
|
147
|
+
/** The gate's human-readable description, when it declared one — what `chant operator status` shows a reader who wasn't there for the run. */
|
|
148
|
+
description?: string;
|
|
149
|
+
/** The run that reached the gate, when the caller identifies its runs. */
|
|
150
|
+
runId?: string;
|
|
151
|
+
/** ISO-8601 timestamp, caller-supplied (library code never calls `Date.now()` internally). */
|
|
152
|
+
timestamp: string;
|
|
153
|
+
/** ISO-8601 expiry, from the gate's `timeout` (default {@link DEFAULT_GATE_EXPIRY}). Past it, the fact is stale and a run re-records it. */
|
|
154
|
+
expiresAt: string;
|
|
155
|
+
/** The address approval happens at, when the run knew one — see {@link resolveApprovalUrl}. */
|
|
156
|
+
url?: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type PendingGateInput = Omit<PendingGateRecord, "version" | "kind">;
|
|
160
|
+
|
|
161
|
+
/** Either kind of line in `_gates/<op>.jsonl`. */
|
|
162
|
+
export type GateLedgerRecord = GateResolutionRecord | PendingGateRecord;
|
|
163
|
+
|
|
164
|
+
/** The default a gate's pending fact expires after when its `GateStep` declares no `timeout` — the same 48h `GateStep.timeout` documents as its own default. */
|
|
165
|
+
export const DEFAULT_GATE_EXPIRY = "48h";
|
|
166
|
+
|
|
167
|
+
/** Whether a pending fact has aged out of relevance at `nowIso`. */
|
|
168
|
+
export function isPendingGateExpired(record: PendingGateRecord, nowIso: string): boolean {
|
|
169
|
+
return new Date(record.expiresAt).getTime() <= new Date(nowIso).getTime();
|
|
170
|
+
}
|
|
125
171
|
|
|
126
172
|
function filename(op: string): string {
|
|
127
173
|
return `${op}.jsonl`;
|
|
128
174
|
}
|
|
129
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Where an Op's gate ledger lives, as a path a human can go and read:
|
|
178
|
+
* `_gates/<op>.jsonl` on the `chant/lifecycle` orphan branch. Exported so a
|
|
179
|
+
* renderer that tells someone a gate is pending can name the file the pending
|
|
180
|
+
* fact was appended to (#2243) rather than describing it in prose that drifts
|
|
181
|
+
* from `DIR`.
|
|
182
|
+
*/
|
|
183
|
+
export function gateLedgerPath(op: string): string {
|
|
184
|
+
return `${DIR}/${filename(op)}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
130
187
|
/** Append one immutable gate-resolution record. Does not push to the remote — call `pushLifecycle` (./git.ts) afterward, same two-step shape every other ledger write here uses. Retries on `RefCASConflictError` the same way `appendConvergeRecord` does (./converge-ledger.ts) — a concurrent writer to a different op's/env's file on the same orphan branch is the ordinary case, not an edge case. The baseline read must be `readPathSha` + `readBlobBySha` rather than `readBlobFromPath`, so the exact sha `existing` came from can be passed as `expectPriorPathSha` — see `writeBlobToPath` (./git.ts) for the race that closes. */
|
|
131
188
|
export async function appendGateResolution(
|
|
132
189
|
input: GateResolutionInput,
|
|
133
190
|
opts?: { cwd?: string },
|
|
134
191
|
): Promise<{ commit: string; record: GateResolutionRecord }> {
|
|
135
192
|
const record: GateResolutionRecord = { version: 1, ...input };
|
|
193
|
+
const commit = await appendGateLine(record, "Gate resolution record", opts);
|
|
194
|
+
return { commit, record };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Append one immutable pending-gate record (#2119) — the fact a run leaves
|
|
199
|
+
* behind when it reaches a gate nobody has approved. Same file, same
|
|
200
|
+
* append-and-retry discipline, same "does not push" contract as
|
|
201
|
+
* {@link appendGateResolution}.
|
|
202
|
+
*/
|
|
203
|
+
export async function appendPendingGate(
|
|
204
|
+
input: PendingGateInput,
|
|
205
|
+
opts?: { cwd?: string },
|
|
206
|
+
): Promise<{ commit: string; record: PendingGateRecord }> {
|
|
207
|
+
const record: PendingGateRecord = { version: 1, kind: "pending", ...input };
|
|
208
|
+
const commit = await appendGateLine(record, "Pending gate record", opts);
|
|
209
|
+
return { commit, record };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function appendGateLine(
|
|
213
|
+
record: GateLedgerRecord,
|
|
214
|
+
message: string,
|
|
215
|
+
opts?: { cwd?: string },
|
|
216
|
+
): Promise<string> {
|
|
136
217
|
const json = JSON.stringify(record, sortedJsonReplacer);
|
|
137
218
|
|
|
138
219
|
let lastErr: unknown;
|
|
@@ -141,11 +222,10 @@ export async function appendGateResolution(
|
|
|
141
222
|
const priorSha = await readPathSha(DIR, filename(record.op), opts);
|
|
142
223
|
const existing = priorSha ? await readBlobBySha(priorSha, opts) : null;
|
|
143
224
|
const content = existing ? `${existing.replace(/\n$/, "")}\n${json}` : json;
|
|
144
|
-
|
|
225
|
+
return await writeBlobToPath(DIR, filename(record.op), content, message, {
|
|
145
226
|
...opts,
|
|
146
227
|
expectPriorPathSha: priorSha,
|
|
147
228
|
});
|
|
148
|
-
return { commit, record };
|
|
149
229
|
} catch (err) {
|
|
150
230
|
if (!(err instanceof RefCASConflictError)) throw err;
|
|
151
231
|
lastErr = err;
|
|
@@ -154,36 +234,74 @@ export async function appendGateResolution(
|
|
|
154
234
|
throw lastErr;
|
|
155
235
|
}
|
|
156
236
|
|
|
157
|
-
/**
|
|
158
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Read every line of `op`'s gate file, oldest first, split into the two kinds
|
|
239
|
+
* (#2119). Malformed lines are skipped and counted, not thrown on — the same
|
|
240
|
+
* graceful-degradation stance `readConvergeLedger` takes. Returns empty arrays
|
|
241
|
+
* (never throws) when `op` has nothing recorded yet.
|
|
242
|
+
*/
|
|
243
|
+
export async function readGateLedger(
|
|
159
244
|
op: string,
|
|
160
245
|
opts?: { cwd?: string },
|
|
161
|
-
): Promise<{
|
|
246
|
+
): Promise<{ resolutions: GateResolutionRecord[]; pending: PendingGateRecord[]; malformed: number }> {
|
|
162
247
|
const content = await readBlobFromPath(DIR, filename(op), opts);
|
|
163
|
-
if (!content) return {
|
|
248
|
+
if (!content) return { resolutions: [], pending: [], malformed: 0 };
|
|
164
249
|
|
|
165
250
|
const lines = content.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
166
|
-
const
|
|
251
|
+
const resolutions: GateResolutionRecord[] = [];
|
|
252
|
+
const pending: PendingGateRecord[] = [];
|
|
167
253
|
let malformed = 0;
|
|
168
254
|
for (const line of lines) {
|
|
169
255
|
try {
|
|
170
|
-
const parsed = JSON.parse(line) as Partial<GateResolutionRecord
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
typeof parsed.op
|
|
174
|
-
typeof parsed.gate
|
|
175
|
-
|
|
176
|
-
typeof parsed.timestamp !== "string"
|
|
177
|
-
) {
|
|
256
|
+
const parsed = JSON.parse(line) as Partial<Omit<GateResolutionRecord, "kind">> &
|
|
257
|
+
Partial<Omit<PendingGateRecord, "kind">> & { kind?: string };
|
|
258
|
+
const common =
|
|
259
|
+
parsed.version === 1 && typeof parsed.op === "string" &&
|
|
260
|
+
typeof parsed.gate === "string" && typeof parsed.timestamp === "string";
|
|
261
|
+
if (!common) {
|
|
178
262
|
malformed++;
|
|
179
263
|
continue;
|
|
180
264
|
}
|
|
181
|
-
|
|
265
|
+
if (parsed.kind === "pending") {
|
|
266
|
+
if (typeof parsed.expiresAt !== "string") {
|
|
267
|
+
malformed++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
pending.push(parsed as PendingGateRecord);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (typeof parsed.resolvedBy !== "string") {
|
|
274
|
+
malformed++;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
resolutions.push(parsed as GateResolutionRecord);
|
|
182
278
|
} catch {
|
|
183
279
|
malformed++;
|
|
184
280
|
}
|
|
185
281
|
}
|
|
186
|
-
return {
|
|
282
|
+
return { resolutions, pending, malformed };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Read every gate-*resolution* record for `op`, oldest first — {@link readGateLedger} narrowed to the half every caller before #2119 wanted. Pending facts are not malformed lines and are not counted as such. */
|
|
286
|
+
export async function readGateResolutions(
|
|
287
|
+
op: string,
|
|
288
|
+
opts?: { cwd?: string },
|
|
289
|
+
): Promise<{ records: GateResolutionRecord[]; malformed: number }> {
|
|
290
|
+
const { resolutions, malformed } = await readGateLedger(op, opts);
|
|
291
|
+
return { records: resolutions, malformed };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** The most recent pending fact for `gate`, expired or not — the anchor {@link latestResolutionSince} measures a resolution against. `undefined` when the gate has never been recorded pending. */
|
|
295
|
+
export function latestPendingGate(
|
|
296
|
+
records: PendingGateRecord[],
|
|
297
|
+
gate: string,
|
|
298
|
+
): PendingGateRecord | undefined {
|
|
299
|
+
let latest: PendingGateRecord | undefined;
|
|
300
|
+
for (const r of records) {
|
|
301
|
+
if (r.gate !== gate) continue;
|
|
302
|
+
if (!latest || new Date(r.timestamp).getTime() >= new Date(latest.timestamp).getTime()) latest = r;
|
|
303
|
+
}
|
|
304
|
+
return latest;
|
|
187
305
|
}
|
|
188
306
|
|
|
189
307
|
/** The most recent resolution for `gate` recorded after `sinceIso` (a gated tick's own timestamp) — what `chant operator status` uses to tell a resolved gate from a still-pending one. `undefined` when no such resolution exists. */
|
package/src/lifecycle/index.ts
CHANGED
|
@@ -98,8 +98,8 @@ export interface ReleaseRecord {
|
|
|
98
98
|
/**
|
|
99
99
|
* Who approved the change at its durable approval gate (#1035). Populated for
|
|
100
100
|
* a gated change — the same identity the approver supplied when they cleared
|
|
101
|
-
* the
|
|
102
|
-
*
|
|
101
|
+
* the gate (`chant approve <op> <gate> --approver`, recorded on the gate
|
|
102
|
+
* resolution fact). Optional and omitted for an
|
|
103
103
|
* ungated change (nothing to approve), so `actor` alone answers "who made
|
|
104
104
|
* it" while `approver` answers "who approved it" only where a gate exists.
|
|
105
105
|
* Distinct from `actor`: the approver is deliberately a different person than
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run ledger tests (#2118) — the same git fixture `converge-ledger.test.ts`
|
|
3
|
+
* uses, so the two ledgers are exercised against one real orphan branch and a
|
|
4
|
+
* change to the shared plumbing under them fails in both places.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, test, expect } from "vitest";
|
|
7
|
+
import { withTestDir } from "@intentius/chant-test-utils";
|
|
8
|
+
import { spawnSync } from "node:child_process";
|
|
9
|
+
import { writeFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import {
|
|
12
|
+
appendRunRecord,
|
|
13
|
+
readRunLedger,
|
|
14
|
+
buildRunRecord,
|
|
15
|
+
runEnvOf,
|
|
16
|
+
DEFAULT_RUN_ENV,
|
|
17
|
+
} from "./run-ledger";
|
|
18
|
+
import type { OpRunRecordInput } from "../op/runtime";
|
|
19
|
+
import { appendConvergeRecord, readConvergeLedger } from "./converge-ledger";
|
|
20
|
+
import { runOpLocally, OpRunFailure } from "../op/local-executor";
|
|
21
|
+
import type { ActivityFn } from "../op/activity-registry";
|
|
22
|
+
import type { OpConfig } from "../op/types";
|
|
23
|
+
|
|
24
|
+
function git(args: string[], cwd: string): { stdout: string; exitCode: number } {
|
|
25
|
+
const r = spawnSync("git", args, { cwd, encoding: "utf-8" });
|
|
26
|
+
return { stdout: r.stdout ?? "", exitCode: r.status ?? -1 };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function initRepo(dir: string): Promise<void> {
|
|
30
|
+
git(["init", "-q", "-b", "main"], dir);
|
|
31
|
+
git(["config", "user.email", "test@chant.dev"], dir);
|
|
32
|
+
git(["config", "user.name", "Test"], dir);
|
|
33
|
+
writeFileSync(join(dir, "README.md"), "fixture\n");
|
|
34
|
+
git(["add", "README.md"], dir);
|
|
35
|
+
git(["commit", "-q", "-m", "init"], dir);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function makeInput(overrides?: Partial<OpRunRecordInput>): OpRunRecordInput {
|
|
39
|
+
return {
|
|
40
|
+
op: "alb-deploy",
|
|
41
|
+
env: "staging",
|
|
42
|
+
started: "2026-01-01T00:00:00.000Z",
|
|
43
|
+
ended: "2026-01-01T00:00:12.000Z",
|
|
44
|
+
status: "ok",
|
|
45
|
+
labels: { Apply: "true", Env: "staging" },
|
|
46
|
+
outcomes: {},
|
|
47
|
+
phases: [{ name: "Apply", status: "ok", steps: [{ fn: "kubectlApply", status: "ok", durationMs: 12_000 }] }],
|
|
48
|
+
...overrides,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const NO_PROFILES = {};
|
|
53
|
+
|
|
54
|
+
function opConfig(overrides?: Partial<OpConfig>): OpConfig {
|
|
55
|
+
return {
|
|
56
|
+
name: "alb-deploy",
|
|
57
|
+
overview: "deploy the alb",
|
|
58
|
+
labels: { Env: "staging" },
|
|
59
|
+
phases: [{ name: "Apply", steps: [{ kind: "activity", fn: "ok", args: {} }] }],
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe("runEnvOf", () => {
|
|
65
|
+
test("reads labels.Env", () => {
|
|
66
|
+
expect(runEnvOf({ labels: { Env: "prod" } })).toBe("prod");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("falls back to the default env when the Op declares no labels", () => {
|
|
70
|
+
expect(runEnvOf({})).toBe(DEFAULT_RUN_ENV);
|
|
71
|
+
expect(runEnvOf({ labels: { Apply: "true" } })).toBe(DEFAULT_RUN_ENV);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("buildRunRecord", () => {
|
|
76
|
+
test("groups step records into phases in execution order and folds outcomes", () => {
|
|
77
|
+
const input = buildRunRecord(
|
|
78
|
+
{ name: "watch", labels: { Watch: "true", Env: "prod" } },
|
|
79
|
+
[
|
|
80
|
+
{ phase: "Snapshot", fn: "lifecycleSnapshot", status: "ok", durationMs: 5 },
|
|
81
|
+
{ phase: "Diff", fn: "lifecycleDiff", status: "ok", durationMs: 7, outcome: { name: "Drift", value: true } },
|
|
82
|
+
{ phase: "Diff", fn: "report", status: "skipped", durationMs: 0 },
|
|
83
|
+
],
|
|
84
|
+
{ started: "2026-01-01T00:00:00.000Z", ended: "2026-01-01T00:00:01.000Z", status: "ok" },
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(input.env).toBe("prod");
|
|
88
|
+
expect(input.status).toBe("ok");
|
|
89
|
+
expect(input.labels).toEqual({ Watch: "true", Env: "prod" });
|
|
90
|
+
expect(input.outcomes).toEqual({ Drift: true });
|
|
91
|
+
expect(input.phases.map((p) => [p.name, p.status])).toEqual([["Snapshot", "ok"], ["Diff", "ok"]]);
|
|
92
|
+
expect(input.phases[1].steps.map((s) => s.status)).toEqual(["ok", "skipped"]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("a phase with a failed step is fail; a phase whose steps all skipped is skipped", () => {
|
|
96
|
+
const input = buildRunRecord(
|
|
97
|
+
{ name: "deploy" },
|
|
98
|
+
[
|
|
99
|
+
{ phase: "Apply", fn: "kubectlApply", status: "fail", durationMs: 3, error: "boom" },
|
|
100
|
+
{ phase: "Verify", fn: "httpCheck", status: "skipped", durationMs: 0 },
|
|
101
|
+
],
|
|
102
|
+
{ started: "2026-01-01T00:00:00.000Z", ended: "2026-01-01T00:00:01.000Z", status: "fail" },
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
expect(input.status).toBe("fail");
|
|
106
|
+
expect(input.env).toBe(DEFAULT_RUN_ENV);
|
|
107
|
+
expect(input.phases.map((p) => [p.name, p.status])).toEqual([["Apply", "fail"], ["Verify", "skipped"]]);
|
|
108
|
+
expect(input.phases[0].steps[0].error).toBe("boom");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("appendRunRecord / readRunLedger", () => {
|
|
113
|
+
test("round-trips a single record", async () => {
|
|
114
|
+
await withTestDir(async (dir) => {
|
|
115
|
+
await initRepo(dir);
|
|
116
|
+
const { record } = await appendRunRecord(makeInput(), { cwd: dir });
|
|
117
|
+
expect(record.version).toBe(1);
|
|
118
|
+
expect(record.id).toMatch(/^[0-9a-f-]{36}$/);
|
|
119
|
+
|
|
120
|
+
const { records, malformed } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
121
|
+
expect(malformed).toBe(0);
|
|
122
|
+
expect(records).toEqual([record]);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("appends without clobbering prior records", async () => {
|
|
127
|
+
await withTestDir(async (dir) => {
|
|
128
|
+
await initRepo(dir);
|
|
129
|
+
await appendRunRecord(makeInput({ ended: "2026-01-01T00:00:12.000Z" }), { cwd: dir });
|
|
130
|
+
await appendRunRecord(makeInput({ ended: "2026-01-01T00:10:12.000Z" }), { cwd: dir });
|
|
131
|
+
await appendRunRecord(makeInput({ ended: "2026-01-01T00:20:12.000Z" }), { cwd: dir });
|
|
132
|
+
|
|
133
|
+
const { records } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
134
|
+
expect(records.map((r) => r.ended)).toEqual([
|
|
135
|
+
"2026-01-01T00:00:12.000Z",
|
|
136
|
+
"2026-01-01T00:10:12.000Z",
|
|
137
|
+
"2026-01-01T00:20:12.000Z",
|
|
138
|
+
]);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("one op's ledger is not another's, and neither disturbs the converge ledger in the same env", async () => {
|
|
143
|
+
await withTestDir(async (dir) => {
|
|
144
|
+
await initRepo(dir);
|
|
145
|
+
await appendRunRecord(makeInput({ op: "alb-deploy" }), { cwd: dir });
|
|
146
|
+
await appendRunRecord(makeInput({ op: "alb-teardown" }), { cwd: dir });
|
|
147
|
+
await appendConvergeRecord(
|
|
148
|
+
{
|
|
149
|
+
op: "staging-converge",
|
|
150
|
+
env: "staging",
|
|
151
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
152
|
+
firedRuleIds: [],
|
|
153
|
+
outcomes: [],
|
|
154
|
+
summary: { drifted: 0, remediated: 0, reported: 0, skippedBudget: 0, skippedFlap: 0, unobserved: 0, adopted: 0 },
|
|
155
|
+
log: "converge(staging): drifted=0",
|
|
156
|
+
},
|
|
157
|
+
{ cwd: dir },
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect((await readRunLedger("staging", "alb-deploy", { cwd: dir })).records).toHaveLength(1);
|
|
161
|
+
expect((await readRunLedger("staging", "alb-teardown", { cwd: dir })).records).toHaveLength(1);
|
|
162
|
+
expect((await readConvergeLedger("staging", { cwd: dir })).records).toHaveLength(1);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("an unwritten ledger reads empty — never throws", async () => {
|
|
167
|
+
await withTestDir(async (dir) => {
|
|
168
|
+
await initRepo(dir);
|
|
169
|
+
const { records, malformed } = await readRunLedger("nowhere", "nothing", { cwd: dir });
|
|
170
|
+
expect(records).toEqual([]);
|
|
171
|
+
expect(malformed).toBe(0);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("skips malformed lines but reports the count", async () => {
|
|
176
|
+
await withTestDir(async (dir) => {
|
|
177
|
+
await initRepo(dir);
|
|
178
|
+
await appendRunRecord(makeInput(), { cwd: dir });
|
|
179
|
+
|
|
180
|
+
const { readBlobFromPath, writeBlobToPath } = await import("./git");
|
|
181
|
+
const existing = await readBlobFromPath("staging", "runs__alb-deploy.jsonl", { cwd: dir });
|
|
182
|
+
const corrupted = `${existing}\n${JSON.stringify({ version: 1, op: "alb-deploy", env: "staging" })}`;
|
|
183
|
+
await writeBlobToPath("staging", "runs__alb-deploy.jsonl", corrupted, "corrupt", { cwd: dir });
|
|
184
|
+
|
|
185
|
+
const { records, malformed } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
186
|
+
expect(records).toHaveLength(1);
|
|
187
|
+
expect(malformed).toBe(1);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("a gated record written by hand round-trips (#2119 produces these; the type carries the status now)", async () => {
|
|
192
|
+
await withTestDir(async (dir) => {
|
|
193
|
+
await initRepo(dir);
|
|
194
|
+
await appendRunRecord(
|
|
195
|
+
makeInput({
|
|
196
|
+
status: "gated",
|
|
197
|
+
phases: [
|
|
198
|
+
{ name: "Plan", status: "ok", steps: [{ fn: "terraformPlan", status: "ok", durationMs: 900 }] },
|
|
199
|
+
{ name: "Approve", status: "skipped", steps: [{ fn: "gate:approve-apply", status: "skipped", durationMs: 0 }] },
|
|
200
|
+
],
|
|
201
|
+
}),
|
|
202
|
+
{ cwd: dir },
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const { records } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
206
|
+
expect(records[0].status).toBe("gated");
|
|
207
|
+
expect(records[0].phases[1]).toMatchObject({ name: "Approve", status: "skipped" });
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("runOpLocally → the run ledger", () => {
|
|
213
|
+
test("a successful run appends exactly one record, and the result carries the same document", async () => {
|
|
214
|
+
await withTestDir(async (dir) => {
|
|
215
|
+
await initRepo(dir);
|
|
216
|
+
const activities = new Map<string, ActivityFn>([["ok", async () => ({ drifted: false })]]);
|
|
217
|
+
const config = opConfig({
|
|
218
|
+
phases: [
|
|
219
|
+
{
|
|
220
|
+
name: "Apply",
|
|
221
|
+
steps: [{ kind: "activity", fn: "ok", args: {}, outcomeAttribute: { name: "Drift", from: "drifted" } }],
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const result = await runOpLocally(config, activities, NO_PROFILES, undefined, { ledger: { cwd: dir } });
|
|
227
|
+
|
|
228
|
+
const { records } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
229
|
+
expect(records).toHaveLength(1);
|
|
230
|
+
expect(records[0]).toEqual(result.record);
|
|
231
|
+
expect(records[0].status).toBe("ok");
|
|
232
|
+
expect(records[0].outcomes).toEqual({ Drift: false });
|
|
233
|
+
expect(records[0].labels).toEqual({ Env: "staging" });
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test("a failed run appends a fail record and still rejects with OpRunFailure", async () => {
|
|
238
|
+
await withTestDir(async (dir) => {
|
|
239
|
+
await initRepo(dir);
|
|
240
|
+
const activities = new Map<string, ActivityFn>([
|
|
241
|
+
["ok", async () => { throw new Error("boom"); }],
|
|
242
|
+
]);
|
|
243
|
+
|
|
244
|
+
const err = await runOpLocally(opConfig(), activities, NO_PROFILES, undefined, { ledger: { cwd: dir } })
|
|
245
|
+
.catch((e: unknown) => e);
|
|
246
|
+
expect(err).toBeInstanceOf(OpRunFailure);
|
|
247
|
+
|
|
248
|
+
const { records } = await readRunLedger("staging", "alb-deploy", { cwd: dir });
|
|
249
|
+
expect(records).toHaveLength(1);
|
|
250
|
+
expect(records[0].status).toBe("fail");
|
|
251
|
+
expect(records[0].phases[0].steps[0].error).toContain("boom");
|
|
252
|
+
expect((err as OpRunFailure).result.record).toEqual(records[0]);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("without the ledger option a run writes nothing, but still carries its record", async () => {
|
|
257
|
+
await withTestDir(async (dir) => {
|
|
258
|
+
await initRepo(dir);
|
|
259
|
+
const activities = new Map<string, ActivityFn>([["ok", async () => ({})]]);
|
|
260
|
+
|
|
261
|
+
const result = await runOpLocally(opConfig(), activities, NO_PROFILES);
|
|
262
|
+
|
|
263
|
+
expect(result.record.op).toBe("alb-deploy");
|
|
264
|
+
expect(result.record.status).toBe("ok");
|
|
265
|
+
expect((await readRunLedger("staging", "alb-deploy", { cwd: dir })).records).toEqual([]);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
});
|