@intentius/chant 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +20 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +14 -8
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +28 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +26 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +20 -21
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +3 -3
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +66 -36
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +9 -15
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/import/ir-utils.d.ts +1 -1
- package/dist/import/ir-utils.d.ts.map +1 -1
- package/dist/import/parser.d.ts +33 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +104 -14
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +71 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +89 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +84 -29
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +113 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +23 -7
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +184 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +30 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +79 -27
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/stack-output.d.ts +5 -0
- package/dist/stack-output.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +61 -17
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +91 -15
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +189 -11
- package/src/cli/commands/audit.ts +73 -27
- package/src/cli/commands/build.test.ts +292 -9
- package/src/cli/commands/build.ts +156 -24
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/import.ts +6 -0
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +48 -0
- package/src/cli/commands/lint.ts +123 -0
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +260 -55
- package/src/cli/handlers/run.test.ts +431 -1287
- package/src/cli/handlers/run.ts +365 -915
- package/src/cli/main.test.ts +23 -15
- package/src/cli/main.ts +88 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/registry.ts +26 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +3 -2
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +10 -5
- package/src/components/cli-support.ts +52 -44
- package/src/components/component.schema.json +2 -2
- package/src/components/component.ts +3 -3
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +92 -22
- package/src/components/driver.ts +193 -83
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.ts +11 -17
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +81 -1
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +2 -2
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/import/ir-utils.ts +11 -1
- package/src/import/parser.ts +35 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +120 -14
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +143 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +1 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +81 -0
- package/src/op/activities/reconcile.ts +187 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +123 -39
- package/src/op/composites/apply-op.ts +208 -0
- package/src/op/composites/composites.test.ts +366 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +107 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +26 -11
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +39 -6
- package/src/op/local-executor.test.ts +163 -34
- package/src/op/local-executor.ts +370 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +281 -0
- package/src/op/op-ir.ts +417 -0
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +26 -5
- package/src/op/operator.test.ts +175 -6
- package/src/op/operator.ts +63 -16
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +84 -24
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/stack-output.ts +6 -1
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `buildParams`, so a `*.component.ts` file reading `params.<name>` always
|
|
7
7
|
* saw `{}` under `chant build --components --generate`, exactly like `chant
|
|
8
8
|
* run --components` (see ../handlers/run.test.ts's "build-time parameters"
|
|
9
|
-
* describe block for the equivalent local
|
|
9
|
+
* describe block for the equivalent local-run coverage).
|
|
10
10
|
*
|
|
11
11
|
* Mocks `generateComponentsPipeline` and `loadChantConfigUpward` (chant
|
|
12
12
|
* #1117 — `runGenerateComponents` walks up to the project root now, same as
|
|
@@ -149,3 +149,83 @@ describe("runBuild --components --generate (chant #1108 build-time parameters)",
|
|
|
149
149
|
expect(generateComponentsPipelineMock).not.toHaveBeenCalled();
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* chant #2060. `chant build --components --generate --format json` forwarded
|
|
155
|
+
* only `{ stages, jobs, yaml }`, dropping `result.env` even though the
|
|
156
|
+
* generator (#2046, PR #2050) resolves and returns it. A consumer reading the
|
|
157
|
+
* structured output (behold does) had no environment identity except by
|
|
158
|
+
* parsing the YAML back, which #2046 was meant to retire.
|
|
159
|
+
*/
|
|
160
|
+
describe("runBuild --components --generate --format json (chant #2060 env passthrough)", () => {
|
|
161
|
+
beforeEach(() => {
|
|
162
|
+
generateComponentsPipelineMock.mockReset();
|
|
163
|
+
loadChantConfigUpwardMock.mockReset().mockResolvedValue({ config: {} });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("--format json includes result.env alongside stages, jobs and yaml", async () => {
|
|
167
|
+
generateComponentsPipelineMock.mockResolvedValue({
|
|
168
|
+
success: true,
|
|
169
|
+
yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
|
|
170
|
+
stages: ["deploy"],
|
|
171
|
+
jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
|
|
172
|
+
env: "prod",
|
|
173
|
+
});
|
|
174
|
+
const stdout: string[] = [];
|
|
175
|
+
vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
|
|
176
|
+
|
|
177
|
+
const exit = await runBuild({
|
|
178
|
+
args: makeArgs({ format: "json", env: "prod" }),
|
|
179
|
+
plugins: [],
|
|
180
|
+
serializers: [],
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(exit).toBe(0);
|
|
184
|
+
expect(stdout).toHaveLength(1);
|
|
185
|
+
const printed = JSON.parse(stdout[0]);
|
|
186
|
+
expect(printed).toEqual({
|
|
187
|
+
stages: ["deploy"],
|
|
188
|
+
jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
|
|
189
|
+
yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
|
|
190
|
+
env: "prod",
|
|
191
|
+
});
|
|
192
|
+
vi.restoreAllMocks();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("--format json omits env when the generator's result carries none", async () => {
|
|
196
|
+
generateComponentsPipelineMock.mockResolvedValue({
|
|
197
|
+
success: true,
|
|
198
|
+
yaml: "stages: []",
|
|
199
|
+
stages: [],
|
|
200
|
+
jobs: [],
|
|
201
|
+
});
|
|
202
|
+
const stdout: string[] = [];
|
|
203
|
+
vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
|
|
204
|
+
|
|
205
|
+
const exit = await runBuild({ args: makeArgs({ format: "json" }), plugins: [], serializers: [] });
|
|
206
|
+
|
|
207
|
+
expect(exit).toBe(0);
|
|
208
|
+
const printed = JSON.parse(stdout[0]);
|
|
209
|
+
expect(printed).toEqual({ stages: [], jobs: [], yaml: "stages: []" });
|
|
210
|
+
expect(printed).not.toHaveProperty("env");
|
|
211
|
+
vi.restoreAllMocks();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("the default text format is unchanged: env is not forwarded and only the raw yaml is printed", async () => {
|
|
215
|
+
generateComponentsPipelineMock.mockResolvedValue({
|
|
216
|
+
success: true,
|
|
217
|
+
yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
|
|
218
|
+
stages: ["deploy"],
|
|
219
|
+
jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
|
|
220
|
+
env: "prod",
|
|
221
|
+
});
|
|
222
|
+
const stdout: string[] = [];
|
|
223
|
+
vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
|
|
224
|
+
|
|
225
|
+
const exit = await runBuild({ args: makeArgs({ env: "prod" }), plugins: [], serializers: [] });
|
|
226
|
+
|
|
227
|
+
expect(exit).toBe(0);
|
|
228
|
+
expect(stdout).toEqual(["name: chant-components-prod\nenv:\n CHANT_ENV: prod\n"]);
|
|
229
|
+
vi.restoreAllMocks();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
@@ -63,7 +63,21 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
63
63
|
|
|
64
64
|
const yaml = result.yaml ?? "";
|
|
65
65
|
if (args.format === "json") {
|
|
66
|
-
console.log(
|
|
66
|
+
console.log(
|
|
67
|
+
JSON.stringify(
|
|
68
|
+
{
|
|
69
|
+
stages: result.stages,
|
|
70
|
+
jobs: result.jobs,
|
|
71
|
+
yaml,
|
|
72
|
+
// The environment the generated pipeline deploys (#2046), the
|
|
73
|
+
// generator's own resolution, forwarded rather than left for a
|
|
74
|
+
// consumer to re-derive by parsing the YAML back (#2060).
|
|
75
|
+
...(result.env ? { env: result.env } : {}),
|
|
76
|
+
},
|
|
77
|
+
null,
|
|
78
|
+
2,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
67
81
|
} else if (args.output) {
|
|
68
82
|
const outputPath = resolve(args.output);
|
|
69
83
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
@@ -233,14 +233,14 @@ describe("runGraph", () => {
|
|
|
233
233
|
filePath: file,
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
-
test("an op discoverOps finds at the project root becomes a
|
|
236
|
+
test("an op discoverOps finds at the project root becomes a Chant::Op node", async () => {
|
|
237
237
|
lintClean(); discovered();
|
|
238
238
|
discoverOpsMock.mockResolvedValue({ ops: new Map([["deploy", rootOp("/proj/deploy.op.ts")]]), errors: [] });
|
|
239
239
|
const exit = await runGraph({ args: makeArgs({ format: "ir", path: "/proj", detail: 3 }), plugins: [], serializers: [] });
|
|
240
240
|
expect(exit).toBe(0);
|
|
241
241
|
const ir = JSON.parse(stdoutBuf.join("\n"));
|
|
242
242
|
const node = ir.nodes.find((n: { id: string }) => n.id === "deploy");
|
|
243
|
-
expect(node).toMatchObject({ kind: "
|
|
243
|
+
expect(node).toMatchObject({ kind: "Chant::Op", lexicon: "chant", sourceLoc: { file: "deploy.op.ts" } });
|
|
244
244
|
expect(node.attrs.phases[0].name).toBe("Apply");
|
|
245
245
|
expect(node.attrs.depends).toEqual(["infra"]);
|
|
246
246
|
});
|
|
@@ -248,7 +248,7 @@ describe("runGraph", () => {
|
|
|
248
248
|
test("an op discovery already loaded from sourceDir is not added twice", async () => {
|
|
249
249
|
lintClean();
|
|
250
250
|
const entities = sampleEntities();
|
|
251
|
-
entities.set("deploy", decl({ lexicon: "
|
|
251
|
+
entities.set("deploy", decl({ lexicon: "chant", entityType: "Chant::Op", props: { name: "deploy", phases: [] } }));
|
|
252
252
|
discoverMock.mockResolvedValue({ entities, errors: [], dependencies: new Map(), sourceFiles: ["/proj/src/deploy.op.ts"] });
|
|
253
253
|
discoverOpsMock.mockResolvedValue({ ops: new Map([["deploy", rootOp("/proj/src/deploy.op.ts")]]), errors: [] });
|
|
254
254
|
const exit = await runGraph({ args: makeArgs({ format: "ir", path: "/proj", detail: 3 }), plugins: [], serializers: [] });
|
|
@@ -3,6 +3,7 @@ import { sep } from "node:path";
|
|
|
3
3
|
import { createMockPlugin, staticDescribeResources, staticObservation, staticDeepObservation, staticListArtifacts } from "@intentius/chant-test-utils";
|
|
4
4
|
import type { LexiconPlugin, ResourceMetadata } from "../../lexicon";
|
|
5
5
|
import { deepObservation } from "../../deep-observation";
|
|
6
|
+
import { heldElsewhere } from "../../held-elsewhere";
|
|
6
7
|
import type { BuildResult } from "../../build";
|
|
7
8
|
import type { ParsedArgs } from "../registry";
|
|
8
9
|
|
|
@@ -565,12 +566,49 @@ describe("runLifecycleDiff --live", () => {
|
|
|
565
566
|
} as never);
|
|
566
567
|
};
|
|
567
568
|
|
|
568
|
-
test("reports the changed property and the undeclared one", async () => {
|
|
569
|
+
test("reports the changed property as drift and the undeclared one as unclaimed", async () => {
|
|
569
570
|
await runDiff([withDeep()]);
|
|
570
571
|
const output = stdoutBuf.join("\n");
|
|
571
572
|
expect(output).toContain("aws (properties)");
|
|
572
573
|
expect(output).toContain("Versioning: Enabled → Suspended");
|
|
573
|
-
|
|
574
|
+
// #2160: source never set Logging.Target, so it is somebody else's field.
|
|
575
|
+
// Still reported, no longer a difference chant proposes to close.
|
|
576
|
+
expect(output).toContain("UNCLAIMED");
|
|
577
|
+
expect(output).toContain("Logging.Target: audit [not in this declaration's claimed fields]");
|
|
578
|
+
expect(output).toContain("1 property drift across 1 resource(s)");
|
|
579
|
+
expect(output).toContain("1 unclaimed");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// #2181 - the early-return guard tested the held count twice and never the
|
|
583
|
+
// unclaimed count, so a report whose only finding was a live value
|
|
584
|
+
// nobody declared printed nothing at all: no summary line, no section. That
|
|
585
|
+
// is the case #2160 was opened to surface.
|
|
586
|
+
test("a report whose only finding is a live value nobody declared still renders", async () => {
|
|
587
|
+
const plugins = [withDeep()];
|
|
588
|
+
const build = makeBuildResult({ aws: ["bucket"] });
|
|
589
|
+
// Declared exactly what is live, so there is no drift left to carry the
|
|
590
|
+
// section into the output.
|
|
591
|
+
build.entities.set("bucket", {
|
|
592
|
+
lexicon: "aws",
|
|
593
|
+
entityType: "AWS::S3::Bucket",
|
|
594
|
+
props: { Versioning: "Suspended" },
|
|
595
|
+
} as never);
|
|
596
|
+
buildMock.mockResolvedValue(build);
|
|
597
|
+
fetchLifecycleMock.mockResolvedValue(undefined);
|
|
598
|
+
readSnapshotMock.mockResolvedValue(null);
|
|
599
|
+
|
|
600
|
+
await runLifecycleDiff({
|
|
601
|
+
args: makeArgs({ command: "state", path: "diff", extraPositional: "prod", live: true }),
|
|
602
|
+
plugins,
|
|
603
|
+
serializers: plugins.map((p) => p.serializer),
|
|
604
|
+
} as never);
|
|
605
|
+
|
|
606
|
+
const output = stdoutBuf.join("\n");
|
|
607
|
+
expect(output).toContain("aws (properties)");
|
|
608
|
+
expect(output).toContain("0 property drift across 0 resource(s)");
|
|
609
|
+
expect(output).toContain("1 unclaimed");
|
|
610
|
+
expect(output).toContain("UNCLAIMED");
|
|
611
|
+
expect(output).toContain("Logging.Target: audit");
|
|
574
612
|
});
|
|
575
613
|
|
|
576
614
|
test("a lexicon with no deep reader prints nothing extra", async () => {
|
|
@@ -579,28 +617,36 @@ describe("runLifecycleDiff --live", () => {
|
|
|
579
617
|
});
|
|
580
618
|
|
|
581
619
|
test("an accepted deviation in the baseline stops re-alerting", async () => {
|
|
620
|
+
// A path source declares: since #2160 the baseline only ever has drift to
|
|
621
|
+
// suppress, because an undeclared path is unclaimed and never alerted.
|
|
582
622
|
readBlobFromPathMock.mockResolvedValue(
|
|
583
623
|
JSON.stringify({
|
|
584
624
|
baseline: "v1",
|
|
585
625
|
environment: "prod",
|
|
586
|
-
lexicons: { aws: { bucket: { accepted: [{ path: "
|
|
626
|
+
lexicons: { aws: { bucket: { accepted: [{ path: "Versioning", value: "Suspended" }] } } },
|
|
587
627
|
}),
|
|
588
628
|
);
|
|
589
629
|
await runDiff([withDeep()]);
|
|
590
630
|
const output = stdoutBuf.join("\n");
|
|
591
|
-
expect(output).toContain("
|
|
592
|
-
expect(output).not.toContain("Logging.Target: <undeclared>");
|
|
631
|
+
expect(output).not.toContain("PROPERTY DRIFT");
|
|
593
632
|
expect(output).toContain("ACCEPTED (in the baseline; not drift)");
|
|
594
633
|
});
|
|
595
634
|
|
|
596
|
-
test("--json carries the property drift under the lexicon's `deep` key", async () => {
|
|
635
|
+
test("--json carries the property drift and the unclaimed fields under the lexicon's `deep` key", async () => {
|
|
597
636
|
await runDiff([withDeep()], { json: true });
|
|
598
637
|
const payload = JSON.parse(stdoutBuf.join("\n")) as {
|
|
599
|
-
lexicons: {
|
|
638
|
+
lexicons: {
|
|
639
|
+
aws: {
|
|
640
|
+
deep: {
|
|
641
|
+
drifted: Array<{ changes: Array<{ path: string }> }>;
|
|
642
|
+
unclaimed: Array<{ fields: Array<{ path: string; live: unknown; source: string }> }>;
|
|
643
|
+
};
|
|
644
|
+
};
|
|
645
|
+
};
|
|
600
646
|
};
|
|
601
|
-
expect(payload.lexicons.aws.deep.drifted[0].changes.map((c) => c.path)
|
|
602
|
-
|
|
603
|
-
"
|
|
647
|
+
expect(payload.lexicons.aws.deep.drifted[0].changes.map((c) => c.path)).toEqual(["Versioning"]);
|
|
648
|
+
expect(payload.lexicons.aws.deep.unclaimed[0].fields).toEqual([
|
|
649
|
+
{ path: "Logging.Target", live: "audit", source: "claimed-fields" },
|
|
604
650
|
]);
|
|
605
651
|
});
|
|
606
652
|
|
|
@@ -628,9 +674,11 @@ describe("runLifecycleDiff --live", () => {
|
|
|
628
674
|
const written = JSON.parse(content) as {
|
|
629
675
|
lexicons: { aws: { bucket: { accepted: Array<{ path: string; value: unknown }> } } };
|
|
630
676
|
};
|
|
631
|
-
|
|
677
|
+
// Only drift is accepted. A held field needs no acceptance: it was never
|
|
678
|
+
// reported as a deviation to begin with (#2160).
|
|
679
|
+
expect(written.lexicons.aws.bucket.accepted.map((a) => a.path)).toEqual(["Versioning"]);
|
|
632
680
|
expect(pushLifecycleMock).toHaveBeenCalled();
|
|
633
|
-
expect(stderrBuf.join("\n")).toContain("accepted
|
|
681
|
+
expect(stderrBuf.join("\n")).toContain("accepted 1 deviation(s)");
|
|
634
682
|
});
|
|
635
683
|
|
|
636
684
|
test("--update-baseline with nothing reported writes nothing", async () => {
|
|
@@ -642,6 +690,72 @@ describe("runLifecycleDiff --live", () => {
|
|
|
642
690
|
});
|
|
643
691
|
});
|
|
644
692
|
|
|
693
|
+
// #2162 — a `heldElsewhere()` marker reports as held, not drift, and a
|
|
694
|
+
// held property nothing ever writes is flagged suspicious on stderr.
|
|
695
|
+
describe("heldElsewhere() markers (#2162)", () => {
|
|
696
|
+
const runHeldDiff = async (
|
|
697
|
+
liveProperties: Record<string, unknown>,
|
|
698
|
+
args: Partial<ParsedArgs> = {},
|
|
699
|
+
) => {
|
|
700
|
+
const build = makeBuildResult({ k8s: ["web"] });
|
|
701
|
+
build.entities.set("web", {
|
|
702
|
+
lexicon: "k8s",
|
|
703
|
+
entityType: "K8s::Apps::Deployment",
|
|
704
|
+
props: { spec: { replicas: heldElsewhere<number>({ by: "hpa", reason: "the autoscaler owns replicas after the first apply" }) } },
|
|
705
|
+
} as never);
|
|
706
|
+
buildMock.mockResolvedValue(build);
|
|
707
|
+
fetchLifecycleMock.mockResolvedValue(undefined);
|
|
708
|
+
readSnapshotMock.mockResolvedValue(null);
|
|
709
|
+
const plugins: LexiconPlugin[] = [
|
|
710
|
+
createMockPlugin({
|
|
711
|
+
name: "k8s",
|
|
712
|
+
describeResources: staticObservation({ web: meta({ type: "K8s::Apps::Deployment" }) }),
|
|
713
|
+
observeResourcesDeep: staticDeepObservation({
|
|
714
|
+
web: { type: "K8s::Apps::Deployment", properties: { spec: liveProperties } },
|
|
715
|
+
}),
|
|
716
|
+
}),
|
|
717
|
+
];
|
|
718
|
+
return runLifecycleDiff({
|
|
719
|
+
args: makeArgs({ command: "state", path: "diff", extraPositional: "prod", live: true, ...args }),
|
|
720
|
+
plugins,
|
|
721
|
+
serializers: plugins.map((p) => p.serializer),
|
|
722
|
+
} as never);
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
test("a live value on the held path renders as HELD, not drift", async () => {
|
|
726
|
+
await runHeldDiff({ replicas: 5 });
|
|
727
|
+
const output = stdoutBuf.join("\n");
|
|
728
|
+
expect(output).toContain("HELD (declared heldElsewhere(); not drift, never proposed for update)");
|
|
729
|
+
expect(output).toContain("spec.replicas: held by hpa — 5 (the autoscaler owns replicas after the first apply)");
|
|
730
|
+
expect(output).not.toContain("PROPERTY DRIFT");
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
test("--json carries the held set under the lexicon's deep.held key", async () => {
|
|
734
|
+
await runHeldDiff({ replicas: 5 }, { json: true });
|
|
735
|
+
const payload = JSON.parse(stdoutBuf.join("\n")) as {
|
|
736
|
+
lexicons: { k8s: { deep: { held: Array<{ name: string; held: Array<{ path: string; by: string }> }> } } };
|
|
737
|
+
};
|
|
738
|
+
expect(payload.lexicons.k8s.deep.held).toEqual([
|
|
739
|
+
{
|
|
740
|
+
name: "web",
|
|
741
|
+
type: "K8s::Apps::Deployment",
|
|
742
|
+
held: [
|
|
743
|
+
{ path: "spec.replicas", by: "hpa", reason: "the autoscaler owns replicas after the first apply", live: 5, suspicious: false },
|
|
744
|
+
],
|
|
745
|
+
},
|
|
746
|
+
]);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
test("no live value at all is flagged suspicious, on the terminal and on stderr", async () => {
|
|
750
|
+
await runHeldDiff({});
|
|
751
|
+
const output = stdoutBuf.join("\n");
|
|
752
|
+
expect(output).toContain("SUSPICIOUS: no live value ever showed up here");
|
|
753
|
+
expect(stderrBuf.join("\n")).toContain(
|
|
754
|
+
'web.spec.replicas is declared heldElsewhere(by: "hpa") but no live value ever showed up there',
|
|
755
|
+
);
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
|
|
645
759
|
// #1166 — an environment can declare its own endpoint (a local emulator like
|
|
646
760
|
// Floci), applied to the ambient var of every observing lexicon that has one
|
|
647
761
|
// unless the ambient shell already set it.
|
|
@@ -799,6 +913,75 @@ describe("runLifecyclePlan", () => {
|
|
|
799
913
|
expect(web.queried).toBe("/apis/apps/v1/namespaces/default/deployments/web");
|
|
800
914
|
});
|
|
801
915
|
|
|
916
|
+
// #2162 — a held property is not an action, so the plan carries it beside
|
|
917
|
+
// `entries` rather than inside one, attributed to its lexicon the same way
|
|
918
|
+
// an entry is.
|
|
919
|
+
test("--json carries the held set beside entries, attributed to its lexicon", async () => {
|
|
920
|
+
const build = makeBuildResult({ k8s: ["web"] });
|
|
921
|
+
build.entities.set("web", {
|
|
922
|
+
lexicon: "k8s",
|
|
923
|
+
entityType: "K8s::Apps::Deployment",
|
|
924
|
+
props: { spec: { replicas: heldElsewhere<number>({ by: "hpa", reason: "the autoscaler owns replicas after the first apply" }) } },
|
|
925
|
+
} as never);
|
|
926
|
+
buildMock.mockResolvedValue(build);
|
|
927
|
+
const plugins: LexiconPlugin[] = [
|
|
928
|
+
createMockPlugin({
|
|
929
|
+
name: "k8s",
|
|
930
|
+
describeResources: staticObservation({ web: meta({ type: "K8s::Apps::Deployment" }) }),
|
|
931
|
+
observeResourcesDeep: staticDeepObservation({
|
|
932
|
+
web: { type: "K8s::Apps::Deployment", properties: { spec: { replicas: 5 } } },
|
|
933
|
+
}),
|
|
934
|
+
}),
|
|
935
|
+
];
|
|
936
|
+
const exit = await runLifecyclePlan({
|
|
937
|
+
args: makeArgs({ path: "plan", extraPositional: "prod", json: true }),
|
|
938
|
+
plugins,
|
|
939
|
+
serializers: plugins.map((p) => p.serializer),
|
|
940
|
+
});
|
|
941
|
+
expect(exit).toBe(0);
|
|
942
|
+
const plan = JSON.parse(stdoutBuf.join("\n"));
|
|
943
|
+
expect(plan.entries.find((e: { name: string }) => e.name === "web").action).not.toBe("update");
|
|
944
|
+
expect(plan.held).toEqual([
|
|
945
|
+
{
|
|
946
|
+
name: "web",
|
|
947
|
+
type: "K8s::Apps::Deployment",
|
|
948
|
+
lexicon: "k8s",
|
|
949
|
+
held: [
|
|
950
|
+
{ path: "spec.replicas", by: "hpa", reason: "the autoscaler owns replicas after the first apply", live: 5, suspicious: false },
|
|
951
|
+
],
|
|
952
|
+
},
|
|
953
|
+
]);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
test("the human render carries a HELD section, and a suspicious one warns on stderr", async () => {
|
|
957
|
+
const build = makeBuildResult({ k8s: ["web"] });
|
|
958
|
+
build.entities.set("web", {
|
|
959
|
+
lexicon: "k8s",
|
|
960
|
+
entityType: "K8s::Apps::Deployment",
|
|
961
|
+
props: { spec: { replicas: heldElsewhere<number>({ by: "hpa", reason: "x" }) } },
|
|
962
|
+
} as never);
|
|
963
|
+
buildMock.mockResolvedValue(build);
|
|
964
|
+
const plugins: LexiconPlugin[] = [
|
|
965
|
+
createMockPlugin({
|
|
966
|
+
name: "k8s",
|
|
967
|
+
describeResources: staticObservation({ web: meta({ type: "K8s::Apps::Deployment" }) }),
|
|
968
|
+
observeResourcesDeep: staticDeepObservation({
|
|
969
|
+
web: { type: "K8s::Apps::Deployment", properties: { spec: {} } },
|
|
970
|
+
}),
|
|
971
|
+
}),
|
|
972
|
+
];
|
|
973
|
+
const exit = await runLifecyclePlan({
|
|
974
|
+
args: makeArgs({ path: "plan", extraPositional: "prod" }),
|
|
975
|
+
plugins,
|
|
976
|
+
serializers: plugins.map((p) => p.serializer),
|
|
977
|
+
});
|
|
978
|
+
expect(exit).toBe(0);
|
|
979
|
+
expect(stdoutBuf.join("\n")).toContain("HELD (declared heldElsewhere(); not drift, never proposed for update)");
|
|
980
|
+
expect(stderrBuf.join("\n")).toContain(
|
|
981
|
+
'web.spec.replicas is declared heldElsewhere(by: "hpa") but no live value ever showed up there',
|
|
982
|
+
);
|
|
983
|
+
});
|
|
984
|
+
|
|
802
985
|
// #1674 — the plan merges every lexicon's change set into one flat
|
|
803
986
|
// `entries[]`; each row must still say which lexicon observed it, and carry
|
|
804
987
|
// the provider's physical id so an adopt/delete/runtime row named by a live
|
|
@@ -4,8 +4,9 @@ import { build } from "../../build";
|
|
|
4
4
|
import { takeSnapshot } from "../../lifecycle/snapshot";
|
|
5
5
|
import { readSnapshot, readSnapshotAt, readEnvironmentSnapshots, listSnapshots, fetchLifecycle, pushLifecycle, snapshotStorageKey, StaleLifecycleBranchError } from "../../lifecycle/git";
|
|
6
6
|
import { deepDiffForLexicon, type DeclaredEntities } from "../../lifecycle/deep-observe";
|
|
7
|
-
import { countPropertyDrift, type DeepDiffResult } from "../../lifecycle/deep-diff";
|
|
8
|
-
import { describePathOrigin, getPathProvenance } from "../../provenance";
|
|
7
|
+
import { countUnclaimed, countPropertyDrift, countHeld, suspiciousHeld, type DeepDiffResult, type DeepEntityHeld } from "../../lifecycle/deep-diff";
|
|
8
|
+
import { describePathOrigin, getPathProvenance, getProvenance, type EntityProvenance } from "../../provenance";
|
|
9
|
+
import { resolveDeepDrift, resolveDriftedField, type FieldReconcile } from "../../fold-provenance";
|
|
9
10
|
import {
|
|
10
11
|
acceptDeviations,
|
|
11
12
|
baselineForLexicon,
|
|
@@ -18,7 +19,7 @@ import {
|
|
|
18
19
|
} from "../../lifecycle/observation-baseline";
|
|
19
20
|
import { computeBuildDigest, diffDigests } from "../../lifecycle/digest";
|
|
20
21
|
import { diffLive, diffLiveArtifacts, diffSnapshots, type LiveDiffResult, type LiveArtifactDiffResult, type SnapshotDiffResult } from "../../lifecycle/live-diff";
|
|
21
|
-
import { buildChangeSet, renderChangeSet, renderChangeSetMarkdown, gitlabMrReport, unobservedPlanNotice, type ChangeSet } from "../../lifecycle/change-set";
|
|
22
|
+
import { buildChangeSet, renderChangeSet, renderChangeSetMarkdown, gitlabMrReport, unobservedPlanNotice, type ChangeSet, type HeldEntitySet } from "../../lifecycle/change-set";
|
|
22
23
|
import { mergeReceiptEntries, observedValueResolver, planReceipts, readReceiptValue, type ReceiptReading } from "../../lifecycle/receipt-plan";
|
|
23
24
|
import { annotateDisruption, disruptionNotices } from "../../lifecycle/disruption";
|
|
24
25
|
import { collectEffectReceipts, isEffectReceipt } from "../../effect-receipt";
|
|
@@ -697,6 +698,13 @@ interface LiveDiffOutcome {
|
|
|
697
698
|
unobserved?: Record<string, UnobservedEntity>;
|
|
698
699
|
/** Property-level drift (#1014), present only for lexicons with a deep reader. */
|
|
699
700
|
deep?: DeepDiffResult;
|
|
701
|
+
/**
|
|
702
|
+
* chant #2161 — one verdict per drifted field: what the fold provenance
|
|
703
|
+
* says produced it, and what the return leg may therefore propose. A
|
|
704
|
+
* sibling of `deep` rather than a field inside it, because `deep` is the
|
|
705
|
+
* comparison and this is what may be done about it.
|
|
706
|
+
*/
|
|
707
|
+
reconcile?: FieldReconcile[];
|
|
700
708
|
artifacts?: LiveArtifactDiffResult;
|
|
701
709
|
/** What `listArtifacts` actually saw, keyed like `artifacts`' entries
|
|
702
710
|
* (behold#146). The diff alone is snapshot-relative key lists — on a
|
|
@@ -882,8 +890,25 @@ async function runLifecycleDiffLive(args: LiveDiffArgs): Promise<LiveDiffOutcome
|
|
|
882
890
|
// otherwise one unreadable entity is counted twice.
|
|
883
891
|
totalUnobserved += deep.unobserved.filter((u) => !observed.unobserved[u.name]).length;
|
|
884
892
|
if (args.updateBaseline) toAccept[lexiconName] = deviationsToAccept(deep);
|
|
885
|
-
|
|
886
|
-
|
|
893
|
+
// chant #2161 — the return leg, classified by fold provenance. Read off
|
|
894
|
+
// the build's own entities, which is where the record lives.
|
|
895
|
+
const provenanceOf = (name: string): EntityProvenance | undefined => {
|
|
896
|
+
const entity = args.buildResult.entities.get(name);
|
|
897
|
+
return entity ? getProvenance(entity) : undefined;
|
|
898
|
+
};
|
|
899
|
+
if (args.json) {
|
|
900
|
+
const entry = (byLexicon[lexiconName] ??= {});
|
|
901
|
+
entry.deep = deep;
|
|
902
|
+
entry.reconcile = resolveDeepDrift(deep.drifted, provenanceOf);
|
|
903
|
+
} else renderDeepDiff(lexiconName, deep, provenanceOf);
|
|
904
|
+
// Printed on stderr regardless of `--json` (#2162), same reason the
|
|
905
|
+
// unobserved/disruption notices are: a shape with no column for
|
|
906
|
+
// "suspicious" must not read as clean.
|
|
907
|
+
for (const s of suspiciousHeld(deep)) {
|
|
908
|
+
console.error(formatWarning({
|
|
909
|
+
message: `${lexiconName}: ${s.name}.${s.path} is declared heldElsewhere(by: "${s.by}") but no live value ever showed up there — the hand-over may never have happened.`,
|
|
910
|
+
}));
|
|
911
|
+
}
|
|
887
912
|
}
|
|
888
913
|
}
|
|
889
914
|
|
|
@@ -939,10 +964,18 @@ function deviationsToAccept(deep: DeepDiffResult): DeviationToAccept[] {
|
|
|
939
964
|
}
|
|
940
965
|
|
|
941
966
|
/** Property-level drift report (#1014). Silent when a lexicon's deep read found nothing to say. */
|
|
942
|
-
function renderDeepDiff(
|
|
967
|
+
function renderDeepDiff(
|
|
968
|
+
lexiconName: string,
|
|
969
|
+
deep: DeepDiffResult,
|
|
970
|
+
provenanceOf: (entity: string) => EntityProvenance | undefined = () => undefined,
|
|
971
|
+
): void {
|
|
943
972
|
const drift = countPropertyDrift(deep);
|
|
973
|
+
const unclaimedCount = countUnclaimed(deep);
|
|
974
|
+
const heldCount = countHeld(deep);
|
|
944
975
|
if (
|
|
945
976
|
drift === 0 &&
|
|
977
|
+
heldCount === 0 &&
|
|
978
|
+
unclaimedCount === 0 &&
|
|
946
979
|
deep.accepted.length === 0 &&
|
|
947
980
|
deep.unobserved.length === 0 &&
|
|
948
981
|
deep.undeclaredEntities.length === 0
|
|
@@ -955,6 +988,8 @@ function renderDeepDiff(lexiconName: string, deep: DeepDiffResult): void {
|
|
|
955
988
|
console.log(
|
|
956
989
|
`${drift} property drift across ${deep.drifted.length} resource(s), ` +
|
|
957
990
|
`${acceptedCount} accepted, ${deep.unchanged.length} unchanged` +
|
|
991
|
+
(heldCount > 0 ? `, ${heldCount} held` : "") +
|
|
992
|
+
(unclaimedCount > 0 ? `, ${unclaimedCount} unclaimed` : "") +
|
|
958
993
|
(deep.unobserved.length > 0 ? `, ${deep.unobserved.length} unobserved` : ""),
|
|
959
994
|
);
|
|
960
995
|
console.log("-".repeat(80));
|
|
@@ -967,6 +1002,7 @@ function renderDeepDiff(lexiconName: string, deep: DeepDiffResult): void {
|
|
|
967
1002
|
console.log(formatBold("\nPROPERTY DRIFT (declared vs live; baseline shown where one exists):"));
|
|
968
1003
|
for (const entity of deep.drifted) {
|
|
969
1004
|
console.log(` - ${entity.name} (${entity.type})`);
|
|
1005
|
+
const provenance = provenanceOf(entity.name);
|
|
970
1006
|
for (const change of entity.changes) {
|
|
971
1007
|
const declared = "declared" in change ? formatValue(change.declared) : "<undeclared>";
|
|
972
1008
|
const live = "live" in change ? formatValue(change.live) : "<absent>";
|
|
@@ -975,9 +1011,42 @@ function renderDeepDiff(lexiconName: string, deep: DeepDiffResult): void {
|
|
|
975
1011
|
const from = change.origin ? ` [from: ${describePathOrigin(change.origin)}]` : "";
|
|
976
1012
|
const owner = change.owner ? ` [owner: ${change.owner}]` : "";
|
|
977
1013
|
console.log(` ${change.path}: ${declared} → ${live}${baseline}${from}${owner}`);
|
|
1014
|
+
// chant #2161 — what may be done about it, when the origin says
|
|
1015
|
+
// something today's behaviour would get wrong. A field the author
|
|
1016
|
+
// declared directly is left unremarked: editing it IS today's
|
|
1017
|
+
// behaviour, and saying so on every row would bury the two that matter.
|
|
1018
|
+
const { resolution } = resolveDriftedField({
|
|
1019
|
+
entity: entity.name,
|
|
1020
|
+
path: change.path,
|
|
1021
|
+
...("declared" in change ? { declared: change.declared } : {}),
|
|
1022
|
+
...("live" in change ? { live: change.live } : {}),
|
|
1023
|
+
...(change.origin ? { origin: change.origin } : {}),
|
|
1024
|
+
...(provenance ? { provenance } : {}),
|
|
1025
|
+
});
|
|
1026
|
+
if (resolution.kind !== "edit-declaration") {
|
|
1027
|
+
console.log(` ${resolution.description}`);
|
|
1028
|
+
}
|
|
978
1029
|
}
|
|
979
1030
|
}
|
|
980
1031
|
}
|
|
1032
|
+
if (deep.unclaimed.length > 0) {
|
|
1033
|
+
// Not drift, and printed after it for that reason (#2160): chant never set
|
|
1034
|
+
// these fields, so nothing here is a change chant proposes to make.
|
|
1035
|
+
console.log(formatBold("\nUNCLAIMED (live values on properties chant never declared; not drift):"));
|
|
1036
|
+
for (const entity of deep.unclaimed) {
|
|
1037
|
+
console.log(` - ${entity.name} (${entity.type})`);
|
|
1038
|
+
for (const field of entity.fields) {
|
|
1039
|
+
const holder = field.heldBy
|
|
1040
|
+
? `held by ${field.heldBy}`
|
|
1041
|
+
: "not in this declaration's claimed fields";
|
|
1042
|
+
console.log(` ${field.path}: ${formatValue(field.live)} [${holder}]`);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
if (heldCount > 0) {
|
|
1047
|
+
console.log(formatBold("\nHELD (declared heldElsewhere(); not drift, never proposed for update):"));
|
|
1048
|
+
for (const line of renderHeldLines(deep.held)) console.log(line);
|
|
1049
|
+
}
|
|
981
1050
|
if (deep.undeclaredEntities.length > 0) {
|
|
982
1051
|
console.log(formatBold("\nUNDECLARED (read deeply, never declared in source):"));
|
|
983
1052
|
for (const name of deep.undeclaredEntities) console.log(` - ${name}`);
|
|
@@ -990,6 +1059,30 @@ function renderDeepDiff(lexiconName: string, deep: DeepDiffResult): void {
|
|
|
990
1059
|
}
|
|
991
1060
|
}
|
|
992
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* Render one `heldElsewhere()` property (#2162) — shared between the deep
|
|
1064
|
+
* diff's HELD section and the plan's, so the two never disagree about what a
|
|
1065
|
+
* held field looks like on the terminal.
|
|
1066
|
+
*/
|
|
1067
|
+
function formatHeldProperty(h: { path: string; by: string; reason: string; live?: unknown; suspicious: boolean; owner?: string }): string {
|
|
1068
|
+
const live = "live" in h ? formatValue(h.live) : "<absent>";
|
|
1069
|
+
const owner = h.owner ? ` [owner: ${h.owner}]` : "";
|
|
1070
|
+
const suspicious = h.suspicious
|
|
1071
|
+
? " [SUSPICIOUS: no live value ever showed up here — check the holder is actually running, or that this is the field it writes]"
|
|
1072
|
+
: "";
|
|
1073
|
+
return ` ${h.path}: held by ${h.by} — ${live}${owner} (${h.reason})${suspicious}`;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/** Lines for every held property across a lexicon's entities, indented and grouped by entity name. */
|
|
1077
|
+
function renderHeldLines(held: readonly DeepEntityHeld[]): string[] {
|
|
1078
|
+
const lines: string[] = [];
|
|
1079
|
+
for (const entity of held) {
|
|
1080
|
+
lines.push(` - ${entity.name} (${entity.type})`);
|
|
1081
|
+
for (const h of entity.held) lines.push(formatHeldProperty(h));
|
|
1082
|
+
}
|
|
1083
|
+
return lines;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
993
1086
|
function renderLiveDiff(lexiconName: string, environment: string, diff: LiveDiffResult): void {
|
|
994
1087
|
const counts =
|
|
995
1088
|
`${diff.missing.length} missing, ${diff.orphan.length} orphan, ` +
|
|
@@ -1148,6 +1241,9 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1148
1241
|
|
|
1149
1242
|
const merged: ChangeSet = { env: environment, entries: [] };
|
|
1150
1243
|
let checked = 0;
|
|
1244
|
+
// Held properties (#2162), across every lexicon this plan checks — not an
|
|
1245
|
+
// action, so it rides beside `entries` rather than inside it.
|
|
1246
|
+
const heldSets: HeldEntitySet[] = [];
|
|
1151
1247
|
|
|
1152
1248
|
// Effect receipts (#1832): declared, diffed, and observed like any resource,
|
|
1153
1249
|
// but observe-only to the generic apply path — the plan compares live value
|
|
@@ -1221,6 +1317,26 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1221
1317
|
});
|
|
1222
1318
|
|
|
1223
1319
|
Object.assign(allObservedResources, observed.resources);
|
|
1320
|
+
|
|
1321
|
+
// Held properties (#2162): opt-in on the same capability the deep diff
|
|
1322
|
+
// path gates on. A held property is never a proposal, so it is
|
|
1323
|
+
// computed here (once per lexicon, against this same observation) and
|
|
1324
|
+
// carried on the plan beside `entries` rather than folded into one.
|
|
1325
|
+
if (plugin.observeResourcesDeep) {
|
|
1326
|
+
const deep = await deepDiffForLexicon(plugin, {
|
|
1327
|
+
environment,
|
|
1328
|
+
buildOutput,
|
|
1329
|
+
entities,
|
|
1330
|
+
componentStacks,
|
|
1331
|
+
});
|
|
1332
|
+
for (const entity of deep.held) heldSets.push({ ...entity, lexicon: lexiconName });
|
|
1333
|
+
for (const s of suspiciousHeld(deep)) {
|
|
1334
|
+
console.error(formatWarning({
|
|
1335
|
+
message: `${lexiconName}: ${s.name}.${s.path} is declared heldElsewhere(by: "${s.by}") but no live value ever showed up there — the hand-over may never have happened.`,
|
|
1336
|
+
}));
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1224
1340
|
for (const [receiptName, receipt] of receipts) {
|
|
1225
1341
|
if (receipt.lexicon !== lexiconName) continue;
|
|
1226
1342
|
const live = observed.resources[receiptName];
|
|
@@ -1301,6 +1417,7 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1301
1417
|
}
|
|
1302
1418
|
|
|
1303
1419
|
merged.entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1420
|
+
if (heldSets.length > 0) merged.held = heldSets.sort((a, b) => a.name.localeCompare(b.name));
|
|
1304
1421
|
|
|
1305
1422
|
// Say it on stderr too, so `--json` and `--report gitlab-mr` consumers (whose
|
|
1306
1423
|
// shapes have no room for it) still learn the plan has a hole (#1089). The
|
package/src/cli/handlers/misc.ts
CHANGED
|
@@ -24,7 +24,7 @@ const CHANT_VERSION: string = (() => {
|
|
|
24
24
|
|
|
25
25
|
const AUDIT_FORMATS: AuditFormat[] = ["stylish", "json", "sarif", "markdown", "html"];
|
|
26
26
|
const AUDIT_TIERS: AuditTier[] = ["merge-worthy", "all"];
|
|
27
|
-
const AUDIT_FAIL_ON: AuditFailOn[] = ["merge-worthy", "warning", "none"];
|
|
27
|
+
const AUDIT_FAIL_ON: AuditFailOn[] = ["merge-worthy", "warning", "error", "none"];
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Parse `--scope system,user,project`. Returns `undefined` (meaning "all") when
|