@intentius/chant 0.57.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/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/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/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/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/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/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
|
@@ -20,6 +20,17 @@
|
|
|
20
20
|
* {@link UNRESOLVED} — an unevaluated intrinsic (`Fn::Sub`, `Ref`) has no
|
|
21
21
|
* source-side value to compare, and reporting one as drift would light up every
|
|
22
22
|
* interpolated property forever.
|
|
23
|
+
*
|
|
24
|
+
* ## The claim decides what counts as drift (#2160)
|
|
25
|
+
*
|
|
26
|
+
* The declared tree is not only one side of a comparison, it is a statement of
|
|
27
|
+
* which fields chant ever set — the claimed-field set (../claimed-fields.ts).
|
|
28
|
+
* A live value on a path outside it is somebody else's field: an autoscaler's
|
|
29
|
+
* replica count, a controller's annotation, a value a person typed into a
|
|
30
|
+
* console. It is reported in {@link DeepDiffResult.unclaimed}, with the
|
|
31
|
+
* manager's name where the substrate records one, and it is not drift. Only a
|
|
32
|
+
* claimed path that moved is, and drift is the only thing that may become an
|
|
33
|
+
* update.
|
|
23
34
|
*/
|
|
24
35
|
|
|
25
36
|
import {
|
|
@@ -29,6 +40,8 @@ import {
|
|
|
29
40
|
type DeepNormalizationHooks,
|
|
30
41
|
type NormalizedDeepObservation,
|
|
31
42
|
} from "../deep-observation";
|
|
43
|
+
import { claimedFieldsFromPaths, heldBy, isClaimed, type FieldClaimSource } from "../claimed-fields";
|
|
44
|
+
import { isNormalizedHeldElsewhere } from "../held-elsewhere";
|
|
32
45
|
import { originOfPath, type PathOrigin } from "../provenance";
|
|
33
46
|
import type { UnobservedResource } from "./live-diff";
|
|
34
47
|
import { acceptedDeviation, type BaselineLexicon } from "./observation-baseline";
|
|
@@ -37,20 +50,30 @@ import { acceptedDeviation, type BaselineLexicon } from "./observation-baseline"
|
|
|
37
50
|
* How a property differs.
|
|
38
51
|
*
|
|
39
52
|
* - `changed` — declared and live both have the path, with different values.
|
|
40
|
-
*
|
|
41
|
-
* to exist: the console-added property CloudFormation itself will not report.
|
|
53
|
+
* The only kind that may become an update.
|
|
42
54
|
* - `absent` — source declares it and the live tree does not carry it. Weaker
|
|
43
|
-
* than
|
|
55
|
+
* than `changed`: a provider that omits a property it considers unset is
|
|
44
56
|
* common, which is what the lexicon's pruning hook is for.
|
|
57
|
+
*
|
|
58
|
+
* A live value on a path source never declared used to be a third kind,
|
|
59
|
+
* `undeclared`. It is no longer drift at all (#2160): chant never set that
|
|
60
|
+
* field, so somebody else holds it, and it is reported in
|
|
61
|
+
* {@link DeepDiffResult.unclaimed} instead. It is still reported — pruning
|
|
62
|
+
* what chant cannot attribute is how #1191 lost a console-added label — it just
|
|
63
|
+
* stopped being a difference chant proposes to close.
|
|
45
64
|
*/
|
|
46
|
-
export type PropertyDriftKind = "changed" | "
|
|
65
|
+
export type PropertyDriftKind = "changed" | "absent";
|
|
47
66
|
|
|
48
67
|
/** One property-level difference. */
|
|
49
68
|
export interface PropertyDrift {
|
|
50
69
|
/** Path within the normalized property tree (`Tags[0].Value`). */
|
|
51
70
|
path: string;
|
|
52
71
|
kind: PropertyDriftKind;
|
|
53
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Value in source. Always present since #2160 — a drift row is only ever
|
|
74
|
+
* raised for a path the declaration claims — and kept optional for the wire
|
|
75
|
+
* shape consumers already branch on.
|
|
76
|
+
*/
|
|
54
77
|
declared?: unknown;
|
|
55
78
|
/** Value in the cloud. Absent for `absent`. */
|
|
56
79
|
live?: unknown;
|
|
@@ -64,7 +87,8 @@ export interface PropertyDrift {
|
|
|
64
87
|
* The field manager that owns this path live, where the substrate records one
|
|
65
88
|
* (#1189) — Kubernetes' `managedFields`, and nowhere else today.
|
|
66
89
|
*
|
|
67
|
-
* `kind` says a path
|
|
90
|
+
* `kind` says whether a claimed path changed or went missing; this says who
|
|
91
|
+
* holds it live.
|
|
68
92
|
* "Owned by `kubectl-client-side-apply`" and "owned by `hpa-controller`" are
|
|
69
93
|
* the same `kind` and mean opposite things: one is somebody bypassing the
|
|
70
94
|
* pipeline, the other is a controller doing its job. Absent on a substrate
|
|
@@ -92,6 +116,76 @@ export interface DeepEntityDrift {
|
|
|
92
116
|
changes: PropertyDrift[];
|
|
93
117
|
}
|
|
94
118
|
|
|
119
|
+
/**
|
|
120
|
+
* One live property value on a path this declaration never claimed (#2160) —
|
|
121
|
+
* a field that exists and that chant did not set.
|
|
122
|
+
*
|
|
123
|
+
* Reported, never proposed. The interesting column is {@link source}: on
|
|
124
|
+
* Kubernetes the API server names the manager and this row says
|
|
125
|
+
* `hpa-controller`; everywhere else the declaration is the only witness and the
|
|
126
|
+
* row says "not mine" without saying whose.
|
|
127
|
+
*/
|
|
128
|
+
export interface PropertyUnclaimed {
|
|
129
|
+
/** Path within the normalized property tree (`spec.replicas`). */
|
|
130
|
+
path: string;
|
|
131
|
+
/** The value the cloud is carrying. */
|
|
132
|
+
live: unknown;
|
|
133
|
+
/**
|
|
134
|
+
* The field manager holding it, where the substrate records one. Absent on
|
|
135
|
+
* every substrate but Kubernetes, and absent on Kubernetes for a path no
|
|
136
|
+
* `managedFields` entry covers.
|
|
137
|
+
*/
|
|
138
|
+
heldBy?: string;
|
|
139
|
+
/** Which source answered: the substrate's manager, or the claimed-field set. */
|
|
140
|
+
source: FieldClaimSource;
|
|
141
|
+
/**
|
|
142
|
+
* The accepted value from the baseline, when this path has one. An unclaimed
|
|
143
|
+
* field needs no acceptance to stay quiet, so this is carried for continuity with
|
|
144
|
+
* baselines recorded before #2160 rather than because it changes anything.
|
|
145
|
+
*/
|
|
146
|
+
baseline?: unknown;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Live property values one declared entity is not claiming. */
|
|
150
|
+
export interface DeepEntityUnclaimed {
|
|
151
|
+
name: string;
|
|
152
|
+
type: string;
|
|
153
|
+
fields: PropertyUnclaimed[];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* One property declared `heldElsewhere()` (#2162) — a fact about who owns the
|
|
158
|
+
* field at runtime, reported beside drift rather than folded into it. Never a
|
|
159
|
+
* {@link PropertyDrift}: a held property is never `changed`, `undeclared`, or
|
|
160
|
+
* `absent`, and is never proposed for update.
|
|
161
|
+
*/
|
|
162
|
+
export interface PropertyHeld {
|
|
163
|
+
/** Path within the normalized property tree, same addressing as {@link PropertyDrift.path}. */
|
|
164
|
+
path: string;
|
|
165
|
+
/** Who holds it — the marker's `by`. */
|
|
166
|
+
by: string;
|
|
167
|
+
/** Why chant does not reconcile it — the marker's `reason`. */
|
|
168
|
+
reason: string;
|
|
169
|
+
/** The live value, when the deep read found one at this path. */
|
|
170
|
+
live?: unknown;
|
|
171
|
+
/**
|
|
172
|
+
* True when this path carried no live value at all — the deep read found
|
|
173
|
+
* nothing here, not even a provider default. A declared hand-over with no
|
|
174
|
+
* evidence anything was ever written is itself worth a look: either the
|
|
175
|
+
* holder never ran, or this is not the field it actually writes.
|
|
176
|
+
*/
|
|
177
|
+
suspicious: boolean;
|
|
178
|
+
/** The field manager that owns this path live, where the substrate records one (#1189). See {@link PropertyDrift.owner}. */
|
|
179
|
+
owner?: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Held properties (#2162) for one declared entity. */
|
|
183
|
+
export interface DeepEntityHeld {
|
|
184
|
+
name: string;
|
|
185
|
+
type: string;
|
|
186
|
+
held: PropertyHeld[];
|
|
187
|
+
}
|
|
188
|
+
|
|
95
189
|
export interface DeepDiffResult {
|
|
96
190
|
/** Entities with at least one reportable property difference. Sorted by name. */
|
|
97
191
|
drifted: DeepEntityDrift[];
|
|
@@ -101,6 +195,28 @@ export interface DeepDiffResult {
|
|
|
101
195
|
* being held back and the count never silently changes meaning.
|
|
102
196
|
*/
|
|
103
197
|
accepted: DeepEntityDrift[];
|
|
198
|
+
/**
|
|
199
|
+
* Live values on paths nobody declared (#2160), per entity. Sorted by name.
|
|
200
|
+
*
|
|
201
|
+
* Not drift, and deliberately a sibling of `drifted` rather than a kind
|
|
202
|
+
* inside it: `countPropertyDrift` does not see this list, `--update-baseline`
|
|
203
|
+
* does not record it, and nothing downstream may turn one of these into an
|
|
204
|
+
* update. It exists so the report can still say the field is there and who
|
|
205
|
+
* has it.
|
|
206
|
+
*
|
|
207
|
+
* Not `held`, which is the opposite fact: `held` is a field source declared
|
|
208
|
+
* and then handed over with `heldElsewhere()`, and this is a field source
|
|
209
|
+
* never declared at all.
|
|
210
|
+
*/
|
|
211
|
+
unclaimed: DeepEntityUnclaimed[];
|
|
212
|
+
/**
|
|
213
|
+
* Properties declared `heldElsewhere()` (#2162) — reported here instead of
|
|
214
|
+
* in `drifted`/`accepted`, whatever the live value is. Not a suppression:
|
|
215
|
+
* every held property is listed, with its holder and reason, so a reader of
|
|
216
|
+
* the plan sees which fields are not being managed and by whom. Sorted by
|
|
217
|
+
* name.
|
|
218
|
+
*/
|
|
219
|
+
held: DeepEntityHeld[];
|
|
104
220
|
/** Entities whose property trees matched. Sorted. */
|
|
105
221
|
unchanged: string[];
|
|
106
222
|
/** Declared entities whose *properties* could not be read (#1089). Sorted. */
|
|
@@ -144,6 +260,8 @@ export function diffDeep(input: DiffDeepInput): DeepDiffResult {
|
|
|
144
260
|
const baseline = input.baseline ?? {};
|
|
145
261
|
const drifted: DeepEntityDrift[] = [];
|
|
146
262
|
const accepted: DeepEntityDrift[] = [];
|
|
263
|
+
const unclaimed: DeepEntityUnclaimed[] = [];
|
|
264
|
+
const held: DeepEntityHeld[] = [];
|
|
147
265
|
const unchanged: string[] = [];
|
|
148
266
|
const unobserved: UnobservedResource[] = [];
|
|
149
267
|
const undeclaredEntities: string[] = [];
|
|
@@ -187,39 +305,85 @@ export function diffDeep(input: DiffDeepInput): DeepDiffResult {
|
|
|
187
305
|
hooks: input.hooks,
|
|
188
306
|
});
|
|
189
307
|
|
|
308
|
+
// The claim (#2160): every path this declaration's props flatten to, in the
|
|
309
|
+
// grammar this loop addresses paths by. Derived here rather than read off
|
|
310
|
+
// `liveEntity.claimedFields` so `diffDeep` stays a pure function of its two
|
|
311
|
+
// trees; `lifecycle/deep-observe.ts` computes the identical set from the
|
|
312
|
+
// identical normalized tree and carries it on the observation for consumers.
|
|
313
|
+
const claimed = claimedFieldsFromPaths(declaredFlat.keys());
|
|
314
|
+
|
|
190
315
|
const paths = [...new Set([...declaredFlat.keys(), ...liveFlat.keys()])].sort();
|
|
191
316
|
const reported: PropertyDrift[] = [];
|
|
192
317
|
const suppressed: PropertyDrift[] = [];
|
|
318
|
+
const unclaimedFields: PropertyUnclaimed[] = [];
|
|
319
|
+
const heldHere: PropertyHeld[] = [];
|
|
193
320
|
|
|
194
321
|
for (const path of paths) {
|
|
195
|
-
const hasDeclared =
|
|
322
|
+
const hasDeclared = isClaimed(claimed, path);
|
|
196
323
|
const hasLive = liveFlat.has(path);
|
|
197
324
|
const declaredValue = declaredFlat.get(path);
|
|
198
325
|
const liveValue = liveFlat.get(path);
|
|
199
326
|
|
|
327
|
+
// A `heldElsewhere()` marker (#2162): never drift, whatever the live
|
|
328
|
+
// value is (or isn't) — reported in its own section instead, with its
|
|
329
|
+
// holder and reason, and never proposed for update. Checked ahead of
|
|
330
|
+
// the UNRESOLVED/equality shortcuts below: a held path is not "no
|
|
331
|
+
// source-side value" (UNRESOLVED) and its declared side will never
|
|
332
|
+
// structurally equal a live value, so without this check every held
|
|
333
|
+
// property would fall through and report as ordinary `changed` drift.
|
|
334
|
+
if (hasDeclared && isNormalizedHeldElsewhere(declaredValue)) {
|
|
335
|
+
heldHere.push({
|
|
336
|
+
path,
|
|
337
|
+
by: declaredValue.by,
|
|
338
|
+
reason: declaredValue.reason,
|
|
339
|
+
...(hasLive ? { live: liveValue } : {}),
|
|
340
|
+
// No live value at all is the one thing chant can check in a
|
|
341
|
+
// single observation: a claimed hand-over that produced no
|
|
342
|
+
// evidence — not even a provider default — is worth a look.
|
|
343
|
+
suspicious: !hasLive,
|
|
344
|
+
...(hasLive && liveEntity.fieldOwners?.[path] ? { owner: liveEntity.fieldOwners[path] } : {}),
|
|
345
|
+
});
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
200
349
|
// An unevaluated intrinsic has no source-side value to compare against.
|
|
201
350
|
if (hasDeclared && declaredValue === UNRESOLVED) continue;
|
|
202
351
|
if (hasDeclared && hasLive && deepValueEqual(declaredValue, liveValue)) continue;
|
|
203
352
|
|
|
204
|
-
const
|
|
353
|
+
const acceptedEntry = acceptedDeviation(baseline, name, path);
|
|
354
|
+
|
|
355
|
+
// A live value on a path nobody claimed is somebody else's field, not a
|
|
356
|
+
// difference chant proposes to close (#2160). Reported, never drift,
|
|
357
|
+
// never a candidate for an update — and the manager name, where the
|
|
358
|
+
// substrate records one, is the whole answer an operator wants.
|
|
359
|
+
if (!hasDeclared) {
|
|
360
|
+
const { holder, source } = heldBy(liveEntity.fieldOwners, path);
|
|
361
|
+
unclaimedFields.push({
|
|
362
|
+
path,
|
|
363
|
+
live: liveValue,
|
|
364
|
+
...(holder ? { heldBy: holder } : {}),
|
|
365
|
+
source,
|
|
366
|
+
...(acceptedEntry ? { baseline: acceptedEntry.value } : {}),
|
|
367
|
+
});
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const kind: PropertyDriftKind = !hasLive ? "absent" : "changed";
|
|
205
372
|
// Who owns the path live, where the substrate records it (#1189). Only
|
|
206
373
|
// meaningful for a path that exists live — an `absent` drift has no live
|
|
207
374
|
// field for anyone to own.
|
|
208
375
|
const owner = hasLive ? liveEntity.fieldOwners?.[path] : undefined;
|
|
209
|
-
// The declared-side counterpart (#1443).
|
|
210
|
-
|
|
211
|
-
// expression for anything to have produced.
|
|
212
|
-
const origin = hasDeclared ? originOfPath(declaredEntity.pathOrigins, path) : undefined;
|
|
376
|
+
// The declared-side counterpart (#1443).
|
|
377
|
+
const origin = originOfPath(declaredEntity.pathOrigins, path);
|
|
213
378
|
const drift: PropertyDrift = {
|
|
214
379
|
path,
|
|
215
380
|
kind,
|
|
216
|
-
|
|
381
|
+
declared: declaredValue,
|
|
217
382
|
...(hasLive ? { live: liveValue } : {}),
|
|
218
383
|
...(owner ? { owner } : {}),
|
|
219
384
|
...(origin ? { origin } : {}),
|
|
220
385
|
};
|
|
221
386
|
|
|
222
|
-
const acceptedEntry = acceptedDeviation(baseline, name, path);
|
|
223
387
|
if (acceptedEntry) {
|
|
224
388
|
drift.baseline = acceptedEntry.value;
|
|
225
389
|
// Value-bound acceptance: the accepted value is not drift, a different
|
|
@@ -233,13 +397,20 @@ export function diffDeep(input: DiffDeepInput): DeepDiffResult {
|
|
|
233
397
|
}
|
|
234
398
|
|
|
235
399
|
if (suppressed.length > 0) accepted.push({ name, type, changes: suppressed });
|
|
400
|
+
if (unclaimedFields.length > 0) unclaimed.push({ name, type, fields: unclaimedFields });
|
|
236
401
|
if (reported.length > 0) drifted.push({ name, type, changes: reported });
|
|
402
|
+
// Held fields do not disqualify an entity from `unchanged`: every property
|
|
403
|
+
// chant declared matches, and the epic's whole point is that a controller's
|
|
404
|
+
// field stops being a finding chant restates on every tick.
|
|
237
405
|
else if (suppressed.length === 0) unchanged.push(name);
|
|
406
|
+
if (heldHere.length > 0) held.push({ name, type, held: heldHere });
|
|
238
407
|
}
|
|
239
408
|
|
|
240
409
|
return {
|
|
241
410
|
drifted: drifted.sort((a, b) => a.name.localeCompare(b.name)),
|
|
242
411
|
accepted: accepted.sort((a, b) => a.name.localeCompare(b.name)),
|
|
412
|
+
unclaimed: unclaimed.sort((a, b) => a.name.localeCompare(b.name)),
|
|
413
|
+
held: held.sort((a, b) => a.name.localeCompare(b.name)),
|
|
243
414
|
unchanged: unchanged.sort(),
|
|
244
415
|
unobserved: unobserved.sort((a, b) => a.name.localeCompare(b.name)),
|
|
245
416
|
undeclaredEntities: undeclaredEntities.sort(),
|
|
@@ -250,3 +421,35 @@ export function diffDeep(input: DiffDeepInput): DeepDiffResult {
|
|
|
250
421
|
export function countPropertyDrift(result: DeepDiffResult): number {
|
|
251
422
|
return result.drifted.reduce((n, e) => n + e.changes.length, 0);
|
|
252
423
|
}
|
|
424
|
+
|
|
425
|
+
/** Total live values on paths no declaration claimed, across every entity (#2160). Never added to the drift count. */
|
|
426
|
+
export function countUnclaimed(result: DeepDiffResult): number {
|
|
427
|
+
return result.unclaimed.reduce((n, e) => n + e.fields.length, 0);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Total held properties (#2162) across every entity. */
|
|
431
|
+
export function countHeld(result: DeepDiffResult): number {
|
|
432
|
+
return result.held.reduce((n, e) => n + e.held.length, 0);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/** One held property flagged suspicious (#2162), with its entity attached. */
|
|
436
|
+
export interface SuspiciousHeld extends PropertyHeld {
|
|
437
|
+
name: string;
|
|
438
|
+
type: string;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Every held property whose declaration looks like a hand-over that never
|
|
443
|
+
* happened — no live value ever showed up for it. Worth a look: either the
|
|
444
|
+
* named holder never ran, or this is not the field it actually writes.
|
|
445
|
+
* Sorted by entity name, then path.
|
|
446
|
+
*/
|
|
447
|
+
export function suspiciousHeld(result: DeepDiffResult): SuspiciousHeld[] {
|
|
448
|
+
const out: SuspiciousHeld[] = [];
|
|
449
|
+
for (const entity of result.held) {
|
|
450
|
+
for (const h of entity.held) {
|
|
451
|
+
if (h.suspicious) out.push({ name: entity.name, type: entity.type, ...h });
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return out.sort((a, b) => a.name.localeCompare(b.name) || a.path.localeCompare(b.path));
|
|
455
|
+
}
|
|
@@ -156,10 +156,12 @@ describe("deepDiffForLexicon", () => {
|
|
|
156
156
|
observeResourcesDeep: async () =>
|
|
157
157
|
deepObservation({ a: { type: "T", properties: { Extra: "accepted-value" } } }),
|
|
158
158
|
});
|
|
159
|
+
// A path source declares: since #2160 the baseline only ever suppresses
|
|
160
|
+
// drift, and a path nobody declared never reaches it (it is unclaimed).
|
|
159
161
|
const opts = {
|
|
160
162
|
environment: "prod",
|
|
161
163
|
buildOutput: "",
|
|
162
|
-
entities: entities({ a: { entityType: "T", props: {} } }),
|
|
164
|
+
entities: entities({ a: { entityType: "T", props: { Extra: "ours" } } }),
|
|
163
165
|
};
|
|
164
166
|
const withoutBaseline = await deepDiffForLexicon(plugin, opts);
|
|
165
167
|
expect(withoutBaseline.drifted[0].changes[0].path).toBe("Extra");
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type DeepResourceObservation,
|
|
27
27
|
type NormalizedDeepObservation,
|
|
28
28
|
} from "../deep-observation";
|
|
29
|
+
import { claimedFieldPaths, claimedFieldsOfTree } from "../claimed-fields";
|
|
29
30
|
import { unobservedAll, type UnobservedEntity } from "../observation";
|
|
30
31
|
import type { PathOrigin } from "../provenance";
|
|
31
32
|
import { diffDeep, type DeclaredDeepEntity, type DeepDiffResult } from "./deep-diff";
|
|
@@ -140,14 +141,15 @@ export function diffDeepObservation(
|
|
|
140
141
|
const declaredPaths = deepPathSet(declaredRaw);
|
|
141
142
|
const livePaths = deepPathSet(liveRaw);
|
|
142
143
|
|
|
144
|
+
const declaredProperties = normalizeDeepProperties(declaredRaw, {
|
|
145
|
+
entityType: entity.entityType,
|
|
146
|
+
side: "declared",
|
|
147
|
+
hooks,
|
|
148
|
+
counterpartPaths: livePaths,
|
|
149
|
+
});
|
|
143
150
|
declared[name] = {
|
|
144
151
|
type: entity.entityType,
|
|
145
|
-
properties:
|
|
146
|
-
entityType: entity.entityType,
|
|
147
|
-
side: "declared",
|
|
148
|
-
hooks,
|
|
149
|
-
counterpartPaths: livePaths,
|
|
150
|
-
}),
|
|
152
|
+
properties: declaredProperties,
|
|
151
153
|
...(entity.pathOrigins ? { pathOrigins: entity.pathOrigins } : {}),
|
|
152
154
|
};
|
|
153
155
|
if (liveEntity) {
|
|
@@ -158,6 +160,14 @@ export function diffDeepObservation(
|
|
|
158
160
|
// up by the flattened path, so a keyed list element (`[#name]`) has
|
|
159
161
|
// no owner today — its raw index path is what the reader recorded.
|
|
160
162
|
...(liveEntity.fieldOwners ? { fieldOwners: liveEntity.fieldOwners } : {}),
|
|
163
|
+
// The claimed-field set (#2160), computed from the declaration and
|
|
164
|
+
// carried on the observation so a consumer holding only this envelope
|
|
165
|
+
// can classify a live value three ways rather than two. Same normalized
|
|
166
|
+
// tree and same hooks `diffDeep` flattens, so the two never disagree
|
|
167
|
+
// about a path.
|
|
168
|
+
claimedFields: claimedFieldPaths(
|
|
169
|
+
claimedFieldsOfTree(declaredProperties, { entityType: entity.entityType, ...(hooks ? { hooks } : {}) }),
|
|
170
|
+
),
|
|
161
171
|
properties: normalizeDeepProperties(liveRaw, {
|
|
162
172
|
entityType: liveEntity.type || entity.entityType,
|
|
163
173
|
side: "live",
|
|
@@ -3,8 +3,12 @@ import { withTestDir } from "@intentius/chant-test-utils";
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
appendGateResolution, appendPendingGate, readGateResolutions, readGateLedger,
|
|
8
|
+
latestResolutionSince, latestPendingGate, isPendingGateExpired,
|
|
9
|
+
resolveApprovalUrl, isApprovalUrl, type PendingGateRecord,
|
|
10
|
+
} from "./gate-ledger";
|
|
11
|
+
import { readBlobFromPath, writeBlobToPath } from "./git";
|
|
8
12
|
|
|
9
13
|
function git(args: string[], cwd: string): { stdout: string; exitCode: number } {
|
|
10
14
|
const r = spawnSync("git", args, { cwd, encoding: "utf-8" });
|
|
@@ -181,3 +185,71 @@ describe("lifecycle/gate-ledger", () => {
|
|
|
181
185
|
});
|
|
182
186
|
});
|
|
183
187
|
});
|
|
188
|
+
|
|
189
|
+
describe("lifecycle/gate-ledger — pending facts (#2119)", () => {
|
|
190
|
+
test("pending facts and resolutions share the file and read back separately", async () => {
|
|
191
|
+
await withTestDir(async (dir) => {
|
|
192
|
+
await initRepo(dir);
|
|
193
|
+
const { record: pending } = await appendPendingGate(
|
|
194
|
+
{
|
|
195
|
+
op: "fountain-apply", gate: "rollout-gate",
|
|
196
|
+
description: "release manager signs off",
|
|
197
|
+
runId: "local-1",
|
|
198
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
199
|
+
expiresAt: "2026-01-03T00:00:00.000Z",
|
|
200
|
+
},
|
|
201
|
+
{ cwd: dir },
|
|
202
|
+
);
|
|
203
|
+
await appendGateResolution(
|
|
204
|
+
{ op: "fountain-apply", gate: "rollout-gate", resolvedBy: "alex", timestamp: "2026-01-02T00:00:00.000Z" },
|
|
205
|
+
{ cwd: dir },
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const { resolutions, pending: pendings, malformed } = await readGateLedger("fountain-apply", { cwd: dir });
|
|
209
|
+
expect(malformed).toBe(0);
|
|
210
|
+
expect(pendings).toEqual([pending]);
|
|
211
|
+
expect(resolutions.map((r) => r.resolvedBy)).toEqual(["alex"]);
|
|
212
|
+
|
|
213
|
+
// A pending line is not a malformed resolution to the narrow reader.
|
|
214
|
+
const narrow = await readGateResolutions("fountain-apply", { cwd: dir });
|
|
215
|
+
expect(narrow.malformed).toBe(0);
|
|
216
|
+
expect(narrow.records).toHaveLength(1);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("latestPendingGate picks the newest fact for the gate, expired or not", () => {
|
|
221
|
+
const at = (timestamp: string, gate = "g"): PendingGateRecord => ({
|
|
222
|
+
version: 1, kind: "pending", op: "o", gate, timestamp,
|
|
223
|
+
expiresAt: "2026-01-09T00:00:00.000Z",
|
|
224
|
+
});
|
|
225
|
+
const records = [at("2026-01-01T00:00:00.000Z"), at("2026-01-05T00:00:00.000Z"), at("2026-01-07T00:00:00.000Z", "other")];
|
|
226
|
+
expect(latestPendingGate(records, "g")?.timestamp).toBe("2026-01-05T00:00:00.000Z");
|
|
227
|
+
expect(latestPendingGate(records, "absent")).toBeUndefined();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("isPendingGateExpired is true at and after expiresAt", () => {
|
|
231
|
+
const record: PendingGateRecord = {
|
|
232
|
+
version: 1, kind: "pending", op: "o", gate: "g",
|
|
233
|
+
timestamp: "2026-01-01T00:00:00.000Z", expiresAt: "2026-01-03T00:00:00.000Z",
|
|
234
|
+
};
|
|
235
|
+
expect(isPendingGateExpired(record, "2026-01-02T23:59:59.000Z")).toBe(false);
|
|
236
|
+
expect(isPendingGateExpired(record, "2026-01-03T00:00:00.000Z")).toBe(true);
|
|
237
|
+
expect(isPendingGateExpired(record, "2026-01-04T00:00:00.000Z")).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("a pending line missing expiresAt is malformed, not read as a resolution", async () => {
|
|
241
|
+
await withTestDir(async (dir) => {
|
|
242
|
+
await initRepo(dir);
|
|
243
|
+
await writeBlobToPath(
|
|
244
|
+
"_gates", "fountain-apply.jsonl",
|
|
245
|
+
JSON.stringify({ version: 1, kind: "pending", op: "fountain-apply", gate: "g", timestamp: "2026-01-01T00:00:00.000Z" }),
|
|
246
|
+
"hand-written",
|
|
247
|
+
{ cwd: dir },
|
|
248
|
+
);
|
|
249
|
+
const { resolutions, pending, malformed } = await readGateLedger("fountain-apply", { cwd: dir });
|
|
250
|
+
expect(malformed).toBe(1);
|
|
251
|
+
expect(pending).toEqual([]);
|
|
252
|
+
expect(resolutions).toEqual([]);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|