@intentius/chant 0.102.0 → 0.104.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/core.d.ts +2 -0
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/change-set.d.ts +232 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.d.ts +11 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -0
- package/dist/cli/handlers/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +7 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/pr.d.ts +31 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +3 -2
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +63 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +16 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +53 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/changed-files.d.ts +31 -0
- package/dist/components/changed-files.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +9 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +24 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/driver.d.ts +13 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-output.d.ts +6 -0
- package/dist/components/fan-out-output.d.ts.map +1 -1
- package/dist/components/fan-out-record.d.ts +41 -0
- package/dist/components/fan-out-record.d.ts.map +1 -0
- package/dist/components/fan-out-run.d.ts +65 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts +2 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts +6 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/gated-wave-pipeline.d.ts +50 -0
- package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layers.d.ts +25 -0
- package/dist/components/layers.d.ts.map +1 -0
- package/dist/components/pr-pipeline.d.ts +61 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -0
- package/dist/components/pr-run.d.ts +119 -0
- package/dist/components/pr-run.d.ts.map +1 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/verbs/shell.d.ts.map +1 -1
- package/dist/components/wave-plan.d.ts +49 -0
- package/dist/components/wave-plan.d.ts.map +1 -0
- package/dist/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +48 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +7 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +46 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +126 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/change-set.d.ts +62 -0
- package/dist/op/activities/change-set.d.ts.map +1 -0
- package/dist/op/activities/decide.d.ts +2 -0
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/factory.d.ts +137 -0
- package/dist/op/activities/factory.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +4 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/builders.d.ts +11 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts +5 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts +4 -2
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/index.d.ts +4 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +2 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/types.d.ts +8 -0
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/plan-summary.d.ts +207 -0
- package/dist/plan-summary.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +105 -0
- package/dist/pr-forge.d.ts.map +1 -0
- package/dist/pr-loop.d.ts +178 -0
- package/dist/pr-loop.d.ts.map +1 -0
- package/dist/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/hcl2json.d.ts +45 -0
- package/dist/terraform/hcl2json.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +4 -40
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/vendor/js-yaml-load.d.ts +56 -0
- package/dist/vendor/js-yaml-load.d.ts.map +1 -0
- package/dist/workspace/box-cli.d.ts +12 -0
- package/dist/workspace/box-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +27 -3
- package/dist/workspace/box-factory.d.ts.map +1 -1
- package/dist/workspace/box-listing.d.ts +85 -0
- package/dist/workspace/box-listing.d.ts.map +1 -0
- package/dist/workspace/box-publish.d.ts +147 -0
- package/dist/workspace/box-publish.d.ts.map +1 -0
- package/dist/workspace/broker-protocol.d.ts +190 -0
- package/dist/workspace/broker-protocol.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +2 -2
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
- package/dist/workspace/conformance/broker.d.ts +202 -0
- package/dist/workspace/conformance/broker.d.ts.map +1 -0
- package/dist/workspace/conformance/index.d.ts +2 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +9 -2
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +108 -14
- package/dist/workspace/conformance/writer.d.ts.map +1 -1
- package/dist/workspace/decide.d.ts +126 -12
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +11 -4
- package/dist/workspace/declaration.d.ts +65 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +153 -4
- package/dist/workspace/environments.d.ts +36 -10
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/factory-rules.d.ts +180 -0
- package/dist/workspace/factory-rules.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +1 -1
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +28 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +102 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/json-edit.d.ts +24 -0
- package/dist/workspace/json-edit.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +11 -0
- package/dist/workspace/jsonc.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +48 -0
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lexicon-symbols.d.ts +29 -0
- package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +42 -2
- package/dist/workspace/points-cli.d.ts +10 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +66 -5
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/reason-codes.d.ts +33 -4
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +5 -7
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-cli.d.ts +7 -0
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +7 -3
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +66 -6
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +28 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +138 -6
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs.d.ts +132 -11
- package/dist/workspace/runs.d.ts.map +1 -1
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/squash.d.ts +80 -0
- package/dist/workspace/squash.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts +2 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +54 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +16 -5
- package/dist/workspace/symbols.d.ts.map +1 -1
- package/dist/workspace/trust/run-commits.d.ts +46 -0
- package/dist/workspace/trust/run-commits.d.ts.map +1 -0
- package/dist/workspace/trust/run-statement.d.ts +128 -0
- package/dist/workspace/trust/run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +6 -1
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.d.ts +1 -1
- package/dist/workspace/trust/verify.d.ts +16 -2
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/wip-cli.d.ts +21 -0
- package/dist/workspace/wip-cli.d.ts.map +1 -0
- package/dist/workspace/wip.d.ts +268 -0
- package/dist/workspace/wip.d.ts.map +1 -0
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-size.d.ts +55 -0
- package/dist/workspace/work-size.d.ts.map +1 -0
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/write-lock-cli.d.ts +60 -0
- package/dist/workspace/write-lock-cli.d.ts.map +1 -0
- package/dist/workspace/write-lock.d.ts +152 -0
- package/dist/workspace/write-lock.d.ts.map +1 -0
- package/dist/workspace/write-scope.d.ts +6 -2
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +1 -1
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
- package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
- package/src/__fixtures__/change-set/warden.plan.json +44 -0
- package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
- package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
- package/src/audit/core.test.ts +15 -0
- package/src/audit/core.ts +8 -2
- package/src/audit/discover.test.ts +11 -0
- package/src/audit/discover.ts +7 -2
- package/src/change-set-bundle.test.ts +57 -0
- package/src/change-set.test.ts +215 -0
- package/src/change-set.ts +445 -0
- package/src/cli/commands/audit-opt-in.test.ts +54 -0
- package/src/cli/commands/audit.ts +29 -2
- package/src/cli/commands/build.test.ts +19 -0
- package/src/cli/commands/build.ts +3 -2
- package/src/cli/handlers/build.ts +13 -1
- package/src/cli/handlers/change-set.test.ts +56 -0
- package/src/cli/handlers/change-set.ts +44 -0
- package/src/cli/handlers/fan-out.test.ts +221 -2
- package/src/cli/handlers/fan-out.ts +165 -75
- package/src/cli/handlers/graph.ts +3 -0
- package/src/cli/handlers/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +34 -3
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.ts +1 -0
- package/src/cli/main.test.ts +20 -0
- package/src/cli/main.ts +185 -23
- package/src/cli/mcp/never-over-mcp.test.ts +101 -0
- package/src/cli/mcp/op-tools.ts +24 -2
- package/src/cli/mcp/workspace-tools.test.ts +1 -1
- package/src/cli/mcp/workspace-tools.ts +34 -6
- package/src/cli/registry.ts +63 -1
- package/src/components/auto-release.ts +1 -1
- package/src/components/capability.ts +55 -0
- package/src/components/changed-files.ts +66 -0
- package/src/components/cli-support.ts +28 -5
- package/src/components/component.schema.json +17 -0
- package/src/components/component.ts +25 -0
- package/src/components/deploy-units.ts +3 -0
- package/src/components/driver.test.ts +52 -0
- package/src/components/driver.ts +31 -13
- package/src/components/fan-out-output.ts +42 -1
- package/src/components/fan-out-record.ts +69 -0
- package/src/components/fan-out-run.test.ts +17 -0
- package/src/components/fan-out-run.ts +304 -1
- package/src/components/fan-out-support.ts +3 -0
- package/src/components/fan-out-waves.test.ts +375 -0
- package/src/components/fan-out.ts +18 -17
- package/src/components/gated-wave-pipeline.ts +82 -0
- package/src/components/index.ts +1 -0
- package/src/components/layers.ts +30 -0
- package/src/components/pr-pipeline.ts +91 -0
- package/src/components/pr-run.test.ts +205 -0
- package/src/components/pr-run.ts +280 -0
- package/src/components/promote.ts +5 -0
- package/src/components/verbs/shell.test.ts +11 -0
- package/src/components/verbs/shell.ts +7 -3
- package/src/components/wave-plan.ts +124 -0
- package/src/discovery/sandbox/bundle.ts +1 -1
- package/src/gated-waves-bundle.test.ts +62 -0
- package/src/gated-waves.test.ts +118 -0
- package/src/gated-waves.ts +240 -0
- package/src/index.ts +1 -0
- package/src/lexicon.ts +51 -0
- package/src/lifecycle/gate-ledger.ts +7 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lint/post-synth.test.ts +19 -0
- package/src/lint/post-synth.ts +19 -1
- package/src/meta/declared-imports.test.ts +1 -1
- package/src/op/activities/activity-contracts.ts +84 -0
- package/src/op/activities/change-set.ts +114 -0
- package/src/op/activities/decide.ts +3 -0
- package/src/op/activities/factory.ts +675 -0
- package/src/op/activities/index.ts +6 -0
- package/src/op/activity-contract.test.ts +21 -1
- package/src/op/activity-contract.ts +19 -9
- package/src/op/builders.ts +23 -0
- package/src/op/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/index.ts +9 -1
- package/src/op/op-ir.test.ts +9 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +3 -0
- package/src/op/types.ts +8 -0
- package/src/op/work-lease-run.ts +3 -0
- package/src/plan-summary.test.ts +263 -0
- package/src/plan-summary.ts +845 -0
- package/src/pr-forge.test.ts +237 -0
- package/src/pr-forge.ts +332 -0
- package/src/pr-loop-bundle.test.ts +46 -0
- package/src/pr-loop.test.ts +171 -0
- package/src/pr-loop.ts +324 -0
- package/src/telemetry-attribution.test.ts +23 -1
- package/src/telemetry-attribution.ts +51 -0
- package/src/terraform/hcl2json.test.ts +21 -0
- package/src/terraform/hcl2json.ts +81 -0
- package/src/terraform/parse.ts +11 -74
- package/src/vendor/js-yaml-load.test.ts +115 -0
- package/src/vendor/js-yaml-load.ts +1939 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +4 -1
- package/src/workspace/box-factory.ts +37 -4
- package/src/workspace/box-listing-write.schema.json +204 -0
- package/src/workspace/box-listing.test.ts +234 -0
- package/src/workspace/box-listing.ts +324 -0
- package/src/workspace/box-publish.schema.json +498 -0
- package/src/workspace/box-publish.test.ts +204 -0
- package/src/workspace/box-publish.ts +420 -0
- package/src/workspace/box-ship.test.ts +96 -0
- package/src/workspace/broker-protocol.schema.json +186 -0
- package/src/workspace/broker-protocol.test.ts +122 -0
- package/src/workspace/broker-protocol.ts +317 -0
- package/src/workspace/builder-tiers.test.ts +146 -0
- package/src/workspace/change-set.schema.json +460 -0
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +3 -0
- package/src/workspace/checks.ts +10 -3
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/composites.schema.json +23 -4
- package/src/workspace/composites.test.ts +8 -8
- package/src/workspace/composites.ts +13 -2
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +7 -2
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +42 -2
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +96 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +14 -8
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +187 -6
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +25 -0
- package/src/workspace/conformance/broker.test.ts +122 -0
- package/src/workspace/conformance/broker.ts +792 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
- package/src/workspace/conformance/index.mjs +22 -1
- package/src/workspace/conformance/index.ts +5 -1
- package/src/workspace/conformance/vitest.ts +33 -1
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +49 -3
- package/src/workspace/conformance/writer.test.ts +32 -2
- package/src/workspace/conformance/writer.ts +339 -28
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +427 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +153 -4
- package/src/workspace/declaration.ts +141 -0
- package/src/workspace/environments.ts +66 -14
- package/src/workspace/factory-rules.test.ts +62 -0
- package/src/workspace/factory-rules.ts +218 -0
- package/src/workspace/graph-cli.ts +2 -2
- package/src/workspace/graph.schema.json +67 -0
- package/src/workspace/identity.test.ts +23 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +26 -9
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +130 -3
- package/src/workspace/intent-record.ts +74 -28
- package/src/workspace/intent-reviews.test.ts +76 -0
- package/src/workspace/intent-squash.test.ts +213 -0
- package/src/workspace/intent-why.test.ts +5 -5
- package/src/workspace/intent.schema.json +234 -4
- package/src/workspace/intent.ts +260 -66
- package/src/workspace/json-edit.test.ts +121 -0
- package/src/workspace/json-edit.ts +142 -0
- package/src/workspace/jsonc.ts +20 -0
- package/src/workspace/kinds.ts +157 -2
- package/src/workspace/lexicon-symbols.test.ts +148 -0
- package/src/workspace/lexicon-symbols.ts +125 -0
- package/src/workspace/lineage-upgrade.test.ts +63 -0
- package/src/workspace/lineage-upgrade.ts +146 -5
- package/src/workspace/plan-summary.schema.json +155 -0
- package/src/workspace/point-answer.schema.json +42 -2
- package/src/workspace/points-cli.ts +42 -16
- package/src/workspace/points-write.schema.json +162 -4
- package/src/workspace/points.schema.json +157 -2
- package/src/workspace/points.test.ts +13 -1
- package/src/workspace/points.ts +118 -12
- package/src/workspace/pr-report.schema.json +95 -0
- package/src/workspace/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +13 -1
- package/src/workspace/reason-codes.ts +38 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +78 -0
- package/src/workspace/records-cli.ts +20 -6
- package/src/workspace/records-close.schema.json +78 -0
- package/src/workspace/records-close.ts +31 -7
- package/src/workspace/records-concurrent.e2e.test.ts +135 -0
- package/src/workspace/records-concurrent.test.ts +145 -0
- package/src/workspace/records-formats.test.ts +46 -10
- package/src/workspace/records-new.schema.json +7 -0
- package/src/workspace/records-review.schema.json +78 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-write.ts +192 -25
- package/src/workspace/records.schema.json +16 -0
- package/src/workspace/records.ts +50 -9
- package/src/workspace/reference-kinds/app/package.json +10 -0
- package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/src/workspace/run-statement.schema.json +622 -0
- package/src/workspace/runs-cli.ts +343 -14
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +416 -5
- package/src/workspace/runs.schema.json +451 -4
- package/src/workspace/runs.test.ts +39 -0
- package/src/workspace/runs.ts +296 -35
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +5 -2
- package/src/workspace/status-gates.ts +3 -1
- package/src/workspace/status.schema.json +126 -3
- package/src/workspace/status.ts +90 -1
- package/src/workspace/symbols.ts +20 -9
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +8 -2
- package/src/workspace/trust/verify-cli.ts +6 -5
- package/src/workspace/trust/verify.ts +39 -6
- package/src/workspace/wip-cli.ts +97 -0
- package/src/workspace/wip-write.schema.json +504 -0
- package/src/workspace/wip.schema.json +334 -0
- package/src/workspace/wip.test.ts +294 -0
- package/src/workspace/wip.ts +753 -0
- package/src/workspace/work-cli.ts +3 -0
- package/src/workspace/work-evidence.schema.json +3 -0
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/write-lock-cli.ts +131 -0
- package/src/workspace/write-lock.schema.json +172 -0
- package/src/workspace/write-lock.test.ts +189 -0
- package/src/workspace/write-lock.ts +474 -0
- package/src/workspace/write-scope.test.ts +16 -1
- package/src/workspace/write-scope.ts +33 -11
- package/src/yaml.ts +31 -21
package/src/workspace/points.ts
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* proposal a person confirms; below it, the next decider is asked.
|
|
16
16
|
* quorum people. Always last: the question escalates to them.
|
|
17
17
|
*
|
|
18
|
+
* A point declared `adhoc` (#3403) has no candidates of its own: its
|
|
19
|
+
* question's text and candidates come with each ask, as an agent's question
|
|
20
|
+
* to the room does, and the answer record keeps them as `asked`, so people's
|
|
21
|
+
* answer is checked against the candidates the question was asked with. Only
|
|
22
|
+
* people decide it: its chain is one quorum.
|
|
23
|
+
*
|
|
18
24
|
* chant never calls a model (ws-052). {@link runChain} takes the model call
|
|
19
25
|
* as a function, {@link ModelAsk}, which the decide Op activity (#2740), a
|
|
20
26
|
* runtime's decider or a test's stub supplies. Without one, a model decider is
|
|
@@ -51,6 +57,8 @@ export const POINT_INPUT_OUTPUTS = {
|
|
|
51
57
|
finding: { schema: "intent", def: "finding", description: "a finding of graph --intent, or of check --changes (#2794)" },
|
|
52
58
|
region: { schema: "intent", def: "region", description: "the region an intent graph covers" },
|
|
53
59
|
commit: { schema: "intent", def: "commit", description: "a commit in an intent graph's window" },
|
|
60
|
+
node: { schema: "intent", def: "node", description: "any node of an intent graph, by its id and kind: a commit, decision, unit, artifact or the region itself, as an intent walk asks of it (#3351)" },
|
|
61
|
+
ask: { schema: "points", def: "question", description: "an ad-hoc question as its asker knows it (#3403): the asker's own id for the ask, such as hud's request id for an agent's question, and who asked" },
|
|
54
62
|
member: { schema: "ls", def: "member", description: "a member, as ls lists it" },
|
|
55
63
|
gate: { schema: "status", def: "gate", description: "a gate, as status lists it" },
|
|
56
64
|
release: { schema: "status", def: "release", description: "a release, as status lists it; a release plan's fields until the lifecycle ledger lists plans (#2717)" },
|
|
@@ -73,7 +81,8 @@ export type QuestionType = "noul" | "choice" | "score";
|
|
|
73
81
|
export interface Question {
|
|
74
82
|
type: QuestionType;
|
|
75
83
|
instructions: string;
|
|
76
|
-
|
|
84
|
+
/** The candidates and what each means. Absent only from an ad-hoc point's declaration, whose candidates come with each ask (#3403). */
|
|
85
|
+
criteria?: Record<string, string> | string[];
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
export type Scalar = string | number | boolean | null;
|
|
@@ -92,6 +101,8 @@ export type Decider =
|
|
|
92
101
|
|
|
93
102
|
export interface Point {
|
|
94
103
|
title: string;
|
|
104
|
+
/** The question's text and candidates come with each ask, not the declaration (#3403). */
|
|
105
|
+
adhoc?: boolean;
|
|
95
106
|
question: Question;
|
|
96
107
|
inputs: Record<string, string>;
|
|
97
108
|
deciders: Decider[];
|
|
@@ -116,8 +127,8 @@ export class PointsError extends Error {
|
|
|
116
127
|
/** A question's candidate answers: true and false, a choice's options, or a score's levels. */
|
|
117
128
|
export function candidates(question: Question): (string | boolean)[] {
|
|
118
129
|
if (question.type === "noul") return [true, false];
|
|
119
|
-
if (question.type === "choice") return Object.keys(question.criteria);
|
|
120
|
-
return [...(question.criteria as string[])];
|
|
130
|
+
if (question.type === "choice") return Object.keys(question.criteria ?? {});
|
|
131
|
+
return [...((question.criteria as string[] | undefined) ?? [])];
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
const ONLY: Record<Decider["kind"], string[]> = { table: ["rows"], model: ["backend", "model", "threshold", "unreachable"], quorum: ["count", "roles"] };
|
|
@@ -140,6 +151,12 @@ function pointProblems(points: Record<string, Point>): PointProblem[] {
|
|
|
140
151
|
});
|
|
141
152
|
}
|
|
142
153
|
}
|
|
154
|
+
if (point.adhoc && (point.deciders.length !== 1 || point.deciders[0].kind !== "quorum")) {
|
|
155
|
+
problems.push({
|
|
156
|
+
field: at("deciders"),
|
|
157
|
+
message: "is an ad-hoc point's chain, and an ad-hoc point is decided by people alone: its chain is one quorum, since no table row or model can know candidates that come with the ask",
|
|
158
|
+
});
|
|
159
|
+
}
|
|
143
160
|
const allowed = candidates(point.question);
|
|
144
161
|
const last = point.deciders.length - 1;
|
|
145
162
|
point.deciders.forEach((d, i) => {
|
|
@@ -210,7 +227,9 @@ export function schemaProblems(data: unknown): PointProblem[] {
|
|
|
210
227
|
? `is missing ${JSON.stringify(e.params.missingProperty)}`
|
|
211
228
|
: e.keyword === "propertyNames"
|
|
212
229
|
? `has a name that is not allowed: ${JSON.stringify(e.params.propertyName)}`
|
|
213
|
-
:
|
|
230
|
+
: e.keyword === "not"
|
|
231
|
+
? "has criteria, and an ad-hoc point's candidates come with each ask (#3403): leave criteria out"
|
|
232
|
+
: (e.message ?? "is invalid");
|
|
214
233
|
const key = `${field}\0${message}`;
|
|
215
234
|
if (seen.has(key)) continue;
|
|
216
235
|
seen.add(key);
|
|
@@ -262,8 +281,71 @@ const sha256 = (text: string): string => createHash("sha256").update(text, "utf8
|
|
|
262
281
|
/** The version of a point: the sha256 of its declaration. Editing the question or any decider changes it. */
|
|
263
282
|
export const pointVersion = (point: Point): string => sha256(canonical(point));
|
|
264
283
|
|
|
265
|
-
/**
|
|
266
|
-
|
|
284
|
+
/**
|
|
285
|
+
* What is answered once: the point, its version and the inputs, and for an
|
|
286
|
+
* ad-hoc point the question and candidates it was asked with (#3403).
|
|
287
|
+
*/
|
|
288
|
+
export const inputsHash = (name: string, version: string, inputs: Record<string, unknown>, asked?: Asked): string => sha256(canonical({ point: name, version, inputs, asked }));
|
|
289
|
+
|
|
290
|
+
// ── Ad-hoc questions (#3403) ─────────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
/** An ad-hoc point's question as one ask gave it: its text and its candidates, in the point's question type's shape. */
|
|
293
|
+
export interface Asked {
|
|
294
|
+
question: string;
|
|
295
|
+
criteria: Record<string, string> | string[];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** The question an answer asks: the point's own, or for an ad-hoc point the one the ask gave. */
|
|
299
|
+
export function askedQuestion(point: Point, asked: Asked | undefined): Question {
|
|
300
|
+
return asked ? { type: point.question.type, instructions: asked.question, criteria: asked.criteria } : point.question;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const nonEmpty = (v: unknown): v is string => typeof v === "string" && v.trim() !== "";
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* An ad-hoc ask's question and candidates (`points ask --candidates`), checked
|
|
307
|
+
* against the point's question type as a declaration's criteria are: noul
|
|
308
|
+
* describes true and false, choice gives 2 to 255 options, each with what it
|
|
309
|
+
* means, and score 2 to 10 distinct ordered levels. Returns the problems, or
|
|
310
|
+
* the question.
|
|
311
|
+
*/
|
|
312
|
+
export function parseAsked(point: Point, value: unknown): { asked: Asked } | { problems: string[] } {
|
|
313
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return { problems: ["the candidates must be a JSON object with question and criteria"] };
|
|
314
|
+
const v = value as Record<string, unknown>;
|
|
315
|
+
const problems: string[] = [];
|
|
316
|
+
const extra = Object.keys(v).filter((k) => k !== "question" && k !== "criteria");
|
|
317
|
+
if (extra.length > 0) problems.push(`the candidates take question and criteria, not ${extra.join(", ")}`);
|
|
318
|
+
if (!nonEmpty(v.question)) problems.push("question must be the question's text");
|
|
319
|
+
const c = v.criteria;
|
|
320
|
+
const type = point.question.type;
|
|
321
|
+
if (type === "score") {
|
|
322
|
+
if (!Array.isArray(c) || c.length < 2 || c.length > 10 || !c.every(nonEmpty) || new Set(c).size !== c.length) problems.push("criteria must be 2 to 10 distinct levels, in order, for a score question");
|
|
323
|
+
} else if (c === null || typeof c !== "object" || Array.isArray(c)) {
|
|
324
|
+
problems.push(`criteria must be an object of ${type === "noul" ? "true and false" : "options"}, each with what it means`);
|
|
325
|
+
} else {
|
|
326
|
+
const entries = Object.entries(c as Record<string, unknown>);
|
|
327
|
+
if (!entries.every(([k, d]) => k !== "" && typeof d === "string")) problems.push("each criterion must be a non-empty name with what it means as a string");
|
|
328
|
+
if (type === "noul") {
|
|
329
|
+
const keys = entries.map(([k]) => k).sort();
|
|
330
|
+
if (keys.length !== 2 || keys[0] !== "false" || keys[1] !== "true") problems.push("criteria must describe true and false, and nothing else, for a noul question");
|
|
331
|
+
} else if (entries.length < 2 || entries.length > 255) {
|
|
332
|
+
problems.push("criteria must give 2 to 255 options for a choice question");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (problems.length > 0) return { problems };
|
|
336
|
+
const criteria = Array.isArray(c) ? [...(c as string[])] : { ...(c as Record<string, string>) };
|
|
337
|
+
return { asked: { question: (v.question as string).trim(), criteria } };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** An answer record's `asked`, when it has one. */
|
|
341
|
+
export function askedOf(data: Record<string, unknown>): Asked | undefined {
|
|
342
|
+
const a = data.asked as Record<string, unknown> | undefined;
|
|
343
|
+
if (a === null || typeof a !== "object" || Array.isArray(a) || typeof a.question !== "string") return undefined;
|
|
344
|
+
const c = a.criteria;
|
|
345
|
+
if (Array.isArray(c)) return { question: a.question, criteria: c.filter((x): x is string => typeof x === "string") };
|
|
346
|
+
if (c !== null && typeof c === "object") return { question: a.question, criteria: Object.fromEntries(Object.entries(c as Record<string, unknown>).filter(([, d]) => typeof d === "string")) as Record<string, string> };
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
267
349
|
|
|
268
350
|
/** The id of the answer to `name` for inputs hashing to `hash`: the name and the hash's first 12 hex digits. */
|
|
269
351
|
export const answerId = (name: string, hash: string): string => `${name}-${hash.slice(0, 12)}`;
|
|
@@ -311,15 +393,28 @@ export interface WireQuestion {
|
|
|
311
393
|
criteria: Record<string, string> | string[];
|
|
312
394
|
}
|
|
313
395
|
|
|
314
|
-
/**
|
|
396
|
+
/**
|
|
397
|
+
* One answer in the wire format's shape. `reason` is the model's own
|
|
398
|
+
* explanation of its answer, when the backend gives one (#3345): kept in the
|
|
399
|
+
* answer record beside a proposal, or in the escalation entry of an answer
|
|
400
|
+
* below the threshold, so a person sees why the model chose.
|
|
401
|
+
*/
|
|
315
402
|
export type WireAnswer =
|
|
316
|
-
| { type: "noul"; noul: number }
|
|
317
|
-
| { type: "choice"; choice: string; probabilities?: Record<string, number>; confidence?: number }
|
|
318
|
-
| { type: "score"; score?: number; legend?: unknown; probabilities?: Record<string, number>; confidence?: number }
|
|
403
|
+
| { type: "noul"; noul: number; reason?: string }
|
|
404
|
+
| { type: "choice"; choice: string; probabilities?: Record<string, number>; confidence?: number; reason?: string }
|
|
405
|
+
| { type: "score"; score?: number; legend?: unknown; probabilities?: Record<string, number>; confidence?: number; reason?: string }
|
|
319
406
|
| { type: "unsupported" };
|
|
320
407
|
|
|
408
|
+
/** A wire answer's reason, trimmed, or undefined when it gives none (or not a string). */
|
|
409
|
+
export function answerReason(answer: WireAnswer | undefined): string | undefined {
|
|
410
|
+
const raw = (answer as { reason?: unknown } | undefined)?.reason;
|
|
411
|
+
if (typeof raw !== "string") return undefined;
|
|
412
|
+
const reason = raw.trim();
|
|
413
|
+
return reason === "" ? undefined : reason;
|
|
414
|
+
}
|
|
415
|
+
|
|
321
416
|
export function wireQuestion(question: Question): WireQuestion {
|
|
322
|
-
return { type: question.type, instructions: question.instructions, criteria: question.criteria };
|
|
417
|
+
return { type: question.type, instructions: question.instructions, criteria: question.criteria ?? {} };
|
|
323
418
|
}
|
|
324
419
|
|
|
325
420
|
/** What a model decider is asked. */
|
|
@@ -388,7 +483,12 @@ export function observe(question: Question, answer: WireAnswer | undefined, thre
|
|
|
388
483
|
return { observed: false, answer: choice, probabilities, confidence, reason: `confidence ${confidence} is below the threshold ${threshold}` };
|
|
389
484
|
}
|
|
390
485
|
|
|
391
|
-
/**
|
|
486
|
+
/**
|
|
487
|
+
* A decider that was asked and did not answer, and why: `reason` is chant's
|
|
488
|
+
* account of why it did not answer. `model_reason` is the model's own
|
|
489
|
+
* explanation of the answer it gave (#3345), when it gave one; it is not named
|
|
490
|
+
* `reason` because that field already says why the decider escalated.
|
|
491
|
+
*/
|
|
392
492
|
export interface Escalation {
|
|
393
493
|
kind: "table" | "model";
|
|
394
494
|
reason: string;
|
|
@@ -398,6 +498,7 @@ export interface Escalation {
|
|
|
398
498
|
probabilities?: Record<string, number>;
|
|
399
499
|
confidence?: number;
|
|
400
500
|
threshold?: number;
|
|
501
|
+
model_reason?: string;
|
|
401
502
|
}
|
|
402
503
|
|
|
403
504
|
export type ChainResult =
|
|
@@ -409,6 +510,8 @@ export type ChainResult =
|
|
|
409
510
|
probabilities: Record<string, number>;
|
|
410
511
|
confidence: number;
|
|
411
512
|
threshold: number;
|
|
513
|
+
/** The model's explanation of its answer, when the backend gave one (#3345). */
|
|
514
|
+
reason?: string;
|
|
412
515
|
escalations: Escalation[];
|
|
413
516
|
}
|
|
414
517
|
| { status: "escalated"; decider: { kind: "quorum"; count: number; roles?: string[] }; escalations: Escalation[] };
|
|
@@ -455,6 +558,7 @@ export async function runChain(name: string, point: Point, inputs: Record<string
|
|
|
455
558
|
continue;
|
|
456
559
|
}
|
|
457
560
|
const seen = observe(point.question, reply.answer, d.threshold);
|
|
561
|
+
const why = answerReason(reply.answer);
|
|
458
562
|
if (seen.observed) {
|
|
459
563
|
return {
|
|
460
564
|
status: "proposed",
|
|
@@ -463,6 +567,7 @@ export async function runChain(name: string, point: Point, inputs: Record<string
|
|
|
463
567
|
probabilities: seen.probabilities,
|
|
464
568
|
confidence: seen.confidence,
|
|
465
569
|
threshold: d.threshold,
|
|
570
|
+
...(why !== undefined ? { reason: why } : {}),
|
|
466
571
|
escalations,
|
|
467
572
|
};
|
|
468
573
|
}
|
|
@@ -475,6 +580,7 @@ export async function runChain(name: string, point: Point, inputs: Record<string
|
|
|
475
580
|
...(seen.confidence !== undefined ? { confidence: seen.confidence } : {}),
|
|
476
581
|
threshold: d.threshold,
|
|
477
582
|
reason: `not observed: ${seen.reason}`,
|
|
583
|
+
...(why !== undefined ? { model_reason: why } : {}),
|
|
478
584
|
});
|
|
479
585
|
} else {
|
|
480
586
|
return { status: "escalated", decider: { kind: "quorum", count: d.count, ...(d.roles ? { roles: d.roles } : {}) }, escalations };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/workspace/pr-report/v1/pr-report.schema.json",
|
|
4
|
+
"title": "pull-request report",
|
|
5
|
+
"description": "What one stage of the pull-request loop (#3183) planned or applied: the members a change reaches, the digest the gate binds, where the approval stands and how the stage ended. Written by `chant components pr-plan` (pr-plan.json) and `chant components pr-apply` (pr-apply.json), and built by prReport in @intentius/chant/components/pr-run. The pull-request note is rendered from it by renderPrNote in @intentius/chant/pr-loop. Version 1 of the workspace read contract. Readers ignore fields they do not know; a field is only ever added within a version.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["$schema", "contract", "stage", "pr", "env", "base", "head", "op", "gate", "digest", "status", "approval", "selection", "members", "changeSet"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "const": "https://intentius.io/chant/schemas/workspace/pr-report/v1/pr-report.schema.json" },
|
|
10
|
+
"contract": { "const": 1 },
|
|
11
|
+
"stage": { "enum": ["plan", "apply"] },
|
|
12
|
+
"pr": {
|
|
13
|
+
"type": ["integer", "null"],
|
|
14
|
+
"minimum": 1,
|
|
15
|
+
"description": "The pull or merge request number. null when an apply found no pull request that merged its commit."
|
|
16
|
+
},
|
|
17
|
+
"env": { "type": "string" },
|
|
18
|
+
"base": { "type": "string", "pattern": "^[0-9a-f]{40,64}$", "description": "The commit the change is measured from: the merge base of the given base and head." },
|
|
19
|
+
"head": { "type": "string", "pattern": "^[0-9a-f]{40,64}$" },
|
|
20
|
+
"op": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "The gate's op, pr-<number>. Its ledger is _gates/<op>.jsonl on chant/lifecycle. pr-unknown when no pull request was found."
|
|
23
|
+
},
|
|
24
|
+
"gate": { "type": "string", "description": "The gate the apply waits on, pr-apply unless the pipeline names another." },
|
|
25
|
+
"digest": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$",
|
|
28
|
+
"description": "The change-set digest of what this stage planned: computePlanDigest(\"change-set\", ...) over every member's { member, planDigest }. What the gate binds."
|
|
29
|
+
},
|
|
30
|
+
"status": {
|
|
31
|
+
"enum": ["planned", "plan-failed", "nothing", "applied", "failed", "refused"],
|
|
32
|
+
"description": "planned: every member planned (plan stage). plan-failed: a member failed to plan, so nothing can apply. nothing: no component deploys what the change touches. applied: every member applied. failed: a member failed to apply and its dependents did not run. refused: nothing applied, see refusal."
|
|
33
|
+
},
|
|
34
|
+
"refusal": {
|
|
35
|
+
"enum": ["not-approved", "plan-changed", "not-a-reviewer", "no-pull-request"],
|
|
36
|
+
"description": "Why an apply refused. plan-changed: an approval stands for another digest, so the plan changed after review."
|
|
37
|
+
},
|
|
38
|
+
"message": { "type": "string", "description": "The refusal or failure as printed." },
|
|
39
|
+
"approval": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"required": ["status"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"status": { "enum": ["approved", "changed", "pending"], "description": "approved: an approval stands for digest. changed: one stands for another digest. pending: none stands." },
|
|
44
|
+
"approvedBy": { "type": "array", "items": { "type": "string" }, "description": "Who approved digest, as the approval names them (github:<login>, gitlab:<login>, <forge>@<host>:<login>, or a signer)." },
|
|
45
|
+
"approved": { "type": "string", "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$", "description": "With changed: the digest that was approved." }
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"selection": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"required": ["changed", "dependents", "unclaimed", "indeterminate", "waves"],
|
|
51
|
+
"description": "Component names. The fan-out derivation the change gives (#2417).",
|
|
52
|
+
"properties": {
|
|
53
|
+
"changed": { "type": "array", "items": { "type": "string" }, "description": "Components deploying a unit the change touched, in dependency order." },
|
|
54
|
+
"dependents": { "type": "array", "items": { "type": "string" }, "description": "Components selected because they depend on a changed one, in dependency order." },
|
|
55
|
+
"unclaimed": { "type": "array", "items": { "type": "string" }, "description": "Units the change touched that no component deploys." },
|
|
56
|
+
"indeterminate": { "type": "array", "items": { "type": "string" }, "description": "Components a source diff cannot judge that the walk did not reach." },
|
|
57
|
+
"waves": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "description": "The selected components in parallel-safe waves, in apply order." }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"members": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"description": "One entry per change-set member, sorted by member.",
|
|
63
|
+
"items": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": ["member", "component", "planDigest", "status", "counts"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"member": { "type": "string", "description": "The member's name in the change set: the root, for a terraform-family step." },
|
|
68
|
+
"component": { "type": "string" },
|
|
69
|
+
"planDigest": { "type": ["string", "null"], "description": "What a gate on this member alone binds. null when it failed to plan." },
|
|
70
|
+
"status": { "enum": ["planned", "plan-failed", "applied", "failed", "blocked"] },
|
|
71
|
+
"counts": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"required": ["create", "update", "replace", "delete"],
|
|
74
|
+
"properties": {
|
|
75
|
+
"create": { "type": "integer", "minimum": 0 },
|
|
76
|
+
"update": { "type": "integer", "minimum": 0 },
|
|
77
|
+
"replace": { "type": "integer", "minimum": 0 },
|
|
78
|
+
"delete": { "type": "integer", "minimum": 0 }
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"error": { "type": "string" },
|
|
82
|
+
"inputsMoved": {
|
|
83
|
+
"type": "array",
|
|
84
|
+
"items": { "type": "string" },
|
|
85
|
+
"description": "Apply stage: components this one depends on whose outputs changed when they applied. It applied the plan it was approved with; the next run plans it against the new values."
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"changeSet": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"description": "The change-set document over every member (change-set.schema.json). Its digest equals digest."
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #3174, ws-096: factory fields are opt-in, and the reference workspace ships
|
|
3
|
+
* three profiles (ideation, app, infra) that `chant workspace init --profile`
|
|
4
|
+
* copies. A records-only workspace, an infra workspace with no factory and an
|
|
5
|
+
* infra workspace whose factory has no app member and no box services all
|
|
6
|
+
* pass `chant workspace check`, and so does a copy of each profile.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
10
|
+
import { mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join, relative } from "node:path";
|
|
13
|
+
import { afterAll, describe, expect, test } from "vitest";
|
|
14
|
+
import { REPO, repo } from "./__fixtures__/contract-repo";
|
|
15
|
+
import { plantability } from "./box-factory";
|
|
16
|
+
import { runDeclarationChecks } from "./checks";
|
|
17
|
+
import { readDeclaration } from "./declaration";
|
|
18
|
+
import { PROFILES, PROFILES_DIR, profileSource } from "./init";
|
|
19
|
+
import { initFromCommand } from "./lineage-init";
|
|
20
|
+
import { workingTree } from "./tree";
|
|
21
|
+
|
|
22
|
+
const scratch: string[] = [];
|
|
23
|
+
afterAll(() => {
|
|
24
|
+
for (const d of scratch) rmSync(d, { recursive: true, force: true });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const REFERENCE = join(REPO, "reference-workspace");
|
|
28
|
+
const CHANT = join(REPO, "packages", "core", "bin", "chant");
|
|
29
|
+
|
|
30
|
+
/** Every file under `dir`, relative to it, sorted. */
|
|
31
|
+
function files(dir: string): string[] {
|
|
32
|
+
const out: string[] = [];
|
|
33
|
+
const walk = (at: string) => {
|
|
34
|
+
for (const name of readdirSync(at)) {
|
|
35
|
+
const p = join(at, name);
|
|
36
|
+
if (statSync(p).isDirectory()) walk(p);
|
|
37
|
+
else out.push(relative(dir, p));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
walk(dir);
|
|
41
|
+
return out.sort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The errors `chant workspace check` reports, as `<id>:<entity>: <message>`. */
|
|
45
|
+
async function errors(root: string): Promise<string[]> {
|
|
46
|
+
const report = await runDeclarationChecks(root);
|
|
47
|
+
return report.diagnostics.filter((d) => d.severity === "error").map((d) => `${d.ruleId}:${d.entity ?? ""}: ${d.message}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A copy of a profile, made the way `chant workspace init --profile` makes it, from this checkout. */
|
|
51
|
+
async function copyOf(profile: string): Promise<string> {
|
|
52
|
+
const dir = realpathSync(mkdtempSync(join(tmpdir(), `chant-3174-${profile}-`)));
|
|
53
|
+
scratch.push(dir);
|
|
54
|
+
const made = await initFromCommand({ from: `${REPO}#${PROFILES_DIR}/${profile}`, path: dir, params: profile === "infra" ? {} : { name: "Fern" } });
|
|
55
|
+
expect(made.success, made.error).toBe(true);
|
|
56
|
+
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
describe("factory fields are opt-in (#3174)", () => {
|
|
61
|
+
test("a records-only workspace passes check, with no member, box or factory", async () => {
|
|
62
|
+
const root = repo({
|
|
63
|
+
"chant.workspace.json": JSON.stringify({ name: "notes", schema: 1, members: [], records: [{ kind: "decisions/decision.kind.mjs" }] }, null, 2),
|
|
64
|
+
"decisions/decision.kind.mjs": readFileSync(join(REFERENCE, "decisions", "decision.kind.mjs"), "utf-8"),
|
|
65
|
+
"decisions/decision.schema.json": readFileSync(join(REFERENCE, "decisions", "decision.schema.json"), "utf-8"),
|
|
66
|
+
});
|
|
67
|
+
expect(await errors(root)).toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("an infra workspace with no factory passes check", async () => {
|
|
71
|
+
const root = repo({
|
|
72
|
+
"chant.workspace.json": JSON.stringify({ name: "estate", schema: 1, members: [{ name: "network", dir: "network", kind: "chant" }] }, null, 2),
|
|
73
|
+
"network/chant.config.json": '{ "lexicons": ["terraform"] }\n',
|
|
74
|
+
});
|
|
75
|
+
expect(await errors(root)).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("an infra workspace whose factory builds an estate member, with no app member and no box services, passes check and isn't plantable", async () => {
|
|
79
|
+
const declaration = {
|
|
80
|
+
name: "estate",
|
|
81
|
+
schema: 1,
|
|
82
|
+
members: [{ name: "network", dir: "network", kind: "chant", box: { factory: { builds: ["network"], check: { run: "chant lint", kind: "lint" } } } }],
|
|
83
|
+
};
|
|
84
|
+
const root = repo({ "chant.workspace.json": JSON.stringify(declaration, null, 2), "network/chant.config.json": '{ "lexicons": ["terraform"] }\n' });
|
|
85
|
+
expect(await errors(root)).toEqual([]);
|
|
86
|
+
expect(plantability(readDeclaration(workingTree(root), "")).reason?.code).toBe("box-none");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("the reference workspace's profiles (#3174)", () => {
|
|
91
|
+
test("are ideation, app and infra, each a template directory with a declaration", () => {
|
|
92
|
+
expect(readdirSync(join(REPO, PROFILES_DIR)).sort()).toEqual([...PROFILES].sort());
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("carry the reference workspace's own record kinds and app kind, byte for byte", () => {
|
|
96
|
+
for (const profile of PROFILES) {
|
|
97
|
+
const dir = join(REPO, PROFILES_DIR, profile);
|
|
98
|
+
for (const f of files(dir).filter((p) => /^(decisions|work|answers|kinds)\//.test(p))) {
|
|
99
|
+
expect(readFileSync(join(dir, f), "utf-8"), `${profile}/${f}`).toBe(readFileSync(join(REFERENCE, f), "utf-8"));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("ideation: records and a stub app of the app kind, no box and no factory, and check passes", async () => {
|
|
105
|
+
const root = await copyOf("ideation");
|
|
106
|
+
expect(await errors(root)).toEqual([]);
|
|
107
|
+
const d = readDeclaration(workingTree(root), "");
|
|
108
|
+
expect(d.members.map((m) => `${m.name}:${m.kind}`)).toEqual(["app:app"]);
|
|
109
|
+
expect(d.members.every((m) => m.box === null)).toBe(true);
|
|
110
|
+
expect(d.records.map((r) => r.kind)).toEqual(["decisions/decision.kind.mjs", "work/work.kind.mjs", "answers/answer.kind.mjs"]);
|
|
111
|
+
expect(readFileSync(join(root, "app", "server.mjs"), "utf-8")).toContain('NAME = "Fern"');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("app: the app member runs as the box's service and the factory builds it, and check passes", async () => {
|
|
115
|
+
const root = await copyOf("app");
|
|
116
|
+
expect(await errors(root)).toEqual([]);
|
|
117
|
+
const d = readDeclaration(workingTree(root), "");
|
|
118
|
+
expect(plantability(d)).toMatchObject({ plantable: true, box: "app" });
|
|
119
|
+
expect(d.members[0].box?.factory?.builds).toEqual(["app"]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("infra: an estate member and a factory, no app member and no box services, and check passes", async () => {
|
|
123
|
+
const root = await copyOf("infra");
|
|
124
|
+
expect(await errors(root)).toEqual([]);
|
|
125
|
+
const d = readDeclaration(workingTree(root), "");
|
|
126
|
+
expect(d.members.map((m) => `${m.name}:${m.kind}`)).toEqual(["network:chant"]);
|
|
127
|
+
expect(d.members[0].box?.factory?.check).toEqual({ run: "cd network && npx chant lint && npx chant build", kind: "lint" });
|
|
128
|
+
expect(d.members[0].box?.services).toEqual([]);
|
|
129
|
+
expect(d.pins).toEqual([]);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("chant workspace init --profile (#3174)", () => {
|
|
134
|
+
test("reads the profile from the chant repository at this chant's tag, or from --from", () => {
|
|
135
|
+
expect(profileSource("app", undefined, "0.103.0")).toBe("https://github.com/INTENTIUS/chant@chant-v0.103.0#reference-workspace/profiles/app");
|
|
136
|
+
expect(profileSource("infra", "/src/chant", "0.103.0")).toBe("/src/chant#reference-workspace/profiles/infra");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("copies the profile with a lineage lock and names the workspace", () => {
|
|
140
|
+
const dir = realpathSync(mkdtempSync(join(tmpdir(), "chant-3174-cli-")));
|
|
141
|
+
scratch.push(dir);
|
|
142
|
+
const run = spawnSync(CHANT, ["workspace", "init", dir, "--profile", "ideation", "--from", REPO, "--name", "fern", "--param", "name=Fern", "--yes"], { encoding: "utf-8" });
|
|
143
|
+
expect(run.status, run.stderr).toBe(0);
|
|
144
|
+
expect(JSON.parse(readFileSync(join(dir, "chant.workspace.json"), "utf-8")).name).toBe("fern");
|
|
145
|
+
expect(readdirSync(join(dir, ".chant"))).toContain("workspace.lock.json");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("names the profiles when given another, and writes nothing without --yes", () => {
|
|
149
|
+
const dir = realpathSync(mkdtempSync(join(tmpdir(), "chant-3174-cli-")));
|
|
150
|
+
scratch.push(dir);
|
|
151
|
+
const bad = spawnSync(CHANT, ["workspace", "init", dir, "--profile", "web"], { encoding: "utf-8" });
|
|
152
|
+
expect(bad.status).toBe(1);
|
|
153
|
+
expect(bad.stderr).toMatch(/the profiles are ideation, app, infra/);
|
|
154
|
+
const dry = spawnSync(CHANT, ["workspace", "init", dir, "--profile", "infra", "--from", REPO], { encoding: "utf-8", input: "" });
|
|
155
|
+
expect(dry.status).toBe(0);
|
|
156
|
+
expect(dry.stdout).toMatch(/Nothing written/);
|
|
157
|
+
expect(readdirSync(dir)).toEqual([]);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -215,7 +215,7 @@ describe("every schema against the reference workspace (#2543)", () => {
|
|
|
215
215
|
expect(doc.components[0].runtimes).toEqual([{ name: "local", lexicon: null, default: true, command: "chant run --components app" }]);
|
|
216
216
|
expect(doc.members.find((m) => m.name === "delivery")!.runtimeReasons).toEqual([]);
|
|
217
217
|
// #2695: the reference config declares no environments, so the app deploys to local only.
|
|
218
|
-
expect(doc.components[0].environments).toEqual([{ name: "local", default: true, source: "builtin", command: "chant run --components app" }]);
|
|
218
|
+
expect(doc.components[0].environments).toEqual([{ name: "local", default: true, source: "builtin", site: null, command: "chant run --components app" }]);
|
|
219
219
|
expect(doc.members.find((m) => m.name === "delivery")!.environmentReasons.map((r) => r.code)).toEqual(["environments-none-declared"]);
|
|
220
220
|
expect(doc.reasons).toEqual([]);
|
|
221
221
|
}
|
|
@@ -244,7 +244,7 @@ describe("every schema against the reference workspace (#2543)", () => {
|
|
|
244
244
|
const doc = await workspacePoints({ cwd: FIXTURE, at });
|
|
245
245
|
expectValid(doc);
|
|
246
246
|
if ("error" in doc) throw new Error(doc.error.message);
|
|
247
|
-
expect(doc.points.map((p) => p.name)).toEqual(["slice-tier", "ship-skip", "finding-triage", "needs-a-decision"]);
|
|
247
|
+
expect(doc.points.map((p) => p.name)).toEqual(["slice-tier", "understand", "ship-skip", "finding-triage", "needs-a-decision", "intent-origin", "intent-judgment", "intent-disposition", "agent-question"]);
|
|
248
248
|
const sliceTier = doc.points.find((p) => p.name === "slice-tier")!;
|
|
249
249
|
expect(sliceTier.criteria).toEqual({
|
|
250
250
|
small: "A haiku-class builder. The work item fits the small limits.",
|
|
@@ -29,7 +29,8 @@ import { WORK_WARNING_CODES } from "./work";
|
|
|
29
29
|
import { BOX_FINDING_CODES } from "./checks/boxes";
|
|
30
30
|
import { DIAGRAM_FINDING_CODES } from "./checks/diagrams";
|
|
31
31
|
import { WORK_ERROR_CODES, WORK_HISTORY_ERROR_CODES, WORK_LEASE_REFUSALS } from "./work-cli";
|
|
32
|
-
import { RUNS_ERROR_CODES, RUNS_REASON_CODES, RUNS_WRITE_ERROR_CODES } from "./runs-cli";
|
|
32
|
+
import { RUN_STATEMENT_ERROR_CODES, RUNS_ERROR_CODES, RUNS_REASON_CODES, RUNS_WRITE_ERROR_CODES } from "./runs-cli";
|
|
33
|
+
import { RUN_STATEMENT_FAILURE_CODES } from "./trust/run-statement";
|
|
33
34
|
import { WORK_EVIDENCE_ERROR_CODES } from "./work-evidence";
|
|
34
35
|
import { RECORD_FINDING_CODES } from "./checks/records";
|
|
35
36
|
import { ANSWER_WARNING_CODES } from "./points";
|
|
@@ -39,6 +40,10 @@ import { PATCH_ERROR_CODES } from "./patch";
|
|
|
39
40
|
import { AGENT_ERROR_CODES } from "./agent-cli";
|
|
40
41
|
import { SCOPE_FINDING_CODES, WRITE_SCOPE_CODES } from "./write-scope";
|
|
41
42
|
import { PLANTABLE_REASON_CODES } from "./box-factory";
|
|
43
|
+
import { BOX_LISTING_ERROR_CODES } from "./box-listing";
|
|
44
|
+
import { BOX_PUBLISH_ERROR_CODES } from "./box-publish";
|
|
45
|
+
import { WRITE_LOCK_ERROR_CODES } from "./write-lock-cli";
|
|
46
|
+
import { WIP_ERROR_CODES, WIP_WRITE_ERROR_CODES } from "./wip";
|
|
42
47
|
import { ROTATION_REFUSAL_CODES } from "./trust/rotation";
|
|
43
48
|
import { SIGNERS_ERROR_CODES } from "./trust/signers-cli";
|
|
44
49
|
import { EVIDENCE_ERROR_CODES } from "./trust/evidence";
|
|
@@ -88,6 +93,8 @@ const PER_COMMAND: Record<string, readonly string[]> = {
|
|
|
88
93
|
RUNS_ERROR_CODES,
|
|
89
94
|
RUNS_REASON_CODES,
|
|
90
95
|
RUNS_WRITE_ERROR_CODES,
|
|
96
|
+
RUN_STATEMENT_ERROR_CODES,
|
|
97
|
+
RUN_STATEMENT_FAILURE_CODES,
|
|
91
98
|
WORK_EVIDENCE_ERROR_CODES,
|
|
92
99
|
RECORD_FINDING_CODES,
|
|
93
100
|
ANSWER_WARNING_CODES,
|
|
@@ -99,6 +106,11 @@ const PER_COMMAND: Record<string, readonly string[]> = {
|
|
|
99
106
|
WRITE_SCOPE_CODES,
|
|
100
107
|
SCOPE_FINDING_CODES,
|
|
101
108
|
PLANTABLE_REASON_CODES,
|
|
109
|
+
BOX_LISTING_ERROR_CODES,
|
|
110
|
+
BOX_PUBLISH_ERROR_CODES,
|
|
111
|
+
WRITE_LOCK_ERROR_CODES,
|
|
112
|
+
WIP_ERROR_CODES,
|
|
113
|
+
WIP_WRITE_ERROR_CODES,
|
|
102
114
|
ROTATION_REFUSAL_CODES,
|
|
103
115
|
SIGNERS_ERROR_CODES,
|
|
104
116
|
EVIDENCE_ERROR_CODES,
|