@intentius/chant 0.124.13 → 0.124.15
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/bin/chant +11 -0
- package/dist/agents/checks.js +326 -0
- package/dist/agents/discover.js +885 -0
- package/dist/agents/importer.js +17 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/types.js +19 -0
- package/dist/apply.js +151 -0
- package/dist/attrref.js +70 -0
- package/dist/audit/catalog.js +350 -0
- package/dist/audit/core.js +252 -0
- package/dist/audit/discover.js +633 -0
- package/dist/audit/fetch.js +666 -0
- package/dist/audit/lineage.js +91 -0
- package/dist/audit/nginx.js +366 -0
- package/dist/audit/prior-art.js +132 -0
- package/dist/audit/proof.js +321 -0
- package/dist/audit/report-html.js +194 -0
- package/dist/audit/report-model.js +198 -0
- package/dist/audit/report.js +102 -0
- package/dist/audit/rules-doc.js +144 -0
- package/dist/audit/secrets.js +405 -0
- package/dist/audit/terraform-state.js +140 -0
- package/dist/audit/wrangler.js +262 -0
- package/dist/behaviour-delta.js +401 -0
- package/dist/behaviour-engine.js +357 -0
- package/dist/behaviour-graph.js +83 -0
- package/dist/behaviour-http.js +188 -0
- package/dist/behaviour-kinds.js +172 -0
- package/dist/behaviour-overlay.js +50 -0
- package/dist/behaviour-predict.js +188 -0
- package/dist/behaviour-request.js +194 -0
- package/dist/behaviour.js +1325 -0
- package/dist/build-params.js +108 -0
- package/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +669 -0
- package/dist/builder.js +44 -0
- package/dist/cdk/advise.js +30 -0
- package/dist/cdk/assembly.js +122 -0
- package/dist/cdk/graph.js +444 -0
- package/dist/cdk/tier-map.js +64 -0
- package/dist/cdk/types.js +24 -0
- package/dist/change-set.d.ts +24 -2
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +361 -0
- package/dist/child-project.js +21 -0
- package/dist/ci-jobs.d.ts +227 -0
- package/dist/ci-jobs.d.ts.map +1 -0
- package/dist/ci-jobs.js +448 -0
- package/dist/claimed-fields.js +135 -0
- package/dist/cli/build-options.js +70 -0
- package/dist/cli/build-params-cli.js +139 -0
- package/dist/cli/command-group.js +123 -0
- package/dist/cli/commands/audit-agents.js +326 -0
- package/dist/cli/commands/audit.js +571 -0
- package/dist/cli/commands/build.js +920 -0
- package/dist/cli/commands/carve-apply.js +153 -0
- package/dist/cli/commands/carve-bridge.js +201 -0
- package/dist/cli/commands/carve-emit.js +332 -0
- package/dist/cli/commands/carve-status.js +119 -0
- package/dist/cli/commands/carve.js +204 -0
- package/dist/cli/commands/check-lexicon-docs.js +79 -0
- package/dist/cli/commands/check-lexicon-examples.js +177 -0
- package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
- package/dist/cli/commands/check-lexicon-mcp.js +82 -0
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +104 -0
- package/dist/cli/commands/check-lexicon.js +766 -0
- package/dist/cli/commands/describe.js +85 -0
- package/dist/cli/commands/diff.js +175 -0
- package/dist/cli/commands/doctor.js +350 -0
- package/dist/cli/commands/import-agents.js +155 -0
- package/dist/cli/commands/import.js +670 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
- package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
- package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
- package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
- package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
- package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
- package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
- package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
- package/dist/cli/commands/init-lexicon.js +172 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
- package/dist/cli/commands/lexicon-surface-diff.js +145 -0
- package/dist/cli/commands/licenses.js +125 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +948 -0
- package/dist/cli/commands/list.js +63 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +423 -0
- package/dist/cli/commands/onboard.js +403 -0
- package/dist/cli/commands/pinned-upgrade.js +191 -0
- package/dist/cli/commands/update.js +194 -0
- package/dist/cli/commands/vendor.js +217 -0
- package/dist/cli/conflict-check.js +104 -0
- package/dist/cli/debug.js +8 -0
- package/dist/cli/format.js +104 -0
- package/dist/cli/handlers/build.js +267 -0
- package/dist/cli/handlers/carve-apply.js +30 -0
- package/dist/cli/handlers/carve-bridge.js +28 -0
- package/dist/cli/handlers/carve-emit.js +50 -0
- package/dist/cli/handlers/carve-status.js +26 -0
- package/dist/cli/handlers/carve.js +40 -0
- package/dist/cli/handlers/change-set.js +46 -0
- package/dist/cli/handlers/components.js +730 -0
- package/dist/cli/handlers/dev.js +113 -0
- package/dist/cli/handlers/emulator.js +233 -0
- package/dist/cli/handlers/explain.js +54 -0
- package/dist/cli/handlers/fan-out.js +422 -0
- package/dist/cli/handlers/gate-resume.js +275 -0
- package/dist/cli/handlers/generate.js +84 -0
- package/dist/cli/handlers/graph.js +969 -0
- package/dist/cli/handlers/init.js +102 -0
- package/dist/cli/handlers/lifecycle.js +1727 -0
- package/dist/cli/handlers/lint.js +62 -0
- package/dist/cli/handlers/migrate.js +48 -0
- package/dist/cli/handlers/misc.js +391 -0
- package/dist/cli/handlers/operator.js +1162 -0
- package/dist/cli/handlers/override-approve.js +102 -0
- package/dist/cli/handlers/pr.js +503 -0
- package/dist/cli/handlers/promote.js +342 -0
- package/dist/cli/handlers/run-generate.js +206 -0
- package/dist/cli/handlers/run-wave.js +66 -0
- package/dist/cli/handlers/run.js +1191 -0
- package/dist/cli/handlers/scenario.js +325 -0
- package/dist/cli/handlers/search.js +924 -0
- package/dist/cli/handlers/serve.js +32 -0
- package/dist/cli/handlers/vendor.js +154 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/is-entry-point.js +23 -0
- package/dist/cli/lsp/capabilities.js +28 -0
- package/dist/cli/lsp/diagnostics.js +34 -0
- package/dist/cli/lsp/server.js +329 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +2540 -0
- package/dist/cli/mcp/lifecycle-tools.js +80 -0
- package/dist/cli/mcp/op-tools.js +306 -0
- package/dist/cli/mcp/resource-handlers.js +258 -0
- package/dist/cli/mcp/resources/context.js +85 -0
- package/dist/cli/mcp/server.js +353 -0
- package/dist/cli/mcp/tools/build.js +111 -0
- package/dist/cli/mcp/tools/composites.js +95 -0
- package/dist/cli/mcp/tools/explain.js +166 -0
- package/dist/cli/mcp/tools/import.js +49 -0
- package/dist/cli/mcp/tools/lint.js +41 -0
- package/dist/cli/mcp/tools/scaffold.js +111 -0
- package/dist/cli/mcp/tools/search.js +112 -0
- package/dist/cli/mcp/types.js +1 -0
- package/dist/cli/mcp/workspace-plugins.js +91 -0
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.js +564 -0
- package/dist/cli/mcp-config.js +70 -0
- package/dist/cli/plugins.js +313 -0
- package/dist/cli/registry.js +23 -0
- package/dist/cli/reporters/stylish.js +329 -0
- package/dist/cli/version.js +15 -0
- package/dist/cli/watch.js +79 -0
- package/dist/codegen/bound-property-types.js +82 -0
- package/dist/codegen/coverage.js +119 -0
- package/dist/codegen/docs-file-markers.js +60 -0
- package/dist/codegen/docs-pages.js +115 -0
- package/dist/codegen/docs-rule-scanning.js +164 -0
- package/dist/codegen/docs-rules.js +76 -0
- package/dist/codegen/docs-sections.js +117 -0
- package/dist/codegen/docs-sidebar.js +65 -0
- package/dist/codegen/docs-types.js +4 -0
- package/dist/codegen/docs.js +356 -0
- package/dist/codegen/fetch.js +340 -0
- package/dist/codegen/generate-post-synth-barrel.js +63 -0
- package/dist/codegen/generate-registry.js +71 -0
- package/dist/codegen/generate-runtime-index.js +56 -0
- package/dist/codegen/generate-typescript.js +119 -0
- package/dist/codegen/generate.js +115 -0
- package/dist/codegen/json-patch.js +141 -0
- package/dist/codegen/json-schema-to-ts.js +344 -0
- package/dist/codegen/json-schema.js +246 -0
- package/dist/codegen/lexicon-regen.js +412 -0
- package/dist/codegen/naming.js +217 -0
- package/dist/codegen/okf-lexicon.js +245 -0
- package/dist/codegen/package.js +150 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.js +494 -0
- package/dist/codegen/registry.js +60 -0
- package/dist/codegen/rehype-base-url.mjs +68 -0
- package/dist/codegen/rolling-upgrade.js +217 -0
- package/dist/codegen/surface-snapshot.js +537 -0
- package/dist/codegen/testdata/postgres-tags.json +242 -0
- package/dist/codegen/topo-sort.js +36 -0
- package/dist/codegen/typecheck.js +115 -0
- package/dist/codegen/validate.js +200 -0
- package/dist/codegen/version-bump.js +35 -0
- package/dist/components/auto-release.js +143 -0
- package/dist/components/builders.js +47 -0
- package/dist/components/capability-plugin-loader.js +175 -0
- package/dist/components/capability-plugin-schema.js +46 -0
- package/dist/components/capability-plugin.js +99 -0
- package/dist/components/capability.js +60 -0
- package/dist/components/changed-files.js +72 -0
- package/dist/components/cli-support.js +427 -0
- package/dist/components/component.js +120 -0
- package/dist/components/component.schema.json +271 -0
- package/dist/components/config-defaults.js +130 -0
- package/dist/components/deploy-units.js +60 -0
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/discover.js +189 -0
- package/dist/components/driver-output.js +86 -0
- package/dist/components/driver.js +728 -0
- package/dist/components/fan-out-output.js +165 -0
- package/dist/components/fan-out-record.js +94 -0
- package/dist/components/fan-out-run.js +373 -0
- package/dist/components/fan-out-support.js +60 -0
- package/dist/components/fan-out.js +273 -0
- package/dist/components/gate-plan.js +41 -0
- package/dist/components/gated-wave-pipeline.js +46 -0
- package/dist/components/index.js +24 -0
- package/dist/components/layers.js +28 -0
- package/dist/components/manifest-persistence.js +108 -0
- package/dist/components/pilots/alb-ecs.pilot.js +59 -0
- package/dist/components/pilots/dynamodb.pilot.js +51 -0
- package/dist/components/pilots/jar-emr.pilot.js +65 -0
- package/dist/components/pilots/lambda.pilot.js +52 -0
- package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
- package/dist/components/pilots/project.js +12 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +135 -0
- package/dist/components/pr-run.js +363 -0
- package/dist/components/presets/ecs-fargate.js +72 -0
- package/dist/components/presets/index.js +28 -0
- package/dist/components/presets/lambda.js +34 -0
- package/dist/components/presets/single-host-compose.js +41 -0
- package/dist/components/promote.js +549 -0
- package/dist/components/registry.js +34 -0
- package/dist/components/run-progress.js +33 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/driver.js +93 -0
- package/dist/components/sandbox/run.js +115 -0
- package/dist/components/starter-plugin.js +104 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
- package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
- package/dist/components/verbs/bom-writer.js +287 -0
- package/dist/components/verbs/build-archive.js +188 -0
- package/dist/components/verbs/build.js +142 -0
- package/dist/components/verbs/cloud-executor.js +110 -0
- package/dist/components/verbs/component-bom.js +125 -0
- package/dist/components/verbs/ensure-secret.js +50 -0
- package/dist/components/verbs/index.js +61 -0
- package/dist/components/verbs/license-policy.js +75 -0
- package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
- package/dist/components/verbs/process-runner.js +78 -0
- package/dist/components/verbs/r2-sync.js +93 -0
- package/dist/components/verbs/reproducibility.js +62 -0
- package/dist/components/verbs/run-agent.js +577 -0
- package/dist/components/verbs/sbom-generator.js +119 -0
- package/dist/components/verbs/sbom.js +97 -0
- package/dist/components/verbs/shell.js +32 -0
- package/dist/components/verbs/sign.js +221 -0
- package/dist/components/verbs/stub.js +28 -0
- package/dist/components/verbs/tool-sbom-generator.js +154 -0
- package/dist/components/verbs/verify.js +112 -0
- package/dist/components/verbs/vex.js +131 -0
- package/dist/components/verbs/vuln-gate.js +152 -0
- package/dist/components/verbs/vuln-scan.js +288 -0
- package/dist/components/verbs/wait-verify.js +106 -0
- package/dist/components/verbs/wrangler.js +179 -0
- package/dist/components/wave-plan.js +102 -0
- package/dist/composite.d.ts +10 -2
- package/dist/composite.d.ts.map +1 -1
- package/dist/composite.js +313 -0
- package/dist/config-import.d.ts.map +1 -1
- package/dist/config-import.js +22 -0
- package/dist/config-sandbox.js +122 -0
- package/dist/config-static.js +206 -0
- package/dist/config.js +605 -0
- package/dist/content-digest.js +23 -0
- package/dist/declarable.js +114 -0
- package/dist/deep-observation.js +437 -0
- package/dist/detectLexicon.js +54 -0
- package/dist/discovery/cache.js +70 -0
- package/dist/discovery/collect.d.ts +2 -1
- package/dist/discovery/collect.d.ts.map +1 -1
- package/dist/discovery/collect.js +223 -0
- package/dist/discovery/cycles.js +95 -0
- package/dist/discovery/entity-wire-codec.js +391 -0
- package/dist/discovery/entity-wire.js +42 -0
- package/dist/discovery/files.js +121 -0
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +4073 -0
- package/dist/discovery/fold-rank.js +292 -0
- package/dist/discovery/graph.js +115 -0
- package/dist/discovery/host-composite.d.ts +35 -0
- package/dist/discovery/host-composite.d.ts.map +1 -0
- package/dist/discovery/host-composite.js +93 -0
- package/dist/discovery/import.d.ts.map +1 -1
- package/dist/discovery/import.js +65 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +333 -0
- package/dist/discovery/param-deps.js +487 -0
- package/dist/discovery/resolve.js +39 -0
- package/dist/discovery/sandbox/bundle.js +214 -0
- package/dist/discovery/sandbox/child-errors.js +26 -0
- package/dist/discovery/sandbox/config-run.js +100 -0
- package/dist/discovery/sandbox/config-wire.js +183 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.js +333 -0
- package/dist/discovery/sandbox/fork.js +229 -0
- package/dist/discovery/sandbox/policy-run.js +142 -0
- package/dist/discovery/sandbox/policy-wire.js +152 -0
- package/dist/discovery/sandbox/run.js +77 -0
- package/dist/discovery/specifier-resolve.js +320 -0
- package/dist/discovery/walk.js +284 -0
- package/dist/effect-receipt.js +340 -0
- package/dist/env.js +55 -0
- package/dist/errors.js +62 -0
- package/dist/fold/fold.js +1434 -0
- package/dist/fold/foldable-helpers.js +229 -0
- package/dist/fold/subset.js +696 -0
- package/dist/fold-provenance.js +414 -0
- package/dist/gate-decision.d.ts +20 -9
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +313 -0
- package/dist/gate-resume-run.js +154 -0
- package/dist/gated-waves.js +165 -0
- package/dist/governance.js +43 -0
- package/dist/graph-declared.js +45 -0
- package/dist/graph-detail.js +207 -0
- package/dist/graph-dot.js +54 -0
- package/dist/graph-effective.js +107 -0
- package/dist/graph-ir.js +623 -0
- package/dist/graph-layout.js +184 -0
- package/dist/graph-lens.js +105 -0
- package/dist/graph-mermaid.js +83 -0
- package/dist/graph-ops.js +39 -0
- package/dist/graph-refs.js +156 -0
- package/dist/held-elsewhere.js +87 -0
- package/dist/identity.js +251 -0
- package/dist/import/base-parser.js +34 -0
- package/dist/import/embedded.js +255 -0
- package/dist/import/generator.js +1 -0
- package/dist/import/ir-utils.js +85 -0
- package/dist/import/parser-options.js +45 -0
- package/dist/import/parser.js +1 -0
- package/dist/index.js +118 -0
- package/dist/intrinsic-interpolation.js +73 -0
- package/dist/intrinsic.js +31 -0
- package/dist/join-key.js +35 -0
- package/dist/kubectl-context.js +150 -0
- package/dist/lexicon-config.js +58 -0
- package/dist/lexicon-integrity.js +47 -0
- package/dist/lexicon-manifest.js +70 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +241 -0
- package/dist/lexicon-output.js +218 -0
- package/dist/lexicon-plugin-helpers.js +104 -0
- package/dist/lexicon-schema.js +136 -0
- package/dist/lexicon.js +130 -0
- package/dist/lifecycle/affected.js +224 -0
- package/dist/lifecycle/assert-live.js +110 -0
- package/dist/lifecycle/build-ledger-store.js +160 -0
- package/dist/lifecycle/build-ledger.js +155 -0
- package/dist/lifecycle/change-set.js +356 -0
- package/dist/lifecycle/converge-ledger.js +161 -0
- package/dist/lifecycle/deep-diff.js +233 -0
- package/dist/lifecycle/deep-observe.js +147 -0
- package/dist/lifecycle/digest.js +143 -0
- package/dist/lifecycle/disruption.js +135 -0
- package/dist/lifecycle/gate-applied.js +113 -0
- package/dist/lifecycle/gate-audit.d.ts +69 -2
- package/dist/lifecycle/gate-audit.d.ts.map +1 -1
- package/dist/lifecycle/gate-audit.js +415 -0
- package/dist/lifecycle/gate-ledger-select.js +89 -0
- package/dist/lifecycle/gate-ledger.d.ts +24 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +201 -0
- package/dist/lifecycle/gate-origin.js +117 -0
- package/dist/lifecycle/gate-pending.js +58 -0
- package/dist/lifecycle/git.js +1182 -0
- package/dist/lifecycle/identity.js +58 -0
- package/dist/lifecycle/index.js +26 -0
- package/dist/lifecycle/lease.js +283 -0
- package/dist/lifecycle/ledger-port.js +1 -0
- package/dist/lifecycle/legacy-digest.js +91 -0
- package/dist/lifecycle/live-diff.js +274 -0
- package/dist/lifecycle/local-note.js +15 -0
- package/dist/lifecycle/member-ledger.js +122 -0
- package/dist/lifecycle/observation-baseline.js +155 -0
- package/dist/lifecycle/observe.js +375 -0
- package/dist/lifecycle/oras-referrer-lookup.js +82 -0
- package/dist/lifecycle/override-ledger.js +54 -0
- package/dist/lifecycle/plan-digest.js +110 -0
- package/dist/lifecycle/plan-ledger.js +129 -0
- package/dist/lifecycle/receipt-plan.js +192 -0
- package/dist/lifecycle/release-ledger.js +155 -0
- package/dist/lifecycle/release-read.js +64 -0
- package/dist/lifecycle/replay.js +193 -0
- package/dist/lifecycle/rollback.js +102 -0
- package/dist/lifecycle/run-ledger.js +183 -0
- package/dist/lifecycle/scenario-eval.js +204 -0
- package/dist/lifecycle/scenario.js +214 -0
- package/dist/lifecycle/snapshot.js +239 -0
- package/dist/lifecycle/status.js +447 -0
- package/dist/lifecycle/symptoms.js +117 -0
- package/dist/lifecycle/teardown.js +255 -0
- package/dist/lifecycle/types.js +1 -0
- package/dist/lifecycle/unobserved-gate.js +33 -0
- package/dist/lifecycle/wave-plans.js +68 -0
- package/dist/lifecycle/work-item-id.js +36 -0
- package/dist/lifecycle/work-lease.js +393 -0
- package/dist/lint/component-checks.js +87 -0
- package/dist/lint/config.js +483 -0
- package/dist/lint/declarative.js +122 -0
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +138 -0
- package/dist/lint/engine.js +246 -0
- package/dist/lint/knowledge-checks.js +64 -0
- package/dist/lint/named-checks.js +22 -0
- package/dist/lint/output-checks.js +87 -0
- package/dist/lint/output-docs.js +163 -0
- package/dist/lint/parser.js +33 -0
- package/dist/lint/pipeline-change-gate.js +70 -0
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/policy-import.d.ts.map +1 -1
- package/dist/lint/policy-import.js +62 -0
- package/dist/lint/policy-sandbox.js +86 -0
- package/dist/lint/policy.js +122 -0
- package/dist/lint/post-synth.js +87 -0
- package/dist/lint/presets/relaxed.json +26 -0
- package/dist/lint/presets/strict.json +24 -24
- package/dist/lint/receipt-checks.js +83 -0
- package/dist/lint/rule-loader.d.ts.map +1 -1
- package/dist/lint/rule-loader.js +89 -0
- package/dist/lint/rule-registry.js +86 -0
- package/dist/lint/rule.js +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
- package/dist/lint/rules/comp/index.js +33 -0
- package/dist/lint/rules/comp/support.js +129 -0
- package/dist/lint/rules/composite-scope.js +51 -0
- package/dist/lint/rules/cor017-composite-name-match.js +93 -0
- package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
- package/dist/lint/rules/cor021-env-literal-name.js +100 -0
- package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
- package/dist/lint/rules/declarable-naming-convention.js +62 -0
- package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
- package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
- package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
- package/dist/lint/rules/evl004-spread-non-const.js +94 -0
- package/dist/lint/rules/evl005-resource-block-body.js +41 -0
- package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
- package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
- package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
- package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
- package/dist/lint/rules/export-required.js +115 -0
- package/dist/lint/rules/file-declarable-limit.js +88 -0
- package/dist/lint/rules/flat-declarations.js +62 -0
- package/dist/lint/rules/index.js +90 -0
- package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
- package/dist/lint/rules/no-redundant-type-import.js +76 -0
- package/dist/lint/rules/no-redundant-value-cast.js +41 -0
- package/dist/lint/rules/no-string-ref.js +59 -0
- package/dist/lint/rules/no-unused-declarable-import.js +75 -0
- package/dist/lint/rules/no-unused-declarable.js +142 -0
- package/dist/lint/rules/op/index.js +28 -0
- package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
- package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
- package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
- package/dist/lint/rules/op/support.js +11 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
- package/dist/lint/rules/property-kind.js +56 -0
- package/dist/lint/rules/single-concern-file.js +71 -0
- package/dist/lint/rules/sys001-no-literal-key.js +60 -0
- package/dist/lint/selectors.js +168 -0
- package/dist/lint/suppressions.js +129 -0
- package/dist/lint/typescript.js +17 -0
- package/dist/live-endpoint.js +113 -0
- package/dist/live-read-session.js +76 -0
- package/dist/lsp/lexicon-providers.js +163 -0
- package/dist/lsp/types.js +5 -0
- package/dist/managed-fields.js +293 -0
- package/dist/mcp/types.js +4 -0
- package/dist/notify-verify.js +0 -1
- package/dist/notify.js +0 -1
- package/dist/notify.schema.json +72 -0
- package/dist/observation.js +266 -0
- package/dist/okf-read.js +134 -0
- package/dist/okf.js +275 -0
- package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
- package/dist/op/activities/activity-contracts.d.ts +1 -1
- package/dist/op/activities/activity-contracts.js +313 -0
- package/dist/op/activities/apply.js +582 -0
- package/dist/op/activities/build.js +18 -0
- package/dist/op/activities/change-coverage.js +40 -0
- package/dist/op/activities/change-set.d.ts +8 -3
- package/dist/op/activities/change-set.d.ts.map +1 -1
- package/dist/op/activities/change-set.js +67 -0
- package/dist/op/activities/converge.js +492 -0
- package/dist/op/activities/decide.js +211 -0
- package/dist/op/activities/env-teardown.js +110 -0
- package/dist/op/activities/factory.js +591 -0
- package/dist/op/activities/forge-pull-request.js +82 -0
- package/dist/op/activities/gh-host.js +78 -0
- package/dist/op/activities/guard-validate.js +165 -0
- package/dist/op/activities/http-check.js +40 -0
- package/dist/op/activities/index.js +59 -0
- package/dist/op/activities/lexicon-upgrade.js +629 -0
- package/dist/op/activities/lifecycle.js +109 -0
- package/dist/op/activities/pipeline-audit.js +147 -0
- package/dist/op/activities/policy.js +26 -0
- package/dist/op/activities/predict-behaviour.js +341 -0
- package/dist/op/activities/propose-upgrade.js +165 -0
- package/dist/op/activities/reconcile.d.ts +28 -16
- package/dist/op/activities/reconcile.d.ts.map +1 -1
- package/dist/op/activities/reconcile.js +1011 -0
- package/dist/op/activities/shell.js +118 -0
- package/dist/op/activities/source-release.js +97 -0
- package/dist/op/activities/source-rollback.js +165 -0
- package/dist/op/activities/teardown.js +17 -0
- package/dist/op/activities/util.js +6 -0
- package/dist/op/activities/wait.js +51 -0
- package/dist/op/activities/work-evidence.js +35 -0
- package/dist/op/activities/workflow-audit.js +133 -0
- package/dist/op/activity-contract-registry.js +106 -0
- package/dist/op/activity-contract.js +232 -0
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/activity-profiles.js +129 -0
- package/dist/op/activity-registry.js +105 -0
- package/dist/op/activity-runtime.js +28 -0
- package/dist/op/builders.d.ts +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +801 -0
- package/dist/op/change-signal.js +118 -0
- package/dist/op/composites/apply-op.js +151 -0
- package/dist/op/composites/behaviour-op.js +65 -0
- package/dist/op/composites/converge-op.js +141 -0
- package/dist/op/composites/index.js +19 -0
- package/dist/op/composites/lexicon-upgrade-op.js +107 -0
- package/dist/op/composites/pipeline-audit-op.js +50 -0
- package/dist/op/composites/reconcile-op.js +84 -0
- package/dist/op/composites/watch-op.js +69 -0
- package/dist/op/composites/workflow-audit-op.js +57 -0
- package/dist/op/converge-rule.js +205 -0
- package/dist/op/cron.js +146 -0
- package/dist/op/decide-backend.js +181 -0
- package/dist/op/decide-config.js +68 -0
- package/dist/op/decide-read-inputs.js +141 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +213 -0
- package/dist/op/duration.js +21 -0
- package/dist/op/emulator-freshness.js +80 -0
- package/dist/op/emulator-lifecycle.js +269 -0
- package/dist/op/factory.js +83 -0
- package/dist/op/gate-approval.js +172 -0
- package/dist/op/gate-name.js +86 -0
- package/dist/op/gate-plan-context.js +167 -0
- package/dist/op/gate-point-run.js +67 -0
- package/dist/op/gate-point.js +111 -0
- package/dist/op/gate-resume-plan.js +155 -0
- package/dist/op/gate-resume.js +31 -0
- package/dist/op/gate-review.js +290 -0
- package/dist/op/gate-run-locator.js +85 -0
- package/dist/op/gate-summary.js +100 -0
- package/dist/op/gate-wait.js +56 -0
- package/dist/op/gate.js +449 -0
- package/dist/op/generate-pipeline.js +124 -0
- package/dist/op/index.js +51 -0
- package/dist/op/lifecycle-receipt-store.js +45 -0
- package/dist/op/local-executor.js +1164 -0
- package/dist/op/local-output.js +140 -0
- package/dist/op/op-ir.js +317 -0
- package/dist/op/op-verb-class.js +131 -0
- package/dist/op/op-waves-notify.js +136 -0
- package/dist/op/op-waves-run.d.ts +1 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +1657 -0
- package/dist/op/op-waves.js +409 -0
- package/dist/op/operator.js +743 -0
- package/dist/op/receipt-store.js +94 -0
- package/dist/op/resource.js +23 -0
- package/dist/op/run-context.js +28 -0
- package/dist/op/run-live.js +256 -0
- package/dist/op/runtime.js +21 -0
- package/dist/op/runtimes/local.js +195 -0
- package/dist/op/source-archive.js +131 -0
- package/dist/op/step-output-ref.js +397 -0
- package/dist/op/steward-beside.js +169 -0
- package/dist/op/steward-points.js +138 -0
- package/dist/op/steward-turn.js +59 -0
- package/dist/op/steward.js +317 -0
- package/dist/op/types.js +25 -0
- package/dist/op/work-lease-decl.js +81 -0
- package/dist/op/work-lease-run.js +393 -0
- package/dist/override-gate.js +284 -0
- package/dist/owner-chain.js +74 -0
- package/dist/ownership.js +92 -0
- package/dist/params.js +61 -0
- package/dist/plan-summary.js +711 -0
- package/dist/point-decision.js +211 -0
- package/dist/pr-forge.js +810 -0
- package/dist/pr-loop.js +203 -0
- package/dist/project-codegen.js +191 -0
- package/dist/project-root.js +74 -0
- package/dist/project-validation.js +50 -0
- package/dist/provenance.js +157 -0
- package/dist/pseudo-parameter.js +40 -0
- package/dist/reconcile.js +450 -0
- package/dist/resource-attributes.js +33 -0
- package/dist/runtime-adapter.js +77 -0
- package/dist/runtime.js +66 -0
- package/dist/secret-materialization.js +153 -0
- package/dist/secret-provenance.js +250 -0
- package/dist/serializer-walker.js +112 -0
- package/dist/serializer.js +1 -0
- package/dist/sort.js +45 -0
- package/dist/stack-output.js +115 -0
- package/dist/telemetry-attribution.js +149 -0
- package/dist/terraform/__fixtures__/build-graph.js +63 -0
- package/dist/terraform/adopt-state.js +40 -0
- package/dist/terraform/aws-resources.js +384 -0
- package/dist/terraform/bridge.js +204 -0
- package/dist/terraform/carve-provider.js +155 -0
- package/dist/terraform/carve.js +138 -0
- package/dist/terraform/data-source-shape.js +57 -0
- package/dist/terraform/emit-source.js +36 -0
- package/dist/terraform/excise.js +123 -0
- package/dist/terraform/graduate.js +128 -0
- package/dist/terraform/graph.js +435 -0
- package/dist/terraform/hcl2json.js +60 -0
- package/dist/terraform/manifest.js +149 -0
- package/dist/terraform/parse.js +81 -0
- package/dist/terraform/providers/aws.js +146 -0
- package/dist/terraform/providers/gcp.js +294 -0
- package/dist/terraform/providers/index.js +17 -0
- package/dist/terraform/providers/kubernetes.js +253 -0
- package/dist/terraform/score.js +151 -0
- package/dist/terraform/state.js +67 -0
- package/dist/terraform/tier-map.js +74 -0
- package/dist/terraform/types.js +13 -0
- package/dist/terraform/unified-diff.js +132 -0
- package/dist/testing.js +295 -0
- package/dist/toml-emit.js +153 -0
- package/dist/toml-parse.js +355 -0
- package/dist/toml-utils.js +60 -0
- package/dist/toml.js +428 -0
- package/dist/ts-loader.d.ts +46 -0
- package/dist/ts-loader.d.ts.map +1 -0
- package/dist/ts-loader.js +103 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +61 -0
- package/dist/validation.js +20 -0
- package/dist/vendor/js-yaml-load.js +1662 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts +7 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.js +119 -0
- package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
- package/dist/workspace/__fixtures__/sessions.d.ts +1 -1
- package/dist/workspace/__fixtures__/sessions.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/sessions.js +91 -0
- package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
- package/dist/workspace/agent-cli.js +99 -0
- package/dist/workspace/agent.schema.json +390 -0
- package/dist/workspace/answers-ledger.js +89 -0
- package/dist/workspace/box-cli.js +142 -0
- package/dist/workspace/box-factory-write.js +196 -0
- package/dist/workspace/box-factory-write.schema.json +342 -0
- package/dist/workspace/box-factory.js +88 -0
- package/dist/workspace/box-intent.js +126 -0
- package/dist/workspace/box-isolation.js +169 -0
- package/dist/workspace/box-listing-write.schema.json +204 -0
- package/dist/workspace/box-listing.js +298 -0
- package/dist/workspace/box-publish.js +352 -0
- package/dist/workspace/box-publish.schema.json +498 -0
- package/dist/workspace/box-services.js +39 -0
- package/dist/workspace/broker-protocol.js +359 -0
- package/dist/workspace/broker-protocol.schema.json +228 -0
- package/dist/workspace/change-set.schema.json +462 -0
- package/dist/workspace/changes-cli.js +56 -0
- package/dist/workspace/changes.js +446 -0
- package/dist/workspace/changes.schema.json +642 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
- package/dist/workspace/chant-migrations.js +113 -0
- package/dist/workspace/check.schema.json +433 -0
- package/dist/workspace/checks/box-isolation.js +62 -0
- package/dist/workspace/checks/boxes.js +491 -0
- package/dist/workspace/checks/diagrams.js +104 -0
- package/dist/workspace/checks/generated.js +419 -0
- package/dist/workspace/checks/ledgers.js +212 -0
- package/dist/workspace/checks/links.js +191 -0
- package/dist/workspace/checks/live.js +100 -0
- package/dist/workspace/checks/pipelines.js +188 -0
- package/dist/workspace/checks/records.js +169 -0
- package/dist/workspace/checks.js +426 -0
- package/dist/workspace/ci-green-cli.js +125 -0
- package/dist/workspace/ci-green-forge.js +83 -0
- package/dist/workspace/ci-green-workflow.d.ts +3 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +202 -0
- package/dist/workspace/ci-green.js +325 -0
- package/dist/workspace/ci-last-green.schema.json +158 -0
- package/dist/workspace/class-data.d.ts +84 -0
- package/dist/workspace/class-data.d.ts.map +1 -0
- package/dist/workspace/class-data.js +238 -0
- package/dist/workspace/compose-graph.js +235 -0
- package/dist/workspace/compose-reports.js +146 -0
- package/dist/workspace/composites.js +264 -0
- package/dist/workspace/composites.schema.json +617 -0
- package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
- package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
- package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
- package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/dist/workspace/conformance/broker.js +736 -0
- package/dist/workspace/conformance/index.js +673 -0
- package/dist/workspace/conformance/vitest.js +108 -0
- package/dist/workspace/conformance/writer.js +1080 -0
- package/dist/workspace/decide.js +879 -0
- package/dist/workspace/decision-points.schema.json +135 -135
- package/dist/workspace/declaration-write-cli.js +74 -0
- package/dist/workspace/declaration-write.js +238 -0
- package/dist/workspace/declaration.js +938 -0
- package/dist/workspace/declaration.schema.json +1413 -1413
- package/dist/workspace/declared-kinds.js +106 -0
- package/dist/workspace/environments.js +164 -0
- package/dist/workspace/evidence.schema.json +279 -0
- package/dist/workspace/export-cli.js +185 -0
- package/dist/workspace/export.js +499 -0
- package/dist/workspace/factory-rules.js +175 -0
- package/dist/workspace/generated-files.js +92 -0
- package/dist/workspace/glob.js +45 -0
- package/dist/workspace/graph-cache.js +352 -0
- package/dist/workspace/graph-cli.js +348 -0
- package/dist/workspace/graph.schema.json +1338 -0
- package/dist/workspace/identity-gate-rule.js +75 -0
- package/dist/workspace/identity.js +126 -0
- package/dist/workspace/import.js +283 -0
- package/dist/workspace/init.js +620 -0
- package/dist/workspace/intent-cli.js +263 -0
- package/dist/workspace/intent-joins.js +201 -0
- package/dist/workspace/intent-record.js +352 -0
- package/dist/workspace/intent-record.schema.json +864 -0
- package/dist/workspace/intent.js +1582 -0
- package/dist/workspace/intent.schema.json +2420 -0
- package/dist/workspace/json-edit.js +221 -0
- package/dist/workspace/jsonc.js +235 -0
- package/dist/workspace/kind-readers.js +103 -0
- package/dist/workspace/kinds.d.ts +3 -7
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +553 -0
- package/dist/workspace/lexicon-symbols.js +112 -0
- package/dist/workspace/lineage-adopt-cli.js +102 -0
- package/dist/workspace/lineage-adopt.js +360 -0
- package/dist/workspace/lineage-check.js +282 -0
- package/dist/workspace/lineage-cli.js +121 -0
- package/dist/workspace/lineage-hash-index.js +284 -0
- package/dist/workspace/lineage-init.js +507 -0
- package/dist/workspace/lineage-lock.js +387 -0
- package/dist/workspace/lineage-merge.js +45 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.js +329 -0
- package/dist/workspace/lineage-provenance.js +36 -0
- package/dist/workspace/lineage-update.js +138 -0
- package/dist/workspace/lineage-upgrade-cli.js +131 -0
- package/dist/workspace/lineage-upgrade.js +889 -0
- package/dist/workspace/lineage-vendor.js +171 -0
- package/dist/workspace/lineage-version.js +128 -0
- package/dist/workspace/lineage-versions.js +275 -0
- package/dist/workspace/links.js +330 -0
- package/dist/workspace/ls-generated.js +95 -0
- package/dist/workspace/ls.js +277 -0
- package/dist/workspace/ls.schema.json +333 -0
- package/dist/workspace/member-commands.js +508 -0
- package/dist/workspace/member-handles.js +216 -0
- package/dist/workspace/member-pipeline.js +258 -0
- package/dist/workspace/member-run.js +117 -0
- package/dist/workspace/member-write.schema.json +193 -0
- package/dist/workspace/nested-graph.js +156 -0
- package/dist/workspace/nesting.js +38 -0
- package/dist/workspace/patch.js +301 -0
- package/dist/workspace/patch.schema.json +321 -0
- package/dist/workspace/pin-cli.js +55 -0
- package/dist/workspace/pin-integrity.js +100 -0
- package/dist/workspace/plan-summary.schema.json +155 -0
- package/dist/workspace/point-answer.schema.json +129 -129
- package/dist/workspace/points-cli.js +291 -0
- package/dist/workspace/points-write.schema.json +660 -0
- package/dist/workspace/points.js +521 -0
- package/dist/workspace/points.schema.json +916 -0
- package/dist/workspace/pr-report.schema.json +108 -0
- package/dist/workspace/principal-classes.d.ts +4 -11
- package/dist/workspace/principal-classes.d.ts.map +1 -1
- package/dist/workspace/principal-classes.js +162 -0
- package/dist/workspace/reason-codes.js +326 -0
- package/dist/workspace/record-assets.js +151 -0
- package/dist/workspace/record-decided.js +105 -0
- package/dist/workspace/record-sessions.js +96 -0
- package/dist/workspace/record-source.js +114 -0
- package/dist/workspace/records-amend.schema.json +284 -0
- package/dist/workspace/records-checkout.js +76 -0
- package/dist/workspace/records-cli.js +707 -0
- package/dist/workspace/records-close.js +116 -0
- package/dist/workspace/records-close.schema.json +278 -0
- package/dist/workspace/records-new.schema.json +202 -0
- package/dist/workspace/records-review.schema.json +367 -0
- package/dist/workspace/records-since.js +317 -0
- package/dist/workspace/records-since.schema.json +218 -0
- package/dist/workspace/records-write.js +1229 -0
- package/dist/workspace/records.js +1345 -0
- package/dist/workspace/records.schema.json +604 -0
- package/dist/workspace/reference-kinds/app/package.json +10 -0
- package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/dist/workspace/returns.js +303 -0
- package/dist/workspace/root-refusal.js +75 -0
- package/dist/workspace/run-statement.schema.json +622 -0
- package/dist/workspace/runs-cli.js +584 -0
- package/dist/workspace/runs-write.schema.json +994 -0
- package/dist/workspace/runs.js +708 -0
- package/dist/workspace/runs.schema.json +1257 -0
- package/dist/workspace/runtimes.js +76 -0
- package/dist/workspace/session-kinds.js +83 -0
- package/dist/workspace/signers.schema.json +206 -0
- package/dist/workspace/source-block.js +125 -0
- package/dist/workspace/squash.js +177 -0
- package/dist/workspace/status-gates.js +162 -0
- package/dist/workspace/status-stewards.js +330 -0
- package/dist/workspace/status.js +514 -0
- package/dist/workspace/status.schema.json +998 -0
- package/dist/workspace/steward-index.js +191 -0
- package/dist/workspace/symbols.js +188 -0
- package/dist/workspace/template-manifest.js +227 -0
- package/dist/workspace/template-pins.js +115 -0
- package/dist/workspace/trailer-joins.js +65 -0
- package/dist/workspace/trailers.js +111 -0
- package/dist/workspace/tree.js +136 -0
- package/dist/workspace/trust/attestor.js +63 -0
- package/dist/workspace/trust/dsse.js +108 -0
- package/dist/workspace/trust/evidence-cli.js +175 -0
- package/dist/workspace/trust/evidence.js +161 -0
- package/dist/workspace/trust/gate-seal.js +226 -0
- package/dist/workspace/trust/policy.js +190 -0
- package/dist/workspace/trust/provenance.js +180 -0
- package/dist/workspace/trust/rotation.js +298 -0
- package/dist/workspace/trust/run-commits.js +101 -0
- package/dist/workspace/trust/run-statement.js +182 -0
- package/dist/workspace/trust/seal.js +272 -0
- package/dist/workspace/trust/signers-cli.js +152 -0
- package/dist/workspace/trust/ssh-commit.js +178 -0
- package/dist/workspace/trust/test-repo.js +118 -0
- package/dist/workspace/trust/trust-files.js +193 -0
- package/dist/workspace/trust/verify-cli.js +63 -0
- package/dist/workspace/trust/verify.js +192 -0
- package/dist/workspace/which-chant.js +141 -0
- package/dist/workspace/wip-cli.js +95 -0
- package/dist/workspace/wip-write.schema.json +504 -0
- package/dist/workspace/wip.js +631 -0
- package/dist/workspace/wip.schema.json +334 -0
- package/dist/workspace/work-cli.js +448 -0
- package/dist/workspace/work-evidence.js +122 -0
- package/dist/workspace/work-evidence.schema.json +222 -0
- package/dist/workspace/work-history.schema.json +421 -0
- package/dist/workspace/work-lease.schema.json +246 -0
- package/dist/workspace/work-size.js +77 -0
- package/dist/workspace/work.js +283 -0
- package/dist/workspace/workspace-kinds.schema.json +259 -259
- package/dist/workspace/workspace-principals.schema.json +53 -53
- package/dist/workspace/write-lock-cli.js +105 -0
- package/dist/workspace/write-lock.js +424 -0
- package/dist/workspace/write-lock.schema.json +172 -0
- package/dist/workspace/write-scope.js +484 -0
- package/dist/yaml.js +459 -0
- package/package.json +2 -2
- package/src/build.ts +8 -0
- package/src/change-set.test.ts +48 -0
- package/src/change-set.ts +52 -2
- package/src/ci-jobs.test.ts +49 -0
- package/src/ci-jobs.ts +515 -0
- package/src/cli/commands/check-lexicon-plugin.ts +2 -0
- package/src/cli/commands/lint.ts +3 -0
- package/src/cli/commands/migrate.ts +2 -0
- package/src/cli/compiled-cli.e2e.test.ts +165 -0
- package/src/cli/main.ts +121 -27
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -0
- package/src/components/discover.ts +2 -0
- package/src/components/pr-pipeline.ts +3 -2
- package/src/components/sandbox/driver.ts +3 -1
- package/src/composite.ts +15 -3
- package/src/config-import.ts +3 -0
- package/src/discovery/collect.ts +15 -1
- package/src/discovery/fold-build-parity.test.ts +71 -0
- package/src/discovery/fold-import.ts +25 -127
- package/src/discovery/fold-project-provenance.test.ts +21 -4
- package/src/discovery/host-composite.ts +101 -0
- package/src/discovery/import.ts +2 -0
- package/src/discovery/index.ts +11 -1
- package/src/discovery/sandbox/driver.ts +3 -1
- package/src/gate-decision-bundle.test.ts +5 -4
- package/src/gate-decision-identity.test.ts +59 -6
- package/src/gate-decision.ts +81 -21
- package/src/lexicon-module.ts +3 -0
- package/src/lifecycle/gate-audit.test.ts +55 -1
- package/src/lifecycle/gate-audit.ts +116 -3
- package/src/lifecycle/gate-ledger.test.ts +20 -1
- package/src/lifecycle/gate-ledger.ts +33 -1
- package/src/lint/config.ts +1 -1
- package/src/lint/discover.ts +28 -8
- package/src/lint/policy-import.ts +4 -1
- package/src/lint/rule-loader.ts +2 -0
- package/src/op/activities/activity-contracts.ts +1 -1
- package/src/op/activities/change-set.ts +11 -3
- package/src/op/activities/lexicon-upgrade.test.ts +2 -0
- package/src/op/activities/reconcile.test.ts +62 -2
- package/src/op/activities/reconcile.ts +46 -22
- package/src/op/builders.ts +1 -1
- package/src/op/discover.ts +3 -0
- package/src/op/op-waves-run.ts +4 -3
- package/src/op/op-waves.test.ts +2 -0
- package/src/op/work-lease-run.test.ts +12 -4
- package/src/ts-loader.test.ts +23 -0
- package/src/ts-loader.ts +122 -0
- package/src/workspace/__fixtures__/contract-repo.ts +17 -1
- package/src/workspace/__fixtures__/sessions.ts +3 -3
- package/src/workspace/change-set.schema.json +5 -3
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
- package/src/workspace/ci-green-workflow.test.ts +4 -4
- package/src/workspace/ci-green-workflow.ts +5 -2
- package/src/workspace/class-data.test.ts +64 -0
- package/src/workspace/class-data.ts +236 -0
- package/src/workspace/declaration.ts +1 -1
- package/src/workspace/kinds.ts +7 -36
- package/src/workspace/lineage-migrations.ts +2 -0
- package/src/workspace/points.ts +1 -1
- package/src/workspace/principal-classes.ts +12 -95
- package/src/workspace/records-formats.test.ts +7 -2
- package/src/workspace/records-sessions-write.test.ts +3 -3
- package/src/workspace/status-contract.e2e.test.ts +37 -0
- package/src/workspace/status-contract.test.ts +23 -21
|
@@ -0,0 +1,1164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Op executor — runs an Op's phases in this process.
|
|
3
|
+
*
|
|
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
|
+
* activity profiles, `outcomeAttribute` capture, and `onFailure` compensation.
|
|
7
|
+
*
|
|
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
|
|
18
|
+
* implementations and profiles are passed in (loaded dynamically by the CLI),
|
|
19
|
+
* so core never statically depends on one.
|
|
20
|
+
*/
|
|
21
|
+
import { outcomeAttributesOf } from "./types.js";
|
|
22
|
+
import { resolveActivity } from "./activity-registry.js";
|
|
23
|
+
import { isStepOutputRef } from "./step-output-ref.js";
|
|
24
|
+
import { parseDuration } from "./duration.js";
|
|
25
|
+
import { stepTimeoutProblem } from "./activity-profiles.js";
|
|
26
|
+
import { describeGateMismatch, evaluateGate, gateIsSealed, gitGateLedgerPort } from "./gate.js";
|
|
27
|
+
import { gateName } from "./gate-name.js";
|
|
28
|
+
import { gatePointOf } from "./gate-point.js";
|
|
29
|
+
import { evaluatePointGate, workspaceGatePointAsker } from "./gate-point-run.js";
|
|
30
|
+
import { GATE_PLAN_CONTEXT_KEY, gatePlanSummaryOfResult } from "./gate-plan-context.js";
|
|
31
|
+
import { withOpRunContext } from "./run-context.js";
|
|
32
|
+
import { isPointWait } from "./steward-points.js";
|
|
33
|
+
import { isGateWait } from "./gate-wait.js";
|
|
34
|
+
import { currentStewardTurn, enterStewardTurn } from "./steward-turn.js";
|
|
35
|
+
import { appendRunRecord, buildRunRecord } from "../lifecycle/run-ledger.js";
|
|
36
|
+
import { randomUUID } from "node:crypto";
|
|
37
|
+
import { RunWorkLease, LEASE_LOST, workLeaseProblems, workLeaseNeedsRunItem } from "./work-lease-run.js";
|
|
38
|
+
import { WORK_LEASE_STEP_ID } from "./types.js";
|
|
39
|
+
import { LiveRun, currentLiveRun, withLiveRun } from "./run-live.js";
|
|
40
|
+
import { runEnvOf } from "../lifecycle/run-ledger.js";
|
|
41
|
+
export { parseDuration } from "./duration.js";
|
|
42
|
+
// ── Errors ────────────────────────────────────────────────────────────────��─
|
|
43
|
+
/**
|
|
44
|
+
* Thrown on terminal Op failure; carries the partial run result for rendering.
|
|
45
|
+
*
|
|
46
|
+
* `cause` is what actually went wrong (#2301). Before it, this class was the
|
|
47
|
+
* end of the line for any error that was not a `PhaseFailure` — the executor
|
|
48
|
+
* caught it, built an `OpRunFailure` from the records it had, and never
|
|
49
|
+
* referenced the error again. Anything thrown outside a step's own
|
|
50
|
+
* error-capturing path therefore reached the operator as `Op "x" failed` and
|
|
51
|
+
* nothing else: no error line, no failing step, exit 1. That is how a gate
|
|
52
|
+
* whose ledger write died on a CI checkout with no `user.email` produced no
|
|
53
|
+
* text naming git, the ledger, or the identity, on INTENTIUS/choudoufu#1026.
|
|
54
|
+
*/
|
|
55
|
+
export class OpRunFailure extends Error {
|
|
56
|
+
constructor(result, options) {
|
|
57
|
+
super(`Op "${result.op}" failed`);
|
|
58
|
+
this.result = result;
|
|
59
|
+
this.name = "OpRunFailure";
|
|
60
|
+
// Assigned rather than passed to `super` — the lib this package compiles
|
|
61
|
+
// against predates Error's `options` parameter.
|
|
62
|
+
if (options && "cause" in options)
|
|
63
|
+
this.cause = options.cause;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Internal: a phase aborted; carries records produced before the abort. */
|
|
67
|
+
class PhaseFailure extends Error {
|
|
68
|
+
constructor(records) {
|
|
69
|
+
super("phase failed");
|
|
70
|
+
this.records = records;
|
|
71
|
+
this.name = "PhaseFailure";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Internal: a phase stopped on an unapproved gate. Not a failure — no compensation follows it. */
|
|
75
|
+
class GateStop extends Error {
|
|
76
|
+
constructor(records, pending, phase,
|
|
77
|
+
/** Whether this run's own append reached the remote — see {@link OpRunResult.gatePushed}. */
|
|
78
|
+
pushed, pushWarning) {
|
|
79
|
+
super(`gate "${pending.gate}" is pending approval`);
|
|
80
|
+
this.records = records;
|
|
81
|
+
this.pending = pending;
|
|
82
|
+
this.phase = phase;
|
|
83
|
+
this.pushed = pushed;
|
|
84
|
+
this.pushWarning = pushWarning;
|
|
85
|
+
this.name = "GateStop";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Internal: a step asked a decision point that is still open (#2749). Not a failure — no compensation follows it. */
|
|
89
|
+
class PointStop extends Error {
|
|
90
|
+
constructor(records, question, phase) {
|
|
91
|
+
super(`waiting on decision point ${question.id}`);
|
|
92
|
+
this.records = records;
|
|
93
|
+
this.question = question;
|
|
94
|
+
this.phase = phase;
|
|
95
|
+
this.name = "PointStop";
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Internal: a step boundary found the run can't go on under its work lease
|
|
100
|
+
* (#2748). `lost` false is a claim that found nothing to claim: not a
|
|
101
|
+
* failure, the run ends `ok` with the rest skipped. `lost` true is a lease
|
|
102
|
+
* that was lost: the run fails with `lease-lost`.
|
|
103
|
+
*/
|
|
104
|
+
class WorkStop extends Error {
|
|
105
|
+
constructor(records, phase, lost) {
|
|
106
|
+
super(lost ? LEASE_LOST : "nothing to claim");
|
|
107
|
+
this.records = records;
|
|
108
|
+
this.phase = phase;
|
|
109
|
+
this.lost = lost;
|
|
110
|
+
this.name = "WorkStop";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ── Helpers ───────────────────────────────────────────────────────────────��─
|
|
114
|
+
const DEFAULT_PROFILE = "fastIdempotent";
|
|
115
|
+
/**
|
|
116
|
+
* The phase a synthetic failure record is filed under when the error did not
|
|
117
|
+
* come from a step (#2301) — a ledger write, an abort, a malformed phase.
|
|
118
|
+
* Named rather than blank so a reader of `--json` or of the run ledger can
|
|
119
|
+
* tell it apart from an authored phase.
|
|
120
|
+
*/
|
|
121
|
+
const UNATTRIBUTED_PHASE = "run";
|
|
122
|
+
const FALLBACK_TIMEOUT_MS = 5 * 60000;
|
|
123
|
+
const isActivity = (s) => s.kind === "activity";
|
|
124
|
+
const isGate = (s) => s.kind === "gate";
|
|
125
|
+
const isEffect = (s) => s.kind === "effect";
|
|
126
|
+
/** Resolve a dot-path into a value; returns the whole value when path is absent. */
|
|
127
|
+
function resolvePath(value, path) {
|
|
128
|
+
if (!path)
|
|
129
|
+
return value;
|
|
130
|
+
return path.split(".").reduce((acc, key) => (acc == null ? acc : acc[key]), value);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Deep-walk `value`, replacing every {@link StepOutputRef} with the recorded
|
|
134
|
+
* result of its producer step, resolved through the ref's optional dot-path
|
|
135
|
+
* exactly like the serializer's compiled `__rN?.path?.segments` (chant #1290)
|
|
136
|
+
* — `resolvePath` gives the same "undefined intermediate resolves to
|
|
137
|
+
* undefined, never throws" semantics. A reference to a step whose result
|
|
138
|
+
* isn't in `resultsById` (never ran, or ran out of the scope
|
|
139
|
+
* `validateStepOutputRefs` allows) resolves to `undefined`, the same way a
|
|
140
|
+
* producer whose declared field is absent would.
|
|
141
|
+
*/
|
|
142
|
+
function resolveStepOutputRefs(value, resultsById) {
|
|
143
|
+
if (isStepOutputRef(value))
|
|
144
|
+
return resolvePath(resultsById.get(value.step), value.path);
|
|
145
|
+
if (Array.isArray(value))
|
|
146
|
+
return value.map((v) => resolveStepOutputRefs(v, resultsById));
|
|
147
|
+
if (value && typeof value === "object") {
|
|
148
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, resolveStepOutputRefs(v, resultsById)]));
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Find the first `policyGate` step anywhere in the Op (phases + `onFailure`,
|
|
154
|
+
* including steps nested inside effect steps), if any.
|
|
155
|
+
*
|
|
156
|
+
* chant #2003 — `--sandbox` is a GLOBAL flag (`../cli/registry.ts`), and
|
|
157
|
+
* `../cli/main.ts` arms the process-wide policy latch off it for every command,
|
|
158
|
+
* `chant run` included. A `policyGate` step then reaches `loadPolicyChecks`,
|
|
159
|
+
* which refuses while armed with a message written for a chant maintainer —
|
|
160
|
+
* shown to a user who passed a documented flag. The combination cannot be
|
|
161
|
+
* honoured until the gate can build and load policies inside the boundary
|
|
162
|
+
* (#1157), so both `chant run` paths pre-flight it with this and refuse before
|
|
163
|
+
* any phase executes. This is the one pre-flight refusal left on the Op path —
|
|
164
|
+
* a `gate` no longer is one (#2119).
|
|
165
|
+
*/
|
|
166
|
+
export function findPolicyGateStep(config) {
|
|
167
|
+
const all = [...config.phases, ...(config.onFailure ?? [])];
|
|
168
|
+
const isPolicyGate = (s) => isActivity(s) && s.fn === "policyGate";
|
|
169
|
+
for (const phase of all) {
|
|
170
|
+
for (const step of phase.steps) {
|
|
171
|
+
if (isPolicyGate(step))
|
|
172
|
+
return step;
|
|
173
|
+
if (isEffect(step)) {
|
|
174
|
+
const nested = step.steps.find(isPolicyGate);
|
|
175
|
+
if (nested)
|
|
176
|
+
return nested;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
183
|
+
/**
|
|
184
|
+
* Race a single activity attempt against its start-to-close timeout. On timeout
|
|
185
|
+
* (or when the run-level `parentSignal` aborts, e.g. Ctrl-C) the attempt's
|
|
186
|
+
* `AbortSignal` fires so the activity can kill its child process, then the call
|
|
187
|
+
* rejects so the retry loop can react. The losing promise is swallowed to keep
|
|
188
|
+
* its eventual rejection from surfacing as an unhandled rejection.
|
|
189
|
+
*/
|
|
190
|
+
async function callWithTimeout(fn, args, timeoutMs, parentSignal) {
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const onParentAbort = () => controller.abort();
|
|
193
|
+
if (parentSignal) {
|
|
194
|
+
if (parentSignal.aborted)
|
|
195
|
+
controller.abort();
|
|
196
|
+
else
|
|
197
|
+
parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
198
|
+
}
|
|
199
|
+
let timer;
|
|
200
|
+
const timeout = new Promise((_, reject) => {
|
|
201
|
+
timer = setTimeout(() => {
|
|
202
|
+
controller.abort();
|
|
203
|
+
reject(new Error(`activity timed out after ${timeoutMs}ms`));
|
|
204
|
+
}, timeoutMs);
|
|
205
|
+
});
|
|
206
|
+
const call = Promise.resolve(fn(args, controller.signal));
|
|
207
|
+
call.catch(() => { }); // losing-race rejection must not become unhandled
|
|
208
|
+
try {
|
|
209
|
+
return await Promise.race([call, timeout]);
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
if (timer)
|
|
213
|
+
clearTimeout(timer);
|
|
214
|
+
if (parentSignal)
|
|
215
|
+
parentSignal.removeEventListener("abort", onParentAbort);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Run one activity step with retry + timeout. Never throws — returns a
|
|
220
|
+
* record. Any {@link StepOutputRef} in `step.args` is resolved against
|
|
221
|
+
* `resultsById` before the activity is called (#1290) — an unresolved
|
|
222
|
+
* placeholder must never reach an activity function, on this runtime or any
|
|
223
|
+
* other; see `resolveStepOutputRefs`.
|
|
224
|
+
*/
|
|
225
|
+
async function runStep(step, phaseName, activities, profiles, resultsById, signal) {
|
|
226
|
+
const args = resolveStepOutputRefs(step.args ?? {}, resultsById);
|
|
227
|
+
const base = { phase: phaseName, fn: step.fn, args };
|
|
228
|
+
const start = Date.now();
|
|
229
|
+
let fn;
|
|
230
|
+
try {
|
|
231
|
+
fn = resolveActivity(activities, step.fn);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
return { record: { ...base, status: "fail", durationMs: 0, error: errMessage(err) } };
|
|
235
|
+
}
|
|
236
|
+
const profile = profiles[step.profile ?? DEFAULT_PROFILE] ?? {};
|
|
237
|
+
// A step's own timeout (#2787) replaces the profile's and keeps its retries.
|
|
238
|
+
if (step.timeout !== undefined) {
|
|
239
|
+
const problem = stepTimeoutProblem(step.timeout);
|
|
240
|
+
if (problem)
|
|
241
|
+
return { record: { ...base, status: "fail", durationMs: 0, error: problem } };
|
|
242
|
+
}
|
|
243
|
+
const timeoutMs = step.timeout !== undefined
|
|
244
|
+
? parseDuration(step.timeout)
|
|
245
|
+
: profile.timeout
|
|
246
|
+
? parseDuration(profile.timeout)
|
|
247
|
+
: FALLBACK_TIMEOUT_MS;
|
|
248
|
+
const maxAttempts = profile.retry?.maximumAttempts && profile.retry.maximumAttempts > 0
|
|
249
|
+
? profile.retry.maximumAttempts
|
|
250
|
+
: 1;
|
|
251
|
+
const initial = profile.retry?.initialInterval ? parseDuration(profile.retry.initialInterval) : 0;
|
|
252
|
+
const backoff = profile.retry?.backoffCoefficient ?? 1;
|
|
253
|
+
const maxInterval = profile.retry?.maximumInterval
|
|
254
|
+
? parseDuration(profile.retry.maximumInterval)
|
|
255
|
+
: Infinity;
|
|
256
|
+
const nonRetryable = profile.retry?.nonRetryableErrorTypes ?? [];
|
|
257
|
+
// The in-flight record names the step while it runs.
|
|
258
|
+
const ended = currentLiveRun()?.stepStarted(step.fn, step.id);
|
|
259
|
+
try {
|
|
260
|
+
return await attempts();
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
ended?.();
|
|
264
|
+
}
|
|
265
|
+
async function attempts() {
|
|
266
|
+
let lastErr;
|
|
267
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
268
|
+
try {
|
|
269
|
+
const result = await callWithTimeout(fn, args, timeoutMs, signal);
|
|
270
|
+
if (step.id)
|
|
271
|
+
resultsById.set(step.id, result);
|
|
272
|
+
const record = { ...base, status: "ok", durationMs: Date.now() - start };
|
|
273
|
+
const attrs = outcomeAttributesOf(step);
|
|
274
|
+
// An attribute whose path the result does not hold is left off, rather than recorded as undefined.
|
|
275
|
+
const outcomes = attrs.map((a) => ({ name: a.name, value: resolvePath(result, a.from) })).filter((o) => o.value !== undefined);
|
|
276
|
+
if (outcomes.length > 0) {
|
|
277
|
+
record.outcomes = outcomes;
|
|
278
|
+
record.outcome = outcomes[0];
|
|
279
|
+
}
|
|
280
|
+
return { record, result };
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
// An open decision point (#2749) is not a failure and not worth a retry:
|
|
284
|
+
// the answer comes from a person, on a later run.
|
|
285
|
+
if (isPointWait(err)) {
|
|
286
|
+
return { record: { ...base, status: "skipped", durationMs: Date.now() - start, point: err.question } };
|
|
287
|
+
}
|
|
288
|
+
// Nor is a command that stopped at a gate of its own (#2779): the run
|
|
289
|
+
// ends `gated` there, and the next run asks the command again.
|
|
290
|
+
if (isGateWait(err)) {
|
|
291
|
+
const gate = { op: err.pending.op, gate: err.pending.gate };
|
|
292
|
+
return { record: { ...base, status: "skipped", durationMs: Date.now() - start, gate }, pending: err.pending };
|
|
293
|
+
}
|
|
294
|
+
lastErr = err;
|
|
295
|
+
// Stop retrying on abort (Ctrl-C / timeout cascade) or a non-retryable error.
|
|
296
|
+
const fatal = signal?.aborted || (err instanceof Error && nonRetryable.includes(err.name));
|
|
297
|
+
if (!fatal && attempt < maxAttempts) {
|
|
298
|
+
const wait = Math.min(initial * Math.pow(backoff, attempt - 1), maxInterval);
|
|
299
|
+
if (wait > 0)
|
|
300
|
+
await sleep(wait);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return { record: { ...base, status: "fail", durationMs: Date.now() - start, error: errMessage(lastErr) } };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// ── Effect steps (#1834) ──────────────────────────────────────────────────────
|
|
310
|
+
/** The step data the executor synthesizes to read a receipt through the store
|
|
311
|
+
* activities (`receiptRead`/`receiptWrite` — provided by the receipt row's
|
|
312
|
+
* lexicon, #1835, or a mock store in tests via `receiptActivities`). */
|
|
313
|
+
function receiptReadStep(step) {
|
|
314
|
+
return {
|
|
315
|
+
kind: "activity",
|
|
316
|
+
fn: "receiptRead",
|
|
317
|
+
args: {
|
|
318
|
+
receipt: step.receipt,
|
|
319
|
+
...(step.expectation !== undefined ? { expectation: step.expectation } : {}),
|
|
320
|
+
},
|
|
321
|
+
profile: "fastIdempotent",
|
|
322
|
+
outcomeAttribute: { name: "EffectApplied", from: "applied" },
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/** A skipped-record for a step that will not run. */
|
|
326
|
+
function skippedRecord(phaseName, fn, args) {
|
|
327
|
+
return { phase: phaseName, fn, args: args ?? {}, status: "skipped", durationMs: 0 };
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The work lease at a step boundary (#2748): claim it when it is due, and
|
|
331
|
+
* say whether the run can go on. The claim's record is pushed onto `sink`.
|
|
332
|
+
* Returns `undefined` to go on, `"unclaimed"` when nothing could be claimed,
|
|
333
|
+
* and `"lost"` when the lease was lost.
|
|
334
|
+
*/
|
|
335
|
+
async function workBoundary(phaseName, ctx, resultsById, sink) {
|
|
336
|
+
const work = ctx.work;
|
|
337
|
+
if (!work)
|
|
338
|
+
return undefined;
|
|
339
|
+
if (work.due(resultsById)) {
|
|
340
|
+
const start = Date.now();
|
|
341
|
+
let claimed;
|
|
342
|
+
try {
|
|
343
|
+
claimed = await work.claim(resultsById);
|
|
344
|
+
}
|
|
345
|
+
catch (err) {
|
|
346
|
+
pushRecord(sink, ctx, {
|
|
347
|
+
phase: phaseName,
|
|
348
|
+
fn: "workLease:claim",
|
|
349
|
+
args: {},
|
|
350
|
+
status: "fail",
|
|
351
|
+
durationMs: Date.now() - start,
|
|
352
|
+
error: errMessage(err),
|
|
353
|
+
});
|
|
354
|
+
throw new PhaseFailure(sink);
|
|
355
|
+
}
|
|
356
|
+
if (claimed.kind === "unclaimed") {
|
|
357
|
+
pushRecord(sink, ctx, {
|
|
358
|
+
phase: phaseName,
|
|
359
|
+
fn: "workLease:claim",
|
|
360
|
+
args: { items: claimed.tried },
|
|
361
|
+
status: "skipped",
|
|
362
|
+
durationMs: Date.now() - start,
|
|
363
|
+
refusal: claimed.refusal,
|
|
364
|
+
outcome: { name: "WorkItem", value: null },
|
|
365
|
+
outcomes: [{ name: "WorkItem", value: null }],
|
|
366
|
+
});
|
|
367
|
+
return "unclaimed";
|
|
368
|
+
}
|
|
369
|
+
resultsById.set(WORK_LEASE_STEP_ID, claimed.lease);
|
|
370
|
+
currentLiveRun()?.item(claimed.lease.item);
|
|
371
|
+
pushRecord(sink, ctx, {
|
|
372
|
+
phase: phaseName,
|
|
373
|
+
fn: "workLease:claim",
|
|
374
|
+
args: { items: claimed.tried },
|
|
375
|
+
status: "ok",
|
|
376
|
+
durationMs: Date.now() - start,
|
|
377
|
+
outcome: { name: "WorkItem", value: claimed.lease.item },
|
|
378
|
+
outcomes: [
|
|
379
|
+
{ name: "WorkItem", value: claimed.lease.item },
|
|
380
|
+
{ name: "WorkLeaseToken", value: claimed.lease.token },
|
|
381
|
+
],
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return work.lost !== undefined ? "lost" : undefined;
|
|
385
|
+
}
|
|
386
|
+
/** Collect records and hand each to the caller's progress sink in one move. */
|
|
387
|
+
function pushRecord(sink, ctx, ...recs) {
|
|
388
|
+
sink.push(...recs);
|
|
389
|
+
for (const r of recs)
|
|
390
|
+
ctx.onRecord?.(r);
|
|
391
|
+
}
|
|
392
|
+
/** The record name a gate step lands under, so a reader (and a JSON consumer) can pick it out of `records`. */
|
|
393
|
+
function gateFn(step) {
|
|
394
|
+
return `gate:${gateName(step)}`;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* A gate's `approval` block as this run resolves it (#2508): each context
|
|
398
|
+
* value that is a step-output reference is replaced by what that step
|
|
399
|
+
* returned, the same walk `plan` goes through. A reference that resolves to
|
|
400
|
+
* nothing is dropped rather than failing the run, so a policy reading it sees
|
|
401
|
+
* the attribute as absent.
|
|
402
|
+
*/
|
|
403
|
+
function resolveGateApproval(step, resultsById) {
|
|
404
|
+
const authored = step.approval;
|
|
405
|
+
if (!authored)
|
|
406
|
+
return undefined;
|
|
407
|
+
let context;
|
|
408
|
+
if (authored.context) {
|
|
409
|
+
context = {};
|
|
410
|
+
for (const [key, value] of Object.entries(authored.context)) {
|
|
411
|
+
const resolved = resolveStepOutputRefs(value, resultsById);
|
|
412
|
+
if (resolved !== undefined && resolved !== null)
|
|
413
|
+
context[key] = resolved;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
// #3182: a policy also sees what the plan does. When the gate's `plan`
|
|
417
|
+
// names the step that planned it and that step returned a change set, its
|
|
418
|
+
// summary lands under `context.plan` with no context code in the Op.
|
|
419
|
+
if (authored.policy && isStepOutputRef(step.plan)) {
|
|
420
|
+
const summary = gatePlanSummaryOfResult(resultsById.get(step.plan.step));
|
|
421
|
+
if (summary)
|
|
422
|
+
context = { ...(context ?? {}), [GATE_PLAN_CONTEXT_KEY]: summary };
|
|
423
|
+
}
|
|
424
|
+
return {
|
|
425
|
+
...(authored.quorum ? { quorum: authored.quorum } : {}),
|
|
426
|
+
...(authored.policy ? { policy: authored.policy } : {}),
|
|
427
|
+
mode: authored.mode ?? "log-only",
|
|
428
|
+
...(context ? { context } : {}),
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Decide one gate against the ledger. A resolution newer than the gate's
|
|
433
|
+
* newest pending fact passes it, and the approver lands on the step record; a
|
|
434
|
+
* pending fact is recorded (or left standing) otherwise, and the caller stops
|
|
435
|
+
* the run.
|
|
436
|
+
*/
|
|
437
|
+
async function runGateStep(step, phaseName, gates, resultsById = new Map()) {
|
|
438
|
+
if (step.point !== undefined)
|
|
439
|
+
return runPointGateStep(step, phaseName, gates, resultsById);
|
|
440
|
+
const start = Date.now();
|
|
441
|
+
// #2300: `plan` is authored as a reference into the Plan phase's result
|
|
442
|
+
// (`plan.out.planDigest`), and is resolved here through the same walk an
|
|
443
|
+
// activity's args go through. A reference that resolves to anything but a
|
|
444
|
+
// string leaves the gate unbound — the pre-#2300 rule — rather than failing
|
|
445
|
+
// a run over a missing digest.
|
|
446
|
+
const resolvedPlan = resolveStepOutputRefs(step.plan, resultsById);
|
|
447
|
+
const planDigest = typeof resolvedPlan === "string" && resolvedPlan !== "" ? resolvedPlan : undefined;
|
|
448
|
+
const approval = resolveGateApproval(step, resultsById);
|
|
449
|
+
let check;
|
|
450
|
+
try {
|
|
451
|
+
check = await evaluateGate(gates.port, {
|
|
452
|
+
op: gates.op,
|
|
453
|
+
gate: gateName(step),
|
|
454
|
+
...(step.description ? { description: step.description } : {}),
|
|
455
|
+
...(step.timeout ? { timeout: step.timeout } : {}),
|
|
456
|
+
...(gates.runId ? { runId: gates.runId } : {}),
|
|
457
|
+
...(planDigest !== undefined ? { planDigest } : {}),
|
|
458
|
+
...(approval ? { approval } : {}),
|
|
459
|
+
...(gates.now ? { now: gates.now } : {}),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
// Deciding a gate reads and writes the `chant/lifecycle` branch, so it
|
|
464
|
+
// fails for all the ordinary git reasons — no committer identity, an
|
|
465
|
+
// unfetched ledger, a rejected ref update. `runStep` has always turned an
|
|
466
|
+
// activity's throw into a failing `StepRecord` carrying the message
|
|
467
|
+
// ("Never throws — returns a record"); `runGateStep` did not, which made
|
|
468
|
+
// the gate the one step kind whose failure produced no record and so no
|
|
469
|
+
// rendered output at all (#2301). It does now, and the phase treats it
|
|
470
|
+
// like any other failing step.
|
|
471
|
+
return {
|
|
472
|
+
record: {
|
|
473
|
+
phase: phaseName,
|
|
474
|
+
fn: gateFn(step),
|
|
475
|
+
args: {},
|
|
476
|
+
status: "fail",
|
|
477
|
+
durationMs: Date.now() - start,
|
|
478
|
+
error: errMessage(err),
|
|
479
|
+
},
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
if (check.satisfied) {
|
|
483
|
+
const { resolution } = check;
|
|
484
|
+
const passedApproval = {
|
|
485
|
+
gate: gateName(step),
|
|
486
|
+
resolvedBy: resolution.resolvedBy,
|
|
487
|
+
timestamp: resolution.timestamp,
|
|
488
|
+
...(resolution.url ? { url: resolution.url } : {}),
|
|
489
|
+
...(check.via ? { via: check.via } : {}),
|
|
490
|
+
...(check.approvals ? { approvers: check.approvals.map((r) => r.resolvedBy) } : {}),
|
|
491
|
+
};
|
|
492
|
+
// #2522: a later step reads this gate's approval from the run context
|
|
493
|
+
// rather than re-tallying the ledger, so it sees the decision this run made.
|
|
494
|
+
gates.passed?.push({ gate: gateName(step), approval: passedApproval });
|
|
495
|
+
return {
|
|
496
|
+
record: {
|
|
497
|
+
phase: phaseName,
|
|
498
|
+
fn: gateFn(step),
|
|
499
|
+
args: {},
|
|
500
|
+
status: "ok",
|
|
501
|
+
durationMs: Date.now() - start,
|
|
502
|
+
approval: passedApproval,
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const refusal = check.mismatch
|
|
507
|
+
? { refusal: describeGateMismatch(gates.op, gateName(step), check.mismatch, await gateIsSealed(gateName(step))) }
|
|
508
|
+
: {};
|
|
509
|
+
return {
|
|
510
|
+
record: {
|
|
511
|
+
phase: phaseName,
|
|
512
|
+
fn: gateFn(step),
|
|
513
|
+
args: {},
|
|
514
|
+
status: "skipped",
|
|
515
|
+
durationMs: Date.now() - start,
|
|
516
|
+
...refusal,
|
|
517
|
+
},
|
|
518
|
+
pending: check.pending,
|
|
519
|
+
pushed: check.pushed,
|
|
520
|
+
...(check.pushWarning ? { pushWarning: check.pushWarning } : {}),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Decide a gate that asks a decision point (#3170, `./gate-point-run.ts`).
|
|
525
|
+
* An answer it passes on lands on the step record as the approval, citing
|
|
526
|
+
* the answer record; an open question puts the question on the record, as an
|
|
527
|
+
* activity's open point does, and the caller ends the run `waiting`; any
|
|
528
|
+
* other answer fails the step.
|
|
529
|
+
*/
|
|
530
|
+
async function runPointGateStep(step, phaseName, gates, resultsById) {
|
|
531
|
+
const start = Date.now();
|
|
532
|
+
const point = gatePointOf(step.point);
|
|
533
|
+
const base = { phase: phaseName, fn: gateFn(step), args: {} };
|
|
534
|
+
const resolvedPlan = resolveStepOutputRefs(step.plan, resultsById);
|
|
535
|
+
const planDigest = typeof resolvedPlan === "string" && resolvedPlan !== "" ? resolvedPlan : undefined;
|
|
536
|
+
const inputs = point.inputs ? resolveStepOutputRefs(point.inputs, resultsById) : undefined;
|
|
537
|
+
try {
|
|
538
|
+
const check = await evaluatePointGate(gates.port, gates.points ?? workspaceGatePointAsker(process.cwd()), {
|
|
539
|
+
op: gates.op,
|
|
540
|
+
gate: gateName(step),
|
|
541
|
+
point,
|
|
542
|
+
...(inputs ? { inputs } : {}),
|
|
543
|
+
...(step.description ? { description: step.description } : {}),
|
|
544
|
+
...(step.timeout ? { timeout: step.timeout } : {}),
|
|
545
|
+
...(gates.runId ? { runId: gates.runId } : {}),
|
|
546
|
+
...(planDigest !== undefined ? { planDigest } : {}),
|
|
547
|
+
...(gates.env !== undefined ? { env: gates.env } : {}),
|
|
548
|
+
...(gates.now ? { now: gates.now } : {}),
|
|
549
|
+
});
|
|
550
|
+
if (check.satisfied) {
|
|
551
|
+
const approval = {
|
|
552
|
+
gate: gateName(step),
|
|
553
|
+
resolvedBy: check.resolution.resolvedBy,
|
|
554
|
+
timestamp: check.resolution.timestamp,
|
|
555
|
+
via: "point",
|
|
556
|
+
...(check.answer.answeredBy ? { approvers: check.answer.answeredBy } : {}),
|
|
557
|
+
answer: check.answer,
|
|
558
|
+
};
|
|
559
|
+
gates.passed?.push({ gate: gateName(step), approval });
|
|
560
|
+
return { record: { ...base, status: "ok", durationMs: Date.now() - start, approval }, pushed: check.pushed, ...(check.pushWarning ? { pushWarning: check.pushWarning } : {}) };
|
|
561
|
+
}
|
|
562
|
+
if ("refused" in check)
|
|
563
|
+
return { record: { ...base, status: "fail", durationMs: Date.now() - start, error: check.refused } };
|
|
564
|
+
return { record: { ...base, status: "skipped", durationMs: Date.now() - start, point: check.waiting }, pushed: check.pushed, ...(check.pushWarning ? { pushWarning: check.pushWarning } : {}) };
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
return { record: { ...base, status: "fail", durationMs: Date.now() - start, error: errMessage(err) } };
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Run one effect step: read-compare-run-write. On a match the nested steps are
|
|
572
|
+
* recorded as skipped ("effect already applied") and nothing is written. On a
|
|
573
|
+
* mismatch the nested steps run in authored order; only when every one
|
|
574
|
+
* succeeds is the receipt written — last, once (the sole writer, #1703
|
|
575
|
+
* decision 3). Any failure leaves the receipt untouched (stale), so the next
|
|
576
|
+
* run re-proposes the effect.
|
|
577
|
+
*
|
|
578
|
+
* A nested `gate` is decided in authored order like any other nested step
|
|
579
|
+
* (#2119). Unapproved, it stops the effect before the receipt is written, so
|
|
580
|
+
* the next run re-reads the receipt, re-proposes the effect, and re-evaluates
|
|
581
|
+
* the gate — the receipt stays honest about what actually happened.
|
|
582
|
+
*/
|
|
583
|
+
async function runEffectStep(step, phaseName, activities, profiles, resultsById, gates, signal) {
|
|
584
|
+
const records = [];
|
|
585
|
+
const read = await runStep(receiptReadStep(step), phaseName, activities, profiles, resultsById, signal);
|
|
586
|
+
pushRecord(records, gates, read.record);
|
|
587
|
+
if (read.record.status === "fail")
|
|
588
|
+
return { records, failed: true };
|
|
589
|
+
const result = read.result;
|
|
590
|
+
if (typeof result?.expectation !== "string") {
|
|
591
|
+
pushRecord(records, gates, {
|
|
592
|
+
phase: phaseName,
|
|
593
|
+
fn: `effect:${step.receipt.name}`,
|
|
594
|
+
args: {},
|
|
595
|
+
status: "fail",
|
|
596
|
+
durationMs: 0,
|
|
597
|
+
error: "receiptRead returned no expectation — the receipt store activity must return { current, expectation }",
|
|
598
|
+
});
|
|
599
|
+
return { records, failed: true };
|
|
600
|
+
}
|
|
601
|
+
const expectation = result.expectation;
|
|
602
|
+
if (result.current === expectation) {
|
|
603
|
+
// Effect already applied — skip the nested steps, write nothing.
|
|
604
|
+
for (const nested of step.steps) {
|
|
605
|
+
pushRecord(records, gates, nested.kind === "activity"
|
|
606
|
+
? skippedRecord(phaseName, nested.fn, nested.args)
|
|
607
|
+
: skippedRecord(phaseName, gateFn(nested)));
|
|
608
|
+
}
|
|
609
|
+
return { records, failed: false };
|
|
610
|
+
}
|
|
611
|
+
const skipRest = (from) => {
|
|
612
|
+
for (const skipped of step.steps.slice(from)) {
|
|
613
|
+
pushRecord(records, gates, skipped.kind === "activity"
|
|
614
|
+
? skippedRecord(phaseName, skipped.fn, skipped.args)
|
|
615
|
+
: skippedRecord(phaseName, gateFn(skipped)));
|
|
616
|
+
}
|
|
617
|
+
pushRecord(records, gates, skippedRecord(phaseName, "receiptWrite"));
|
|
618
|
+
};
|
|
619
|
+
for (let i = 0; i < step.steps.length; i++) {
|
|
620
|
+
const nested = step.steps[i];
|
|
621
|
+
if (isGate(nested)) {
|
|
622
|
+
const { record, pending, pushed, pushWarning } = await runGateStep(nested, phaseName, gates, resultsById);
|
|
623
|
+
pushRecord(records, gates, record);
|
|
624
|
+
if (record.status === "fail") {
|
|
625
|
+
// Receipt left untouched, as for any other failing nested step
|
|
626
|
+
// (#2301) — the effect is not applied and the next run re-proposes it.
|
|
627
|
+
skipRest(i + 1);
|
|
628
|
+
return { records, failed: true };
|
|
629
|
+
}
|
|
630
|
+
if (pending) {
|
|
631
|
+
// Receipt left untouched — the next run re-proposes the effect and
|
|
632
|
+
// re-evaluates the gate against whatever the ledger says by then.
|
|
633
|
+
skipRest(i + 1);
|
|
634
|
+
return { records, failed: false, pending, pushed, ...(pushWarning ? { pushWarning } : {}) };
|
|
635
|
+
}
|
|
636
|
+
if (record.point) {
|
|
637
|
+
// A gate's open decision point (#3170): as for an activity's.
|
|
638
|
+
skipRest(i + 1);
|
|
639
|
+
return { records, failed: false, point: record.point };
|
|
640
|
+
}
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
const ran = await runStep(nested, phaseName, activities, profiles, resultsById, signal);
|
|
644
|
+
pushRecord(records, gates, ran.record);
|
|
645
|
+
if (ran.pending) {
|
|
646
|
+
// A command's own gate (#2779): the receipt is left untouched, as for a
|
|
647
|
+
// pending gate step.
|
|
648
|
+
skipRest(i + 1);
|
|
649
|
+
return { records, failed: false, pending: ran.pending };
|
|
650
|
+
}
|
|
651
|
+
if (ran.record.point) {
|
|
652
|
+
// Receipt left untouched, as for a pending gate: the next run re-proposes
|
|
653
|
+
// the effect and asks the point again, and finds the answer by then.
|
|
654
|
+
skipRest(i + 1);
|
|
655
|
+
return { records, failed: false, point: ran.record.point };
|
|
656
|
+
}
|
|
657
|
+
if (ran.record.status === "fail") {
|
|
658
|
+
// Receipt left untouched (stale) — the next run re-proposes the effect.
|
|
659
|
+
skipRest(i + 1);
|
|
660
|
+
return { records, failed: true };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// Sole writer of the receipt: on success of every nested step, last.
|
|
664
|
+
const wrote = await runStep({
|
|
665
|
+
kind: "activity",
|
|
666
|
+
fn: "receiptWrite",
|
|
667
|
+
args: { receipt: step.receipt, expectation },
|
|
668
|
+
profile: "fastIdempotent",
|
|
669
|
+
}, phaseName, activities, profiles, resultsById, signal);
|
|
670
|
+
pushRecord(records, gates, wrote.record);
|
|
671
|
+
return { records, failed: wrote.record.status === "fail" };
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Run a phase. Throws `PhaseFailure` (with the records so far) if any step
|
|
675
|
+
* fails, or `GateStop` if a `gate` step in it is still pending approval.
|
|
676
|
+
*/
|
|
677
|
+
async function runPhase(phase, activities, profiles, resultsById, gates, signal) {
|
|
678
|
+
if (phase.parallel) {
|
|
679
|
+
const eff = phase.steps.find(isEffect);
|
|
680
|
+
if (eff) {
|
|
681
|
+
throw new Error(`effect step "${eff.receipt.name}" cannot run in a parallel phase — read-compare-run-write is ordered`);
|
|
682
|
+
}
|
|
683
|
+
// Gates in a parallel phase are decided before the fan-out: a gate is a
|
|
684
|
+
// read of the ledger, not work, and starting activities that a pending
|
|
685
|
+
// gate is about to strand would defeat the point of stopping at it.
|
|
686
|
+
const gateRecords = [];
|
|
687
|
+
const stop = await workBoundary(phase.name, gates, resultsById, gateRecords);
|
|
688
|
+
if (stop) {
|
|
689
|
+
for (const skipped of phase.steps) {
|
|
690
|
+
pushRecord(gateRecords, gates, isGate(skipped) ? skippedRecord(phase.name, gateFn(skipped)) : skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
691
|
+
}
|
|
692
|
+
throw new WorkStop(gateRecords, phase.name, stop === "lost");
|
|
693
|
+
}
|
|
694
|
+
for (const step of phase.steps.filter(isGate)) {
|
|
695
|
+
const { record, pending, pushed, pushWarning } = await runGateStep(step, phase.name, gates, resultsById);
|
|
696
|
+
pushRecord(gateRecords, gates, record);
|
|
697
|
+
if (record.status === "fail") {
|
|
698
|
+
// The gate could not be decided at all (#2301). Same treatment as a
|
|
699
|
+
// pending one: nothing fans out, the activities are recorded skipped.
|
|
700
|
+
for (const skipped of phase.steps.filter(isActivity)) {
|
|
701
|
+
pushRecord(gateRecords, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
702
|
+
}
|
|
703
|
+
throw new PhaseFailure(gateRecords);
|
|
704
|
+
}
|
|
705
|
+
if (pending) {
|
|
706
|
+
for (const skipped of phase.steps.filter(isActivity)) {
|
|
707
|
+
pushRecord(gateRecords, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
708
|
+
}
|
|
709
|
+
throw new GateStop(gateRecords, pending, phase.name, pushed, pushWarning);
|
|
710
|
+
}
|
|
711
|
+
if (record.point) {
|
|
712
|
+
// A gate's open decision point (#3170): nothing fans out.
|
|
713
|
+
for (const skipped of phase.steps.filter(isActivity)) {
|
|
714
|
+
pushRecord(gateRecords, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
715
|
+
}
|
|
716
|
+
throw new PointStop(gateRecords, record.point, phase.name);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
const steps = phase.steps.filter(isActivity);
|
|
720
|
+
const settled = await Promise.all(steps.map((s) => runStep(s, phase.name, activities, profiles, resultsById, signal)));
|
|
721
|
+
const ran = settled.map((r) => r.record);
|
|
722
|
+
for (const r of ran)
|
|
723
|
+
gates.onRecord?.(r);
|
|
724
|
+
const records = gateRecords.concat(ran);
|
|
725
|
+
if (records.some((r) => r.status === "fail"))
|
|
726
|
+
throw new PhaseFailure(records);
|
|
727
|
+
// A step whose command stopped at its own gate (#2779) stops the run at
|
|
728
|
+
// this phase, as a gate step would, once its siblings have finished.
|
|
729
|
+
const gated = settled.find((r) => r.pending)?.pending;
|
|
730
|
+
if (gated)
|
|
731
|
+
throw new GateStop(records, gated, phase.name);
|
|
732
|
+
// The fan-out has already run, so the siblings of an open decision point
|
|
733
|
+
// finished; the run still stops at this phase (#2749).
|
|
734
|
+
const waiting = ran.find((r) => r.point);
|
|
735
|
+
if (waiting?.point)
|
|
736
|
+
throw new PointStop(records, waiting.point, phase.name);
|
|
737
|
+
return records;
|
|
738
|
+
}
|
|
739
|
+
const steps = phase.steps;
|
|
740
|
+
const records = [];
|
|
741
|
+
const skipRemaining = (from) => {
|
|
742
|
+
for (const skipped of steps.slice(from)) {
|
|
743
|
+
if (isEffect(skipped)) {
|
|
744
|
+
pushRecord(records, gates, skippedRecord(phase.name, `effect:${skipped.receipt.name}`));
|
|
745
|
+
}
|
|
746
|
+
else if (isGate(skipped)) {
|
|
747
|
+
pushRecord(records, gates, skippedRecord(phase.name, gateFn(skipped)));
|
|
748
|
+
}
|
|
749
|
+
else {
|
|
750
|
+
pushRecord(records, gates, skippedRecord(phase.name, skipped.fn, skipped.args));
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
for (let i = 0; i < steps.length; i++) {
|
|
755
|
+
const step = steps[i];
|
|
756
|
+
// The work lease (#2748): claimed here when it is due, and checked before
|
|
757
|
+
// every step, so no step starts once the lease is lost.
|
|
758
|
+
const stop = await workBoundary(phase.name, gates, resultsById, records);
|
|
759
|
+
if (stop) {
|
|
760
|
+
skipRemaining(i);
|
|
761
|
+
throw new WorkStop(records, phase.name, stop === "lost");
|
|
762
|
+
}
|
|
763
|
+
if (isGate(step)) {
|
|
764
|
+
const { record, pending, pushed, pushWarning } = await runGateStep(step, phase.name, gates, resultsById);
|
|
765
|
+
pushRecord(records, gates, record);
|
|
766
|
+
if (record.status === "fail") {
|
|
767
|
+
// A gate that could not be decided is a failed step, not a pending
|
|
768
|
+
// one (#2301) — the run failed, and the record says why.
|
|
769
|
+
skipRemaining(i + 1);
|
|
770
|
+
throw new PhaseFailure(records);
|
|
771
|
+
}
|
|
772
|
+
if (pending) {
|
|
773
|
+
skipRemaining(i + 1);
|
|
774
|
+
throw new GateStop(records, pending, phase.name, pushed, pushWarning);
|
|
775
|
+
}
|
|
776
|
+
if (record.point) {
|
|
777
|
+
// A gate that asks a decision point (#3170) and found it open: the
|
|
778
|
+
// run waits on the question, as at an activity's open point.
|
|
779
|
+
skipRemaining(i + 1);
|
|
780
|
+
throw new PointStop(records, record.point, phase.name);
|
|
781
|
+
}
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
if (isEffect(step)) {
|
|
785
|
+
const { records: effRecords, failed, pending, pushed, pushWarning, point } = await runEffectStep(step, phase.name, activities, profiles, resultsById, gates, signal);
|
|
786
|
+
records.push(...effRecords); // already emitted by runEffectStep
|
|
787
|
+
if (point) {
|
|
788
|
+
skipRemaining(i + 1);
|
|
789
|
+
throw new PointStop(records, point, phase.name);
|
|
790
|
+
}
|
|
791
|
+
if (pending) {
|
|
792
|
+
skipRemaining(i + 1);
|
|
793
|
+
throw new GateStop(records, pending, phase.name, pushed, pushWarning);
|
|
794
|
+
}
|
|
795
|
+
if (failed) {
|
|
796
|
+
skipRemaining(i + 1);
|
|
797
|
+
throw new PhaseFailure(records);
|
|
798
|
+
}
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
const { record, pending } = await runStep(step, phase.name, activities, profiles, resultsById, signal);
|
|
802
|
+
pushRecord(records, gates, record);
|
|
803
|
+
if (pending) {
|
|
804
|
+
// The step's command stopped at its own gate (#2779): the run ends
|
|
805
|
+
// `gated` there, as at a pending gate step.
|
|
806
|
+
skipRemaining(i + 1);
|
|
807
|
+
throw new GateStop(records, pending, phase.name);
|
|
808
|
+
}
|
|
809
|
+
if (record.point) {
|
|
810
|
+
// An open decision point (#2749) ends the run as a pending gate does.
|
|
811
|
+
skipRemaining(i + 1);
|
|
812
|
+
throw new PointStop(records, record.point, phase.name);
|
|
813
|
+
}
|
|
814
|
+
if (record.status === "fail") {
|
|
815
|
+
// Mark the remaining steps in this phase as skipped, then abort.
|
|
816
|
+
skipRemaining(i + 1);
|
|
817
|
+
throw new PhaseFailure(records);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return records;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Execute an Op locally.
|
|
824
|
+
*
|
|
825
|
+
* Resolves with the run result when every phase succeeds (`status: "ok"`), and
|
|
826
|
+
* also when the run stopped at an unapproved gate (`status: "gated"`, with the
|
|
827
|
+
* pending fact on `result.gate`) — a gate is a fact, not an error, so it is not
|
|
828
|
+
* thrown. So does an activity's open decision point (`status: "waiting"`, with
|
|
829
|
+
* the question on `result.point`, #2749). Rejects with `OpRunFailure` (carrying the partial result) on terminal
|
|
830
|
+
* failure, after running any `onFailure` phases in reverse order; a gated or
|
|
831
|
+
* waiting run runs no `onFailure` phase, because nothing failed and nothing was left
|
|
832
|
+
* half-applied to compensate for.
|
|
833
|
+
*
|
|
834
|
+
* Whichever of the three ways it settles, the run carries an
|
|
835
|
+
* {@link OpRunRecord} on `result.record` (#2118). With `options.ledger` that
|
|
836
|
+
* record is also appended to `<env>/runs__<op>.jsonl` on the lifecycle branch
|
|
837
|
+
* before this returns or rejects, so an Op's outcome outlives the process that
|
|
838
|
+
* produced it.
|
|
839
|
+
*/
|
|
840
|
+
export async function runOpLocally(config, activities, profiles, signal, options = {}) {
|
|
841
|
+
// The run id is the gate ledger's and the run ledger's alike: a pending gate
|
|
842
|
+
// fact and the record naming that gate carry the same string.
|
|
843
|
+
const runId = options.runId ?? randomUUID();
|
|
844
|
+
// In a steward's turn (#2749: `chant operator --steward`, or `chant acp
|
|
845
|
+
// --steward` on Fountain) the run is the steward's: its record names the
|
|
846
|
+
// steward, and a decision point asked during it names this run.
|
|
847
|
+
const turn = currentStewardTurn();
|
|
848
|
+
const steward = options.steward ?? turn?.steward;
|
|
849
|
+
const restore = turn && turn.run !== runId ? enterStewardTurn({ ...turn, run: runId }) : undefined;
|
|
850
|
+
// #2522: every activity in this run can read the run it is in.
|
|
851
|
+
const run = {
|
|
852
|
+
op: config.name,
|
|
853
|
+
runId,
|
|
854
|
+
...(options.env !== undefined ? { env: options.env } : {}),
|
|
855
|
+
passedGates: [],
|
|
856
|
+
};
|
|
857
|
+
// A run that writes to the ledger also says what it is doing while it runs
|
|
858
|
+
// (./run-live.ts), and removes that once its record is written.
|
|
859
|
+
const live = options.ledger
|
|
860
|
+
? await LiveRun.open({
|
|
861
|
+
cwd: options.ledger.cwd ?? options.cwd ?? process.cwd(),
|
|
862
|
+
env: runEnvOf(config),
|
|
863
|
+
op: config.name,
|
|
864
|
+
id: runId,
|
|
865
|
+
started: options.now ?? new Date().toISOString(),
|
|
866
|
+
...(steward ? { steward } : {}),
|
|
867
|
+
})
|
|
868
|
+
: undefined;
|
|
869
|
+
try {
|
|
870
|
+
return await withLiveRun(live, () => withOpRunContext(run, () => runOpInTurn(config, activities, profiles, signal, { ...options, runId, ...(steward ? { steward } : {}) }, run)));
|
|
871
|
+
}
|
|
872
|
+
finally {
|
|
873
|
+
live?.close();
|
|
874
|
+
restore?.();
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
async function runOpInTurn(config, activities, profiles, signal, options, run) {
|
|
878
|
+
const runId = options.runId;
|
|
879
|
+
const gates = {
|
|
880
|
+
op: config.name,
|
|
881
|
+
port: options.gates ?? gitGateLedgerPort(options.cwd ? { cwd: options.cwd } : undefined),
|
|
882
|
+
...(options.now ? { now: options.now } : {}),
|
|
883
|
+
runId,
|
|
884
|
+
...(options.onRecord ? { onRecord: options.onRecord } : {}),
|
|
885
|
+
passed: run.passedGates,
|
|
886
|
+
points: options.points ?? workspaceGatePointAsker(options.cwd ?? process.cwd()),
|
|
887
|
+
...(options.env !== undefined ? { env: options.env } : {}),
|
|
888
|
+
};
|
|
889
|
+
// Effect steps are ordered (read-compare-run-write): refuse them in a
|
|
890
|
+
// parallel phase up front, with the phase named, rather than mid-run.
|
|
891
|
+
for (const phase of [...config.phases, ...(config.onFailure ?? [])]) {
|
|
892
|
+
const eff = phase.parallel ? phase.steps.find(isEffect) : undefined;
|
|
893
|
+
if (eff) {
|
|
894
|
+
throw new Error(`phase "${phase.name}": effect step "${eff.receipt.name}" cannot run in a ` +
|
|
895
|
+
`parallel phase — read-compare-run-write is ordered`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
// The work lease (#2748). An Op that changes the checkout without one, or
|
|
899
|
+
// whose lease names no item and whose run names none, is refused before
|
|
900
|
+
// anything runs.
|
|
901
|
+
const workProblems = workLeaseProblems(config);
|
|
902
|
+
if (workProblems.length > 0)
|
|
903
|
+
throw new Error(workProblems.join("\n"));
|
|
904
|
+
if (workLeaseNeedsRunItem(config) && !options.work?.item) {
|
|
905
|
+
throw new Error(`Op "${config.name}" runs under a work item's lease and names no item: pass one with \`chant run ${config.name} --work <id>\``);
|
|
906
|
+
}
|
|
907
|
+
const work = config.workLease
|
|
908
|
+
? new RunWorkLease(config, {
|
|
909
|
+
cwd: options.ledger?.cwd ?? options.cwd ?? process.cwd(),
|
|
910
|
+
...(options.work?.holder ? { holder: options.work.holder } : {}),
|
|
911
|
+
...(options.work?.item ? { item: options.work.item } : {}),
|
|
912
|
+
...(options.onWorkLeaseWarning ? { onRenewError: options.onWorkLeaseWarning } : {}),
|
|
913
|
+
})
|
|
914
|
+
: undefined;
|
|
915
|
+
if (work)
|
|
916
|
+
gates.work = work;
|
|
917
|
+
// Steps run under a signal that also fires when the work lease is lost, so
|
|
918
|
+
// the step in flight stops (chud's dispatcher stopped its agent the same way).
|
|
919
|
+
let stepSignal = signal;
|
|
920
|
+
if (work) {
|
|
921
|
+
const both = new AbortController();
|
|
922
|
+
const forward = () => both.abort();
|
|
923
|
+
if (signal?.aborted)
|
|
924
|
+
both.abort();
|
|
925
|
+
else
|
|
926
|
+
signal?.addEventListener("abort", forward, { once: true });
|
|
927
|
+
work.lostSignal.addEventListener("abort", forward, { once: true });
|
|
928
|
+
stepSignal = both.signal;
|
|
929
|
+
}
|
|
930
|
+
/** Release (or not) the work lease once the run's outcome is settled. */
|
|
931
|
+
const finishWork = async (status) => work ? { workLease: await work.finish(status, resultsById) } : {};
|
|
932
|
+
/** The record a lost lease leaves, naming why. */
|
|
933
|
+
const lostRecord = () => ({
|
|
934
|
+
phase: UNATTRIBUTED_PHASE,
|
|
935
|
+
fn: "workLease:lost",
|
|
936
|
+
args: {},
|
|
937
|
+
status: "fail",
|
|
938
|
+
durationMs: 0,
|
|
939
|
+
error: `${LEASE_LOST}: ${work?.lost ?? "the lease was lost"}. The run stopped and was not recorded as done.`,
|
|
940
|
+
});
|
|
941
|
+
const skipLaterPhases = (after) => {
|
|
942
|
+
const stoppedAt = config.phases.findIndex((p) => p.name === after);
|
|
943
|
+
if (stoppedAt < 0)
|
|
944
|
+
return;
|
|
945
|
+
for (const phase of config.phases.slice(stoppedAt + 1)) {
|
|
946
|
+
for (const step of phase.steps) {
|
|
947
|
+
records.push(isEffect(step)
|
|
948
|
+
? skippedRecord(phase.name, `effect:${step.receipt.name}`)
|
|
949
|
+
: isGate(step)
|
|
950
|
+
? skippedRecord(phase.name, gateFn(step))
|
|
951
|
+
: skippedRecord(phase.name, step.fn, step.args));
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
const records = [];
|
|
956
|
+
const start = Date.now();
|
|
957
|
+
// Each phase's wall-clock time, for the run record and the in-flight one.
|
|
958
|
+
const phaseDurations = {};
|
|
959
|
+
const timedPhase = async (phase, ctx, phaseSignal) => {
|
|
960
|
+
const live = currentLiveRun();
|
|
961
|
+
const t0 = Date.now();
|
|
962
|
+
live?.phaseStarted(phase.name);
|
|
963
|
+
try {
|
|
964
|
+
const ran = await runPhase(phase, activities, profiles, resultsById, ctx, phaseSignal);
|
|
965
|
+
live?.phaseEnded(phase.name, phaseVerdict(ran), Date.now() - t0);
|
|
966
|
+
return ran;
|
|
967
|
+
}
|
|
968
|
+
finally {
|
|
969
|
+
phaseDurations[phase.name] = (phaseDurations[phase.name] ?? 0) + (Date.now() - t0);
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
const startedAt = options.now ?? new Date(start).toISOString();
|
|
973
|
+
/**
|
|
974
|
+
* Build the run's ledger record, append it when asked, and hand it back for
|
|
975
|
+
* the result. Called once, at whichever of the three exits the run takes.
|
|
976
|
+
*/
|
|
977
|
+
const settle = async (settled, status, gate, point) => {
|
|
978
|
+
const ended = options.now ?? new Date().toISOString();
|
|
979
|
+
const input = buildRunRecord(config, settled, {
|
|
980
|
+
started: startedAt,
|
|
981
|
+
ended,
|
|
982
|
+
status,
|
|
983
|
+
id: runId,
|
|
984
|
+
// A gate recorded under another op (#2779: a command's own gate) names it.
|
|
985
|
+
...(gate ? { gate: { name: gate.gate, since: gate.timestamp, ...(gate.op !== config.name ? { op: gate.op } : {}) } } : {}),
|
|
986
|
+
...(point ? { point: { ...point, since: ended } } : {}),
|
|
987
|
+
...(options.steward ? { steward: options.steward } : {}),
|
|
988
|
+
phaseDurations,
|
|
989
|
+
});
|
|
990
|
+
const record = { version: 1, ...input, id: runId };
|
|
991
|
+
if (!options.ledger)
|
|
992
|
+
return record;
|
|
993
|
+
try {
|
|
994
|
+
return (await appendRunRecord(input, options.ledger)).record;
|
|
995
|
+
}
|
|
996
|
+
catch (err) {
|
|
997
|
+
options.onLedgerError?.(err);
|
|
998
|
+
return record;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
// Completed step id → its activity result (#1290). Populated as main-phase
|
|
1002
|
+
// steps finish, so a later step's step-output references resolve to real
|
|
1003
|
+
// values before reaching an activity function — see `runStep`.
|
|
1004
|
+
const resultsById = new Map();
|
|
1005
|
+
try {
|
|
1006
|
+
for (const phase of config.phases) {
|
|
1007
|
+
if (signal?.aborted)
|
|
1008
|
+
throw new PhaseFailure([]);
|
|
1009
|
+
records.push(...(await timedPhase(phase, gates, stepSignal)));
|
|
1010
|
+
}
|
|
1011
|
+
// The last renewal before the run is recorded (#2748): a run whose lease
|
|
1012
|
+
// was lost is never recorded as done.
|
|
1013
|
+
if (work && !(await work.fence()))
|
|
1014
|
+
throw new WorkStop([], UNATTRIBUTED_PHASE, true);
|
|
1015
|
+
}
|
|
1016
|
+
catch (err) {
|
|
1017
|
+
// Nothing to claim, or every candidate held (#2748): not a failure. The
|
|
1018
|
+
// rest of the run is skipped and the claim's record says why.
|
|
1019
|
+
if (err instanceof WorkStop && !err.lost) {
|
|
1020
|
+
records.push(...err.records);
|
|
1021
|
+
skipLaterPhases(err.phase);
|
|
1022
|
+
const record = await settle(records, "ok");
|
|
1023
|
+
return {
|
|
1024
|
+
op: config.name,
|
|
1025
|
+
records,
|
|
1026
|
+
totalMs: Date.now() - start,
|
|
1027
|
+
status: "ok",
|
|
1028
|
+
startedAt,
|
|
1029
|
+
record,
|
|
1030
|
+
...(await finishWork("ok")),
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
// An open decision point ends the run the way a pending gate does (#2749):
|
|
1034
|
+
// no later phase and no compensation, and the run is `waiting`.
|
|
1035
|
+
if (err instanceof PointStop) {
|
|
1036
|
+
records.push(...err.records);
|
|
1037
|
+
skipLaterPhases(err.phase);
|
|
1038
|
+
const record = await settle(records, "waiting", undefined, err.question);
|
|
1039
|
+
return {
|
|
1040
|
+
op: config.name,
|
|
1041
|
+
records,
|
|
1042
|
+
totalMs: Date.now() - start,
|
|
1043
|
+
status: "waiting",
|
|
1044
|
+
startedAt,
|
|
1045
|
+
point: err.question,
|
|
1046
|
+
record,
|
|
1047
|
+
...(await finishWork("waiting")),
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
// A pending gate ends the run where it stands: no later phase, and no
|
|
1051
|
+
// `onFailure` compensation — nothing failed, so there is nothing to undo.
|
|
1052
|
+
if (err instanceof GateStop) {
|
|
1053
|
+
records.push(...err.records);
|
|
1054
|
+
skipLaterPhases(err.phase);
|
|
1055
|
+
const record = await settle(records, "gated", err.pending);
|
|
1056
|
+
return {
|
|
1057
|
+
op: config.name,
|
|
1058
|
+
records,
|
|
1059
|
+
totalMs: Date.now() - start,
|
|
1060
|
+
status: "gated",
|
|
1061
|
+
startedAt,
|
|
1062
|
+
gate: err.pending,
|
|
1063
|
+
...(err.pushed !== undefined ? { gatePushed: err.pushed } : {}),
|
|
1064
|
+
...(err.pushWarning ? { gatePushWarning: err.pushWarning } : {}),
|
|
1065
|
+
record,
|
|
1066
|
+
...(await finishWork("gated")),
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
if (err instanceof WorkStop) {
|
|
1070
|
+
// The lease was lost (#2748): the rest is skipped, and the lost record
|
|
1071
|
+
// below says why.
|
|
1072
|
+
records.push(...err.records);
|
|
1073
|
+
skipLaterPhases(err.phase);
|
|
1074
|
+
}
|
|
1075
|
+
else if (err instanceof PhaseFailure) {
|
|
1076
|
+
records.push(...err.records);
|
|
1077
|
+
}
|
|
1078
|
+
else {
|
|
1079
|
+
// Everything else the phase loop can throw (#2301). `PhaseFailure` and
|
|
1080
|
+
// `GateStop` are the two shapes that carry their own records; anything
|
|
1081
|
+
// else — a git failure inside a ledger write, a bad phase definition, a
|
|
1082
|
+
// bug — used to be dropped here without being read, leaving a result
|
|
1083
|
+
// whose `records` hold nothing marked failed and nothing carrying a
|
|
1084
|
+
// message. The renderer prints text only from records, so the operator
|
|
1085
|
+
// got `Op "x" failed after 43.8s` and no cause at all.
|
|
1086
|
+
//
|
|
1087
|
+
// A synthetic record is what makes it visible: it renders as a failing
|
|
1088
|
+
// step like any other, lands in the run ledger, and appears in
|
|
1089
|
+
// `--json`. `cause` on the thrown `OpRunFailure` carries the original
|
|
1090
|
+
// error for a caller that wants the object rather than the text.
|
|
1091
|
+
records.push({
|
|
1092
|
+
phase: UNATTRIBUTED_PHASE,
|
|
1093
|
+
fn: "opFailure",
|
|
1094
|
+
args: {},
|
|
1095
|
+
status: "fail",
|
|
1096
|
+
durationMs: 0,
|
|
1097
|
+
error: errMessage(err),
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
// A step that failed because the lease was lost mid-step, or a lease lost
|
|
1101
|
+
// at any boundary: one record names it (#2748).
|
|
1102
|
+
if (work?.lost !== undefined)
|
|
1103
|
+
records.push(lostRecord());
|
|
1104
|
+
// Compensation: run onFailure phases in reverse order (best-effort). Skipped
|
|
1105
|
+
// on abort (Ctrl-C) — the user asked to stop, so don't start new work.
|
|
1106
|
+
// It runs whatever the work lease did, so it takes no work boundary.
|
|
1107
|
+
const compensation = { ...gates, work: undefined };
|
|
1108
|
+
if (!signal?.aborted) {
|
|
1109
|
+
for (const phase of [...(config.onFailure ?? [])].reverse()) {
|
|
1110
|
+
try {
|
|
1111
|
+
records.push(...(await timedPhase(phase, compensation, signal)));
|
|
1112
|
+
}
|
|
1113
|
+
catch (compErr) {
|
|
1114
|
+
if (compErr instanceof PhaseFailure || compErr instanceof GateStop || compErr instanceof PointStop) {
|
|
1115
|
+
records.push(...compErr.records);
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
// The same swallow, one level down (#2301): a compensation phase
|
|
1119
|
+
// that threw something else left no trace whatsoever.
|
|
1120
|
+
records.push({
|
|
1121
|
+
phase: phase.name,
|
|
1122
|
+
fn: "onFailure",
|
|
1123
|
+
args: {},
|
|
1124
|
+
status: "fail",
|
|
1125
|
+
durationMs: 0,
|
|
1126
|
+
error: errMessage(compErr),
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
const failed = await settle(records, "fail");
|
|
1133
|
+
throw new OpRunFailure({
|
|
1134
|
+
op: config.name,
|
|
1135
|
+
records,
|
|
1136
|
+
totalMs: Date.now() - start,
|
|
1137
|
+
status: "fail",
|
|
1138
|
+
startedAt,
|
|
1139
|
+
record: failed,
|
|
1140
|
+
...(await finishWork("fail")),
|
|
1141
|
+
}, { cause: err });
|
|
1142
|
+
}
|
|
1143
|
+
const record = await settle(records, "ok");
|
|
1144
|
+
return {
|
|
1145
|
+
op: config.name,
|
|
1146
|
+
records,
|
|
1147
|
+
totalMs: Date.now() - start,
|
|
1148
|
+
status: "ok",
|
|
1149
|
+
startedAt,
|
|
1150
|
+
record,
|
|
1151
|
+
...(await finishWork("ok")),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
/** A finished phase's verdict, as the run ledger folds it: `fail`, `skipped` when every step was, else `ok`. */
|
|
1155
|
+
function phaseVerdict(records) {
|
|
1156
|
+
if (records.some((r) => r.status === "fail"))
|
|
1157
|
+
return "fail";
|
|
1158
|
+
if (records.length > 0 && records.every((r) => r.status === "skipped"))
|
|
1159
|
+
return "skipped";
|
|
1160
|
+
return "ok";
|
|
1161
|
+
}
|
|
1162
|
+
function errMessage(err) {
|
|
1163
|
+
return err instanceof Error ? err.message : String(err);
|
|
1164
|
+
}
|