@intentius/chant 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts +13 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +73 -37
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +10 -22
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +273 -16
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +79 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +149 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +29 -9
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +185 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +93 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +96 -29
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +194 -1
- package/src/cli/commands/lint.ts +205 -7
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +82 -2
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +3 -3
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +296 -16
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +154 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/pipeline-change-gate.test.ts +2 -2
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +161 -0
- package/src/op/activities/reconcile.ts +354 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +110 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +106 -26
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
package/src/op/local-executor.ts
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local Op executor — runs an Op's phases in
|
|
2
|
+
* Local Op executor — runs an Op's phases in this process.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Ops. Provides phase sequencing, parallel phases, per-step retry + timeout via
|
|
4
|
+
* The default runtime (#2121), and the one dev loops, CI, and drift/observation
|
|
5
|
+
* Ops use. Provides phase sequencing, parallel phases, per-step retry + timeout via
|
|
6
6
|
* activity profiles, `outcomeAttribute` capture, and `onFailure` compensation.
|
|
7
|
-
* Gates and schedules are unsupported and rejected before any phase runs.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
8
|
+
* A gate is a fact, not a wait (#2119). Reaching one, the executor consults the
|
|
9
|
+
* gate ledger through `./gate.ts`: a resolution newer than the gate's newest
|
|
10
|
+
* pending fact lets the step pass, carrying the approver onto its record;
|
|
11
|
+
* anything else records the pending fact and ends the run with status `gated`.
|
|
12
|
+
* No later phase runs and `onFailure` does not run — a gate is not a failure,
|
|
13
|
+
* and there is nothing to compensate for. The next run re-evaluates from the
|
|
14
|
+
* ledger, so `chant approve <op> <gate>` followed by `chant run <op>` is the
|
|
15
|
+
* whole loop.
|
|
16
|
+
*
|
|
17
|
+
* The executor is deliberately decoupled from any lexicon: activity
|
|
10
18
|
* implementations and profiles are passed in (loaded dynamically by the CLI),
|
|
11
|
-
* so core never statically depends on
|
|
19
|
+
* so core never statically depends on one.
|
|
12
20
|
*/
|
|
13
21
|
|
|
22
|
+
import { outcomeAttributesOf } from "./types";
|
|
14
23
|
import type { OpConfig, PhaseDefinition, ActivityStep, GateStep, EffectStep, StepDefinition } from "./types";
|
|
15
24
|
import { resolveActivity, type ActivityFn, type ActivityProfile } from "./activity-registry";
|
|
16
25
|
import type { ReceiptReadResult } from "./receipt-store";
|
|
17
26
|
import { isStepOutputRef } from "./step-output-ref";
|
|
27
|
+
import { parseDuration } from "./duration";
|
|
28
|
+
import { evaluateGate, gitGateLedgerPort, type GateLedgerPort } from "./gate";
|
|
29
|
+
import { gateName } from "./gate-name";
|
|
30
|
+
import type { PendingGateRecord } from "../lifecycle/gate-ledger";
|
|
31
|
+
import { appendRunRecord, buildRunRecord } from "../lifecycle/run-ledger";
|
|
32
|
+
import type { OpRunRecord } from "./runtime";
|
|
33
|
+
import { randomUUID } from "node:crypto";
|
|
34
|
+
|
|
35
|
+
export { parseDuration } from "./duration";
|
|
18
36
|
|
|
19
37
|
// ── Records ─────────────────────────────────────────────────────────────────
|
|
20
38
|
|
|
@@ -22,38 +40,53 @@ export interface StepRecord {
|
|
|
22
40
|
phase: string;
|
|
23
41
|
fn: string;
|
|
24
42
|
/**
|
|
25
|
-
* Present for a local-executor record.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* populated with a guess.
|
|
43
|
+
* Present for a local-executor record. A runtime that reconstructs records
|
|
44
|
+
* from its own run history may not have an activity's scheduled input to
|
|
45
|
+
* hand, and omits the field rather than guessing at it.
|
|
29
46
|
*/
|
|
30
47
|
args?: Record<string, unknown>;
|
|
31
48
|
status: "ok" | "fail" | "skipped";
|
|
32
49
|
durationMs: number;
|
|
50
|
+
/**
|
|
51
|
+
* The first outcome attribute the step published, kept singular because a
|
|
52
|
+
* step publishing one is the ordinary case and every reader of this field
|
|
53
|
+
* predates the plural form. {@link StepRecord.outcomes} is the whole list.
|
|
54
|
+
*/
|
|
33
55
|
outcome?: { name: string; value: unknown };
|
|
56
|
+
/** Every outcome attribute the step published, in authored order (#2105). Absent when it published none. */
|
|
57
|
+
outcomes?: Array<{ name: string; value: unknown }>;
|
|
34
58
|
error?: string;
|
|
59
|
+
/** Set on a `gate` step that passed (#2119): who resolved it, when, and at what address. */
|
|
60
|
+
approval?: { gate: string; resolvedBy: string; timestamp: string; url?: string };
|
|
35
61
|
}
|
|
36
62
|
|
|
37
63
|
export interface OpRunResult {
|
|
38
64
|
op: string;
|
|
39
65
|
records: StepRecord[];
|
|
40
66
|
totalMs: number;
|
|
41
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Three-state outcome (#2119). `gated` is neither success nor failure: the
|
|
69
|
+
* run reached a gate nobody has approved, recorded the fact, and stopped.
|
|
70
|
+
* The CLI exits 3 for it so CI can tell "waiting on a human" from "broken".
|
|
71
|
+
*
|
|
72
|
+
* Written to the run ledger as the record's own `status` (#2118).
|
|
73
|
+
*/
|
|
74
|
+
status: "ok" | "fail" | "gated";
|
|
75
|
+
/** ISO-8601 start of this run. */
|
|
76
|
+
startedAt: string;
|
|
77
|
+
/** Present when `status === "gated"`: the pending fact the run ended on. */
|
|
78
|
+
gate?: PendingGateRecord;
|
|
79
|
+
/**
|
|
80
|
+
* The run's ledger record (#2118) — always built, whether or not it was
|
|
81
|
+
* appended. `chant run <op> --json` prints exactly this, so what a caller
|
|
82
|
+
* reads on stdout and what a later `readRunLedger` reads back are the same
|
|
83
|
+
* document.
|
|
84
|
+
*/
|
|
85
|
+
record: OpRunRecord;
|
|
42
86
|
}
|
|
43
87
|
|
|
44
88
|
// ── Errors ────────────────────────────────────────────────────────────────��─
|
|
45
89
|
|
|
46
|
-
/** Thrown when an Op contains a gate (or schedule) that local mode cannot run. */
|
|
47
|
-
export class LocalGateUnsupportedError extends Error {
|
|
48
|
-
constructor(public readonly signalName: string) {
|
|
49
|
-
super(
|
|
50
|
-
`gate "${signalName}" is not supported in local mode — gates and schedules ` +
|
|
51
|
-
`need a durable runtime. Re-run with --temporal.`,
|
|
52
|
-
);
|
|
53
|
-
this.name = "LocalGateUnsupportedError";
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
90
|
/** Thrown on terminal Op failure; carries the partial run result for rendering. */
|
|
58
91
|
export class OpRunFailure extends Error {
|
|
59
92
|
constructor(public readonly result: OpRunResult) {
|
|
@@ -70,6 +103,18 @@ class PhaseFailure extends Error {
|
|
|
70
103
|
}
|
|
71
104
|
}
|
|
72
105
|
|
|
106
|
+
/** Internal: a phase stopped on an unapproved gate. Not a failure — no compensation follows it. */
|
|
107
|
+
class GateStop extends Error {
|
|
108
|
+
constructor(
|
|
109
|
+
public readonly records: StepRecord[],
|
|
110
|
+
public readonly pending: PendingGateRecord,
|
|
111
|
+
public readonly phase: string,
|
|
112
|
+
) {
|
|
113
|
+
super(`gate "${pending.gate}" is pending approval`);
|
|
114
|
+
this.name = "GateStop";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
73
118
|
// ── Helpers ───────────────────────────────────────────────────────────────��─
|
|
74
119
|
|
|
75
120
|
const DEFAULT_PROFILE = "fastIdempotent";
|
|
@@ -79,19 +124,6 @@ const isActivity = (s: StepDefinition): s is ActivityStep => s.kind === "activit
|
|
|
79
124
|
const isGate = (s: StepDefinition): s is GateStep => s.kind === "gate";
|
|
80
125
|
const isEffect = (s: StepDefinition): s is EffectStep => s.kind === "effect";
|
|
81
126
|
|
|
82
|
-
/** Parse a Temporal duration string ("5m", "30s", "1h30m", "100ms") to ms. */
|
|
83
|
-
export function parseDuration(s: string): number {
|
|
84
|
-
const units: Record<string, number> = { ms: 1, s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
85
|
-
let total = 0;
|
|
86
|
-
let matched = false;
|
|
87
|
-
for (const m of s.matchAll(/(\d+)(ms|s|m|h|d)/g)) {
|
|
88
|
-
total += Number(m[1]) * units[m[2]];
|
|
89
|
-
matched = true;
|
|
90
|
-
}
|
|
91
|
-
if (!matched) throw new Error(`unparseable duration: "${s}"`);
|
|
92
|
-
return total;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
127
|
/** Resolve a dot-path into a value; returns the whole value when path is absent. */
|
|
96
128
|
function resolvePath(value: unknown, path?: string): unknown {
|
|
97
129
|
if (!path) return value;
|
|
@@ -120,22 +152,6 @@ function resolveStepOutputRefs(value: unknown, resultsById: ReadonlyMap<string,
|
|
|
120
152
|
return value;
|
|
121
153
|
}
|
|
122
154
|
|
|
123
|
-
/** Find the first gate step anywhere in the Op (phases + onFailure, including
|
|
124
|
-
* gates nested inside effect steps), if any. */
|
|
125
|
-
export function findGate(config: OpConfig): GateStep | undefined {
|
|
126
|
-
const all = [...config.phases, ...(config.onFailure ?? [])];
|
|
127
|
-
for (const phase of all) {
|
|
128
|
-
for (const step of phase.steps) {
|
|
129
|
-
if (isGate(step)) return step;
|
|
130
|
-
if (isEffect(step)) {
|
|
131
|
-
const nested = step.steps.find(isGate);
|
|
132
|
-
if (nested) return nested;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
155
|
/**
|
|
140
156
|
* Find the first `policyGate` step anywhere in the Op (phases + `onFailure`,
|
|
141
157
|
* including steps nested inside effect steps), if any.
|
|
@@ -147,7 +163,8 @@ export function findGate(config: OpConfig): GateStep | undefined {
|
|
|
147
163
|
* shown to a user who passed a documented flag. The combination cannot be
|
|
148
164
|
* honoured until the gate can build and load policies inside the boundary
|
|
149
165
|
* (#1157), so both `chant run` paths pre-flight it with this and refuse before
|
|
150
|
-
* any phase executes
|
|
166
|
+
* any phase executes. This is the one pre-flight refusal left on the Op path —
|
|
167
|
+
* a `gate` no longer is one (#2119).
|
|
151
168
|
*/
|
|
152
169
|
export function findPolicyGateStep(config: OpConfig): ActivityStep | undefined {
|
|
153
170
|
const all = [...config.phases, ...(config.onFailure ?? [])];
|
|
@@ -217,9 +234,9 @@ interface RanStep {
|
|
|
217
234
|
/**
|
|
218
235
|
* Run one activity step with retry + timeout. Never throws — returns a
|
|
219
236
|
* record. Any {@link StepOutputRef} in `step.args` is resolved against
|
|
220
|
-
* `resultsById` before the activity is called (#1290) —
|
|
221
|
-
*
|
|
222
|
-
*
|
|
237
|
+
* `resultsById` before the activity is called (#1290) — an unresolved
|
|
238
|
+
* placeholder must never reach an activity function, on this runtime or any
|
|
239
|
+
* other; see `resolveStepOutputRefs`.
|
|
223
240
|
*/
|
|
224
241
|
async function runStep(
|
|
225
242
|
step: ActivityStep,
|
|
@@ -241,8 +258,8 @@ async function runStep(
|
|
|
241
258
|
}
|
|
242
259
|
|
|
243
260
|
const profile = profiles[step.profile ?? DEFAULT_PROFILE] ?? {};
|
|
244
|
-
const timeoutMs = profile.
|
|
245
|
-
? parseDuration(profile.
|
|
261
|
+
const timeoutMs = profile.timeout
|
|
262
|
+
? parseDuration(profile.timeout)
|
|
246
263
|
: FALLBACK_TIMEOUT_MS;
|
|
247
264
|
const maxAttempts =
|
|
248
265
|
profile.retry?.maximumAttempts && profile.retry.maximumAttempts > 0
|
|
@@ -261,11 +278,10 @@ async function runStep(
|
|
|
261
278
|
const result = await callWithTimeout(fn, args, timeoutMs, signal);
|
|
262
279
|
if (step.id) resultsById.set(step.id, result);
|
|
263
280
|
const record: StepRecord = { ...base, status: "ok", durationMs: Date.now() - start };
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
};
|
|
281
|
+
const attrs = outcomeAttributesOf(step);
|
|
282
|
+
if (attrs.length > 0) {
|
|
283
|
+
record.outcomes = attrs.map((a) => ({ name: a.name, value: resolvePath(result, a.from) }));
|
|
284
|
+
record.outcome = record.outcomes[0];
|
|
269
285
|
}
|
|
270
286
|
return { record, result };
|
|
271
287
|
} catch (err) {
|
|
@@ -307,6 +323,75 @@ function skippedRecord(phaseName: string, fn: string, args?: Record<string, unkn
|
|
|
307
323
|
return { phase: phaseName, fn, args: args ?? {}, status: "skipped", durationMs: 0 };
|
|
308
324
|
}
|
|
309
325
|
|
|
326
|
+
// ── Gate steps (#2119) ───────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
/** What a run needs to decide a gate against the ledger — see `./gate.ts`. */
|
|
329
|
+
interface GateContext {
|
|
330
|
+
op: string;
|
|
331
|
+
port: GateLedgerPort;
|
|
332
|
+
now?: string;
|
|
333
|
+
runId?: string;
|
|
334
|
+
/** Called once per settled step, in production order (#2121) — what `--progress-json` streams from. */
|
|
335
|
+
onRecord?: (record: StepRecord) => void;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Collect records and hand each to the caller's progress sink in one move. */
|
|
339
|
+
function pushRecord(sink: StepRecord[], ctx: GateContext, ...recs: StepRecord[]): void {
|
|
340
|
+
sink.push(...recs);
|
|
341
|
+
for (const r of recs) ctx.onRecord?.(r);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** The record name a gate step lands under, so a reader (and a JSON consumer) can pick it out of `records`. */
|
|
345
|
+
function gateFn(step: GateStep): string {
|
|
346
|
+
return `gate:${gateName(step)}`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Decide one gate against the ledger. A resolution newer than the gate's
|
|
351
|
+
* newest pending fact passes it, and the approver lands on the step record; a
|
|
352
|
+
* pending fact is recorded (or left standing) otherwise, and the caller stops
|
|
353
|
+
* the run.
|
|
354
|
+
*/
|
|
355
|
+
async function runGateStep(
|
|
356
|
+
step: GateStep,
|
|
357
|
+
phaseName: string,
|
|
358
|
+
gates: GateContext,
|
|
359
|
+
): Promise<{ record: StepRecord; pending?: PendingGateRecord }> {
|
|
360
|
+
const start = Date.now();
|
|
361
|
+
const check = await evaluateGate(gates.port, {
|
|
362
|
+
op: gates.op,
|
|
363
|
+
gate: gateName(step),
|
|
364
|
+
...(step.description ? { description: step.description } : {}),
|
|
365
|
+
...(step.timeout ? { timeout: step.timeout } : {}),
|
|
366
|
+
...(gates.runId ? { runId: gates.runId } : {}),
|
|
367
|
+
...(gates.now ? { now: gates.now } : {}),
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
if (check.satisfied) {
|
|
371
|
+
const { resolution } = check;
|
|
372
|
+
return {
|
|
373
|
+
record: {
|
|
374
|
+
phase: phaseName,
|
|
375
|
+
fn: gateFn(step),
|
|
376
|
+
args: {},
|
|
377
|
+
status: "ok",
|
|
378
|
+
durationMs: Date.now() - start,
|
|
379
|
+
approval: {
|
|
380
|
+
gate: gateName(step),
|
|
381
|
+
resolvedBy: resolution.resolvedBy,
|
|
382
|
+
timestamp: resolution.timestamp,
|
|
383
|
+
...(resolution.url ? { url: resolution.url } : {}),
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
record: { phase: phaseName, fn: gateFn(step), args: {}, status: "skipped", durationMs: Date.now() - start },
|
|
391
|
+
pending: check.pending,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
310
395
|
/**
|
|
311
396
|
* Run one effect step: read-compare-run-write. On a match the nested steps are
|
|
312
397
|
* recorded as skipped ("effect already applied") and nothing is written. On a
|
|
@@ -314,6 +399,11 @@ function skippedRecord(phaseName: string, fn: string, args?: Record<string, unkn
|
|
|
314
399
|
* succeeds is the receipt written — last, once (the sole writer, #1703
|
|
315
400
|
* decision 3). Any failure leaves the receipt untouched (stale), so the next
|
|
316
401
|
* run re-proposes the effect.
|
|
402
|
+
*
|
|
403
|
+
* A nested `gate` is decided in authored order like any other nested step
|
|
404
|
+
* (#2119). Unapproved, it stops the effect before the receipt is written, so
|
|
405
|
+
* the next run re-reads the receipt, re-proposes the effect, and re-evaluates
|
|
406
|
+
* the gate — the receipt stays honest about what actually happened.
|
|
317
407
|
*/
|
|
318
408
|
async function runEffectStep(
|
|
319
409
|
step: EffectStep,
|
|
@@ -321,17 +411,18 @@ async function runEffectStep(
|
|
|
321
411
|
activities: Map<string, ActivityFn>,
|
|
322
412
|
profiles: Record<string, ActivityProfile>,
|
|
323
413
|
resultsById: Map<string, unknown>,
|
|
414
|
+
gates: GateContext,
|
|
324
415
|
signal?: AbortSignal,
|
|
325
|
-
): Promise<{ records: StepRecord[]; failed: boolean }> {
|
|
416
|
+
): Promise<{ records: StepRecord[]; failed: boolean; pending?: PendingGateRecord }> {
|
|
326
417
|
const records: StepRecord[] = [];
|
|
327
418
|
|
|
328
419
|
const read = await runStep(receiptReadStep(step), phaseName, activities, profiles, resultsById, signal);
|
|
329
|
-
records
|
|
420
|
+
pushRecord(records, gates, read.record);
|
|
330
421
|
if (read.record.status === "fail") return { records, failed: true };
|
|
331
422
|
|
|
332
423
|
const result = read.result as Partial<ReceiptReadResult> | undefined;
|
|
333
424
|
if (typeof result?.expectation !== "string") {
|
|
334
|
-
records
|
|
425
|
+
pushRecord(records, gates, {
|
|
335
426
|
phase: phaseName,
|
|
336
427
|
fn: `effect:${step.receipt.name}`,
|
|
337
428
|
args: {},
|
|
@@ -346,22 +437,44 @@ async function runEffectStep(
|
|
|
346
437
|
if (result.current === expectation) {
|
|
347
438
|
// Effect already applied — skip the nested steps, write nothing.
|
|
348
439
|
for (const nested of step.steps) {
|
|
349
|
-
|
|
440
|
+
pushRecord(records, gates,
|
|
441
|
+
nested.kind === "activity"
|
|
442
|
+
? skippedRecord(phaseName, nested.fn, nested.args)
|
|
443
|
+
: skippedRecord(phaseName, gateFn(nested)),
|
|
444
|
+
);
|
|
350
445
|
}
|
|
351
446
|
return { records, failed: false };
|
|
352
447
|
}
|
|
353
448
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
449
|
+
const skipRest = (from: number) => {
|
|
450
|
+
for (const skipped of step.steps.slice(from)) {
|
|
451
|
+
pushRecord(records, gates,
|
|
452
|
+
skipped.kind === "activity"
|
|
453
|
+
? skippedRecord(phaseName, skipped.fn, skipped.args)
|
|
454
|
+
: skippedRecord(phaseName, gateFn(skipped)),
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
pushRecord(records, gates, skippedRecord(phaseName, "receiptWrite"));
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
for (let i = 0; i < step.steps.length; i++) {
|
|
461
|
+
const nested = step.steps[i];
|
|
462
|
+
if (isGate(nested)) {
|
|
463
|
+
const { record, pending } = await runGateStep(nested, phaseName, gates);
|
|
464
|
+
pushRecord(records, gates, record);
|
|
465
|
+
if (pending) {
|
|
466
|
+
// Receipt left untouched — the next run re-proposes the effect and
|
|
467
|
+
// re-evaluates the gate against whatever the ledger says by then.
|
|
468
|
+
skipRest(i + 1);
|
|
469
|
+
return { records, failed: false, pending };
|
|
470
|
+
}
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
const ran = await runStep(nested, phaseName, activities, profiles, resultsById, signal);
|
|
474
|
+
pushRecord(records, gates, ran.record);
|
|
359
475
|
if (ran.record.status === "fail") {
|
|
360
476
|
// Receipt left untouched (stale) — the next run re-proposes the effect.
|
|
361
|
-
|
|
362
|
-
records.push(skippedRecord(phaseName, skipped.fn, skipped.args));
|
|
363
|
-
}
|
|
364
|
-
records.push(skippedRecord(phaseName, "receiptWrite"));
|
|
477
|
+
skipRest(i + 1);
|
|
365
478
|
return { records, failed: true };
|
|
366
479
|
}
|
|
367
480
|
}
|
|
@@ -380,25 +493,22 @@ async function runEffectStep(
|
|
|
380
493
|
resultsById,
|
|
381
494
|
signal,
|
|
382
495
|
);
|
|
383
|
-
records
|
|
496
|
+
pushRecord(records, gates, wrote.record);
|
|
384
497
|
return { records, failed: wrote.record.status === "fail" };
|
|
385
498
|
}
|
|
386
499
|
|
|
387
|
-
/**
|
|
500
|
+
/**
|
|
501
|
+
* Run a phase. Throws `PhaseFailure` (with the records so far) if any step
|
|
502
|
+
* fails, or `GateStop` if a `gate` step in it is still pending approval.
|
|
503
|
+
*/
|
|
388
504
|
async function runPhase(
|
|
389
505
|
phase: PhaseDefinition,
|
|
390
506
|
activities: Map<string, ActivityFn>,
|
|
391
507
|
profiles: Record<string, ActivityProfile>,
|
|
392
508
|
resultsById: Map<string, unknown>,
|
|
509
|
+
gates: GateContext,
|
|
393
510
|
signal?: AbortSignal,
|
|
394
511
|
): Promise<StepRecord[]> {
|
|
395
|
-
// Defensive: gates are pre-flighted, but never execute one if it slips
|
|
396
|
-
// through — including a gate nested inside an effect step.
|
|
397
|
-
const gate =
|
|
398
|
-
phase.steps.find(isGate) ??
|
|
399
|
-
phase.steps.filter(isEffect).flatMap((e) => e.steps).find(isGate);
|
|
400
|
-
if (gate) throw new LocalGateUnsupportedError(gate.signalName);
|
|
401
|
-
|
|
402
512
|
if (phase.parallel) {
|
|
403
513
|
const eff = phase.steps.find(isEffect);
|
|
404
514
|
if (eff) {
|
|
@@ -406,32 +516,65 @@ async function runPhase(
|
|
|
406
516
|
`effect step "${eff.receipt.name}" cannot run in a parallel phase — read-compare-run-write is ordered`,
|
|
407
517
|
);
|
|
408
518
|
}
|
|
519
|
+
// Gates in a parallel phase are decided before the fan-out: a gate is a
|
|
520
|
+
// read of the ledger, not work, and starting activities that a pending
|
|
521
|
+
// gate is about to strand would defeat the point of stopping at it.
|
|
522
|
+
const gateRecords: StepRecord[] = [];
|
|
523
|
+
for (const step of phase.steps.filter(isGate)) {
|
|
524
|
+
const { record, pending } = await runGateStep(step, phase.name, gates);
|
|
525
|
+
pushRecord(gateRecords, gates, record);
|
|
526
|
+
if (pending) {
|
|
527
|
+
for (const skipped of phase.steps.filter(isActivity)) {
|
|
528
|
+
pushRecord(gateRecords, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
529
|
+
}
|
|
530
|
+
throw new GateStop(gateRecords, pending, phase.name);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
409
533
|
const steps = phase.steps.filter(isActivity);
|
|
410
|
-
const
|
|
534
|
+
const ran = (
|
|
411
535
|
await Promise.all(steps.map((s) => runStep(s, phase.name, activities, profiles, resultsById, signal)))
|
|
412
536
|
).map((r) => r.record);
|
|
537
|
+
for (const r of ran) gates.onRecord?.(r);
|
|
538
|
+
const records = gateRecords.concat(ran);
|
|
413
539
|
if (records.some((r) => r.status === "fail")) throw new PhaseFailure(records);
|
|
414
540
|
return records;
|
|
415
541
|
}
|
|
416
542
|
|
|
417
|
-
const steps = phase.steps
|
|
543
|
+
const steps = phase.steps;
|
|
418
544
|
const records: StepRecord[] = [];
|
|
419
545
|
|
|
420
546
|
const skipRemaining = (from: number) => {
|
|
421
547
|
for (const skipped of steps.slice(from)) {
|
|
422
548
|
if (isEffect(skipped)) {
|
|
423
|
-
records
|
|
549
|
+
pushRecord(records, gates, skippedRecord(phase.name, `effect:${skipped.receipt.name}`));
|
|
550
|
+
} else if (isGate(skipped)) {
|
|
551
|
+
pushRecord(records, gates, skippedRecord(phase.name, gateFn(skipped)));
|
|
424
552
|
} else {
|
|
425
|
-
records
|
|
553
|
+
pushRecord(records, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
426
554
|
}
|
|
427
555
|
}
|
|
428
556
|
};
|
|
429
557
|
|
|
430
558
|
for (let i = 0; i < steps.length; i++) {
|
|
431
559
|
const step = steps[i];
|
|
560
|
+
if (isGate(step)) {
|
|
561
|
+
const { record, pending } = await runGateStep(step, phase.name, gates);
|
|
562
|
+
pushRecord(records, gates, record);
|
|
563
|
+
if (pending) {
|
|
564
|
+
skipRemaining(i + 1);
|
|
565
|
+
throw new GateStop(records, pending, phase.name);
|
|
566
|
+
}
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
432
569
|
if (isEffect(step)) {
|
|
433
|
-
const { records: effRecords, failed } = await runEffectStep(
|
|
434
|
-
|
|
570
|
+
const { records: effRecords, failed, pending } = await runEffectStep(
|
|
571
|
+
step, phase.name, activities, profiles, resultsById, gates, signal,
|
|
572
|
+
);
|
|
573
|
+
records.push(...effRecords); // already emitted by runEffectStep
|
|
574
|
+
if (pending) {
|
|
575
|
+
skipRemaining(i + 1);
|
|
576
|
+
throw new GateStop(records, pending, phase.name);
|
|
577
|
+
}
|
|
435
578
|
if (failed) {
|
|
436
579
|
skipRemaining(i + 1);
|
|
437
580
|
throw new PhaseFailure(records);
|
|
@@ -439,7 +582,7 @@ async function runPhase(
|
|
|
439
582
|
continue;
|
|
440
583
|
}
|
|
441
584
|
const { record } = await runStep(step, phase.name, activities, profiles, resultsById, signal);
|
|
442
|
-
records
|
|
585
|
+
pushRecord(records, gates, record);
|
|
443
586
|
if (record.status === "fail") {
|
|
444
587
|
// Mark the remaining steps in this phase as skipped, then abort.
|
|
445
588
|
skipRemaining(i + 1);
|
|
@@ -451,20 +594,78 @@ async function runPhase(
|
|
|
451
594
|
|
|
452
595
|
// ── Public API ────────────────────────────────────────────────────────────��─
|
|
453
596
|
|
|
597
|
+
/** How a run reaches the gate ledger, and what it calls itself there (#2119). */
|
|
598
|
+
export interface RunOpOptions {
|
|
599
|
+
/**
|
|
600
|
+
* Where gate facts are read and written. Defaults to the `chant/lifecycle`
|
|
601
|
+
* orphan branch under `cwd`; a test (or a caller that already holds the
|
|
602
|
+
* ledger) passes `memoryGateLedgerPort()` from `./gate.ts` instead.
|
|
603
|
+
*/
|
|
604
|
+
gates?: GateLedgerPort;
|
|
605
|
+
/** Working directory for the default git-backed gate ledger. */
|
|
606
|
+
cwd?: string;
|
|
607
|
+
/** ISO-8601 "now", so a gate decision is deterministic under test. */
|
|
608
|
+
now?: string;
|
|
609
|
+
/** Identifies this run on any pending fact it records. */
|
|
610
|
+
runId?: string;
|
|
611
|
+
/**
|
|
612
|
+
* Called once per settled step, in the order the records are produced
|
|
613
|
+
* (#2121) — what the local op runtime (./runtimes/local.ts) feeds
|
|
614
|
+
* `--progress-json` from. Side-effect free when omitted.
|
|
615
|
+
*/
|
|
616
|
+
onRecord?: (record: StepRecord) => void;
|
|
617
|
+
/**
|
|
618
|
+
* Append the run's {@link OpRunRecord} to the run ledger
|
|
619
|
+
* (`../lifecycle/run-ledger.ts`) when the run settles (#2118). Opt-in on
|
|
620
|
+
* purpose: the executor is called from unit tests and in-process harnesses
|
|
621
|
+
* whose working directory is an ordinary checkout, and a run there must not
|
|
622
|
+
* write to the lifecycle branch. The local runtime (./runtimes/local.ts) and
|
|
623
|
+
* `chant operator` pass it; nothing else does.
|
|
624
|
+
*/
|
|
625
|
+
ledger?: { cwd?: string };
|
|
626
|
+
/**
|
|
627
|
+
* Called when the ledger append itself fails. The run's own outcome is
|
|
628
|
+
* already decided by then, so a ledger failure is reported to the caller,
|
|
629
|
+
* never promoted into a run failure.
|
|
630
|
+
*/
|
|
631
|
+
onLedgerError?: (err: unknown) => void;
|
|
632
|
+
}
|
|
633
|
+
|
|
454
634
|
/**
|
|
455
|
-
* Execute an Op locally.
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
635
|
+
* Execute an Op locally.
|
|
636
|
+
*
|
|
637
|
+
* Resolves with the run result when every phase succeeds (`status: "ok"`), and
|
|
638
|
+
* also when the run stopped at an unapproved gate (`status: "gated"`, with the
|
|
639
|
+
* pending fact on `result.gate`) — a gate is a fact, not an error, so it is not
|
|
640
|
+
* thrown. Rejects with `OpRunFailure` (carrying the partial result) on terminal
|
|
641
|
+
* failure, after running any `onFailure` phases in reverse order; a gated run
|
|
642
|
+
* runs no `onFailure` phase, because nothing failed and nothing was left
|
|
643
|
+
* half-applied to compensate for.
|
|
644
|
+
*
|
|
645
|
+
* Whichever of the three ways it settles, the run carries an
|
|
646
|
+
* {@link OpRunRecord} on `result.record` (#2118). With `options.ledger` that
|
|
647
|
+
* record is also appended to `<env>/runs__<op>.jsonl` on the lifecycle branch
|
|
648
|
+
* before this returns or rejects, so an Op's outcome outlives the process that
|
|
649
|
+
* produced it.
|
|
459
650
|
*/
|
|
460
651
|
export async function runOpLocally(
|
|
461
652
|
config: OpConfig,
|
|
462
653
|
activities: Map<string, ActivityFn>,
|
|
463
654
|
profiles: Record<string, ActivityProfile>,
|
|
464
655
|
signal?: AbortSignal,
|
|
656
|
+
options: RunOpOptions = {},
|
|
465
657
|
): Promise<OpRunResult> {
|
|
466
|
-
|
|
467
|
-
|
|
658
|
+
// The run id is the gate ledger's and the run ledger's alike: a pending gate
|
|
659
|
+
// fact and the record naming that gate carry the same string.
|
|
660
|
+
const runId = options.runId ?? randomUUID();
|
|
661
|
+
|
|
662
|
+
const gates: GateContext = {
|
|
663
|
+
op: config.name,
|
|
664
|
+
port: options.gates ?? gitGateLedgerPort(options.cwd ? { cwd: options.cwd } : undefined),
|
|
665
|
+
...(options.now ? { now: options.now } : {}),
|
|
666
|
+
runId,
|
|
667
|
+
...(options.onRecord ? { onRecord: options.onRecord } : {}),
|
|
668
|
+
};
|
|
468
669
|
|
|
469
670
|
// Effect steps are ordered (read-compare-run-write): refuse them in a
|
|
470
671
|
// parallel phase up front, with the phase named, rather than mid-run.
|
|
@@ -480,6 +681,33 @@ export async function runOpLocally(
|
|
|
480
681
|
|
|
481
682
|
const records: StepRecord[] = [];
|
|
482
683
|
const start = Date.now();
|
|
684
|
+
const startedAt = options.now ?? new Date(start).toISOString();
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Build the run's ledger record, append it when asked, and hand it back for
|
|
688
|
+
* the result. Called once, at whichever of the three exits the run takes.
|
|
689
|
+
*/
|
|
690
|
+
const settle = async (
|
|
691
|
+
settled: StepRecord[],
|
|
692
|
+
status: OpRunResult["status"],
|
|
693
|
+
gate?: PendingGateRecord,
|
|
694
|
+
): Promise<OpRunRecord> => {
|
|
695
|
+
const input = buildRunRecord(config, settled, {
|
|
696
|
+
started: startedAt,
|
|
697
|
+
ended: options.now ?? new Date().toISOString(),
|
|
698
|
+
status,
|
|
699
|
+
id: runId,
|
|
700
|
+
...(gate ? { gate: { name: gate.gate, since: gate.timestamp } } : {}),
|
|
701
|
+
});
|
|
702
|
+
const record: OpRunRecord = { version: 1, ...input, id: runId };
|
|
703
|
+
if (!options.ledger) return record;
|
|
704
|
+
try {
|
|
705
|
+
return (await appendRunRecord(input, options.ledger)).record;
|
|
706
|
+
} catch (err) {
|
|
707
|
+
options.onLedgerError?.(err);
|
|
708
|
+
return record;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
483
711
|
|
|
484
712
|
// Completed step id → its activity result (#1290). Populated as main-phase
|
|
485
713
|
// steps finish, so a later step's step-output references resolve to real
|
|
@@ -489,9 +717,36 @@ export async function runOpLocally(
|
|
|
489
717
|
try {
|
|
490
718
|
for (const phase of config.phases) {
|
|
491
719
|
if (signal?.aborted) throw new PhaseFailure([]);
|
|
492
|
-
records.push(...(await runPhase(phase, activities, profiles, resultsById, signal)));
|
|
720
|
+
records.push(...(await runPhase(phase, activities, profiles, resultsById, gates, signal)));
|
|
493
721
|
}
|
|
494
722
|
} catch (err) {
|
|
723
|
+
// A pending gate ends the run where it stands: no later phase, and no
|
|
724
|
+
// `onFailure` compensation — nothing failed, so there is nothing to undo.
|
|
725
|
+
if (err instanceof GateStop) {
|
|
726
|
+
records.push(...err.records);
|
|
727
|
+
const stoppedAt = config.phases.findIndex((p) => p.name === err.phase);
|
|
728
|
+
for (const phase of config.phases.slice(stoppedAt + 1)) {
|
|
729
|
+
for (const step of phase.steps) {
|
|
730
|
+
records.push(
|
|
731
|
+
isEffect(step)
|
|
732
|
+
? skippedRecord(phase.name, `effect:${step.receipt.name}`)
|
|
733
|
+
: isGate(step)
|
|
734
|
+
? skippedRecord(phase.name, gateFn(step))
|
|
735
|
+
: skippedRecord(phase.name, step.fn, step.args),
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return {
|
|
740
|
+
op: config.name,
|
|
741
|
+
records,
|
|
742
|
+
totalMs: Date.now() - start,
|
|
743
|
+
status: "gated",
|
|
744
|
+
startedAt,
|
|
745
|
+
gate: err.pending,
|
|
746
|
+
record: await settle(records, "gated", err.pending),
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
495
750
|
if (err instanceof PhaseFailure) records.push(...err.records);
|
|
496
751
|
|
|
497
752
|
// Compensation: run onFailure phases in reverse order (best-effort). Skipped
|
|
@@ -499,17 +754,31 @@ export async function runOpLocally(
|
|
|
499
754
|
if (!signal?.aborted) {
|
|
500
755
|
for (const phase of [...(config.onFailure ?? [])].reverse()) {
|
|
501
756
|
try {
|
|
502
|
-
records.push(...(await runPhase(phase, activities, profiles, resultsById, signal)));
|
|
757
|
+
records.push(...(await runPhase(phase, activities, profiles, resultsById, gates, signal)));
|
|
503
758
|
} catch (compErr) {
|
|
504
|
-
if (compErr instanceof PhaseFailure) records.push(...compErr.records);
|
|
759
|
+
if (compErr instanceof PhaseFailure || compErr instanceof GateStop) records.push(...compErr.records);
|
|
505
760
|
}
|
|
506
761
|
}
|
|
507
762
|
}
|
|
508
763
|
|
|
509
|
-
throw new OpRunFailure({
|
|
764
|
+
throw new OpRunFailure({
|
|
765
|
+
op: config.name,
|
|
766
|
+
records,
|
|
767
|
+
totalMs: Date.now() - start,
|
|
768
|
+
status: "fail",
|
|
769
|
+
startedAt,
|
|
770
|
+
record: await settle(records, "fail"),
|
|
771
|
+
});
|
|
510
772
|
}
|
|
511
773
|
|
|
512
|
-
return {
|
|
774
|
+
return {
|
|
775
|
+
op: config.name,
|
|
776
|
+
records,
|
|
777
|
+
totalMs: Date.now() - start,
|
|
778
|
+
status: "ok",
|
|
779
|
+
startedAt,
|
|
780
|
+
record: await settle(records, "ok"),
|
|
781
|
+
};
|
|
513
782
|
}
|
|
514
783
|
|
|
515
784
|
function errMessage(err: unknown): string {
|