@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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work evidence that cites an ops result (#3171), on a workspace built from
|
|
3
|
+
* the reference workspace's work kind in a throwaway git repository.
|
|
4
|
+
*
|
|
5
|
+
* W-010 is in progress with a runtime criterion, "the web component runs
|
|
6
|
+
* green in staging". The staging run ledger of `deploy-web` holds an `ok`
|
|
7
|
+
* run, a `fail` run and a gated one. The run holding W-010's lease cites the
|
|
8
|
+
* ok run, the citation verifies against the ledger, and the criterion is met.
|
|
9
|
+
* The others, and citations the ledger does not hold, are refused and
|
|
10
|
+
* nothing is written.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
import { cleanScratch, contract, git, REPO, repo } from "./__fixtures__/contract-repo";
|
|
17
|
+
import { queryRecords } from "./records-cli";
|
|
18
|
+
import recordsSchema from "./records.schema.json";
|
|
19
|
+
import { attachWorkEvidence } from "./work-evidence";
|
|
20
|
+
import workEvidenceSchema from "./work-evidence.schema.json";
|
|
21
|
+
import { appendRunRecord } from "../lifecycle/run-ledger";
|
|
22
|
+
import { appendGateResolution } from "../lifecycle/gate-ledger";
|
|
23
|
+
import { persistReleasePlan } from "../lifecycle/plan-ledger";
|
|
24
|
+
import { claimWorkLease, releaseWorkLease } from "../lifecycle/work-lease";
|
|
25
|
+
import type { OpRunRecordInput } from "../op/runtime";
|
|
26
|
+
|
|
27
|
+
const REF = join(REPO, "reference-workspace");
|
|
28
|
+
const KIND = "work/work.kind.mjs";
|
|
29
|
+
|
|
30
|
+
function work(id: string, fields: Record<string, unknown>): string {
|
|
31
|
+
const data = {
|
|
32
|
+
schema: 1,
|
|
33
|
+
id,
|
|
34
|
+
title: `Work ${id}`,
|
|
35
|
+
state: "in-progress",
|
|
36
|
+
implements: [],
|
|
37
|
+
needs: [],
|
|
38
|
+
constrains: ["member:app"],
|
|
39
|
+
evidence: [],
|
|
40
|
+
owner: "alice",
|
|
41
|
+
opened_on: "2026-10-23",
|
|
42
|
+
closed_on: null,
|
|
43
|
+
source: { kind: "workspace", member: "app" },
|
|
44
|
+
supersedes: [],
|
|
45
|
+
...fields,
|
|
46
|
+
};
|
|
47
|
+
return `---\n${JSON.stringify(data, null, 2)}\n---\n\n# ${id}\n`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const run = (id: string, status: OpRunRecordInput["status"]): OpRunRecordInput => ({
|
|
51
|
+
id,
|
|
52
|
+
op: "deploy-web",
|
|
53
|
+
env: "staging",
|
|
54
|
+
started: "2026-10-23T10:00:00.000Z",
|
|
55
|
+
ended: "2026-10-23T10:05:00.000Z",
|
|
56
|
+
status,
|
|
57
|
+
labels: { Env: "staging" },
|
|
58
|
+
outcomes: {},
|
|
59
|
+
phases: [{ name: "Apply", status: status === "fail" ? "fail" : "ok", steps: [] }],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let root: string;
|
|
63
|
+
let token: string;
|
|
64
|
+
const evidenceDoc = contract(workEvidenceSchema);
|
|
65
|
+
const records = contract(recordsSchema);
|
|
66
|
+
|
|
67
|
+
beforeAll(async () => {
|
|
68
|
+
root = repo({
|
|
69
|
+
"chant.workspace.json": JSON.stringify({
|
|
70
|
+
name: "studio",
|
|
71
|
+
schema: 1,
|
|
72
|
+
members: [{ name: "app", dir: "app", kind: "other", because: "a plain Node server" }],
|
|
73
|
+
records: [{ kind: "decisions/decision.kind.mjs" }, { kind: KIND }],
|
|
74
|
+
}),
|
|
75
|
+
"app/server.mjs": "export const port = 8080;\n",
|
|
76
|
+
"decisions/decision.kind.mjs": readFileSync(join(REF, "decisions/decision.kind.mjs"), "utf-8"),
|
|
77
|
+
"decisions/decision.schema.json": readFileSync(join(REF, "decisions/decision.schema.json"), "utf-8"),
|
|
78
|
+
[KIND]: readFileSync(join(REF, KIND), "utf-8"),
|
|
79
|
+
"work/work.schema.json": readFileSync(join(REF, "work/work.schema.json"), "utf-8"),
|
|
80
|
+
"work/W-010-staging.md": work("W-010", {
|
|
81
|
+
acceptance: [
|
|
82
|
+
{ id: "AC-1", text: "The web component runs green in staging", verification: "runtime" },
|
|
83
|
+
{ id: "AC-2", text: "The release plan for staging has no deletes", verification: "runtime" },
|
|
84
|
+
],
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
git(root, "config", "user.name", "t");
|
|
88
|
+
git(root, "config", "user.email", "t@example.com");
|
|
89
|
+
git(root, "config", "commit.gpgsign", "false");
|
|
90
|
+
git(root, "add", "-A");
|
|
91
|
+
git(root, "commit", "-q", "-m", "the work");
|
|
92
|
+
for (const [id, status] of [["r-ok", "ok"], ["r-fail", "fail"], ["r-gated", "gated"]] as const) await appendRunRecord(run(id, status), { cwd: root });
|
|
93
|
+
await appendGateResolution({ op: "deploy-web", gate: "promote", resolvedBy: "bob", timestamp: "2026-10-23T09:00:00.000Z" }, { cwd: root });
|
|
94
|
+
await persistReleasePlan({ digest: "sha256:abc", deletes: [] }, { cwd: root });
|
|
95
|
+
const claimed = await claimWorkLease("W-010", "box/verify@h1", { cwd: join(root, "work") });
|
|
96
|
+
if (!claimed.ok) throw new Error(claimed.message);
|
|
97
|
+
token = claimed.lease.token;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
afterAll(async () => {
|
|
101
|
+
await releaseWorkLease("W-010", "box/verify@h1", { cwd: join(root, "work"), token });
|
|
102
|
+
cleanScratch();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const cite = (over: Partial<Parameters<typeof attachWorkEvidence>[0]>) =>
|
|
106
|
+
attachWorkEvidence({ cwd: root, item: "W-010", holder: "box/verify@h1", token, criterion: "AC-1", result: "pass", title: "staging run", ...over });
|
|
107
|
+
|
|
108
|
+
async function w10() {
|
|
109
|
+
const doc = await queryRecords({ kind: join(root, KIND), cwd: root, workGaps: false });
|
|
110
|
+
records.expectValid(doc);
|
|
111
|
+
if ("error" in doc || !("records" in doc)) throw new Error(JSON.stringify(doc));
|
|
112
|
+
return doc.records.find((r) => r.id === "W-010")!;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
describe("work evidence cites an ops result (#3171)", () => {
|
|
116
|
+
test("refusals write nothing: a run the ledger lacks, a failed run as a pass, a gated run, a wrong hash, two kinds of evidence", async () => {
|
|
117
|
+
const refused = async (over: Partial<Parameters<typeof attachWorkEvidence>[0]>, code: string) => {
|
|
118
|
+
const doc = await cite(over);
|
|
119
|
+
evidenceDoc.expectValid(doc);
|
|
120
|
+
expect(doc).toMatchObject({ error: { code } });
|
|
121
|
+
};
|
|
122
|
+
await refused({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-nope" } }, "work-evidence-ops-missing");
|
|
123
|
+
await refused({ ops: { ledger: "run", env: "prod", op: "deploy-web", id: "r-ok" } }, "work-evidence-ops-missing");
|
|
124
|
+
await refused({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-fail" } }, "work-evidence-ops-mismatch");
|
|
125
|
+
await refused({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-gated" } }, "work-evidence-ops-unfinished");
|
|
126
|
+
await refused({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-ok", sha256: "0".repeat(64) } }, "work-evidence-ops-mismatch");
|
|
127
|
+
await refused({ ops: { ledger: "run", env: "../x", op: "deploy-web", id: "r-ok" } as never }, "write-input-invalid");
|
|
128
|
+
await refused({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-ok" }, url: "https://example.com/x" }, "write-usage-invalid");
|
|
129
|
+
expect((await w10()).acceptance).toMatchObject({ met: 0, total: 2 });
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("a failed run cited as failing evidence is written, and does not meet the criterion", async () => {
|
|
133
|
+
const doc = await cite({ result: "fail", ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-fail" } });
|
|
134
|
+
evidenceDoc.expectValid(doc);
|
|
135
|
+
expect(doc).toMatchObject({ evidence: { ops: { ledger: "run", outcome: "fail" }, result: "fail" }, acceptance: { met: 0 } });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("an ok run in staging ticks the runtime criterion, and the entry names the ledger line by its hash", async () => {
|
|
139
|
+
const doc = await cite({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-ok" } });
|
|
140
|
+
evidenceDoc.expectValid(doc);
|
|
141
|
+
if ("error" in doc) throw new Error(doc.error.message);
|
|
142
|
+
const line = git(root, "show", "chant/lifecycle:staging/runs__deploy-web.jsonl")
|
|
143
|
+
.split("\n")
|
|
144
|
+
.find((l) => l.includes('"r-ok"'))!
|
|
145
|
+
.trim();
|
|
146
|
+
const { createHash } = await import("node:crypto");
|
|
147
|
+
expect(doc.evidence).toMatchObject({
|
|
148
|
+
criterion: "AC-1",
|
|
149
|
+
verification: "runtime",
|
|
150
|
+
result: "pass",
|
|
151
|
+
by: "box/verify@h1",
|
|
152
|
+
ops: { ledger: "run", ref: "chant/lifecycle:staging/runs__deploy-web.jsonl", field: "id", value: "r-ok", env: "staging", outcome: "ok", sha256: createHash("sha256").update(line).digest("hex") },
|
|
153
|
+
});
|
|
154
|
+
expect(doc.acceptance).toMatchObject({ met: 1, total: 2 });
|
|
155
|
+
// The record still validates against the reference work schema with the ops entry in it.
|
|
156
|
+
const rec = await w10();
|
|
157
|
+
expect(rec.valid).toBe(true);
|
|
158
|
+
expect(rec.acceptance).toMatchObject({ met: 1, total: 2 });
|
|
159
|
+
|
|
160
|
+
// Citing it again with the hash it was given verifies too.
|
|
161
|
+
const again = await cite({ ops: { ledger: "run", env: "staging", op: "deploy-web", id: "r-ok", sha256: (doc.evidence.ops as { sha256: string }).sha256 } });
|
|
162
|
+
expect("error" in again).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("a release plan and a gate answer can be cited, and a plan or gate the branch lacks is refused", async () => {
|
|
166
|
+
const plan = await cite({ criterion: "AC-2", title: "the staging plan", ops: { ledger: "plan", digest: "sha256:abc" } });
|
|
167
|
+
evidenceDoc.expectValid(plan);
|
|
168
|
+
expect(plan).toMatchObject({ evidence: { ops: { ledger: "plan", ref: "chant/lifecycle:_plans/sha256_abc.json", field: "digest", value: "sha256:abc" } }, acceptance: { met: 2, total: 2 } });
|
|
169
|
+
const gate = await cite({ criterion: "AC-2", title: "promote approved", ops: { ledger: "gate", op: "deploy-web", gate: "promote", at: "2026-10-23T09:00:00.000Z" } });
|
|
170
|
+
expect(gate).toMatchObject({ evidence: { ops: { ledger: "gate", ref: "chant/lifecycle:_gates/deploy-web.jsonl", field: "timestamp" } } });
|
|
171
|
+
expect(await cite({ ops: { ledger: "plan", digest: "sha256:nope" } })).toMatchObject({ error: { code: "work-evidence-ops-missing" } });
|
|
172
|
+
expect(await cite({ ops: { ledger: "gate", op: "deploy-web", gate: "promote", at: "2026-01-01T00:00:00.000Z" } })).toMatchObject({ error: { code: "work-evidence-ops-missing" } });
|
|
173
|
+
expect(await cite({ ops: { ledger: "deploy", env: "staging", runId: "r-ok" } })).toMatchObject({ error: { code: "work-evidence-ops-missing" } });
|
|
174
|
+
expect((await w10()).valid).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence that cites an ops result (#3171): a run on the Op run ledger, a
|
|
3
|
+
* deploy on an environment's release ledger, a gate answer on a gate ledger,
|
|
4
|
+
* or a release plan in `_plans/`. `attachWorkEvidence` resolves the citation
|
|
5
|
+
* here before it writes anything, so a criterion is only ticked by a record
|
|
6
|
+
* the `chant/lifecycle` branch really holds.
|
|
7
|
+
*
|
|
8
|
+
* The citation names the record the way `chant workspace graph --intent`'s
|
|
9
|
+
* `trace` names its links (#4023): `ref` is the ledger file on the branch,
|
|
10
|
+
* `field` and `value` are what picks the record out of it, and `sha256` is
|
|
11
|
+
* the hash of the record as stored, a ledger line or a plan file. A citation
|
|
12
|
+
* that comes with a `sha256` is refused when the record no longer hashes to
|
|
13
|
+
* it.
|
|
14
|
+
*
|
|
15
|
+
* A run says what it showed: an `ok` run is passing evidence and a `fail`
|
|
16
|
+
* run failing evidence, and the result given must agree. A run that is
|
|
17
|
+
* still gated or waiting has no outcome yet and is refused. A deploy, a gate
|
|
18
|
+
* answer and a plan show what they record; whether that meets the criterion
|
|
19
|
+
* is the citer's `result`.
|
|
20
|
+
*
|
|
21
|
+
* Everything is read from the local `chant/lifecycle` branch. Nothing is
|
|
22
|
+
* fetched, the stance `graph --intent` takes.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { createHash } from "node:crypto";
|
|
26
|
+
import { ledgerDir, readBlobFromPath } from "../lifecycle/git";
|
|
27
|
+
import type { EvidenceResult } from "./work";
|
|
28
|
+
|
|
29
|
+
/** The ledgers evidence can cite. */
|
|
30
|
+
export const OPS_EVIDENCE_LEDGERS = ["run", "deploy", "gate", "plan"] as const;
|
|
31
|
+
export type OpsEvidenceLedger = (typeof OPS_EVIDENCE_LEDGERS)[number];
|
|
32
|
+
|
|
33
|
+
/** What a caller cites: which record, in which ledger, and optionally the hash it expects. */
|
|
34
|
+
export type OpsCitation = {
|
|
35
|
+
/** The workspace member whose ledger holds the record, when it is not the flat layout. */
|
|
36
|
+
member?: string;
|
|
37
|
+
/** The hash of the record as stored, when the caller already has it. */
|
|
38
|
+
sha256?: string;
|
|
39
|
+
} & (
|
|
40
|
+
| { ledger: "run"; env: string; op: string; id: string }
|
|
41
|
+
| { ledger: "deploy"; env: string; runId: string; component?: string }
|
|
42
|
+
| { ledger: "gate"; op: string; gate: string; at: string }
|
|
43
|
+
| { ledger: "plan"; digest: string }
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
/** The citation as the evidence entry stores it, once it resolved. */
|
|
47
|
+
export interface OpsEvidence {
|
|
48
|
+
ledger: OpsEvidenceLedger;
|
|
49
|
+
/** The ledger file, as `chant/lifecycle:<path>`. */
|
|
50
|
+
ref: string;
|
|
51
|
+
/** The field of the record that picked it out, and its value. */
|
|
52
|
+
field: string;
|
|
53
|
+
value: string;
|
|
54
|
+
/** Hex SHA-256 of the record as stored. */
|
|
55
|
+
sha256: string;
|
|
56
|
+
/** The environment, for a run or a deploy. */
|
|
57
|
+
env?: string;
|
|
58
|
+
/** The run's status, for a run. */
|
|
59
|
+
outcome?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type OpsCitationError = { code: "write-input-invalid" | "work-evidence-ops-missing" | "work-evidence-ops-mismatch" | "work-evidence-ops-unfinished"; message: string };
|
|
63
|
+
|
|
64
|
+
const NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
65
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
66
|
+
|
|
67
|
+
const sha256 = (s: string): string => createHash("sha256").update(s).digest("hex");
|
|
68
|
+
|
|
69
|
+
function lines(text: string): { line: string; rec: Record<string, unknown> }[] {
|
|
70
|
+
const out: { line: string; rec: Record<string, unknown> }[] = [];
|
|
71
|
+
for (const raw of text.split("\n")) {
|
|
72
|
+
const line = raw.trim();
|
|
73
|
+
if (line === "") continue;
|
|
74
|
+
try {
|
|
75
|
+
const rec: unknown = JSON.parse(line);
|
|
76
|
+
if (rec !== null && typeof rec === "object" && !Array.isArray(rec)) out.push({ line, rec: rec as Record<string, unknown> });
|
|
77
|
+
} catch {
|
|
78
|
+
// A malformed line is skipped, as every ledger reader skips it.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Check a citation's shape, before anything is read. Returns the message for a bad one. */
|
|
85
|
+
export function opsCitationProblem(cite: unknown): string | null {
|
|
86
|
+
if (cite === null || typeof cite !== "object" || Array.isArray(cite)) return "ops is an object naming a ledger";
|
|
87
|
+
const c = cite as Record<string, unknown>;
|
|
88
|
+
const str = (k: string) => typeof c[k] === "string" && (c[k] as string) !== "";
|
|
89
|
+
const name = (k: string) => typeof c[k] === "string" && NAME.test(c[k] as string);
|
|
90
|
+
if (!(OPS_EVIDENCE_LEDGERS as readonly string[]).includes(c.ledger as string)) return `ops.ledger is one of ${OPS_EVIDENCE_LEDGERS.join(", ")}, not ${JSON.stringify(c.ledger)}`;
|
|
91
|
+
if (c.member !== undefined && !name("member")) return "ops.member is a member name";
|
|
92
|
+
if (c.sha256 !== undefined && !(typeof c.sha256 === "string" && HEX64.test(c.sha256))) return "ops.sha256 is a hex SHA-256";
|
|
93
|
+
const allowed: Record<OpsEvidenceLedger, { names: string[]; strings: string[]; optional: string[] }> = {
|
|
94
|
+
run: { names: ["env", "op"], strings: ["id"], optional: [] },
|
|
95
|
+
deploy: { names: ["env"], strings: ["runId"], optional: ["component"] },
|
|
96
|
+
gate: { names: ["op"], strings: ["gate", "at"], optional: [] },
|
|
97
|
+
plan: { names: [], strings: ["digest"], optional: [] },
|
|
98
|
+
};
|
|
99
|
+
const spec = allowed[c.ledger as OpsEvidenceLedger];
|
|
100
|
+
for (const k of spec.names) if (!name(k)) return `a ${c.ledger} citation names ops.${k}`;
|
|
101
|
+
for (const k of spec.strings) if (!str(k)) return `a ${c.ledger} citation names ops.${k}`;
|
|
102
|
+
for (const k of spec.optional) if (c[k] !== undefined && !str(k)) return `ops.${k} is a string`;
|
|
103
|
+
const known = new Set(["ledger", "member", "sha256", ...spec.names, ...spec.strings, ...spec.optional]);
|
|
104
|
+
const extra = Object.keys(c).filter((k) => !known.has(k));
|
|
105
|
+
if (extra.length > 0) return `a ${c.ledger} citation takes ${[...known].join(", ")}, not ${extra.join(", ")}`;
|
|
106
|
+
if (c.ledger === "plan" && /[/\\]/.test(c.digest as string)) return "ops.digest is a plan digest, not a path";
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Find the cited record on the local `chant/lifecycle` branch and check it
|
|
112
|
+
* against the citation and the result given. Never throws for a refusal.
|
|
113
|
+
*/
|
|
114
|
+
export async function resolveOpsCitation(cite: OpsCitation, result: EvidenceResult, cwd: string): Promise<{ ops: OpsEvidence } | { error: OpsCitationError }> {
|
|
115
|
+
const problem = opsCitationProblem(cite);
|
|
116
|
+
if (problem) return { error: { code: "write-input-invalid", message: problem } };
|
|
117
|
+
const loc = { cwd, ...(cite.member !== undefined ? { member: cite.member } : {}) };
|
|
118
|
+
const missing = (what: string): { error: OpsCitationError } => ({ error: { code: "work-evidence-ops-missing", message: `the local chant/lifecycle branch has no ${what}` } });
|
|
119
|
+
|
|
120
|
+
let found: { dir: string; file: string; text: string; field: string; value: string; env?: string; outcome?: string };
|
|
121
|
+
switch (cite.ledger) {
|
|
122
|
+
case "run": {
|
|
123
|
+
const file = `runs__${cite.op}.jsonl`;
|
|
124
|
+
const content = await readBlobFromPath(cite.env, file, loc);
|
|
125
|
+
const hit = content === null ? undefined : lines(content).find((l) => l.rec.id === cite.id);
|
|
126
|
+
if (!hit) return missing(`run ${cite.id} of ${cite.op} in ${cite.env}`);
|
|
127
|
+
const status = String(hit.rec.status);
|
|
128
|
+
if (status !== "ok" && status !== "fail") {
|
|
129
|
+
return { error: { code: "work-evidence-ops-unfinished", message: `run ${cite.id} of ${cite.op} is ${status}: it has no outcome yet to cite` } };
|
|
130
|
+
}
|
|
131
|
+
const shows: EvidenceResult = status === "ok" ? "pass" : "fail";
|
|
132
|
+
if (shows !== result) {
|
|
133
|
+
return { error: { code: "work-evidence-ops-mismatch", message: `run ${cite.id} of ${cite.op} in ${cite.env} ended ${status}, so it is ${shows} evidence, not ${result}` } };
|
|
134
|
+
}
|
|
135
|
+
found = { dir: cite.env, file, text: hit.line, field: "id", value: cite.id, env: cite.env, outcome: status };
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "deploy": {
|
|
139
|
+
const file = "releases.jsonl";
|
|
140
|
+
const content = await readBlobFromPath(cite.env, file, loc);
|
|
141
|
+
const hits = content === null ? [] : lines(content).filter((l) => l.rec.runId === cite.runId && (cite.component === undefined || l.rec.component === cite.component));
|
|
142
|
+
if (hits.length === 0) return missing(`deploy by run ${cite.runId}${cite.component ? ` of ${cite.component}` : ""} in ${cite.env}`);
|
|
143
|
+
if (hits.length > 1) {
|
|
144
|
+
return { error: { code: "write-input-invalid", message: `run ${cite.runId} deployed ${hits.length} components in ${cite.env}: name the one cited in ops.component` } };
|
|
145
|
+
}
|
|
146
|
+
found = { dir: cite.env, file, text: hits[0].line, field: "runId", value: cite.runId, env: cite.env };
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case "gate": {
|
|
150
|
+
const file = `${cite.op}.jsonl`;
|
|
151
|
+
const content = await readBlobFromPath("_gates", file, loc);
|
|
152
|
+
const hit = content === null ? undefined : lines(content).find((l) => (l.rec.kind ?? "resolution") === "resolution" && l.rec.gate === cite.gate && l.rec.timestamp === cite.at);
|
|
153
|
+
if (!hit) return missing(`answer to gate ${cite.gate} of ${cite.op} at ${cite.at}`);
|
|
154
|
+
found = { dir: "_gates", file, text: hit.line, field: "timestamp", value: cite.at };
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "plan": {
|
|
158
|
+
const file = `${cite.digest.replace(/:/g, "_")}.json`;
|
|
159
|
+
const content = await readBlobFromPath("_plans", file, loc);
|
|
160
|
+
if (content === null) return missing(`release plan ${cite.digest}`);
|
|
161
|
+
let digest: unknown;
|
|
162
|
+
try {
|
|
163
|
+
digest = (JSON.parse(content) as { digest?: unknown }).digest;
|
|
164
|
+
} catch {
|
|
165
|
+
digest = undefined;
|
|
166
|
+
}
|
|
167
|
+
if (digest !== cite.digest) return { error: { code: "work-evidence-ops-mismatch", message: `the plan stored for ${cite.digest} names another digest` } };
|
|
168
|
+
found = { dir: "_plans", file, text: content, field: "digest", value: cite.digest };
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const hash = sha256(found.text);
|
|
174
|
+
if (cite.sha256 !== undefined && cite.sha256 !== hash) {
|
|
175
|
+
return { error: { code: "work-evidence-ops-mismatch", message: `the ${cite.ledger} record cited hashes to ${hash}, not the ${cite.sha256} given: it is another record` } };
|
|
176
|
+
}
|
|
177
|
+
const ref = `chant/lifecycle:${await ledgerDir(found.dir, loc)}/${found.file}`;
|
|
178
|
+
return {
|
|
179
|
+
ops: {
|
|
180
|
+
ledger: cite.ledger,
|
|
181
|
+
ref,
|
|
182
|
+
field: found.field,
|
|
183
|
+
value: found.value,
|
|
184
|
+
sha256: hash,
|
|
185
|
+
...(found.env !== undefined ? { env: found.env } : {}),
|
|
186
|
+
...(found.outcome !== undefined ? { outcome: found.outcome } : {}),
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"evidence": {
|
|
47
47
|
"type": "object",
|
|
48
|
-
"description": "The entry appended: a title, a url
|
|
48
|
+
"description": "The entry appended: a title, a url, a path pinned by sha256 or an ops result verified against its ledger (#3171), as_of, and the criterion, its verification, the result and by, the lease holder.",
|
|
49
49
|
"required": [
|
|
50
50
|
"title",
|
|
51
51
|
"criterion",
|
|
@@ -91,6 +91,50 @@
|
|
|
91
91
|
"by": {
|
|
92
92
|
"type": "string",
|
|
93
93
|
"description": "The lease holder that attached it."
|
|
94
|
+
},
|
|
95
|
+
"ops": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "An ops result on the chant/lifecycle branch (#3171), named the way graph --intent's trace names a link: the ledger file in ref, the field and value that pick the record out of it, and the record's sha256 as stored. A run carries its env and outcome, a deploy its env.",
|
|
98
|
+
"required": [
|
|
99
|
+
"ledger",
|
|
100
|
+
"ref",
|
|
101
|
+
"field",
|
|
102
|
+
"value",
|
|
103
|
+
"sha256"
|
|
104
|
+
],
|
|
105
|
+
"properties": {
|
|
106
|
+
"ledger": {
|
|
107
|
+
"enum": [
|
|
108
|
+
"run",
|
|
109
|
+
"deploy",
|
|
110
|
+
"gate",
|
|
111
|
+
"plan"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"ref": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"pattern": "^chant/lifecycle:"
|
|
117
|
+
},
|
|
118
|
+
"field": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"value": {
|
|
122
|
+
"type": "string"
|
|
123
|
+
},
|
|
124
|
+
"sha256": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
127
|
+
},
|
|
128
|
+
"env": {
|
|
129
|
+
"type": "string"
|
|
130
|
+
},
|
|
131
|
+
"outcome": {
|
|
132
|
+
"enum": [
|
|
133
|
+
"ok",
|
|
134
|
+
"fail"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
94
138
|
}
|
|
95
139
|
}
|
|
96
140
|
},
|
|
@@ -207,7 +251,10 @@
|
|
|
207
251
|
"lease-held",
|
|
208
252
|
"lease-not-held",
|
|
209
253
|
"lease-token-mismatch",
|
|
210
|
-
"not-a-git-repository"
|
|
254
|
+
"not-a-git-repository",
|
|
255
|
+
"work-evidence-ops-missing",
|
|
256
|
+
"work-evidence-ops-mismatch",
|
|
257
|
+
"work-evidence-ops-unfinished"
|
|
211
258
|
]
|
|
212
259
|
},
|
|
213
260
|
"message": {
|
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
* one: the run holding the lease is the item's implementer, and a manual
|
|
18
18
|
* verdict comes from someone else. A person records that verdict with
|
|
19
19
|
* `records amend`, naming themselves in `by`.
|
|
20
|
+
*
|
|
21
|
+
* Evidence is a public link, a workspace file pinned by hash, or an ops
|
|
22
|
+
* result (#3171): a run, a deploy, a gate answer or a release plan on the
|
|
23
|
+
* `chant/lifecycle` branch, cited the way `graph --intent`'s trace cites it.
|
|
24
|
+
* The citation is resolved against the ledger it names before anything is
|
|
25
|
+
* written, and a run's outcome must agree with the result
|
|
26
|
+
* (`./work-evidence-ops.ts`).
|
|
20
27
|
*/
|
|
21
28
|
|
|
22
29
|
import { relative, sep } from "node:path";
|
|
@@ -26,6 +33,7 @@ import { pinFile } from "./records-cli";
|
|
|
26
33
|
import { AMEND_ERROR_CODES, amendRecord } from "./records-write";
|
|
27
34
|
import { acceptanceCriteria, EVIDENCE_RESULTS, workAcceptance, type EvidenceResult, type VerificationType, type WorkAcceptance } from "./work";
|
|
28
35
|
import { findWorkItem, WorkError } from "./work-cli";
|
|
36
|
+
import { resolveOpsCitation, type OpsCitation } from "./work-evidence-ops";
|
|
29
37
|
|
|
30
38
|
/** Why evidence was not attached. Closed. Nothing is written with any of them. */
|
|
31
39
|
export const WORK_EVIDENCE_ERROR_CODES = [
|
|
@@ -40,6 +48,9 @@ export const WORK_EVIDENCE_ERROR_CODES = [
|
|
|
40
48
|
"lease-not-held",
|
|
41
49
|
"lease-token-mismatch",
|
|
42
50
|
"not-a-git-repository",
|
|
51
|
+
"work-evidence-ops-missing",
|
|
52
|
+
"work-evidence-ops-mismatch",
|
|
53
|
+
"work-evidence-ops-unfinished",
|
|
43
54
|
] as const satisfies readonly ReasonCode[];
|
|
44
55
|
export type WorkEvidenceErrorCode = (typeof WORK_EVIDENCE_ERROR_CODES)[number];
|
|
45
56
|
|
|
@@ -59,8 +70,10 @@ export interface AttachWorkEvidenceRequest {
|
|
|
59
70
|
title: string;
|
|
60
71
|
/** A public link, or */
|
|
61
72
|
url?: string;
|
|
62
|
-
/** a workspace file, pinned by the hash of its bytes now
|
|
73
|
+
/** a workspace file, pinned by the hash of its bytes now, or */
|
|
63
74
|
path?: string;
|
|
75
|
+
/** an ops result on the `chant/lifecycle` branch (#3171), verified against its ledger. */
|
|
76
|
+
ops?: OpsCitation;
|
|
64
77
|
/** When the evidence was taken, as an ISO 8601 timestamp. Now by default. */
|
|
65
78
|
asOf?: string;
|
|
66
79
|
}
|
|
@@ -111,7 +124,9 @@ export async function attachWorkEvidence(req: AttachWorkEvidenceRequest): Promis
|
|
|
111
124
|
throw new EvidenceError("write-usage-invalid", `result is pass or fail, not ${JSON.stringify(req.result)}`);
|
|
112
125
|
}
|
|
113
126
|
if (typeof req.title !== "string" || req.title.trim() === "") throw new EvidenceError("write-usage-invalid", "the evidence has no title");
|
|
114
|
-
if (
|
|
127
|
+
if ([req.url, req.path, req.ops].filter((v) => v !== undefined).length !== 1) {
|
|
128
|
+
throw new EvidenceError("write-usage-invalid", "the evidence is a url, a path or an ops result, exactly one of them");
|
|
129
|
+
}
|
|
115
130
|
if (req.url !== undefined && !req.url.startsWith("https://")) throw new EvidenceError("write-input-invalid", `evidence links are https://, not ${JSON.stringify(req.url)}`);
|
|
116
131
|
|
|
117
132
|
const found = await findWorkItem(req.item, req.cwd, req.kind);
|
|
@@ -139,7 +154,11 @@ export async function attachWorkEvidence(req: AttachWorkEvidenceRequest): Promis
|
|
|
139
154
|
}
|
|
140
155
|
|
|
141
156
|
let pin: Record<string, unknown>;
|
|
142
|
-
if (req.
|
|
157
|
+
if (req.ops !== undefined) {
|
|
158
|
+
const resolved = await resolveOpsCitation(req.ops, req.result, req.cwd);
|
|
159
|
+
if ("error" in resolved) throw new EvidenceError(resolved.error.code, resolved.error.message);
|
|
160
|
+
pin = { ops: resolved.ops };
|
|
161
|
+
} else if (req.path !== undefined) {
|
|
143
162
|
const pinned = pinFile(req.path, req.cwd);
|
|
144
163
|
if ("error" in pinned) throw new EvidenceError("write-input-invalid", pinned.error);
|
|
145
164
|
pin = { path: pinned.path, sha256: pinned.sha256 };
|