@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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
|
-
import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { cpSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
13
|
import Ajv2020 from "ajv/dist/2020";
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
type StatusDocument,
|
|
27
27
|
} from "./status";
|
|
28
28
|
import schema from "./status.schema.json";
|
|
29
|
+
import { REPO } from "./__fixtures__/contract-repo";
|
|
30
|
+
import { parseFrontMatter } from "./records";
|
|
29
31
|
import { appendRunRecord } from "../lifecycle/run-ledger";
|
|
30
32
|
import { acquireStewardLease } from "../op/operator";
|
|
31
33
|
import { stewardWorkHolder } from "../op/work-lease-run";
|
|
@@ -525,6 +527,8 @@ describe("gate state in chant workspace status --json (#2674)", () => {
|
|
|
525
527
|
approvals: [{ principal: "alice", channel: "cli", relayedBy: null, at: "2026-09-20T01:00:00.000Z" }],
|
|
526
528
|
needed: 1,
|
|
527
529
|
signed: null,
|
|
530
|
+
// No record kind is declared, so no decision covers web.
|
|
531
|
+
decisions: [],
|
|
528
532
|
approve: `chant approve web deploy --env staging --plan ${D("1")}`,
|
|
529
533
|
},
|
|
530
534
|
{
|
|
@@ -538,6 +542,7 @@ describe("gate state in chant workspace status --json (#2674)", () => {
|
|
|
538
542
|
approvals: [],
|
|
539
543
|
needed: 1,
|
|
540
544
|
signed: null,
|
|
545
|
+
decisions: [],
|
|
541
546
|
approve: `chant approve web deploy --env prod --plan ${D("2")}`,
|
|
542
547
|
},
|
|
543
548
|
{
|
|
@@ -552,6 +557,7 @@ describe("gate state in chant workspace status --json (#2674)", () => {
|
|
|
552
557
|
approvals: [{ principal: "bob", channel: "cli", relayedBy: null, at: "2026-09-20T02:00:00.000Z" }],
|
|
553
558
|
needed: 2,
|
|
554
559
|
signed: null,
|
|
560
|
+
decisions: [],
|
|
555
561
|
approve: `chant approve web review --env staging --plan ${D("4")}`,
|
|
556
562
|
},
|
|
557
563
|
]);
|
|
@@ -629,6 +635,45 @@ describe("gate state in chant workspace status --json (#2674)", () => {
|
|
|
629
635
|
});
|
|
630
636
|
});
|
|
631
637
|
|
|
638
|
+
describe("the decisions covering a gate's member (#3616)", () => {
|
|
639
|
+
test("each gate names the current decisions covering its member, ranked as why ranks them", async () => {
|
|
640
|
+
const ref = join(REPO, "reference-workspace", "decisions");
|
|
641
|
+
const fm = parseFrontMatter(readFileSync(join(ref, "ref-001-how-the-app-is-deployed.md"), "utf-8"));
|
|
642
|
+
if (!fm.ok) throw new Error(fm.message);
|
|
643
|
+
const base = fm.value;
|
|
644
|
+
const decision = (id: string, fields: Record<string, unknown>) =>
|
|
645
|
+
`---\n${JSON.stringify({ ...base, id, title: `Decision ${id}`, state: "decided", supersedes: [], evidence: [], reviews: [], ...fields }, null, 2)}\n---\n\n# ${id}\n`;
|
|
646
|
+
const root = repo({
|
|
647
|
+
"chant.workspace.json": JSON.stringify({
|
|
648
|
+
name: "acme",
|
|
649
|
+
schema: 1,
|
|
650
|
+
records: [{ kind: "decisions/decision.kind.mjs" }],
|
|
651
|
+
members: [
|
|
652
|
+
{ name: "web", dir: "apps/web", kind: "other", because: "the app" },
|
|
653
|
+
{ name: "api", dir: "apps/api", kind: "other", because: "the api" },
|
|
654
|
+
],
|
|
655
|
+
}),
|
|
656
|
+
"decisions/decision.kind.mjs": readFileSync(join(ref, "decision.kind.mjs"), "utf-8"),
|
|
657
|
+
"decisions/decision.schema.json": readFileSync(join(ref, "decision.schema.json"), "utf-8"),
|
|
658
|
+
"apps/web/server.ts": "export {};\n",
|
|
659
|
+
"decisions/s-001-d.md": decision("s-001", { constrains: ["member:web"] }),
|
|
660
|
+
"decisions/s-002-d.md": decision("s-002", { constrains: ["path:apps"] }),
|
|
661
|
+
"decisions/s-003-d.md": decision("s-003", { constrains: ["path:apps/web/server.ts"] }),
|
|
662
|
+
"decisions/s-004-d.md": decision("s-004", { constrains: ["path:apps/web"] }),
|
|
663
|
+
"decisions/s-005-d.md": decision("s-005", { constrains: ["path:elsewhere"], supersedes: [{ decision: "s-004" }] }),
|
|
664
|
+
"decisions/s-006-d.md": decision("s-006", { constrains: ["member:api"] }),
|
|
665
|
+
});
|
|
666
|
+
lifecycle(root, { "_members/web/_gates/web.jsonl": jsonl(pending("web", "deploy", "2026-09-20T00:00:00.000Z", { environment: "staging", planDigest: D("1") })) });
|
|
667
|
+
const doc = result(await workspaceStatus({ cwd: root, env: "staging", now: NOW }));
|
|
668
|
+
expectValid(doc);
|
|
669
|
+
const [web, api] = doc.members;
|
|
670
|
+
// s-002 by a path above, s-001 by member, s-003 by a path inside; s-004 stands for s-005, which supersedes it.
|
|
671
|
+
expect(web.gates.map((g) => g.decisions)).toEqual([["decision/s-002", "decision/s-001", "decision/s-003", "decision/s-005"]]);
|
|
672
|
+
// A member with no gate reads no decisions.
|
|
673
|
+
expect(api.gates).toEqual([]);
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
632
677
|
describe("stewards in chant workspace status --json (#2731)", () => {
|
|
633
678
|
const op = (name: string, cron?: string) => ({
|
|
634
679
|
name,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type { Declaration } from "./declaration";
|
|
3
|
+
import type { LoadedRecordKind, RecordEntry } from "./records";
|
|
4
|
+
import { memberDecisionsReader, type DecisionKindReader } from "./status-decisions";
|
|
5
|
+
|
|
6
|
+
const members = [
|
|
7
|
+
{ name: "root", dir: "." },
|
|
8
|
+
{ name: "api", dir: "services/api" },
|
|
9
|
+
{ name: "edge", dir: "services/api/edge" },
|
|
10
|
+
{ name: "web", dir: "web" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
function declaration(kinds: string[]): Declaration {
|
|
14
|
+
return {
|
|
15
|
+
records: kinds.map((path) => ({ kind: path, path, name: null, member: null, pointer: "/records/0" })),
|
|
16
|
+
members: members.map((m) => ({ ...m, records: [] })),
|
|
17
|
+
} as unknown as Declaration;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function kind(name: string, extra: Record<string, unknown> = {}): LoadedRecordKind {
|
|
21
|
+
return { kind: { name, constrains: { field: "constrains" }, closedStates: ["accepted"], ...extra } } as unknown as LoadedRecordKind;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function record(id: string, constrains: string[], state = "proposed", supersededBy: string | null = null): RecordEntry {
|
|
25
|
+
return { id, path: `decisions/${id}.md`, state, supersededBy, data: { constrains } } as unknown as RecordEntry;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function reader(kinds: Record<string, { loaded: LoadedRecordKind; records: RecordEntry[]; workspaceRoot?: string } | Error>): DecisionKindReader {
|
|
29
|
+
return async (file) => {
|
|
30
|
+
const k = Object.entries(kinds).find(([path]) => file.endsWith(path))?.[1];
|
|
31
|
+
if (!k) throw new Error(`no kind ${file}`);
|
|
32
|
+
if (k instanceof Error) throw k;
|
|
33
|
+
return { loaded: k.loaded, top: undefined, workspaceRoot: k.workspaceRoot ?? ".", records: k.records };
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("the decisions covering a gate's member (#3616)", () => {
|
|
38
|
+
test("path above, member and path inside, ranked as why ranks them", async () => {
|
|
39
|
+
const read = reader({
|
|
40
|
+
"decision.kind.mjs": {
|
|
41
|
+
loaded: kind("decision"),
|
|
42
|
+
records: [
|
|
43
|
+
record("d-inside", ["path:services/api/src/handler.ts"]),
|
|
44
|
+
record("d-member", ["member:api"]),
|
|
45
|
+
record("d-services", ["path:services"]),
|
|
46
|
+
record("d-api", ["path:services/api"], "accepted"),
|
|
47
|
+
record("d-api-open", ["path:services/api"]),
|
|
48
|
+
record("d-web", ["path:web", "member:web"]),
|
|
49
|
+
record("d-edge-only", ["path:services/api/edge/x.ts"]),
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo", "", read);
|
|
54
|
+
// Closed before open at one path; a longer path before a shorter one; then member; then inside.
|
|
55
|
+
expect(covering(members[1])).toEqual(["decision/d-api", "decision/d-api-open", "decision/d-services", "decision/d-member", "decision/d-inside"]);
|
|
56
|
+
// A path inside a nested member is the nested member's, and the path above covers it too.
|
|
57
|
+
expect(covering(members[2])).toEqual(["decision/d-api", "decision/d-api-open", "decision/d-services", "decision/d-edge-only"]);
|
|
58
|
+
expect(covering(members[3])).toEqual(["decision/d-web"]);
|
|
59
|
+
// The root member holds services itself, and no path another member holds.
|
|
60
|
+
expect(covering(members[0])).toEqual(["decision/d-services"]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("a superseded covering decision stands for the current one at the end of its chain", async () => {
|
|
64
|
+
const read = reader({
|
|
65
|
+
"decision.kind.mjs": {
|
|
66
|
+
loaded: kind("decision"),
|
|
67
|
+
records: [record("old", ["member:web"], "superseded", "mid"), record("mid", [], "superseded", "new"), record("new", ["path:elsewhere"], "accepted"), record("gone", ["member:web"], "superseded", "missing")],
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo", "", read);
|
|
71
|
+
expect(covering(members[3])).toEqual(["decision/new"]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("path entries resolve from the kind's workspace root, and a member's dir from the workspace's", async () => {
|
|
75
|
+
const read = reader({
|
|
76
|
+
"decision.kind.mjs": { loaded: kind("decision"), workspaceRoot: "ws", records: [record("d", ["path:web"])] },
|
|
77
|
+
});
|
|
78
|
+
const covering = await memberDecisionsReader(declaration(["decision.kind.mjs"]), "/repo/ws", "ws", read);
|
|
79
|
+
expect(covering(members[3])).toEqual(["decision/d"]);
|
|
80
|
+
expect(covering(members[1])).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("work kinds, kinds without constrains and unreadable kinds cover nothing", async () => {
|
|
84
|
+
const read = reader({
|
|
85
|
+
"work.kind.mjs": { loaded: kind("work", { work: {} }), records: [record("w", ["member:web"])] },
|
|
86
|
+
"note.kind.mjs": { loaded: kind("note", { constrains: undefined }), records: [record("n", ["member:web"])] },
|
|
87
|
+
"broken.kind.mjs": new Error("kind-unreadable"),
|
|
88
|
+
"adr.kind.mjs": { loaded: kind("adr"), records: [record("a", ["member:web"])] },
|
|
89
|
+
});
|
|
90
|
+
const covering = await memberDecisionsReader(declaration(["work.kind.mjs", "note.kind.mjs", "broken.kind.mjs", "adr.kind.mjs"]), "/repo", "", read);
|
|
91
|
+
expect(covering(members[3])).toEqual(["adr/a"]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("no declared record kind reads nothing", async () => {
|
|
95
|
+
const covering = await memberDecisionsReader(declaration([]), "/repo", "", async () => {
|
|
96
|
+
throw new Error("not read");
|
|
97
|
+
});
|
|
98
|
+
expect(covering(members[3])).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decisions covering each member, for the gates in `chant workspace
|
|
3
|
+
* status --json` (#3616): a reader showing a gate to the person about to
|
|
4
|
+
* approve it names the decision the gate enforces without a
|
|
5
|
+
* `graph --intent` walk of its own.
|
|
6
|
+
*
|
|
7
|
+
* This is the part of the intent walk (`intent.ts`) that reads only records.
|
|
8
|
+
* A decision covers a member when one of its `constrains` entries is
|
|
9
|
+
* `member:<name>`, or a `path:` that is the member's directory, a directory
|
|
10
|
+
* above it, or a path inside it that the member holds (not a member nested
|
|
11
|
+
* in it). A superseded covering decision stands for the decision that
|
|
12
|
+
* supersedes it, at the end of its chain. Only current decisions are listed,
|
|
13
|
+
* as `<kind>/<id>`, ranked as `why.decisions` ranks them
|
|
14
|
+
* (`decision-rank.ts`). `carried` needs the member's history, so it never
|
|
15
|
+
* applies, and neither do `issue` or `contract`, which need commits. Every
|
|
16
|
+
* declared record kind other than a work kind is read, as the intent walk
|
|
17
|
+
* reads them; a kind that can't be read is left out.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { declaredRecordKinds, type Declaration } from "./declaration";
|
|
21
|
+
import { declaredKindFile } from "./declared-kinds";
|
|
22
|
+
import { compareDecisionRank, type DecisionRankKey, type WhyRelevance } from "./decision-rank";
|
|
23
|
+
import { decidedCommits } from "./record-decided";
|
|
24
|
+
import { constraintCovers, isWorkspacePath, memberHolding } from "./record-assets";
|
|
25
|
+
import type { LoadedRecordKind, RecordEntry } from "./records";
|
|
26
|
+
import { joinPath } from "./tree";
|
|
27
|
+
|
|
28
|
+
interface ReadKind {
|
|
29
|
+
loaded: LoadedRecordKind;
|
|
30
|
+
top: string | undefined;
|
|
31
|
+
/** Where the kind's `path:` entries resolve, from the git top. */
|
|
32
|
+
prefix: string;
|
|
33
|
+
records: RecordEntry[];
|
|
34
|
+
byId: Map<string, RecordEntry>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Reads one kind's records, current and superseded; `readRecordsFor` in the working tree unless a test swaps it. */
|
|
38
|
+
export type DecisionKindReader = (file: string, root: string) => Promise<{ loaded: LoadedRecordKind; top: string | undefined; workspaceRoot: string; records: RecordEntry[] }>;
|
|
39
|
+
|
|
40
|
+
const defaultReader: DecisionKindReader = async (file, root) => {
|
|
41
|
+
const { readRecordsFor } = await import("./records-cli");
|
|
42
|
+
const read = await readRecordsFor({ kind: file, cwd: root });
|
|
43
|
+
return { loaded: read.loaded, top: read.top, workspaceRoot: read.workspaceRoot, records: read.result.records };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Read the declared decision kinds once and return the covering decisions of
|
|
48
|
+
* a member. `root` is the workspace root on disk and `rootDir` the same from
|
|
49
|
+
* the git top (`""` at the top).
|
|
50
|
+
*/
|
|
51
|
+
export async function memberDecisionsReader(
|
|
52
|
+
declaration: Declaration,
|
|
53
|
+
root: string,
|
|
54
|
+
rootDir: string,
|
|
55
|
+
read: DecisionKindReader = defaultReader,
|
|
56
|
+
): Promise<(member: { name: string; dir: string }) => string[]> {
|
|
57
|
+
const kinds: ReadKind[] = [];
|
|
58
|
+
for (const d of declaredRecordKinds(declaration)) {
|
|
59
|
+
try {
|
|
60
|
+
const r = await read(declaredKindFile(d, root), root);
|
|
61
|
+
if (r.loaded.kind.work) continue;
|
|
62
|
+
const byId = new Map<string, RecordEntry>();
|
|
63
|
+
for (const v of r.records) if (v.id !== null) byId.set(v.id, v);
|
|
64
|
+
kinds.push({ loaded: r.loaded, top: r.top, prefix: r.workspaceRoot === "." ? "" : r.workspaceRoot, records: r.records, byId });
|
|
65
|
+
} catch {
|
|
66
|
+
// A kind that can't be read covers nothing here; workspace check and records report why.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// When each current decision was decided, read once per kind on first need.
|
|
70
|
+
const decidedOn = new Map<ReadKind, Map<string, string | null>>();
|
|
71
|
+
const decidedDate = (k: ReadKind, v: RecordEntry): string | null => {
|
|
72
|
+
if (!k.loaded.kind.approval || !k.top) return null;
|
|
73
|
+
let dates = decidedOn.get(k);
|
|
74
|
+
if (!dates) {
|
|
75
|
+
const current = k.records.filter((r) => r.id !== null && r.supersededBy === null).map((r) => r.path);
|
|
76
|
+
const decided = decidedCommits(k.top, "HEAD", current, k.loaded.kind);
|
|
77
|
+
dates = new Map(current.map((p) => [p, decided.get(p)?.date ?? null]));
|
|
78
|
+
decidedOn.set(k, dates);
|
|
79
|
+
}
|
|
80
|
+
return dates.get(v.path) ?? null;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return (member) => {
|
|
84
|
+
const memberFull = joinPath(rootDir, member.dir);
|
|
85
|
+
const ranked: { key: DecisionRankKey; label: string }[] = [];
|
|
86
|
+
for (const k of kinds) {
|
|
87
|
+
const field = k.loaded.kind.constrains?.field;
|
|
88
|
+
if (!field) continue;
|
|
89
|
+
const name = k.loaded.kind.name;
|
|
90
|
+
/** How each record covers the member: the relevance and the longest covering path entry. */
|
|
91
|
+
const covers = (v: RecordEntry): { relevance: WhyRelevance; specificity: number } | null => {
|
|
92
|
+
const list = v.data?.[field];
|
|
93
|
+
if (!Array.isArray(list)) return null;
|
|
94
|
+
let path = 0;
|
|
95
|
+
let byMember = false;
|
|
96
|
+
let inside = false;
|
|
97
|
+
for (const entry of list) {
|
|
98
|
+
if (typeof entry !== "string") continue;
|
|
99
|
+
if (entry.startsWith("member:")) {
|
|
100
|
+
if (entry.slice("member:".length) === member.name) byMember = true;
|
|
101
|
+
} else if (entry.startsWith("path:")) {
|
|
102
|
+
const p = entry.slice("path:".length);
|
|
103
|
+
if (!isWorkspacePath(p)) continue;
|
|
104
|
+
const full = joinPath(k.prefix, p);
|
|
105
|
+
if (memberFull !== "" && constraintCovers(full, memberFull)) path = Math.max(path, entry.length);
|
|
106
|
+
else if (memberFull === "" || full.startsWith(`${memberFull}/`)) {
|
|
107
|
+
// Inside the member's directory, and not in a member nested in it.
|
|
108
|
+
const inWorkspace = rootDir === "" ? full : full.startsWith(`${rootDir}/`) ? full.slice(rootDir.length + 1) : null;
|
|
109
|
+
if (inWorkspace !== null && memberHolding(inWorkspace, declaration.members) === member.name) inside = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (path > 0) return { relevance: "path", specificity: path };
|
|
114
|
+
if (byMember) return { relevance: "member", specificity: 0 };
|
|
115
|
+
return inside ? { relevance: "related", specificity: 0 } : null;
|
|
116
|
+
};
|
|
117
|
+
// Each covering record, and the current record at the end of its supersession chain.
|
|
118
|
+
const current = new Set<string>();
|
|
119
|
+
for (const v of k.records) {
|
|
120
|
+
if (v.id === null || covers(v) === null) continue;
|
|
121
|
+
let at: RecordEntry = v;
|
|
122
|
+
const seen = new Set<string>();
|
|
123
|
+
while (at.supersededBy !== null && !seen.has(at.id!)) {
|
|
124
|
+
seen.add(at.id!);
|
|
125
|
+
const next = k.byId.get(at.supersededBy);
|
|
126
|
+
if (!next) break;
|
|
127
|
+
at = next;
|
|
128
|
+
}
|
|
129
|
+
if (at.supersededBy === null && at.id !== null) current.add(at.id);
|
|
130
|
+
}
|
|
131
|
+
for (const id of current) {
|
|
132
|
+
const v = k.byId.get(id)!;
|
|
133
|
+
// A decision in the list only through the chain is related, as in why.
|
|
134
|
+
const c = covers(v) ?? { relevance: "related" as const, specificity: 0 };
|
|
135
|
+
ranked.push({
|
|
136
|
+
label: `${name}/${id}`,
|
|
137
|
+
key: {
|
|
138
|
+
id: `record:${name}/${id}`,
|
|
139
|
+
current: true,
|
|
140
|
+
relevance: c.relevance,
|
|
141
|
+
lines: 0,
|
|
142
|
+
closed: v.state !== null && (k.loaded.kind.closedStates ?? []).includes(v.state),
|
|
143
|
+
specificity: c.specificity,
|
|
144
|
+
decidedOn: decidedDate(k, v),
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return ranked.sort((a, b) => compareDecisionRank(a.key, b.key)).map((r) => r.label);
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -82,6 +82,15 @@ export interface StatusGate {
|
|
|
82
82
|
* `release-revoked`. Added by `workspace status`; absent otherwise.
|
|
83
83
|
*/
|
|
84
84
|
revoked?: ReleaseRevocation;
|
|
85
|
+
/**
|
|
86
|
+
* The current decisions covering the gate's member (#3616), as
|
|
87
|
+
* `<kind>/<id>`, most relevant first: by a `path:` at or above the
|
|
88
|
+
* member's directory, by `member:`, then by a path inside it or through
|
|
89
|
+
* supersession, ranked as the intent graph's `why.decisions`. Read from
|
|
90
|
+
* the records only, without history. Added by `workspace status`; absent
|
|
91
|
+
* otherwise.
|
|
92
|
+
*/
|
|
93
|
+
decisions?: string[];
|
|
85
94
|
/** When the run recorded the pending fact the state is read against. */
|
|
86
95
|
recordedAt: string;
|
|
87
96
|
/** The commit the run reached the gate at (#4020), from the pending fact. Absent on a fact written before chant 0.124.28. */
|
|
@@ -104,6 +104,7 @@
|
|
|
104
104
|
"required": ["name", "root", "file"],
|
|
105
105
|
"properties": {
|
|
106
106
|
"name": { "type": "string" },
|
|
107
|
+
"repo": { "type": ["string", "null"], "description": "Added in contract 1 by #3168. The repository the document came from: the URL of the remote origin of the git repository that holds the workspace, with any user name or password removed, or null when there is no origin or the workspace is outside git. With name, root and the revision, it says which repository's workspace a document describes, so a reader that gathers several repositories' documents, such as an org workspace's repo members, tells them apart." },
|
|
107
108
|
"root": { "type": "string", "description": "The workspace root relative to the git root, with / separators, \".\" for the git root itself." },
|
|
108
109
|
"file": { "enum": ["chant.workspace.json", "chant.workspace.jsonc"] }
|
|
109
110
|
}
|
|
@@ -987,6 +988,11 @@
|
|
|
987
988
|
"changeSet": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Added in contract 1 by #4022, written by chant 0.124.28 and newer. The change set the gate binds: planDigest, when a change-set document is stored under it in the member's _change-sets/ on chant/lifecycle, as a pull-request gate's apply and a release gate (#4045) store it. chant change-set show <changeSet> --json prints it, each entry with its graph node. Absent when none is stored, as for a component gate, which binds a lifecycle-plan digest." },
|
|
988
989
|
"releaseDigest": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "Added in contract 1 by #4045, written by chant 0.124.28 and newer. The release the gate binds, from the pending fact: set on a release gate, the gate chant components promote --release passes for an environment, whose component is the op release. An approval counts toward it only when it was recorded for this release, environment and planDigest. Absent on every other gate." },
|
|
989
990
|
"revoked": { "$ref": "#/$defs/revocation", "description": "Added in contract 1 by #4033 (ws-105), written by chant 0.124.29 and newer. Set on a release gate whose release was cut from a commit with a ci/revoked/<sha> tag, judged as release cut judges it: the tag. The gate's state is then superseded, or expired when its pending fact has expired. Absent otherwise." },
|
|
991
|
+
"decisions": {
|
|
992
|
+
"type": "array",
|
|
993
|
+
"items": { "type": "string", "pattern": "^[^/]+/.+$" },
|
|
994
|
+
"description": "Added in contract 1 by #3616, written by chant 0.124.47 and newer. The current decisions covering the gate's member, as <kind>/<id>, most relevant first, so a reader names the decision a gate enforces without a graph --intent walk. A decision covers the member by a path: constraint that is the member's directory or a directory above it, by member:<name>, or by a path: inside the directory that the member holds; a superseded covering decision stands for the current one at the end of its chain. Ranked as the intent graph's why.decisions ranks them (path, then member, then the rest; then closed, longer path, newest decided, id), without carried, issue or contract, which need history. Read from every declared record kind but work kinds, in the working tree; a kind that can't be read is left out. The same list on every gate of a member, and empty when nothing covers it. Absent from an older chant."
|
|
995
|
+
},
|
|
990
996
|
"expiresAt": { "type": "string" },
|
|
991
997
|
"approvals": {
|
|
992
998
|
"description": "The approvals that count toward the gate for its plan, oldest first.",
|
package/src/workspace/status.ts
CHANGED
|
@@ -50,6 +50,7 @@ import { findWorkspaceRoot } from "../project-root";
|
|
|
50
50
|
import { resolveBoxes, type ResolvedIsolation } from "./box-isolation";
|
|
51
51
|
import { resolveBoxIntents, unresolvedIntent, type BoxIntent } from "./box-intent";
|
|
52
52
|
import { loadKindRegistry, resolveMemberFields, type MemberFields } from "./kinds";
|
|
53
|
+
import { repoIdentity } from "./repo-ref";
|
|
53
54
|
import { factoryView, listingView, plantability, treeBytes, type FactoryView, type ListingView, type Plantable } from "./box-factory";
|
|
54
55
|
import { declaredRecordKinds, extensionsAt, readDeclaration, readerVersion, WorkspaceReadError, type Declaration, type ErrorLocation, type Member } from "./declaration";
|
|
55
56
|
import type { ReasonCode } from "./reason-codes";
|
|
@@ -63,6 +64,7 @@ import { scopeSource } from "./write-scope";
|
|
|
63
64
|
import { GATE_REASON_CODES, readMemberGates, type GateLedgerReader, type StatusGate, type StatusGateLedger } from "./status-gates";
|
|
64
65
|
import { trustQuorumJudge } from "../op/gate-quorum";
|
|
65
66
|
import { STEWARD_REASON_CODES, readMemberStewards, type StatusSteward, type StewardReasonCode } from "./status-stewards";
|
|
67
|
+
import { memberDecisionsReader, type DecisionKindReader } from "./status-decisions";
|
|
66
68
|
import { gitTop, workingTree } from "./tree";
|
|
67
69
|
import { handToRootChant } from "./which-chant";
|
|
68
70
|
|
|
@@ -387,7 +389,7 @@ export type StatusDocument =
|
|
|
387
389
|
lifecycle: { ref: string; commit: string | null };
|
|
388
390
|
/** The branch, head and base of the checkout read (#3160). `records --uncommitted` lists the records it holds uncommitted. */
|
|
389
391
|
checkout: CheckoutHead;
|
|
390
|
-
workspace: { name: string; root: string; file: string };
|
|
392
|
+
workspace: { name: string; root: string; file: string; repo: string | null };
|
|
391
393
|
/** Whether a host can plant the workspace as one box (#3146): exactly one member's box block declares services. */
|
|
392
394
|
plantable: Plantable;
|
|
393
395
|
members: StatusMember[];
|
|
@@ -433,6 +435,8 @@ export interface StatusQuery {
|
|
|
433
435
|
readStewards?: typeof readMemberStewards;
|
|
434
436
|
/** Reads one member's promotion order from its directory; its chant.config.ts unless a test swaps it. */
|
|
435
437
|
readPromotionOrder?: (dir: string) => Promise<PromotionStep[] | null>;
|
|
438
|
+
/** Reads one record kind for the decisions covering each gate's member (#3616); the working tree unless a test swaps it. */
|
|
439
|
+
readDecisionKind?: DecisionKindReader;
|
|
436
440
|
}
|
|
437
441
|
|
|
438
442
|
/** A factory view with the declaration's x- keys on it and on its check, publish and tiers (#3595). */
|
|
@@ -727,6 +731,9 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
727
731
|
const revoked = () => (revokedCommits ??= revokedCommitsAt(top, ruleSource.declaration?.ci?.green ?? null).catch(() => new Map()));
|
|
728
732
|
// #4024: the flag records, read once for every member. Unreadable records list as null.
|
|
729
733
|
const flags = await readStatusFlags(declaration, found.dir);
|
|
734
|
+
// #3616: the decisions covering each member, read from the records once and only when a gate is met.
|
|
735
|
+
let coveringReader: ReturnType<typeof memberDecisionsReader> | undefined;
|
|
736
|
+
const covering = () => (coveringReader ??= memberDecisionsReader(declaration, found.dir, rootDir, query.readDecisionKind));
|
|
730
737
|
const members: StatusMember[] = [];
|
|
731
738
|
for (const m of declaration.members) {
|
|
732
739
|
const revokedOf = revokedReleaseLookup(resolve(found.dir, m.dir), revoked);
|
|
@@ -748,7 +755,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
748
755
|
compare: query.compareTo === undefined ? null : compareEnvironments(environments[0], environments[environments.length - 1]),
|
|
749
756
|
readable: environments.every((e) => e.reason === null),
|
|
750
757
|
gateLedger: gates.ledger,
|
|
751
|
-
gates: await supersedeRevokedGates(gates.gates, revokedOf),
|
|
758
|
+
gates: await withDecisions(await supersedeRevokedGates(gates.gates, revokedOf), m, covering),
|
|
752
759
|
box:
|
|
753
760
|
m.box === null
|
|
754
761
|
? null
|
|
@@ -807,7 +814,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
807
814
|
compareTo: query.compareTo ?? null,
|
|
808
815
|
lifecycle: { ref: LIFECYCLE_REF, commit },
|
|
809
816
|
checkout: readCheckoutHead(top),
|
|
810
|
-
workspace: { name: declaration.name, root: rootDir === "" ? "." : rootDir, file: declaration.file },
|
|
817
|
+
workspace: { name: declaration.name, root: rootDir === "" ? "." : rootDir, file: declaration.file, repo: repoIdentity(found.dir) },
|
|
811
818
|
plantable: plantability(declaration),
|
|
812
819
|
members,
|
|
813
820
|
leases,
|
|
@@ -889,6 +896,13 @@ async function readStatusFlags(declaration: Declaration, root: string): Promise<
|
|
|
889
896
|
}
|
|
890
897
|
}
|
|
891
898
|
|
|
899
|
+
/** Each gate with the current decisions covering its member (#3616), when the member has gates. */
|
|
900
|
+
async function withDecisions(gates: StatusGate[], m: { name: string; dir: string }, covering: () => ReturnType<typeof memberDecisionsReader>): Promise<StatusGate[]> {
|
|
901
|
+
if (gates.length === 0) return gates;
|
|
902
|
+
const decisions = (await covering())(m);
|
|
903
|
+
return gates.map((g) => ({ ...g, decisions: [...decisions] }));
|
|
904
|
+
}
|
|
905
|
+
|
|
892
906
|
/** The overlap report (#4025); null when no work kind is declared or it can't be read. */
|
|
893
907
|
async function readStatusOverlap(declaration: Declaration, root: string, top: string, changeSets: OverlapChangeSetRef[]): Promise<OverlapReport | null> {
|
|
894
908
|
if (declaredRecordKinds(declaration).length === 0) return null;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parseArgs } from "../cli/main";
|
|
3
|
+
import { matchesWhere, parseWhere } from "../read-filter";
|
|
4
|
+
import { filterRecordsDocument, RECORD_FILTER_FIELDS, type RecordsDocument } from "./records-cli";
|
|
5
|
+
import { RUN_FILTER_FIELDS, RunsFilterError, workspaceRuns } from "./runs-cli";
|
|
6
|
+
|
|
7
|
+
describe("--where on records and runs (#4363)", () => {
|
|
8
|
+
it("parses --where as a repeatable flag", () => {
|
|
9
|
+
expect(parseArgs(["ledger", "gates", "--where", "op=tf-apply", "--where", "kind=pending"]).where).toEqual(["op=tf-apply", "kind=pending"]);
|
|
10
|
+
expect(() => parseArgs(["ledger", "gates", "--where"])).toThrow(/--where needs a clause/);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("filters the records a read lists and counts summary over them", () => {
|
|
14
|
+
const rec = (id: string, state: string, valid: boolean, data: Record<string, unknown>) => ({ id, path: `d/${id}.md`, state, valid, data, supersededBy: null, provenance: { level: "unattested" } });
|
|
15
|
+
const doc = {
|
|
16
|
+
$schema: "x",
|
|
17
|
+
contract: 1,
|
|
18
|
+
records: [rec("D-1", "accepted", true, { owner: "ops" }), rec("D-2", "proposed", true, { owner: "dev" }), rec("D-3", "accepted", false, { owner: "dev" })],
|
|
19
|
+
summary: { total: 3, valid: 2, invalid: 1, superseded: 4 },
|
|
20
|
+
} as unknown as RecordsDocument;
|
|
21
|
+
const where = ["state=accepted", "data.owner=dev"];
|
|
22
|
+
const out = filterRecordsDocument(doc, parseWhere(where, RECORD_FILTER_FIELDS), where);
|
|
23
|
+
if ("error" in out) throw new Error("failed");
|
|
24
|
+
expect(out.records.map((r) => r.id)).toEqual(["D-3"]);
|
|
25
|
+
expect(out.summary).toEqual({ total: 1, valid: 0, invalid: 1, superseded: 4 });
|
|
26
|
+
expect(out.where).toEqual(where);
|
|
27
|
+
expect(filterRecordsDocument(doc, [], [])).toBe(doc);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("filters runs on their typed fields", () => {
|
|
31
|
+
const run = { id: "r1", state: "ended", startedAt: "2026-10-22T00:00:00.000Z", model: "opus", unit: { id: "W-1", kind: "work" }, cost: { amount: 1.5, currency: "USD" } };
|
|
32
|
+
expect(matchesWhere(run, parseWhere(["cost.amount>1", "unit.id=W-1", "startedAt>=2026-10-21"], RUN_FILTER_FIELDS))).toBe(true);
|
|
33
|
+
expect(matchesWhere(run, parseWhere(["model!=opus"], RUN_FILTER_FIELDS))).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("refuses a runs --where it can't apply before reading anything", async () => {
|
|
37
|
+
await expect(workspaceRuns({ cwd: "/nonexistent", where: ["tokens>5"] })).rejects.toThrow(RunsFilterError);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -436,7 +436,8 @@ export function formatWorkHistory(doc: Extract<WorkHistoryDocument, { claims: un
|
|
|
436
436
|
* <file|->` (#3159): the `workEvidence` activity (#2772) as a command, so a
|
|
437
437
|
* writer that is not an Op, such as hud, attaches evidence through chant under
|
|
438
438
|
* the lease it holds. `--from` gives the entry as JSON: criterion, result,
|
|
439
|
-
* title, a url
|
|
439
|
+
* title, a url, a path or an ops result to cite (#3171), and optionally
|
|
440
|
+
* as_of. It always prints the
|
|
440
441
|
* work-evidence document; exit 0 when the entry was appended, 1 otherwise.
|
|
441
442
|
*/
|
|
442
443
|
async function runWorkEvidence(ctx: CommandContext): Promise<number> {
|
|
@@ -452,7 +453,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
|
|
|
452
453
|
if (!id) return fail("evidence needs a work item id");
|
|
453
454
|
if (!args.holder) return fail("evidence needs --holder <name>: the lease's holder");
|
|
454
455
|
if (!args.token) return fail("evidence needs --token <token>: the lease's fencing token, as its claim printed it");
|
|
455
|
-
if (args.migrateFrom === undefined) return fail("evidence needs --from <file|->: the entry as JSON, with criterion, result, title and a url or
|
|
456
|
+
if (args.migrateFrom === undefined) return fail("evidence needs --from <file|->: the entry as JSON, with criterion, result, title and a url, a path or an ops result");
|
|
456
457
|
for (const [flag, v] of [["--ttl", args.ttl], ["--outcome", args.outcome], ["--note", args.note]] as const) {
|
|
457
458
|
if (v !== undefined) return fail(`evidence takes no ${flag}`);
|
|
458
459
|
}
|
|
@@ -470,7 +471,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
|
|
|
470
471
|
1,
|
|
471
472
|
);
|
|
472
473
|
}
|
|
473
|
-
const known = ["criterion", "result", "title", "url", "path", "as_of"];
|
|
474
|
+
const known = ["criterion", "result", "title", "url", "path", "ops", "as_of"];
|
|
474
475
|
const unknown = Object.keys(fields).filter((k) => !known.includes(k));
|
|
475
476
|
if (unknown.length > 0) return fail(`the entry takes ${known.join(", ")}, not ${unknown.join(", ")}`);
|
|
476
477
|
const str = (k: string): string | undefined => (typeof fields[k] === "string" ? (fields[k] as string) : undefined);
|
|
@@ -485,6 +486,7 @@ async function runWorkEvidence(ctx: CommandContext): Promise<number> {
|
|
|
485
486
|
title: str("title") ?? "",
|
|
486
487
|
url: str("url"),
|
|
487
488
|
path: str("path"),
|
|
489
|
+
ops: fields.ops as never,
|
|
488
490
|
asOf: str("as_of"),
|
|
489
491
|
});
|
|
490
492
|
return print(doc, "error" in doc ? 1 : 0);
|