@intentius/chant 0.124.45 → 0.124.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
- package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
- package/dist/__golden__/wave-loop/op-denied.json +16 -0
- package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on.json +16 -0
- package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/dist/__golden__/wave-loop/op-overridden.json +16 -0
- package/dist/__golden__/wave-loop/op-per-run.json +20 -0
- package/dist/__golden__/wave-loop/op-point.json +13 -0
- package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
- package/dist/__golden__/wave-loop/op-sealed.json +10 -0
- package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/dist/__golden__/wave-loop/op-spend.json +10 -0
- package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/dist/__golden__/wave-loop/op-wide.json +39 -0
- package/dist/action-pins.d.ts +61 -0
- package/dist/action-pins.d.ts.map +1 -0
- package/dist/action-pins.js +77 -0
- package/dist/capabilities/aws.paths +148 -0
- package/dist/capabilities/base-mappings.json +122 -0
- package/dist/capabilities/catalog.d.ts +89 -0
- package/dist/capabilities/catalog.d.ts.map +1 -0
- package/dist/capabilities/catalog.js +204 -0
- package/dist/capabilities/language.d.ts +103 -0
- package/dist/capabilities/language.d.ts.map +1 -0
- package/dist/capabilities/language.js +335 -0
- package/dist/capabilities/matcher.d.ts +65 -0
- package/dist/capabilities/matcher.d.ts.map +1 -0
- package/dist/capabilities/matcher.js +299 -0
- package/dist/capabilities/view.d.ts +207 -0
- package/dist/capabilities/view.d.ts.map +1 -0
- package/dist/capabilities/view.js +484 -0
- package/dist/cli/commands/carve.d.ts +3 -0
- package/dist/cli/commands/carve.d.ts.map +1 -1
- package/dist/cli/commands/carve.js +36 -7
- package/dist/cli/commands/import-report.d.ts +26 -0
- package/dist/cli/commands/import-report.d.ts.map +1 -0
- package/dist/cli/commands/import-report.js +65 -0
- package/dist/cli/commands/import.d.ts +11 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/import.js +22 -3
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +1 -0
- package/dist/cli/commands/migrate.d.ts +13 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +134 -10
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +21 -2
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +6 -1
- package/dist/cli/handlers/declared-graph.d.ts +44 -0
- package/dist/cli/handlers/declared-graph.d.ts.map +1 -0
- package/dist/cli/handlers/declared-graph.js +87 -0
- package/dist/cli/handlers/graph.d.ts +25 -0
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +93 -87
- package/dist/cli/handlers/ledger.d.ts +3 -0
- package/dist/cli/handlers/ledger.d.ts.map +1 -0
- package/dist/cli/handlers/ledger.js +55 -0
- package/dist/cli/handlers/migrate.d.ts.map +1 -1
- package/dist/cli/handlers/migrate.js +18 -11
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/misc.js +12 -1
- package/dist/cli/handlers/pr-env.d.ts.map +1 -1
- package/dist/cli/handlers/pr-env.js +4 -3
- package/dist/cli/handlers/pr.d.ts +15 -1
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +143 -39
- package/dist/cli/handlers/query.d.ts +7 -2
- package/dist/cli/handlers/query.d.ts.map +1 -1
- package/dist/cli/handlers/query.js +16 -4
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +6 -3
- package/dist/cli/handlers/search-count.d.ts +89 -0
- package/dist/cli/handlers/search-count.d.ts.map +1 -0
- package/dist/cli/handlers/search-count.js +132 -0
- package/dist/cli/handlers/search.d.ts +356 -6
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +1039 -155
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +88 -17
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/server.js +3 -0
- package/dist/cli/mcp/tools/capabilities.d.ts +7 -0
- package/dist/cli/mcp/tools/capabilities.d.ts.map +1 -0
- package/dist/cli/mcp/tools/capabilities.js +27 -0
- package/dist/cli/mcp/workspace-tools.d.ts +3 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.js +47 -2
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +100 -19
- package/dist/cli/registry.d.ts +36 -4
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/builders.d.ts +5 -1
- package/dist/components/builders.d.ts.map +1 -1
- package/dist/components/builders.js +5 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.js +16 -1
- package/dist/components/capability-plugin.d.ts +14 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/pr-env-ports.d.ts +29 -0
- package/dist/components/pr-env-ports.d.ts.map +1 -0
- package/dist/components/pr-env-ports.js +77 -0
- package/dist/components/pr-env-run.d.ts +5 -21
- package/dist/components/pr-env-run.d.ts.map +1 -1
- package/dist/components/pr-env-run.js +6 -70
- package/dist/components/pr-environment.d.ts +2 -1
- package/dist/components/pr-environment.d.ts.map +1 -1
- package/dist/components/pr-environment.js +1 -1
- package/dist/components/pr-hooks.d.ts +21 -1
- package/dist/components/pr-hooks.d.ts.map +1 -1
- package/dist/components/pr-hooks.js +72 -4
- package/dist/components/pr-pipeline.d.ts +45 -10
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +47 -14
- package/dist/components/pr-policy.d.ts +36 -0
- package/dist/components/pr-policy.d.ts.map +1 -1
- package/dist/components/pr-policy.js +36 -0
- package/dist/components/starter-plugin.d.ts +1 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/starter-plugin.js +5 -1
- package/dist/components/verbs/index.d.ts +2 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/index.js +2 -0
- package/dist/components/verbs/publish-artifact.d.ts +65 -0
- package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
- package/dist/components/verbs/publish-artifact.js +74 -0
- package/dist/components/verbs/publish-image.d.ts +129 -0
- package/dist/components/verbs/publish-image.d.ts.map +1 -0
- package/dist/components/verbs/publish-image.js +145 -0
- package/dist/config-environments.d.ts +112 -0
- package/dist/config-environments.d.ts.map +1 -0
- package/dist/config-environments.js +114 -0
- package/dist/config.d.ts +32 -84
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -96
- package/dist/gate-decision.d.ts +11 -2
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +15 -3
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +15 -3
- package/dist/graph-effective.d.ts +33 -2
- package/dist/graph-effective.d.ts.map +1 -1
- package/dist/graph-effective.js +215 -68
- package/dist/graph-ir.d.ts +48 -0
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-ir.js +130 -0
- package/dist/graph-sub-template.d.ts +11 -0
- package/dist/graph-sub-template.d.ts.map +1 -0
- package/dist/graph-sub-template.js +19 -0
- package/dist/graph-walk.d.ts +66 -0
- package/dist/graph-walk.d.ts.map +1 -0
- package/dist/graph-walk.js +70 -0
- package/dist/import/parser.d.ts +19 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/lexicon.d.ts +80 -6
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +11 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +2 -5
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/ledger-read.d.ts +65 -0
- package/dist/lifecycle/ledger-read.d.ts.map +1 -0
- package/dist/lifecycle/ledger-read.js +160 -0
- package/dist/lifecycle/observe.d.ts +28 -0
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/observe.js +23 -1
- package/dist/lifecycle/release-workstation.d.ts +7 -0
- package/dist/lifecycle/release-workstation.d.ts.map +1 -1
- package/dist/lifecycle/release-workstation.js +25 -0
- package/dist/lifecycle/run-ledger.d.ts +4 -3
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -0
- package/dist/lint/discover.js +3 -1
- package/dist/lint/post-synth.d.ts +127 -1
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/post-synth.js +84 -2
- package/dist/lint/rule.d.ts +6 -0
- package/dist/lint/rule.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +1 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +2 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/live-endpoint.d.ts.map +1 -1
- package/dist/live-endpoint.js +1 -1
- package/dist/observation.d.ts +48 -1
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +21 -5
- package/dist/op/activities/activity-contracts.d.ts +9 -6
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +5 -2
- package/dist/op/activities/index.d.ts +2 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +1 -1
- package/dist/op/activities/review-agent.d.ts +90 -4
- package/dist/op/activities/review-agent.d.ts.map +1 -1
- package/dist/op/activities/review-agent.js +217 -19
- package/dist/op/activities/work-evidence.d.ts +8 -1
- package/dist/op/activities/work-evidence.d.ts.map +1 -1
- package/dist/op/activities/work-evidence.js +1 -0
- package/dist/op/builders.d.ts +9 -5
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -5
- package/dist/op/composites/apply-op.d.ts +29 -2
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/apply-op.js +20 -1
- package/dist/op/gate-approval.d.ts +11 -5
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-approval.js +11 -6
- package/dist/op/gate-quorum.d.ts +100 -3
- package/dist/op/gate-quorum.d.ts.map +1 -1
- package/dist/op/gate-quorum.js +108 -6
- package/dist/op/gate-review.d.ts +9 -0
- package/dist/op/gate-review.d.ts.map +1 -1
- package/dist/op/gate-review.js +13 -0
- package/dist/op/gate.d.ts +44 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +25 -4
- package/dist/op/index.d.ts +3 -3
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +1 -1
- package/dist/op/local-executor.d.ts +38 -3
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +48 -6
- package/dist/op/op-waves-run.d.ts +26 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +259 -13
- package/dist/op/op-waves.d.ts +72 -5
- package/dist/op/op-waves.d.ts.map +1 -1
- package/dist/op/op-waves.js +110 -15
- package/dist/op/runtime.d.ts +11 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/schedule-overdue.d.ts +16 -0
- package/dist/op/schedule-overdue.d.ts.map +1 -1
- package/dist/op/schedule-overdue.js +36 -0
- package/dist/op/stage-hooks.d.ts +9 -2
- package/dist/op/stage-hooks.d.ts.map +1 -1
- package/dist/op/stage-hooks.js +7 -5
- package/dist/op/workspace-run-env.d.ts +22 -0
- package/dist/op/workspace-run-env.d.ts.map +1 -0
- package/dist/op/workspace-run-env.js +21 -0
- package/dist/pr-forge.d.ts +24 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +47 -0
- package/dist/pr-post.d.ts +42 -0
- package/dist/pr-post.d.ts.map +1 -1
- package/dist/pr-post.js +67 -1
- package/dist/read-filter.d.ts +65 -0
- package/dist/read-filter.d.ts.map +1 -0
- package/dist/read-filter.js +179 -0
- package/dist/run-event.d.ts +1 -1
- package/dist/run-event.d.ts.map +1 -1
- package/dist/terraform/carve.d.ts +24 -3
- package/dist/terraform/carve.d.ts.map +1 -1
- package/dist/terraform/carve.js +32 -14
- package/dist/terraform/cuts.d.ts +97 -0
- package/dist/terraform/cuts.d.ts.map +1 -0
- package/dist/terraform/cuts.js +138 -0
- package/dist/terraform/folds.d.ts +26 -0
- package/dist/terraform/folds.d.ts.map +1 -0
- package/dist/terraform/folds.js +38 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/graph.js +10 -0
- package/dist/terraform/reach.d.ts +140 -0
- package/dist/terraform/reach.d.ts.map +1 -0
- package/dist/terraform/reach.js +170 -0
- package/dist/terraform/score.d.ts +14 -0
- package/dist/terraform/score.d.ts.map +1 -1
- package/dist/terraform/score.js +14 -31
- package/dist/terraform/state.d.ts.map +1 -1
- package/dist/terraform/state.js +4 -2
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/dist/wave-blocked.d.ts +10 -1
- package/dist/wave-blocked.d.ts.map +1 -1
- package/dist/wave-blocked.js +31 -3
- package/dist/wave-runtime.mjs +266 -256
- package/dist/workspace/capabilities-contract.d.ts +66 -0
- package/dist/workspace/capabilities-contract.d.ts.map +1 -0
- package/dist/workspace/capabilities-contract.js +107 -0
- package/dist/workspace/capabilities.schema.json +229 -0
- package/dist/workspace/check.schema.json +11 -2
- package/dist/workspace/checks/ci-branch.d.ts +44 -0
- package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
- package/dist/workspace/checks/ci-branch.js +133 -0
- package/dist/workspace/checks/links.d.ts +3 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/links.js +12 -1
- package/dist/workspace/checks/org.d.ts +48 -0
- package/dist/workspace/checks/org.d.ts.map +1 -0
- package/dist/workspace/checks/org.js +156 -0
- package/dist/workspace/checks.d.ts +11 -1
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +59 -7
- package/dist/workspace/ci-branches.d.ts +16 -0
- package/dist/workspace/ci-branches.d.ts.map +1 -1
- package/dist/workspace/ci-branches.js +27 -0
- package/dist/workspace/ci-green-cli.js +7 -7
- package/dist/workspace/ci-green-workflow.d.ts +1 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +13 -8
- package/dist/workspace/ci-green.d.ts +14 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +44 -11
- package/dist/workspace/ci-run.d.ts +9 -1
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +67 -6
- package/dist/workspace/ci-serve.d.ts +9 -0
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +114 -76
- package/dist/workspace/compose-graph.d.ts +23 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/compose-graph.js +3 -1
- package/dist/workspace/composites.d.ts +4 -1
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/composites.js +5 -2
- package/dist/workspace/composites.schema.json +22 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/dist/workspace/conformance/index.d.ts +1 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/index.js +39 -2
- package/dist/workspace/cross-root-lint.d.ts +56 -0
- package/dist/workspace/cross-root-lint.d.ts.map +1 -0
- package/dist/workspace/cross-root-lint.js +111 -0
- package/dist/workspace/dbt-models-reader.d.ts +44 -0
- package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
- package/dist/workspace/dbt-models-reader.js +356 -0
- package/dist/workspace/dbt-project-common.d.ts +40 -0
- package/dist/workspace/dbt-project-common.d.ts.map +1 -0
- package/dist/workspace/dbt-project-common.js +106 -0
- package/dist/workspace/dbt-project-reader.d.ts +4 -3
- package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
- package/dist/workspace/dbt-project-reader.js +14 -108
- package/dist/workspace/decision-rank.d.ts +26 -0
- package/dist/workspace/decision-rank.d.ts.map +1 -0
- package/dist/workspace/decision-rank.js +16 -0
- package/dist/workspace/declaration.d.ts +43 -2
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +45 -11
- package/dist/workspace/declaration.schema.json +133 -24
- package/dist/workspace/environments.d.ts +26 -2
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/environments.js +26 -2
- package/dist/workspace/flyway-dir.d.ts +39 -0
- package/dist/workspace/flyway-dir.d.ts.map +1 -0
- package/dist/workspace/flyway-dir.js +104 -0
- package/dist/workspace/flyway-layout.d.ts +96 -0
- package/dist/workspace/flyway-layout.d.ts.map +1 -0
- package/dist/workspace/flyway-layout.js +308 -0
- package/dist/workspace/graph-cache.d.ts +8 -0
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cache.js +27 -3
- package/dist/workspace/graph-cli.d.ts +39 -2
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +92 -32
- package/dist/workspace/graph.schema.json +182 -0
- package/dist/workspace/intent.d.ts +2 -3
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +5 -9
- package/dist/workspace/kind-link-readers.d.ts +59 -2
- package/dist/workspace/kind-link-readers.d.ts.map +1 -1
- package/dist/workspace/kind-link-readers.js +17 -1
- package/dist/workspace/kind-readers.d.ts +3 -0
- package/dist/workspace/kind-readers.d.ts.map +1 -1
- package/dist/workspace/kind-readers.js +7 -1
- package/dist/workspace/kinds.d.ts +66 -2
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +98 -4
- package/dist/workspace/ledger.schema.json +158 -0
- package/dist/workspace/lexicon-outputs.d.ts +20 -1
- package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
- package/dist/workspace/lexicon-outputs.js +102 -10
- package/dist/workspace/lineage-check.d.ts +3 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-check.js +23 -4
- package/dist/workspace/links.d.ts +8 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/links.js +25 -1
- package/dist/workspace/ls.d.ts +8 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +7 -1
- package/dist/workspace/ls.schema.json +7 -0
- package/dist/workspace/member-commands.d.ts +10 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/member-commands.js +71 -6
- package/dist/workspace/migrate-links.d.ts +45 -0
- package/dist/workspace/migrate-links.d.ts.map +1 -0
- package/dist/workspace/migrate-links.js +100 -0
- package/dist/workspace/migration-dirs.d.ts +74 -0
- package/dist/workspace/migration-dirs.d.ts.map +1 -0
- package/dist/workspace/migration-dirs.js +254 -0
- package/dist/workspace/nested-graph.d.ts +2 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -1
- package/dist/workspace/nested-graph.js +32 -1
- package/dist/workspace/reason-codes.d.ts +18 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +23 -0
- package/dist/workspace/records-cli.d.ts +11 -0
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-cli.js +57 -5
- package/dist/workspace/records.schema.json +5 -0
- package/dist/workspace/release-candidates.d.ts +2 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -1
- package/dist/workspace/release-candidates.js +5 -2
- package/dist/workspace/release-train.d.ts +53 -0
- package/dist/workspace/release-train.d.ts.map +1 -0
- package/dist/workspace/release-train.js +134 -0
- package/dist/workspace/release-workflow.d.ts.map +1 -1
- package/dist/workspace/release-workflow.js +4 -3
- package/dist/workspace/repo-ref.d.ts +45 -0
- package/dist/workspace/repo-ref.d.ts.map +1 -0
- package/dist/workspace/repo-ref.js +114 -0
- package/dist/workspace/run-event.schema.json +2 -2
- package/dist/workspace/runs-cli.d.ts +9 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs-cli.js +48 -3
- package/dist/workspace/runs.schema.json +7 -0
- package/dist/workspace/search-cli.d.ts +204 -0
- package/dist/workspace/search-cli.d.ts.map +1 -0
- package/dist/workspace/search-cli.js +466 -0
- package/dist/workspace/search-contract.d.ts +56 -0
- package/dist/workspace/search-contract.d.ts.map +1 -0
- package/dist/workspace/search-contract.js +70 -0
- package/dist/workspace/search.schema.json +822 -0
- package/dist/workspace/status-decisions.d.ts +37 -0
- package/dist/workspace/status-decisions.d.ts.map +1 -0
- package/dist/workspace/status-decisions.js +147 -0
- package/dist/workspace/status-gates.d.ts +9 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +4 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +14 -2
- package/dist/workspace/status.schema.json +6 -0
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-cli.js +5 -3
- package/dist/workspace/work-evidence-ops.d.ts +83 -0
- package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
- package/dist/workspace/work-evidence-ops.js +169 -0
- package/dist/workspace/work-evidence.d.ts +12 -2
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-evidence.js +21 -3
- package/dist/workspace/work-evidence.schema.json +49 -2
- package/dist/workspace/workspace-gates.d.ts +110 -0
- package/dist/workspace/workspace-gates.d.ts.map +1 -0
- package/dist/workspace/workspace-gates.js +140 -0
- package/dist/workspace/workspace-kinds.schema.json +58 -3
- package/dist/workspace/workspace-ledger.d.ts +76 -0
- package/dist/workspace/workspace-ledger.d.ts.map +1 -0
- package/dist/workspace/workspace-ledger.js +91 -0
- package/dist/workspace/workspace-run.d.ts +112 -0
- package/dist/workspace/workspace-run.d.ts.map +1 -0
- package/dist/workspace/workspace-run.js +432 -0
- package/package.json +1 -1
- package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/src/__golden__/wave-loop/op-cost-member.json +13 -0
- package/src/__golden__/wave-loop/op-denied-source.json +16 -0
- package/src/__golden__/wave-loop/op-denied.json +16 -0
- package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/src/__golden__/wave-loop/op-held-on.json +16 -0
- package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/src/__golden__/wave-loop/op-overridden.json +16 -0
- package/src/__golden__/wave-loop/op-per-run.json +20 -0
- package/src/__golden__/wave-loop/op-point.json +13 -0
- package/src/__golden__/wave-loop/op-pr-review.json +10 -0
- package/src/__golden__/wave-loop/op-sealed.json +10 -0
- package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/src/__golden__/wave-loop/op-spend.json +10 -0
- package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/src/__golden__/wave-loop/op-wide.json +39 -0
- package/src/__snapshots__/okf.test.ts.snap +10 -0
- package/src/action-pins.test.ts +78 -0
- package/src/action-pins.ts +92 -0
- package/src/capabilities/aws.paths +148 -0
- package/src/capabilities/base-mappings.json +122 -0
- package/src/capabilities/catalog.ts +230 -0
- package/src/capabilities/language.test.ts +191 -0
- package/src/capabilities/language.ts +373 -0
- package/src/capabilities/matcher.ts +315 -0
- package/src/capabilities/view-compose.test.ts +76 -0
- package/src/capabilities/view.ts +631 -0
- package/src/cli/commands/carve-score-once.test.ts +99 -0
- package/src/cli/commands/carve.ts +37 -6
- package/src/cli/commands/check-lexicon.test.ts +2 -2
- package/src/cli/commands/import-report.ts +71 -0
- package/src/cli/commands/import.ts +33 -3
- package/src/cli/commands/lint.ts +1 -0
- package/src/cli/commands/migrate-dialect.test.ts +145 -0
- package/src/cli/commands/migrate.ts +132 -11
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
- package/src/cli/handlers/approve.ts +23 -2
- package/src/cli/handlers/build.ts +7 -1
- package/src/cli/handlers/declared-graph.ts +99 -0
- package/src/cli/handlers/graph.test.ts +94 -3
- package/src/cli/handlers/graph.ts +123 -96
- package/src/cli/handlers/ledger.ts +54 -0
- package/src/cli/handlers/migrate.ts +21 -12
- package/src/cli/handlers/misc.ts +10 -1
- package/src/cli/handlers/pr-env.ts +3 -4
- package/src/cli/handlers/pr.ts +138 -36
- package/src/cli/handlers/query.ts +16 -4
- package/src/cli/handlers/release.ts +6 -3
- package/src/cli/handlers/search-build-roots.test.ts +144 -0
- package/src/cli/handlers/search-count.test.ts +191 -0
- package/src/cli/handlers/search-count.ts +165 -0
- package/src/cli/handlers/search-json.test.ts +333 -0
- package/src/cli/handlers/search-live.test.ts +387 -0
- package/src/cli/handlers/search-paths.test.ts +235 -0
- package/src/cli/handlers/search.ts +1291 -166
- package/src/cli/main.test.ts +43 -3
- package/src/cli/main.ts +88 -17
- package/src/cli/mcp/server.test.ts +3 -3
- package/src/cli/mcp/server.ts +3 -0
- package/src/cli/mcp/tools/capabilities.ts +32 -0
- package/src/cli/mcp/workspace-tools.e2e.test.ts +21 -1
- package/src/cli/mcp/workspace-tools.ts +47 -2
- package/src/cli/parse-args.ts +79 -15
- package/src/cli/registry.ts +36 -4
- package/src/components/builders.ts +8 -0
- package/src/components/capability-plugin-loader.ts +13 -1
- package/src/components/capability-plugin.ts +16 -0
- package/src/components/pr-env-ports.ts +89 -0
- package/src/components/pr-env-run-bundle.test.ts +54 -0
- package/src/components/pr-env-run.ts +5 -76
- package/src/components/pr-environment.ts +2 -1
- package/src/components/pr-hooks.test.ts +73 -5
- package/src/components/pr-hooks.ts +95 -5
- package/src/components/pr-pipeline.ts +64 -16
- package/src/components/pr-policy.test.ts +64 -1
- package/src/components/pr-policy.ts +53 -0
- package/src/components/registry.test.ts +1 -1
- package/src/components/starter-plugin.ts +6 -0
- package/src/components/verbs/index.ts +2 -0
- package/src/components/verbs/publish-artifact.test.ts +60 -0
- package/src/components/verbs/publish-artifact.ts +122 -0
- package/src/components/verbs/publish-image.test.ts +101 -0
- package/src/components/verbs/publish-image.ts +265 -0
- package/src/config-environments.ts +160 -0
- package/src/config.ts +44 -124
- package/src/gate-decision-bundle.test.ts +1 -0
- package/src/gate-decision-identity.test.ts +9 -0
- package/src/gate-decision.ts +26 -3
- package/src/graph-detail.ts +15 -3
- package/src/graph-effective.ts +226 -75
- package/src/graph-ir.test.ts +163 -0
- package/src/graph-ir.ts +174 -0
- package/src/graph-sub-template.ts +22 -0
- package/src/graph-walk.test.ts +44 -0
- package/src/graph-walk.ts +102 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +84 -6
- package/src/lifecycle/gate-ledger.ts +8 -0
- package/src/lifecycle/git.ts +2 -2
- package/src/lifecycle/ledger-read.test.ts +107 -0
- package/src/lifecycle/ledger-read.ts +195 -0
- package/src/lifecycle/observe.test.ts +27 -1
- package/src/lifecycle/observe.ts +43 -1
- package/src/lifecycle/release-workstation.ts +24 -0
- package/src/lifecycle/run-ledger.ts +5 -2
- package/src/lint/cross-root.test.ts +122 -0
- package/src/lint/discover.ts +3 -1
- package/src/lint/post-synth.ts +212 -2
- package/src/lint/rule.ts +6 -0
- package/src/lint/rules/op/index.ts +2 -0
- package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
- package/src/live-endpoint.ts +1 -1
- package/src/observation.test.ts +25 -0
- package/src/observation.ts +69 -5
- package/src/op/activities/activity-contracts.ts +5 -2
- package/src/op/activities/index.ts +2 -2
- package/src/op/activities/review-agent.test.ts +221 -4
- package/src/op/activities/review-agent.ts +265 -22
- package/src/op/activities/work-evidence.ts +9 -1
- package/src/op/builders.ts +9 -5
- package/src/op/composites/apply-op.test.ts +108 -0
- package/src/op/composites/apply-op.ts +37 -2
- package/src/op/gate-approval.test.ts +6 -1
- package/src/op/gate-approval.ts +12 -6
- package/src/op/gate-quorum-at-base.test.ts +211 -0
- package/src/op/gate-quorum.ts +156 -8
- package/src/op/gate-review.ts +14 -0
- package/src/op/gate.ts +67 -8
- package/src/op/index.ts +3 -2
- package/src/op/local-executor.ts +69 -9
- package/src/op/op-waves-depends-on.test.ts +81 -0
- package/src/op/op-waves-hook-targets.test.ts +4 -2
- package/src/op/op-waves-quorum-product.test.ts +158 -0
- package/src/op/op-waves-run.ts +288 -14
- package/src/op/op-waves.ts +143 -14
- package/src/op/runtime.ts +8 -0
- package/src/op/schedule-overdue.ts +33 -0
- package/src/op/stage-hooks.ts +13 -5
- package/src/op/workspace-run-env.ts +29 -0
- package/src/pr-forge-bundle.test.ts +2 -2
- package/src/pr-forge.test.ts +47 -0
- package/src/pr-forge.ts +68 -0
- package/src/pr-post-open.e2e.test.ts +36 -0
- package/src/pr-post.test.ts +102 -3
- package/src/pr-post.ts +89 -1
- package/src/read-filter.test.ts +54 -0
- package/src/read-filter.ts +193 -0
- package/src/run-event.ts +1 -1
- package/src/stage-hooks-bundle.test.ts +1 -0
- package/src/terraform/carve.ts +52 -15
- package/src/terraform/cuts.test.ts +173 -0
- package/src/terraform/cuts.ts +188 -0
- package/src/terraform/folds.ts +44 -0
- package/src/terraform/graph.ts +9 -0
- package/src/terraform/radius.test.ts +90 -0
- package/src/terraform/reach.test.ts +146 -0
- package/src/terraform/reach.ts +247 -0
- package/src/terraform/score.ts +27 -29
- package/src/terraform/state.ts +3 -1
- package/src/terraform/types.ts +8 -0
- package/src/wave-blocked.ts +28 -3
- package/src/wave-loop-golden.test.ts +4 -3
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/capabilities-contract.test.ts +88 -0
- package/src/workspace/capabilities-contract.ts +132 -0
- package/src/workspace/capabilities.schema.json +229 -0
- package/src/workspace/check-contract.test.ts +7 -6
- package/src/workspace/check.schema.json +11 -2
- package/src/workspace/checks/ci-branch.test.ts +128 -0
- package/src/workspace/checks/ci-branch.ts +141 -0
- package/src/workspace/checks/links.ts +12 -1
- package/src/workspace/checks/org.ts +169 -0
- package/src/workspace/checks.ts +64 -7
- package/src/workspace/ci-branches.ts +31 -0
- package/src/workspace/ci-green-branches.test.ts +153 -0
- package/src/workspace/ci-green-cli.ts +7 -7
- package/src/workspace/ci-green-workflow.test.ts +4 -3
- package/src/workspace/ci-green-workflow.ts +13 -9
- package/src/workspace/ci-green.ts +49 -12
- package/src/workspace/ci-run.test.ts +72 -1
- package/src/workspace/ci-run.ts +68 -8
- package/src/workspace/ci-serve.test.ts +95 -0
- package/src/workspace/ci-serve.ts +106 -65
- package/src/workspace/component-environments.test.ts +25 -2
- package/src/workspace/compose-graph.ts +19 -3
- package/src/workspace/composites.schema.json +22 -0
- package/src/workspace/composites.test.ts +39 -8
- package/src/workspace/composites.ts +6 -2
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/src/workspace/conformance/conformance.e2e.test.ts +14 -1
- package/src/workspace/conformance/index.ts +31 -2
- package/src/workspace/cross-root-lint.test.ts +90 -0
- package/src/workspace/cross-root-lint.ts +126 -0
- package/src/workspace/dbt-kind.test.ts +3 -2
- package/src/workspace/dbt-models-reader.ts +362 -0
- package/src/workspace/dbt-models.test.ts +248 -0
- package/src/workspace/dbt-project-common.ts +113 -0
- package/src/workspace/dbt-project-reader.ts +29 -112
- package/src/workspace/decision-rank.ts +40 -0
- package/src/workspace/declaration.schema.json +133 -24
- package/src/workspace/declaration.ts +84 -15
- package/src/workspace/environments.ts +40 -4
- package/src/workspace/flyway-dir.ts +113 -0
- package/src/workspace/flyway-layout.ts +337 -0
- package/src/workspace/graph-cache.ts +27 -3
- package/src/workspace/graph-cli.ts +119 -32
- package/src/workspace/graph-contract.test.ts +4 -2
- package/src/workspace/graph.schema.json +182 -0
- package/src/workspace/identity.test.ts +14 -2
- package/src/workspace/intent.ts +6 -14
- package/src/workspace/kind-link-readers.ts +68 -3
- package/src/workspace/kind-readers.e2e.test.ts +28 -0
- package/src/workspace/kind-readers.test.ts +1 -1
- package/src/workspace/kind-readers.ts +7 -1
- package/src/workspace/kinds.test.ts +12 -7
- package/src/workspace/kinds.ts +132 -7
- package/src/workspace/ledger.schema.json +158 -0
- package/src/workspace/lexicon-outputs.ts +132 -13
- package/src/workspace/lineage-check.ts +30 -7
- package/src/workspace/links.ts +24 -1
- package/src/workspace/ls-contract.test.ts +1 -1
- package/src/workspace/ls.schema.json +7 -0
- package/src/workspace/ls.ts +10 -1
- package/src/workspace/member-commands.ts +82 -3
- package/src/workspace/member-file-schema.test.ts +124 -0
- package/src/workspace/migrate-links.test.ts +99 -0
- package/src/workspace/migrate-links.ts +108 -0
- package/src/workspace/migration-dirs.test.ts +272 -0
- package/src/workspace/migration-dirs.ts +267 -0
- package/src/workspace/nested-graph.ts +32 -1
- package/src/workspace/org-scope.test.ts +238 -0
- package/src/workspace/reason-codes.test.ts +13 -1
- package/src/workspace/reason-codes.ts +23 -0
- package/src/workspace/records-cli.ts +58 -5
- package/src/workspace/records.schema.json +5 -0
- package/src/workspace/release-candidates.ts +7 -2
- package/src/workspace/release-train.ts +157 -0
- package/src/workspace/release-workflow.ts +4 -3
- package/src/workspace/repo-ref.ts +113 -0
- package/src/workspace/run-event.schema.json +2 -2
- package/src/workspace/runs-cli.ts +48 -4
- package/src/workspace/runs.schema.json +7 -0
- package/src/workspace/search-cli.e2e.test.ts +305 -0
- package/src/workspace/search-cli.ts +591 -0
- package/src/workspace/search-contract.ts +95 -0
- package/src/workspace/search.schema.json +822 -0
- package/src/workspace/status-contract.test.ts +46 -1
- package/src/workspace/status-decisions.test.ts +100 -0
- package/src/workspace/status-decisions.ts +151 -0
- package/src/workspace/status-gates.ts +9 -0
- package/src/workspace/status.schema.json +6 -0
- package/src/workspace/status.ts +17 -3
- package/src/workspace/where-filters.test.ts +39 -0
- package/src/workspace/work-cli.ts +5 -3
- package/src/workspace/work-evidence-ops.test.ts +176 -0
- package/src/workspace/work-evidence-ops.ts +189 -0
- package/src/workspace/work-evidence.schema.json +49 -2
- package/src/workspace/work-evidence.ts +22 -3
- package/src/workspace/workspace-gates.ts +200 -0
- package/src/workspace/workspace-kinds.schema.json +58 -3
- package/src/workspace/workspace-ledger.ts +130 -0
- package/src/workspace/workspace-run.test.ts +322 -0
- package/src/workspace/workspace-run.ts +461 -0
package/src/op/local-executor.ts
CHANGED
|
@@ -35,13 +35,14 @@ import { contentDigest } from "../content-digest";
|
|
|
35
35
|
import { parseDuration } from "./duration";
|
|
36
36
|
import { stepLabel, withRunConsole, withStepConsole } from "./step-console";
|
|
37
37
|
import { stepTimeoutProblem } from "./activity-profiles";
|
|
38
|
-
import { describeGateMismatch, evaluateGate, gateIsSealed, gitGateLedgerPort, type GateCheck, type GateLedgerPort } from "./gate";
|
|
38
|
+
import { describeGateMismatch, evaluateGate, gateIsSealed, gitGateLedgerPort, type GateApprovalRule, type GateCheck, type GateLedgerPort, type WorkspaceGateStandIn } from "./gate";
|
|
39
|
+
import { resolveWorkspaceRun, type WorkspaceRunCitation } from "./workspace-run-env";
|
|
39
40
|
import { gateName } from "./gate-name";
|
|
40
41
|
import { resolveGateAliases } from "./gate-alias";
|
|
41
42
|
import { gatePointOf } from "./gate-point";
|
|
42
43
|
import { evaluatePointGate, workspaceGatePointAsker, type GatePointAsker } from "./gate-point-run";
|
|
43
44
|
import type { ResolvedGateApproval } from "./gate-approval";
|
|
44
|
-
import { quorumRules, quorumRulesFor } from "./gate-quorum";
|
|
45
|
+
import { quorumRules, quorumRulesFor, type GateQuorumSpec } from "./gate-quorum";
|
|
45
46
|
import { GATE_PLAN_CONTEXT_KEY, gatePlanSummaryOfResult } from "./gate-plan-context";
|
|
46
47
|
import { withOpRunContext, type OpRunContext, type PassedGate } from "./run-context";
|
|
47
48
|
import type { GateAnswerRef, PendingGateRecord } from "../lifecycle/gate-ledger";
|
|
@@ -109,8 +110,11 @@ export interface StepRecord {
|
|
|
109
110
|
/**
|
|
110
111
|
* On a gate with an `approval` block (#2508): whether a quorum or a policy permit passed it. `"point"` on a gate that asks a decision point (#3170).
|
|
111
112
|
* `"alias"` (#3949) when an approval recorded under one of the gate's aliases counted, on any gate.
|
|
113
|
+
* `"workspace"` (#2554) when a workspace gate's approval stood in for it.
|
|
112
114
|
*/
|
|
113
|
-
via?: "quorum" | "policy" | "point" | "alias" | "empty";
|
|
115
|
+
via?: "quorum" | "policy" | "point" | "alias" | "empty" | "workspace";
|
|
116
|
+
/** With `via: "workspace"` (#2554): the workspace gate and the digest of the member plans its approval covers. */
|
|
117
|
+
workspaceGate?: { gate: string; digest: string };
|
|
114
118
|
/** On a gate with a quorum (#2508): every approver who counted toward it. */
|
|
115
119
|
approvers?: string[];
|
|
116
120
|
/** On a gate that asks a decision point (#3170): the answer record that passed it, which the gate ledger's resolution cites too. */
|
|
@@ -612,6 +616,8 @@ interface GateContext {
|
|
|
612
616
|
onRecord?: (record: StepRecord) => void;
|
|
613
617
|
/** Where the run's events go (#4041): a step's start, its settle and its gate's decision. */
|
|
614
618
|
emit?: RunEventSink;
|
|
619
|
+
/** A workspace gate that may stand in for this run's gates (#2554). Absent outside a workspace run started with a gate. */
|
|
620
|
+
workspace?: WorkspaceGateStandIn;
|
|
615
621
|
/** The run context's list of passed gates (#2522). A gate that passes is appended here. */
|
|
616
622
|
passed?: PassedGate[];
|
|
617
623
|
/** The run's hold on its work item's lease (#2748). Absent in compensation phases, which run whatever the lease did. */
|
|
@@ -729,14 +735,23 @@ function gateFn(step: GateStep): string {
|
|
|
729
735
|
* returned, the same walk `plan` goes through. A reference that resolves to
|
|
730
736
|
* nothing is dropped rather than failing the run, so a policy reading it sees
|
|
731
737
|
* the attribute as absent.
|
|
738
|
+
*
|
|
739
|
+
* #4324: the quorum is `identity.gates.<gate>.quorum` in the workspace
|
|
740
|
+
* declaration at base (`atBase`) whenever that sets one, and the Op's own
|
|
741
|
+
* `approval.quorum` is not read then, so a change can't lower the quorum its
|
|
742
|
+
* own run needs. The base quorum applies to a gate whose Op declares no
|
|
743
|
+
* `approval` block too. With none at base, the Op's quorum applies as before.
|
|
732
744
|
*/
|
|
733
|
-
function resolveGateApproval(
|
|
745
|
+
export function resolveGateApproval(
|
|
734
746
|
step: GateStep,
|
|
735
747
|
resultsById: ReadonlyMap<string, unknown>,
|
|
736
748
|
env?: string,
|
|
749
|
+
atBase?: GateQuorumSpec | null,
|
|
737
750
|
): ResolvedGateApproval | undefined {
|
|
738
|
-
const
|
|
751
|
+
const baseQuorum = atBase ?? undefined;
|
|
752
|
+
const authored = step.approval ?? (baseQuorum !== undefined ? {} : undefined);
|
|
739
753
|
if (!authored) return undefined;
|
|
754
|
+
const quorum = baseQuorum ?? authored.quorum;
|
|
740
755
|
let context: Record<string, unknown> | undefined;
|
|
741
756
|
if (authored.context) {
|
|
742
757
|
context = {};
|
|
@@ -755,10 +770,10 @@ function resolveGateApproval(
|
|
|
755
770
|
// #4290: the rules this run's gate takes, by its environment. A rule with
|
|
756
771
|
// `targets` never covers a run with no environment. One rule with no
|
|
757
772
|
// `targets` keeps its own shape, so a standing pending fact still matches.
|
|
758
|
-
const single =
|
|
759
|
-
const rules =
|
|
773
|
+
const single = quorum !== undefined && !Array.isArray(quorum) && (quorum as { targets?: unknown }).targets === undefined;
|
|
774
|
+
const rules = quorum ? quorumRulesFor(quorumRules(quorum), env !== undefined ? [env] : []) : [];
|
|
760
775
|
return {
|
|
761
|
-
...(single ? { quorum
|
|
776
|
+
...(single ? { quorum } : rules.length > 0 ? { quorum: rules } : {}),
|
|
762
777
|
...(authored.policy ? { policy: authored.policy } : {}),
|
|
763
778
|
mode: authored.mode ?? "log-only",
|
|
764
779
|
...(context ? { context } : {}),
|
|
@@ -786,7 +801,16 @@ async function runGateStep(
|
|
|
786
801
|
// a run over a missing digest.
|
|
787
802
|
const resolvedPlan = resolveStepOutputRefs(step.plan, resultsById);
|
|
788
803
|
const planDigest = typeof resolvedPlan === "string" && resolvedPlan !== "" ? resolvedPlan : undefined;
|
|
789
|
-
|
|
804
|
+
// #4324: the workspace's rule for this gate at base, read once: its quorum
|
|
805
|
+
// replaces the Op's, and evaluateGate judges approvals by it. A read that
|
|
806
|
+
// fails ends the step as a failing record, as a ledger read does below.
|
|
807
|
+
let rule: GateApprovalRule | null;
|
|
808
|
+
try {
|
|
809
|
+
rule = (await gates.port.approvalRule?.(gateName(step))) ?? null;
|
|
810
|
+
} catch (err) {
|
|
811
|
+
return { record: { phase: phaseName, fn: gateFn(step), args: {}, status: "fail", durationMs: Date.now() - start, error: errMessage(err) } };
|
|
812
|
+
}
|
|
813
|
+
const approval = resolveGateApproval(step, resultsById, gates.env, rule?.requirement.quorum);
|
|
790
814
|
// #3947: a gate that resumes stores the outputs the steps after it read.
|
|
791
815
|
const resumeAt = gates.resume?.gates.get(step);
|
|
792
816
|
let checkpoint: GateCheckpoint | undefined;
|
|
@@ -814,9 +838,11 @@ async function runGateStep(
|
|
|
814
838
|
...(gates.gitSha ? { gitSha: gates.gitSha } : {}),
|
|
815
839
|
...(planDigest !== undefined ? { planDigest } : {}),
|
|
816
840
|
...(approval ? { approval } : {}),
|
|
841
|
+
rule,
|
|
817
842
|
...(gates.now ? { now: gates.now } : {}),
|
|
818
843
|
...(checkpoint ? { checkpoint } : {}),
|
|
819
844
|
...(step.aliases?.length ? { aliases: resolveGateAliases(step, gates.op) } : {}),
|
|
845
|
+
...(gates.workspace ? { workspace: gates.workspace } : {}),
|
|
820
846
|
});
|
|
821
847
|
} catch (err) {
|
|
822
848
|
// Deciding a gate reads and writes the `chant/lifecycle` branch, so it
|
|
@@ -847,6 +873,7 @@ async function runGateStep(
|
|
|
847
873
|
timestamp: resolution.timestamp,
|
|
848
874
|
...(resolution.url ? { url: resolution.url } : {}),
|
|
849
875
|
...(check.via ? { via: check.via } : {}),
|
|
876
|
+
...(resolution.workspaceGate ? { workspaceGate: resolution.workspaceGate } : {}),
|
|
850
877
|
...(check.approvals ? { approvers: check.approvals.map((r) => r.resolvedBy) } : {}),
|
|
851
878
|
...(check.carried?.length
|
|
852
879
|
? { carriedFrom: check.carried.map((r) => ({ op: r.carriedFrom!.op, gate: r.carriedFrom!.gate, resolvedBy: r.resolvedBy, timestamp: r.carriedFrom!.timestamp })) }
|
|
@@ -1278,6 +1305,18 @@ export interface RunOpOptions {
|
|
|
1278
1305
|
gates?: GateLedgerPort;
|
|
1279
1306
|
/** Working directory for the default git-backed gate ledger. */
|
|
1280
1307
|
cwd?: string;
|
|
1308
|
+
/**
|
|
1309
|
+
* The workspace run that started this run (#2554). Defaults to the one the
|
|
1310
|
+
* environment names (`CHANT_WORKSPACE_RUN`, `./workspace-run-env.ts`). The
|
|
1311
|
+
* run record cites it.
|
|
1312
|
+
*/
|
|
1313
|
+
workspaceRun?: WorkspaceRunCitation;
|
|
1314
|
+
/**
|
|
1315
|
+
* The workspace gate that may stand in for this run's gates (#2554). Defaults
|
|
1316
|
+
* to the gate the workspace run names, read from the workspace ledger with
|
|
1317
|
+
* the member's opt-in at base; a test passes a stub.
|
|
1318
|
+
*/
|
|
1319
|
+
workspaceGate?: WorkspaceGateStandIn;
|
|
1281
1320
|
/** ISO-8601 "now", so a gate decision is deterministic under test. */
|
|
1282
1321
|
now?: string;
|
|
1283
1322
|
/** Identifies this run on any pending fact it records. */
|
|
@@ -1492,6 +1531,8 @@ async function runOpInTurn(
|
|
|
1492
1531
|
const commit = options.commit ?? (await resolveCommitSha(options.cwd ? { cwd: options.cwd } : {}));
|
|
1493
1532
|
// #4020: the CI run this one is in, in the shape a deploy record carries it.
|
|
1494
1533
|
const ciRun = resolveCiRun();
|
|
1534
|
+
// #2554: the workspace run that started this one, which its record cites.
|
|
1535
|
+
const workspaceRun = options.workspaceRun ?? resolveWorkspaceRun();
|
|
1495
1536
|
// #4041: the run's events name it the way its run record does: its own id,
|
|
1496
1537
|
// the commit, and the CI run it is in.
|
|
1497
1538
|
// #4042: a run that writes to the ledger also keeps its events on this host,
|
|
@@ -1535,6 +1576,11 @@ async function runOpInTurn(
|
|
|
1535
1576
|
passed: run.passedGates,
|
|
1536
1577
|
points: options.points ?? workspaceGatePointAsker(options.cwd ?? process.cwd()),
|
|
1537
1578
|
...(options.env !== undefined ? { env: options.env } : {}),
|
|
1579
|
+
...(options.workspaceGate
|
|
1580
|
+
? { workspace: options.workspaceGate }
|
|
1581
|
+
: workspaceRun?.gate
|
|
1582
|
+
? { workspace: lazyWorkspaceGate(options.cwd ?? process.cwd(), workspaceRun.gate) }
|
|
1583
|
+
: {}),
|
|
1538
1584
|
};
|
|
1539
1585
|
|
|
1540
1586
|
// Effect steps are ordered (read-compare-run-write): refuse them in a
|
|
@@ -1658,6 +1704,7 @@ async function runOpInTurn(
|
|
|
1658
1704
|
...(resumed ? { resumed } : {}),
|
|
1659
1705
|
...(commit ? { gitSha: commit } : {}),
|
|
1660
1706
|
...(options.runner ? { runOrigin: options.runner.runOrigin } : ciRun ? { runOrigin: ciRun.runOrigin } : {}),
|
|
1707
|
+
...(workspaceRun ? { workspaceRun: { id: workspaceRun.id, ...(workspaceRun.gate ? { gate: workspaceRun.gate } : {}) } } : {}),
|
|
1661
1708
|
phaseDurations,
|
|
1662
1709
|
});
|
|
1663
1710
|
if (status === "fail" && options.describeFailure) {
|
|
@@ -1954,3 +2001,16 @@ function phaseVerdict(records: readonly StepRecord[]): "ok" | "fail" | "skipped"
|
|
|
1954
2001
|
function errMessage(err: unknown): string {
|
|
1955
2002
|
return err instanceof Error ? err.message : String(err);
|
|
1956
2003
|
}
|
|
2004
|
+
|
|
2005
|
+
/**
|
|
2006
|
+
* The workspace gate stand-in for a member run (#2554), loading the workspace
|
|
2007
|
+
* code only when a gate is asked about it.
|
|
2008
|
+
*/
|
|
2009
|
+
function lazyWorkspaceGate(cwd: string, gate: string): WorkspaceGateStandIn {
|
|
2010
|
+
return {
|
|
2011
|
+
async standIn(q) {
|
|
2012
|
+
const { memberGateStandIn } = await import("../workspace/workspace-gates");
|
|
2013
|
+
return memberGateStandIn(cwd, gate, q);
|
|
2014
|
+
},
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A failed run blocks only the runs that depend on it (#4322): the waves'
|
|
3
|
+
* jobs pass outcome files, and a later wave's job reads them.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { assertOpWavesSpec, opWaveJobs, type OpWavesSpec } from "./op-waves";
|
|
11
|
+
import { runOpWave, type OpWaveExec, type OpWaveShowAtBase } from "./op-waves-run";
|
|
12
|
+
import { memoryGateLedgerPort } from "./gate";
|
|
13
|
+
|
|
14
|
+
const spec: OpWavesSpec = {
|
|
15
|
+
name: "roots",
|
|
16
|
+
op: "tf",
|
|
17
|
+
plan: ["tool", "plan", "{target}", "--out", "{plan}"],
|
|
18
|
+
apply: ["tool", "apply", "{target}", "--plan", "{plan}"],
|
|
19
|
+
waves: [
|
|
20
|
+
{ name: "base", runs: [{ target: "a" }, { target: "b" }, { target: "b2", dependsOn: ["a"] }], gate: "never" },
|
|
21
|
+
{ name: "app", runs: [{ target: "c", dependsOn: ["b"] }, { target: "d", dependsOn: ["a"] }, { target: "e", dependsOn: ["b2"] }, { target: "f", dependsOn: ["d"] }], gate: "never" },
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const digest = (n: string) => `sha256:${n.repeat(64)}`;
|
|
26
|
+
|
|
27
|
+
function harness(failing: string[], s: OpWavesSpec = spec) {
|
|
28
|
+
const cwd = mkdtempSync(join(tmpdir(), "op-waves-deps-"));
|
|
29
|
+
const calls: string[] = [];
|
|
30
|
+
const exec: OpWaveExec = (argv, dir) => {
|
|
31
|
+
calls.push(argv.join(" "));
|
|
32
|
+
if (argv[1] === "plan") writeFileSync(join(dir, argv[4]!), JSON.stringify({ planDigest: digest("1") }));
|
|
33
|
+
if (argv[1] === "apply" && failing.includes(argv[2]!)) return 1;
|
|
34
|
+
return 0;
|
|
35
|
+
};
|
|
36
|
+
const show: OpWaveShowAtBase = () => ({ sha: "b".repeat(40), text: JSON.stringify(s) });
|
|
37
|
+
const run = (wave: number) => runOpWave({ spec: s, specFile: "waves.json", wave, cwd, exec, show, gates: memoryGateLedgerPort(), log: () => {} });
|
|
38
|
+
return { cwd, calls, run, done: () => rmSync(cwd, { recursive: true, force: true }) };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("run-level dependsOn on Op waves (#4322)", () => {
|
|
42
|
+
test("two runs in wave 1, one failing: the wave 2 run that depends on the other applies", async () => {
|
|
43
|
+
const h = harness(["a"]);
|
|
44
|
+
const one = await h.run(1);
|
|
45
|
+
expect(one).toMatchObject({ exitCode: 1, applied: ["b"], failed: ["a"], blocked: { b2: "a" } });
|
|
46
|
+
const two = await h.run(2);
|
|
47
|
+
expect(two.applied).toEqual(["c"]);
|
|
48
|
+
expect(two.blocked).toEqual({ d: "a", e: "a", f: "a" });
|
|
49
|
+
expect(two.exitCode).toBe(1);
|
|
50
|
+
expect(h.calls.some((c) => c.startsWith("tool apply c "))).toBe(true);
|
|
51
|
+
expect(h.calls.some((c) => c.startsWith("tool plan d") || c.startsWith("tool apply d"))).toBe(false);
|
|
52
|
+
h.done();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("with nothing failed every run applies and the wave 2 job exits 0", async () => {
|
|
56
|
+
const h = harness([]);
|
|
57
|
+
expect((await h.run(1)).exitCode).toBe(0);
|
|
58
|
+
const two = await h.run(2);
|
|
59
|
+
expect(two).toMatchObject({ exitCode: 0, applied: ["c", "d", "e", "f"] });
|
|
60
|
+
expect(two.blocked).toBeUndefined();
|
|
61
|
+
h.done();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("a run listed before in its own wave blocks its dependent when it fails", async () => {
|
|
65
|
+
const h = harness(["c"]);
|
|
66
|
+
await h.run(1);
|
|
67
|
+
const two = await h.run(2);
|
|
68
|
+
expect(two).toMatchObject({ exitCode: 1, failed: ["c"] });
|
|
69
|
+
expect(two.applied).toEqual(["d", "e", "f"]);
|
|
70
|
+
h.done();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("a spec whose dependsOn names no earlier or preceding run is refused", () => {
|
|
74
|
+
const bad: OpWavesSpec = { ...spec, waves: [{ name: "x", runs: [{ target: "a", dependsOn: ["nope"] }], gate: "never" }] };
|
|
75
|
+
expect(() => assertOpWavesSpec(bad)).toThrow(/depends on "nope"/);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("every wave job names an outcome file", () => {
|
|
79
|
+
for (const job of opWaveJobs(spec, "waves.json")) expect(job.outcome).toMatch(/^\.chant\/op-waves\/roots\/outcomes\/outcome-wave-\d/);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -27,8 +27,10 @@ describe("hook targets and before.observe in the spec (#4288)", () => {
|
|
|
27
27
|
expect(() => assertOpWaveHooks("w", { before: { observe: [{ command: ["x"], targets: ["prod/**"], onFailure: "approve" }] } })).not.toThrow();
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
test("a pull-request job
|
|
31
|
-
expect(() => assertPrLoopHooks("ci.hooks", { after: { gate: [{ command: ["x"] }] } })).toThrow(
|
|
30
|
+
test("a pull-request job accepts after.gate (#4323) and refuses apply.runBy", () => {
|
|
31
|
+
expect(() => assertPrLoopHooks("ci.hooks", { after: { gate: [{ command: ["x"] }] } })).not.toThrow();
|
|
32
|
+
// onFailure "approve" stays refused at after.gate, as in an Op waves job.
|
|
33
|
+
expect(() => assertPrLoopHooks("ci.hooks", { after: { gate: [{ command: ["x"], onFailure: "approve" }] } })).toThrow(/after.gate/);
|
|
32
34
|
expect(() => assertPrLoopHooks("ci.hooks", { apply: { runBy: "apply" } })).toThrow(/runBy is for an Op waves spec/);
|
|
33
35
|
expect(() => assertPrLoopHooks("ci.hooks", { before: { observe: [{ command: ["x"] }], apply: [{ command: ["y"] }] } })).not.toThrow();
|
|
34
36
|
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { assertOpWavesSpec, type OpWavesSpec } from "./op-waves";
|
|
6
|
+
import { runOpWave, type OpWaveExec, type OpWaveShowAtBase } from "./op-waves-run";
|
|
7
|
+
import { memoryGateLedgerPort, type GateLedgerPort } from "./gate";
|
|
8
|
+
import { changeInvolvement, recordedReviewApprovals, requestedByTrailers, trustQuorumJudge } from "./gate-quorum";
|
|
9
|
+
import { waveSetDigest } from "../gated-waves";
|
|
10
|
+
import type { GateResolutionRecord } from "../lifecycle/gate-ledger";
|
|
11
|
+
import type { TrustPolicy } from "../workspace/trust/policy";
|
|
12
|
+
import type { MergedReview, ReviewSource } from "./gate-review";
|
|
13
|
+
|
|
14
|
+
// A review a product records itself (terragucci's `tf-apply` ledger under
|
|
15
|
+
// `pr-review`), and everyone involved in a change (#4333), as terragucci's
|
|
16
|
+
// ruleApprovers (apply.ts) and Involved (involved.ts) judge them.
|
|
17
|
+
|
|
18
|
+
const digest = (n: string) => `sha256:${n.repeat(64)}`;
|
|
19
|
+
const spec: OpWavesSpec = {
|
|
20
|
+
name: "migrations",
|
|
21
|
+
op: "migrate",
|
|
22
|
+
plan: ["tool", "plan", "{target}", "--out", "{plan}"],
|
|
23
|
+
apply: ["tool", "apply", "{target}", "--plan", "{plan}"],
|
|
24
|
+
waves: [{ name: "prod", approval: "pr-review", runs: [{ target: "prod-eu" }] }],
|
|
25
|
+
};
|
|
26
|
+
const set = waveSetDigest([{ member: "prod-eu", planDigest: digest("e") }]);
|
|
27
|
+
const atBase: OpWavesSpec = {
|
|
28
|
+
...spec,
|
|
29
|
+
approvals: {
|
|
30
|
+
quorum: [{ count: 2, roles: ["platform"], notAuthor: true }],
|
|
31
|
+
reviewLedger: "tf-apply",
|
|
32
|
+
involved: { agents: ["tg-bot"], exclude: true },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
const headSha = "r".repeat(40);
|
|
36
|
+
|
|
37
|
+
function harness(base: OpWavesSpec) {
|
|
38
|
+
const cwd = mkdtempSync(join(tmpdir(), "op-waves-product-"));
|
|
39
|
+
const exec: OpWaveExec = (argv, dir) => {
|
|
40
|
+
if (argv[1] === "plan") writeFileSync(join(dir, argv[4]!), JSON.stringify({ planDigest: digest("e") }));
|
|
41
|
+
return 0;
|
|
42
|
+
};
|
|
43
|
+
const show: OpWaveShowAtBase = () => ({ sha: "b".repeat(40), text: JSON.stringify(base) });
|
|
44
|
+
return { cwd, exec, show, done: () => rmSync(cwd, { recursive: true, force: true }) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const trust = (): TrustPolicy =>
|
|
48
|
+
({
|
|
49
|
+
base: "b".repeat(40), signersPath: ".chant/allowed_signers", active: false, signers: [], excluded: [],
|
|
50
|
+
roles: { platform: ["github:alice", "github:bob", "github:carol", "github:dana", "github:tg-bot"] },
|
|
51
|
+
adopted: [], runners: [], excludedRunners: [], admitted: {}, problems: [],
|
|
52
|
+
}) as TrustPolicy;
|
|
53
|
+
|
|
54
|
+
/** A port whose `read(op)` returns that op's lines, as the lifecycle branch's `_gates/<op>.jsonl` does. */
|
|
55
|
+
function ledgerPort(lines: GateResolutionRecord[]): GateLedgerPort & { resolved: GateResolutionRecord[] } {
|
|
56
|
+
const inner = memoryGateLedgerPort({ resolutions: lines });
|
|
57
|
+
return { ...inner, resolved: inner.resolved, async read(op) { const r = await inner.read(op); return { ...r, resolutions: r.resolutions.filter((x) => x.op === op) }; } };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** What terragucci writes under `pr-review`: one line, every reviewer, none of them `resolvedBy` on their own. */
|
|
61
|
+
const productReview = (reviewers: string[], at: string, o: Partial<Record<string, unknown>> = {}): GateResolutionRecord =>
|
|
62
|
+
({ version: 1, kind: "resolution", op: "tf-apply", gate: "migrations-wave-1", resolvedBy: reviewers.join(","), timestamp: at, planDigest: set, via: "pr-review", pr: 7, head: headSha, reviewers, ...o }) as unknown as GateResolutionRecord;
|
|
63
|
+
|
|
64
|
+
const merged: MergedReview = { pr: 7, head: headSha, author: "github:dana", approvers: [], refused: [] };
|
|
65
|
+
const reviews: ReviewSource = { kind: "github", mergedReview: async () => merged };
|
|
66
|
+
const requestedByBob = () => [{ sha: "abc1234def", message: "feat: widen the pool\n\nRequested-by: bob" }];
|
|
67
|
+
|
|
68
|
+
const run = (h: ReturnType<typeof harness>, gates: GateLedgerPort, o: Partial<Parameters<typeof runOpWave>[0]> = {}) =>
|
|
69
|
+
runOpWave({ spec: atBase, specFile: "waves.json", wave: 1, cwd: h.cwd, exec: h.exec, show: h.show, gates, head: "m".repeat(40), reviews, trust: trust, commits: requestedByBob, now: "2026-10-22T02:00:00Z", ...o });
|
|
70
|
+
|
|
71
|
+
describe("a review a product records, and everyone involved in a change (#4333)", () => {
|
|
72
|
+
test("the spec checks approvals.reviewLedger and approvals.involved", () => {
|
|
73
|
+
expect(() => assertOpWavesSpec(atBase)).not.toThrow();
|
|
74
|
+
expect(() => assertOpWavesSpec({ ...spec, approvals: { reviewLedger: "../x" } })).toThrow(/reviewLedger must name an op/);
|
|
75
|
+
expect(() => assertOpWavesSpec({ ...spec, approvals: { involved: { agents: [] } } })).toThrow(/involved.agents/);
|
|
76
|
+
expect(() => assertOpWavesSpec({ ...spec, approvals: { involved: { exclude: "yes" } } } as unknown as OpWavesSpec)).toThrow(/involved.exclude/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("Requested-by trailers and an agent's account are involved, as terragucci's Involved reads them", () => {
|
|
80
|
+
expect(requestedByTrailers("fix\n\nRequested-by: bob\nrequested-by: Bob\nRequested-by: not a login!")).toEqual(["bob"]);
|
|
81
|
+
const principal = (l: string) => `github:${l}`;
|
|
82
|
+
const inv = changeInvolvement({ author: "github:dana", commits: requestedByBob(), agents: ["github:tg-bot"], principal });
|
|
83
|
+
expect(inv).toEqual([
|
|
84
|
+
{ who: "github:dana", why: "github:dana opened the change" },
|
|
85
|
+
{ who: "github:bob", why: "bob asked for abc1234" },
|
|
86
|
+
{ who: "github:tg-bot", why: "github:tg-bot is an account an agent acts as" },
|
|
87
|
+
]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("the judge proves a reviewer from a recorded review, and leaves out the involved, as ruleApprovers does", () => {
|
|
91
|
+
const principal = (l: string) => `github:${l}`;
|
|
92
|
+
const read = recordedReviewApprovals([productReview(["alice", "bob", "tg-bot"], "2026-10-22T01:00:00Z")], principal);
|
|
93
|
+
expect(read.records.map((r) => r.resolvedBy)).toEqual(["github:alice", "github:bob", "github:tg-bot"]);
|
|
94
|
+
const judge = trustQuorumJudge({
|
|
95
|
+
signers: trust(),
|
|
96
|
+
roles: trust().roles,
|
|
97
|
+
authors: ["github:dana"],
|
|
98
|
+
involved: changeInvolvement({ commits: requestedByBob(), agents: ["github:tg-bot"], principal }),
|
|
99
|
+
excludeInvolved: true,
|
|
100
|
+
recorded: read.reviews,
|
|
101
|
+
});
|
|
102
|
+
const j = (who: string) => judge(read.records.find((r) => r.resolvedBy === who)!);
|
|
103
|
+
expect(j("github:alice")).toEqual({ proven: true, roles: ["platform"], author: false });
|
|
104
|
+
expect(j("github:bob")).toMatchObject({ proven: true, author: true, excluded: "bob asked for abc1234, so github:bob's approval does not count" });
|
|
105
|
+
expect(j("github:tg-bot").excluded).toMatch(/account an agent acts as/);
|
|
106
|
+
// Without a recorded review the same approval proves nobody.
|
|
107
|
+
const none = trustQuorumJudge({ signers: trust(), roles: trust().roles });
|
|
108
|
+
expect(none(read.records[0]!)).toEqual({ proven: false, roles: [] });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("a wave counts each reviewer of a recorded review, leaves out the requester and the agent, and passes on a second", async () => {
|
|
112
|
+
const h = harness(atBase);
|
|
113
|
+
const logs: string[] = [];
|
|
114
|
+
// alice reviewed with bob (who asked for the change) and the agent's account: only alice counts.
|
|
115
|
+
const gates = ledgerPort([productReview(["alice", "bob", "tg-bot"], "2026-10-22T01:00:00Z")]);
|
|
116
|
+
const one = await run(h, gates, { log: (l) => logs.push(l) });
|
|
117
|
+
expect(one.exitCode).toBe(3);
|
|
118
|
+
expect(one.decision?.quorumProgress?.[0]).toMatchObject({ approvers: ["github:alice"], met: false });
|
|
119
|
+
expect(logs.some((l) => /bob asked for abc1234, so github:bob's approval does not count/.test(l))).toBe(true);
|
|
120
|
+
expect(logs.some((l) => /github:tg-bot is an account an agent acts as/.test(l))).toBe(true);
|
|
121
|
+
// carol reviews later, in a second line: two distinct, proven, uninvolved approvers.
|
|
122
|
+
const two = ledgerPort([productReview(["alice", "bob", "tg-bot"], "2026-10-22T01:00:00Z"), productReview(["carol"], "2026-10-22T01:30:00Z")]);
|
|
123
|
+
const done = await run(h, two);
|
|
124
|
+
expect(done.exitCode).toBe(0);
|
|
125
|
+
expect(done.decision?.approvedBy).toBe("github:alice, github:carol");
|
|
126
|
+
h.done();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("the pull request's author never counts, though a recorded review names them", async () => {
|
|
130
|
+
const h = harness(atBase);
|
|
131
|
+
const gates = ledgerPort([productReview(["dana", "alice"], "2026-10-22T01:00:00Z")]);
|
|
132
|
+
const r = await run(h, gates);
|
|
133
|
+
expect(r.exitCode).toBe(3);
|
|
134
|
+
expect(r.decision?.quorumProgress?.[0]?.approvers).toEqual(["github:alice"]);
|
|
135
|
+
h.done();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("the ledger and the exclusion are read at base: a change that names its own ledger or agents gains nothing", async () => {
|
|
139
|
+
// Base sets a quorum and nothing else; the change adds reviewLedger and drops involved.
|
|
140
|
+
const baseOnly: OpWavesSpec = { ...spec, approvals: { quorum: [{ count: 1, roles: ["platform"] }] } };
|
|
141
|
+
const h = harness(baseOnly);
|
|
142
|
+
const gates = ledgerPort([productReview(["alice"], "2026-10-22T01:00:00Z")]);
|
|
143
|
+
const r = await run(h, gates, { spec: { ...baseOnly, approvals: { quorum: [{ count: 1 }], reviewLedger: "tf-apply" } } });
|
|
144
|
+
expect(r.exitCode).toBe(3);
|
|
145
|
+
expect(r.decision?.reviewLedger).toBeUndefined();
|
|
146
|
+
expect(gates.resolved).toEqual([]);
|
|
147
|
+
h.done();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("a review of another digest, or a ledger line with no reviewers, proves nobody", async () => {
|
|
151
|
+
const h = harness(atBase);
|
|
152
|
+
const gates = ledgerPort([productReview(["alice", "carol"], "2026-10-22T01:00:00Z", { planDigest: digest("0") }), productReview([], "2026-10-22T01:10:00Z")]);
|
|
153
|
+
const r = await run(h, gates);
|
|
154
|
+
expect(r.exitCode).toBe(3);
|
|
155
|
+
expect(r.decision?.quorumProgress?.[0]?.approvers).toEqual([]);
|
|
156
|
+
h.done();
|
|
157
|
+
});
|
|
158
|
+
});
|