@intentius/chant 0.101.0 → 0.104.0
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/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- 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/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.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/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.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/dev.d.ts.map +1 -1
- 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/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +16 -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/lsp/server.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/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +4 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +74 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/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-plugin-loader.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/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/shell.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.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/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +103 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +22 -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/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.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/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +137 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.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 +5 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.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/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.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/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.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/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +6 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.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/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +16 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- 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/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/emit-source.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/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- 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 +97 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- 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/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.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 +68 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +19 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +462 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- 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 +156 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +383 -5
- 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/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.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 +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +36 -2
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +249 -8
- 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 +66 -4
- 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-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/links.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/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +53 -4
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.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-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +34 -1
- 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-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +68 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +296 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +544 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.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 +17 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +64 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +63 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.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 +38 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.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 +39 -3
- 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/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/workspace-principals.schema.json +60 -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 +83 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +7 -2
- 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/audit/prior-art.ts +15 -0
- 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/__fixtures__/init-lexicon-output/package.json +1 -1
- 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/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -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/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- 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/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +121 -6
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +86 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +21 -0
- package/src/cli/main.ts +246 -30
- 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 +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -7
- package/src/cli/registry.ts +74 -3
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/testdata/postgres-tags.json +242 -0
- 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/config.test.ts +21 -0
- package/src/config.ts +15 -0
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/sandbox/bundle.ts +1 -1
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- 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/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/index.ts +1 -0
- package/src/lexicon.ts +106 -3
- package/src/lifecycle/gate-ledger.ts +23 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- 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/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- 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 +9 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- 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/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +11 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -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/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +16 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +76 -11
- 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/provenance.ts +35 -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/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +323 -0
- package/src/workspace/box-factory.ts +136 -0
- 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/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +5 -0
- package/src/workspace/checks.ts +39 -8
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/compose-graph.ts +7 -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 +32 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- 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 +228 -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 +54 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -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 +36 -3
- package/src/workspace/conformance/index.mjs +51 -3
- package/src/workspace/conformance/index.ts +107 -15
- package/src/workspace/conformance/vitest.ts +76 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
- package/src/workspace/conformance/writer.test.ts +186 -0
- package/src/workspace/conformance/writer.ts +1191 -0
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +433 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +383 -5
- package/src/workspace/declaration.ts +315 -10
- 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 +6 -3
- package/src/workspace/graph.schema.json +314 -0
- package/src/workspace/identity.test.ts +219 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +84 -13
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +336 -1
- package/src/workspace/intent-record.ts +96 -16
- 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 +274 -0
- package/src/workspace/intent.schema.json +950 -9
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +722 -65
- 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 +201 -39
- 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 +163 -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/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -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 +23 -3
- package/src/workspace/reason-codes.ts +61 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +80 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +123 -17
- package/src/workspace/records-close.schema.json +79 -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 +9 -0
- package/src/workspace/records-review.schema.json +80 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +219 -30
- package/src/workspace/records.schema.json +88 -1
- package/src/workspace/records.ts +76 -8
- 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 +710 -0
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +994 -0
- package/src/workspace/runs.schema.json +1257 -0
- package/src/workspace/runs.test.ts +281 -0
- package/src/workspace/runs.ts +970 -0
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +10 -2
- package/src/workspace/status-gates.ts +25 -9
- package/src/workspace/status.schema.json +252 -4
- package/src/workspace/status.ts +110 -1
- package/src/workspace/symbols.ts +191 -0
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +58 -1
- 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.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +136 -8
- package/src/workspace/work-evidence.schema.json +5 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/workspace-principals.schema.json +60 -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 +144 -3
- package/src/workspace/write-scope.ts +192 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -158,12 +158,39 @@ describe("chant workspace work (#2732)", () => {
|
|
|
158
158
|
expect(json(closed).error.code).toBe("work-item-closed");
|
|
159
159
|
const verb = await chant(root, ["workspace", "work", "grab", "W-001", "--holder", "a"]);
|
|
160
160
|
expect(verb.code).toBe(1);
|
|
161
|
-
expect(verb.stderr).toContain("claim, renew, release or
|
|
161
|
+
expect(verb.stderr).toContain("claim, renew, release, history or evidence");
|
|
162
162
|
const noHolder = await chant(root, ["workspace", "work", "claim", "W-001"]);
|
|
163
163
|
expect(noHolder.code).toBe(1);
|
|
164
164
|
expect(noHolder.stderr).toContain("--holder");
|
|
165
165
|
}, 120_000);
|
|
166
166
|
|
|
167
|
+
test("evidence (#3159): needs the holder, the token and the entry, runs only under the live lease, and names only a criterion the item lists", async () => {
|
|
168
|
+
const entry = JSON.stringify({ criterion: "AC-1", result: "pass", title: "The test", url: "https://example.com/ci/1" });
|
|
169
|
+
const usage = await chant(root, ["workspace", "work", "evidence", "W-002", "--holder", "a", "--from", "-"]);
|
|
170
|
+
expect(usage.code).toBe(1);
|
|
171
|
+
expect(JSON.parse(usage.stdout).error).toMatchObject({ code: "write-usage-invalid", message: expect.stringContaining("--token") });
|
|
172
|
+
const evidence = (holder: string, token: string) =>
|
|
173
|
+
new Promise<Run>((resolve) => {
|
|
174
|
+
const child = spawn(CHANT[0], [...CHANT.slice(1), "workspace", "work", "evidence", "W-002", "--holder", holder, "--token", token, "--from", "-"], { cwd: root, env: { ...process.env, NO_COLOR: "1" } });
|
|
175
|
+
let stdout = "";
|
|
176
|
+
let stderr = "";
|
|
177
|
+
child.stdout.on("data", (d) => (stdout += d));
|
|
178
|
+
child.stderr.on("data", (d) => (stderr += d));
|
|
179
|
+
child.on("close", (code) => resolve({ code, stdout, stderr }));
|
|
180
|
+
child.stdin.end(entry);
|
|
181
|
+
});
|
|
182
|
+
// worker-d holds W-002 since the records test above: anyone else is refused.
|
|
183
|
+
const held = json(await chant(root, ["workspace", "work", "claim", "W-002", "--holder", "ev", "--json"])).refused.heldBy as { holder: string; token: string };
|
|
184
|
+
const other = await evidence("ev", "none");
|
|
185
|
+
expect(other.code).toBe(1);
|
|
186
|
+
expect(JSON.parse(other.stdout).error.code).toBe("lease-held");
|
|
187
|
+
const stale = await evidence(held.holder, "not-the-token");
|
|
188
|
+
expect(JSON.parse(stale.stdout).error.code).toBe("lease-token-mismatch");
|
|
189
|
+
const unlisted = await evidence(held.holder, held.token);
|
|
190
|
+
expect(unlisted.code).toBe(1);
|
|
191
|
+
expect(JSON.parse(unlisted.stdout).error.code).toBe("work-criterion-unknown");
|
|
192
|
+
}, 120_000);
|
|
193
|
+
|
|
167
194
|
test("the lease fields reach an MCP client through workspace-records and workspace-status", async () => {
|
|
168
195
|
const claim = await chant(root, ["workspace", "work", "claim", "W-001", "--holder", "mcp-worker", "--json"]);
|
|
169
196
|
expect(claim.code, claim.stderr).toBe(0);
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* workspace work history <id>` (#2785): the item's lease history, each claim
|
|
5
5
|
* and how it ended, a read-contract output (`work-history.schema.json`).
|
|
6
6
|
*
|
|
7
|
+
* And `chant workspace work evidence <id>` (#3159): the `workEvidence`
|
|
8
|
+
* activity as a command, so a writer outside an Op attaches evidence under
|
|
9
|
+
* the lease it holds.
|
|
10
|
+
*
|
|
7
11
|
* The lease itself is `../lifecycle/work-lease.ts`, the operator lease under
|
|
8
12
|
* the key `work/<id>`. This file finds the work item first: in the work kind
|
|
9
13
|
* `--kind` names, or in the one work kind the declaration names that has a
|
|
@@ -26,13 +30,18 @@ import type { CommandContext } from "../cli/registry";
|
|
|
26
30
|
import { parseDuration } from "../op/duration";
|
|
27
31
|
import {
|
|
28
32
|
claimWorkLease,
|
|
33
|
+
isWorkLeaseOutcome,
|
|
29
34
|
leaseHistoryPath,
|
|
35
|
+
listKeptAttempts,
|
|
30
36
|
listWorkLeases,
|
|
37
|
+
outcomeCountsAsAttempt,
|
|
31
38
|
readLeaseHistory,
|
|
32
39
|
releaseWorkLease,
|
|
33
40
|
renewWorkLease,
|
|
34
41
|
workLeaseRef,
|
|
35
42
|
WORK_ITEM_ID_PATTERN,
|
|
43
|
+
WORK_LEASE_OUTCOMES,
|
|
44
|
+
type KeptAttempt,
|
|
36
45
|
type WorkLease,
|
|
37
46
|
type WorkLeaseRefusal,
|
|
38
47
|
type WorkLeaseResult,
|
|
@@ -46,6 +55,7 @@ import { declaredKindFiles, readRecordsFor } from "./records-cli";
|
|
|
46
55
|
import { loadRecordKind, RecordReadError, type LoadedRecordKind, type RecordEntry } from "./records";
|
|
47
56
|
import { gitRoot } from "./record-source";
|
|
48
57
|
import type { ReasonCode } from "./reason-codes";
|
|
58
|
+
import { replicateAfter } from "./wip";
|
|
49
59
|
|
|
50
60
|
/** The version of the `work` output this chant writes. */
|
|
51
61
|
export const WORK_LEASE_CONTRACT_VERSION = 1;
|
|
@@ -53,11 +63,12 @@ export const WORK_LEASE_CONTRACT_VERSION = 1;
|
|
|
53
63
|
/** `$id` of the JSON Schema for the `--json` output, shipped beside this file. */
|
|
54
64
|
export const WORK_LEASE_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/work-lease/v1/work-lease.schema.json";
|
|
55
65
|
|
|
56
|
-
export { WORK_LEASE_REFUSALS } from "../lifecycle/work-lease";
|
|
66
|
+
export { WORK_LEASE_REFUSALS, WORK_LEASE_OUTCOMES } from "../lifecycle/work-lease";
|
|
57
67
|
|
|
58
68
|
const USAGE = [
|
|
59
|
-
"chant workspace work claim|renew|release <id> --holder <name> [--kind <kind file>] [--ttl <seconds|duration>] [--token <token>] [--outcome <
|
|
69
|
+
"chant workspace work claim|renew|release <id> --holder <name> [--kind <kind file>] [--ttl <seconds|duration>] [--token <token>] [--outcome <outcome>] [--note <text>] [--json]",
|
|
60
70
|
"chant workspace work history <id> [--kind <kind file>] [--json]",
|
|
71
|
+
"chant workspace work evidence <id> --holder <name> --token <token> --from <file|-> [--kind <kind file>]",
|
|
61
72
|
].join("\n");
|
|
62
73
|
|
|
63
74
|
/** Exit code when the lease was refused rather than the command failing. */
|
|
@@ -193,6 +204,9 @@ export async function workLease(req: WorkLeaseRequest): Promise<WorkLeaseDocumen
|
|
|
193
204
|
const doc = { $schema: WORK_LEASE_OUTPUT_SCHEMA_ID, contract: WORK_LEASE_CONTRACT_VERSION };
|
|
194
205
|
try {
|
|
195
206
|
if (!WORK_ITEM_ID_PATTERN.test(req.id) || req.id.includes("..")) throw new WorkError("write-usage-invalid", `${JSON.stringify(req.id)} is not a work item id`);
|
|
207
|
+
if (req.outcome !== undefined && !isWorkLeaseOutcome(req.outcome)) {
|
|
208
|
+
throw new WorkError("write-usage-invalid", `${JSON.stringify(req.outcome)} is not a lease outcome: use one of ${WORK_LEASE_OUTCOMES.join(", ")}`);
|
|
209
|
+
}
|
|
196
210
|
if (!gitRoot(req.cwd)) throw new WorkError("not-a-git-repository", "a work lease is a git ref, and this directory is not in a git repository");
|
|
197
211
|
const { loaded, state, root } = await findWorkItem(req.id, req.cwd, req.kind);
|
|
198
212
|
if (req.verb === "claim" && state !== null && (loaded.kind.closedStates ?? []).includes(state)) {
|
|
@@ -210,6 +224,8 @@ export async function workLease(req: WorkLeaseRequest): Promise<WorkLeaseDocumen
|
|
|
210
224
|
const heldBy = result.heldBy ? strip(result.heldBy) : null;
|
|
211
225
|
return { ...head, refused: { code: result.reason, message: result.message, heldBy } };
|
|
212
226
|
}
|
|
227
|
+
// #3172: a box's replicate policy may push its work in progress once a lease is released. Best effort; status shows what is behind.
|
|
228
|
+
if (req.verb === "release") replicateAfter("release", req.cwd);
|
|
213
229
|
return { ...head, lease: strip(result.lease), history: result.history };
|
|
214
230
|
} catch (err) {
|
|
215
231
|
if (err instanceof WorkError) return { ...doc, error: { code: err.code, message: err.message } };
|
|
@@ -259,6 +275,27 @@ export interface LeaseClaim {
|
|
|
259
275
|
ended: ClaimEnd;
|
|
260
276
|
/** The release, when it was released. */
|
|
261
277
|
release: { by: string; at: string; outcome: string | null; note: string | null } | null;
|
|
278
|
+
/**
|
|
279
|
+
* Whether the claim counts toward the item's attempt limit (#3147): one
|
|
280
|
+
* released `not_done` or `abandoned`, with no outcome or an outcome from
|
|
281
|
+
* before the list was closed, or one that expired or was lost unreleased.
|
|
282
|
+
* Not one that is held, and not one released with any other outcome.
|
|
283
|
+
*/
|
|
284
|
+
attempt: boolean;
|
|
285
|
+
/** The ref keeping this claim's unfinished work, `refs/chant/kept/.../<item>/<token>`, or null. */
|
|
286
|
+
kept: string | null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** An item's attempts against its limit (#3147). */
|
|
290
|
+
export interface WorkAttempts {
|
|
291
|
+
/** The claims that count as attempts. */
|
|
292
|
+
failed: number;
|
|
293
|
+
/** The item's limit: its own field, else its kind's default; null when neither declares one. */
|
|
294
|
+
limit: number | null;
|
|
295
|
+
/** How many attempts are left, never below 0; null without a limit. */
|
|
296
|
+
remaining: number | null;
|
|
297
|
+
/** True once failed reaches the limit: a runner leaves the item to people. */
|
|
298
|
+
exhausted: boolean;
|
|
262
299
|
}
|
|
263
300
|
|
|
264
301
|
/** What `work history --json` prints. */
|
|
@@ -283,17 +320,21 @@ export type WorkHistoryDocument =
|
|
|
283
320
|
/** Lines of the history that are not lease events, left out. */
|
|
284
321
|
malformed: number;
|
|
285
322
|
summary: { claims: number; released: number; held: number; expired: number; lost: number; outcomes: Record<string, number> };
|
|
323
|
+
/** The item's attempts against its limit (#3147). */
|
|
324
|
+
attempts: WorkAttempts;
|
|
325
|
+
/** Every kept attempt of the item, by ref (#3147). */
|
|
326
|
+
kept: KeptAttempt[];
|
|
286
327
|
}
|
|
287
328
|
| { $schema: string; contract: number; chant: string; error: { code: WorkHistoryErrorCode; message: string } };
|
|
288
329
|
|
|
289
330
|
/** Fold a history into its claims: one per token, in the order they were first seen. */
|
|
290
|
-
export function claimsOf(events: LeaseHistoryRecord[], live: Pick<WorkLeaseState, "token" | "state"> | null): LeaseClaim[] {
|
|
331
|
+
export function claimsOf(events: LeaseHistoryRecord[], live: Pick<WorkLeaseState, "token" | "state"> | null, kept: readonly KeptAttempt[] = []): LeaseClaim[] {
|
|
291
332
|
const byToken = new Map<string, LeaseClaim>();
|
|
292
333
|
const order: string[] = [];
|
|
293
334
|
for (const e of events) {
|
|
294
335
|
let c = byToken.get(e.token);
|
|
295
336
|
if (!c) {
|
|
296
|
-
c = { token: e.token, holder: e.holder, acquiredAt: e.acquiredAt, expiresAt: e.expiresAt, renewals: 0, ended: "expired", release: null };
|
|
337
|
+
c = { token: e.token, holder: e.holder, acquiredAt: e.acquiredAt, expiresAt: e.expiresAt, renewals: 0, ended: "expired", release: null, attempt: false, kept: null };
|
|
297
338
|
byToken.set(e.token, c);
|
|
298
339
|
order.push(e.token);
|
|
299
340
|
}
|
|
@@ -307,10 +348,30 @@ export function claimsOf(events: LeaseHistoryRecord[], live: Pick<WorkLeaseState
|
|
|
307
348
|
else if (live && live.token === token) c.ended = live.state === "active" ? "held" : "expired";
|
|
308
349
|
else if (i < order.length - 1) c.ended = "lost";
|
|
309
350
|
else c.ended = "expired";
|
|
351
|
+
c.attempt = c.ended === "released" ? outcomeCountsAsAttempt(c.release?.outcome) : c.ended !== "held";
|
|
352
|
+
c.kept = kept.find((k) => k.token === token)?.ref ?? null;
|
|
310
353
|
return c;
|
|
311
354
|
});
|
|
312
355
|
}
|
|
313
356
|
|
|
357
|
+
/**
|
|
358
|
+
* The attempt limit of a work record (#3147): the integer in the field the
|
|
359
|
+
* kind's `work.attempts.field` names, else the kind's `work.attempts.max`;
|
|
360
|
+
* null when the kind declares no attempts.
|
|
361
|
+
*/
|
|
362
|
+
export function attemptLimit(kind: LoadedRecordKind["kind"], data: Record<string, unknown> | null): number | null {
|
|
363
|
+
const spec = kind.work?.attempts;
|
|
364
|
+
if (!spec) return null;
|
|
365
|
+
const own = data?.[spec.field];
|
|
366
|
+
return typeof own === "number" && Number.isInteger(own) && own >= 1 ? own : spec.max;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Count `claims`' attempts against `limit`. */
|
|
370
|
+
export function attemptsOf(claims: readonly LeaseClaim[], limit: number | null): WorkAttempts {
|
|
371
|
+
const failed = claims.filter((c) => c.attempt).length;
|
|
372
|
+
return { failed, limit, remaining: limit === null ? null : Math.max(0, limit - failed), exhausted: limit !== null && failed >= limit };
|
|
373
|
+
}
|
|
374
|
+
|
|
314
375
|
/**
|
|
315
376
|
* Read work item `id`'s lease history (#2785): every claim, renew and release
|
|
316
377
|
* on `_leases/<id>.jsonl` in the ledger of the member owning the work kind,
|
|
@@ -322,12 +383,13 @@ export async function workHistory(req: { id: string; cwd: string; kind?: string
|
|
|
322
383
|
try {
|
|
323
384
|
if (!WORK_ITEM_ID_PATTERN.test(req.id) || req.id.includes("..")) throw new WorkError("work-item-unknown", `${JSON.stringify(req.id)} is not a work item id`);
|
|
324
385
|
if (!gitRoot(req.cwd)) throw new WorkError("not-a-git-repository", "a work lease's history is on the chant/lifecycle branch, and this directory is not in a git repository");
|
|
325
|
-
const { loaded, root } = await findWorkItem(req.id, req.cwd, req.kind);
|
|
386
|
+
const { loaded, root, record } = await findWorkItem(req.id, req.cwd, req.kind);
|
|
326
387
|
const leaseCwd = dirname(loaded.file);
|
|
327
|
-
const { prefix } = await resolveMemberLedger(leaseCwd);
|
|
388
|
+
const { prefix, members } = await resolveMemberLedger(leaseCwd);
|
|
328
389
|
const { records: events, malformed } = await readLeaseHistory(req.id, { cwd: leaseCwd });
|
|
329
390
|
const live = (await listWorkLeases({ cwd: leaseCwd, memberPrefix: prefix })).find((l) => l.item === req.id) ?? null;
|
|
330
|
-
const
|
|
391
|
+
const kept = await listKeptAttempts(req.id, { cwd: leaseCwd, members });
|
|
392
|
+
const claims = claimsOf(events, live, kept);
|
|
331
393
|
const count = (end: ClaimEnd) => claims.filter((c) => c.ended === end).length;
|
|
332
394
|
const outcomes: Record<string, number> = {};
|
|
333
395
|
for (const c of claims) if (c.release?.outcome) outcomes[c.release.outcome] = (outcomes[c.release.outcome] ?? 0) + 1;
|
|
@@ -342,6 +404,8 @@ export async function workHistory(req: { id: string; cwd: string; kind?: string
|
|
|
342
404
|
events,
|
|
343
405
|
malformed,
|
|
344
406
|
summary: { claims: claims.length, released: count("released"), held: count("held"), expired: count("expired"), lost: count("lost"), outcomes },
|
|
407
|
+
attempts: attemptsOf(claims, attemptLimit(loaded.kind, record.data)),
|
|
408
|
+
kept,
|
|
345
409
|
};
|
|
346
410
|
} catch (err) {
|
|
347
411
|
if (err instanceof WorkError) return { ...head, error: { code: err.code as WorkHistoryErrorCode, message: err.message } };
|
|
@@ -357,10 +421,73 @@ export function formatWorkHistory(doc: Extract<WorkHistoryDocument, { claims: un
|
|
|
357
421
|
lines.push(` ${c.acquiredAt} ${c.holder} token ${c.token} ${c.renewals} renewal${c.renewals === 1 ? "" : "s"} ${how}`);
|
|
358
422
|
}
|
|
359
423
|
if (doc.claims.length === 0) lines.push(" never claimed");
|
|
424
|
+
const a = doc.attempts;
|
|
425
|
+
if (a.limit !== null) lines.push(` ${a.failed} of ${a.limit} attempt${a.limit === 1 ? "" : "s"} used${a.exhausted ? "; left to people" : ""}`);
|
|
426
|
+
else if (a.failed > 0) lines.push(` ${a.failed} attempt${a.failed === 1 ? "" : "s"} counted; the kind declares no limit`);
|
|
427
|
+
for (const k of doc.kept) lines.push(` kept: ${k.ref} (${k.commit.slice(0, 12)})`);
|
|
360
428
|
if (doc.malformed > 0) lines.push(` ${doc.malformed} malformed line${doc.malformed === 1 ? "" : "s"} left out`);
|
|
361
429
|
return lines.join("\n");
|
|
362
430
|
}
|
|
363
431
|
|
|
432
|
+
/**
|
|
433
|
+
* `chant workspace work evidence <id> --holder <name> --token <token> --from
|
|
434
|
+
* <file|->` (#3159): the `workEvidence` activity (#2772) as a command, so a
|
|
435
|
+
* writer that is not an Op, such as hud, attaches evidence through chant under
|
|
436
|
+
* the lease it holds. `--from` gives the entry as JSON: criterion, result,
|
|
437
|
+
* title, a url or a path, and optionally as_of. It always prints the
|
|
438
|
+
* work-evidence document; exit 0 when the entry was appended, 1 otherwise.
|
|
439
|
+
*/
|
|
440
|
+
async function runWorkEvidence(ctx: CommandContext): Promise<number> {
|
|
441
|
+
const { args } = ctx;
|
|
442
|
+
const { attachWorkEvidence, WORK_EVIDENCE_CONTRACT_VERSION, WORK_EVIDENCE_OUTPUT_SCHEMA_ID } = await import("./work-evidence");
|
|
443
|
+
const print = (doc: unknown, code: number): number => {
|
|
444
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
445
|
+
return code;
|
|
446
|
+
};
|
|
447
|
+
const fail = (message: string): number =>
|
|
448
|
+
print({ $schema: WORK_EVIDENCE_OUTPUT_SCHEMA_ID, contract: WORK_EVIDENCE_CONTRACT_VERSION, error: { code: "write-usage-invalid", message: `${message}\n${USAGE}` } }, 1);
|
|
449
|
+
const id = args.extraPositional2;
|
|
450
|
+
if (!id) return fail("evidence needs a work item id");
|
|
451
|
+
if (!args.holder) return fail("evidence needs --holder <name>: the lease's holder");
|
|
452
|
+
if (!args.token) return fail("evidence needs --token <token>: the lease's fencing token, as its claim printed it");
|
|
453
|
+
if (args.migrateFrom === undefined) return fail("evidence needs --from <file|->: the entry as JSON, with criterion, result, title and a url or a path");
|
|
454
|
+
for (const [flag, v] of [["--ttl", args.ttl], ["--outcome", args.outcome], ["--note", args.note]] as const) {
|
|
455
|
+
if (v !== undefined) return fail(`evidence takes no ${flag}`);
|
|
456
|
+
}
|
|
457
|
+
let fields: Record<string, unknown>;
|
|
458
|
+
try {
|
|
459
|
+
const { readFileSync } = await import("node:fs");
|
|
460
|
+
const { resolve } = await import("node:path");
|
|
461
|
+
const text = readFileSync(args.migrateFrom === "-" ? 0 : resolve(process.cwd(), args.migrateFrom), "utf-8");
|
|
462
|
+
const parsed: unknown = JSON.parse(text);
|
|
463
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("the entry is not a JSON object");
|
|
464
|
+
fields = parsed as Record<string, unknown>;
|
|
465
|
+
} catch (err) {
|
|
466
|
+
return print(
|
|
467
|
+
{ $schema: WORK_EVIDENCE_OUTPUT_SCHEMA_ID, contract: WORK_EVIDENCE_CONTRACT_VERSION, error: { code: "write-input-invalid", message: `--from ${args.migrateFrom} could not be read: ${err instanceof Error ? err.message : String(err)}` } },
|
|
468
|
+
1,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
const known = ["criterion", "result", "title", "url", "path", "as_of"];
|
|
472
|
+
const unknown = Object.keys(fields).filter((k) => !known.includes(k));
|
|
473
|
+
if (unknown.length > 0) return fail(`the entry takes ${known.join(", ")}, not ${unknown.join(", ")}`);
|
|
474
|
+
const str = (k: string): string | undefined => (typeof fields[k] === "string" ? (fields[k] as string) : undefined);
|
|
475
|
+
const doc = await attachWorkEvidence({
|
|
476
|
+
cwd: process.cwd(),
|
|
477
|
+
item: id,
|
|
478
|
+
kind: args.kind,
|
|
479
|
+
holder: args.holder,
|
|
480
|
+
token: args.token,
|
|
481
|
+
criterion: str("criterion") ?? "",
|
|
482
|
+
result: fields.result as never,
|
|
483
|
+
title: str("title") ?? "",
|
|
484
|
+
url: str("url"),
|
|
485
|
+
path: str("path"),
|
|
486
|
+
asOf: str("as_of"),
|
|
487
|
+
});
|
|
488
|
+
return print(doc, "error" in doc ? 1 : 0);
|
|
489
|
+
}
|
|
490
|
+
|
|
364
491
|
async function runWorkHistory(ctx: CommandContext): Promise<number> {
|
|
365
492
|
const { args } = ctx;
|
|
366
493
|
const id = args.extraPositional2;
|
|
@@ -385,13 +512,14 @@ export async function runWorkspaceWork(ctx: CommandContext): Promise<number> {
|
|
|
385
512
|
const { args } = ctx;
|
|
386
513
|
const verb = args.extraPositional;
|
|
387
514
|
if (verb === "history") return runWorkHistory(ctx);
|
|
515
|
+
if (verb === "evidence") return runWorkEvidence(ctx);
|
|
388
516
|
const fail = (message: string): number => {
|
|
389
517
|
if (args.json) console.log(JSON.stringify({ $schema: WORK_LEASE_OUTPUT_SCHEMA_ID, contract: WORK_LEASE_CONTRACT_VERSION, error: { code: "write-usage-invalid", message } }, null, 2));
|
|
390
518
|
else console.error(formatError({ message, hint: USAGE }));
|
|
391
519
|
return 1;
|
|
392
520
|
};
|
|
393
521
|
if (verb !== "claim" && verb !== "renew" && verb !== "release") {
|
|
394
|
-
return fail(verb ? `chant workspace work takes claim, renew, release or
|
|
522
|
+
return fail(verb ? `chant workspace work takes claim, renew, release, history or evidence, not ${verb}` : "chant workspace work needs claim, renew, release, history or evidence");
|
|
395
523
|
}
|
|
396
524
|
const id = args.extraPositional2;
|
|
397
525
|
if (!id) return fail(`${verb} needs a work item id`);
|
|
@@ -182,9 +182,14 @@
|
|
|
182
182
|
"amend-supersede-instead",
|
|
183
183
|
"record-sign-failed",
|
|
184
184
|
"ratify-quorum-not-met",
|
|
185
|
+
"record-conflict",
|
|
186
|
+
"write-lock-timeout",
|
|
187
|
+
"write-lock-not-held",
|
|
185
188
|
"write-scope-member",
|
|
186
189
|
"write-scope-kind",
|
|
190
|
+
"write-scope-class-unknown",
|
|
187
191
|
"agent-unknown",
|
|
192
|
+
"principal-unidentified",
|
|
188
193
|
"record-unparseable",
|
|
189
194
|
"record-schema-invalid",
|
|
190
195
|
"record-id-duplicate",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"outcome": {
|
|
67
67
|
"type": "string",
|
|
68
|
-
"description": "How the work ended, on a release
|
|
68
|
+
"description": "How the work ended, on a release: one of the closed list in work-lease.schema.json's $defs/outcome (#3147), done, not_done, abandoned, gated, waiting, dropped, redraft or ask. A line written before #3147 may hold other free text."
|
|
69
69
|
},
|
|
70
70
|
"note": {
|
|
71
71
|
"type": "string"
|
|
@@ -146,6 +146,17 @@
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
]
|
|
149
|
+
},
|
|
150
|
+
"attempt": {
|
|
151
|
+
"type": "boolean",
|
|
152
|
+
"description": "Added in contract 1 by #3147. Whether the claim counts toward the item's attempt limit: released not_done or abandoned, released with no outcome or with free text from before the outcomes were closed, or ended expired or lost. Never one that is held, and never one released done, gated, waiting, dropped, redraft or ask."
|
|
153
|
+
},
|
|
154
|
+
"kept": {
|
|
155
|
+
"type": [
|
|
156
|
+
"string",
|
|
157
|
+
"null"
|
|
158
|
+
],
|
|
159
|
+
"description": "Added in contract 1 by #3147. The ref keeping the claim's unfinished work, refs/chant/kept/[<member>/]<item>/<token>, written when a run that changes the checkout ended not_done; null when there is none."
|
|
149
160
|
}
|
|
150
161
|
}
|
|
151
162
|
},
|
|
@@ -300,6 +311,67 @@
|
|
|
300
311
|
"description": "How many released claims gave each outcome."
|
|
301
312
|
}
|
|
302
313
|
}
|
|
314
|
+
},
|
|
315
|
+
"attempts": {
|
|
316
|
+
"type": "object",
|
|
317
|
+
"description": "Added in contract 1 by #3147. The item's attempts against its limit. limit is the item's own field named by the kind's work.attempts.field, else the kind's work.attempts.max, else null. A runner leaves an exhausted item to people.",
|
|
318
|
+
"required": [
|
|
319
|
+
"failed",
|
|
320
|
+
"limit",
|
|
321
|
+
"remaining",
|
|
322
|
+
"exhausted"
|
|
323
|
+
],
|
|
324
|
+
"properties": {
|
|
325
|
+
"failed": {
|
|
326
|
+
"type": "integer",
|
|
327
|
+
"minimum": 0,
|
|
328
|
+
"description": "The claims whose attempt is true."
|
|
329
|
+
},
|
|
330
|
+
"limit": {
|
|
331
|
+
"type": [
|
|
332
|
+
"integer",
|
|
333
|
+
"null"
|
|
334
|
+
],
|
|
335
|
+
"minimum": 1
|
|
336
|
+
},
|
|
337
|
+
"remaining": {
|
|
338
|
+
"type": [
|
|
339
|
+
"integer",
|
|
340
|
+
"null"
|
|
341
|
+
],
|
|
342
|
+
"minimum": 0,
|
|
343
|
+
"description": "limit minus failed, never below 0; null without a limit."
|
|
344
|
+
},
|
|
345
|
+
"exhausted": {
|
|
346
|
+
"type": "boolean",
|
|
347
|
+
"description": "True once failed reaches the limit; false without one."
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
"kept": {
|
|
352
|
+
"type": "array",
|
|
353
|
+
"description": "Added in contract 1 by #3147. Every kept attempt of the item, from the local refs under refs/chant/kept/[<member>/]<item>/, sorted by ref.",
|
|
354
|
+
"items": {
|
|
355
|
+
"type": "object",
|
|
356
|
+
"required": [
|
|
357
|
+
"token",
|
|
358
|
+
"ref",
|
|
359
|
+
"commit"
|
|
360
|
+
],
|
|
361
|
+
"properties": {
|
|
362
|
+
"token": {
|
|
363
|
+
"type": "string",
|
|
364
|
+
"description": "The lease token the attempt ran under."
|
|
365
|
+
},
|
|
366
|
+
"ref": {
|
|
367
|
+
"type": "string"
|
|
368
|
+
},
|
|
369
|
+
"commit": {
|
|
370
|
+
"type": "string",
|
|
371
|
+
"description": "The commit the ref points at."
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
303
375
|
}
|
|
304
376
|
}
|
|
305
377
|
},
|
|
@@ -9,14 +9,14 @@ import { join } from "node:path";
|
|
|
9
9
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
10
10
|
import { cleanScratch, contract, git, REPO, repo } from "./__fixtures__/contract-repo";
|
|
11
11
|
import { claimWorkLease, releaseWorkLease, renewWorkLease, type LeaseHistoryRecord } from "../lifecycle/work-lease";
|
|
12
|
-
import { claimsOf, formatWorkHistory, workHistory, type WorkHistoryDocument } from "./work-cli";
|
|
12
|
+
import { claimsOf, formatWorkHistory, workHistory, workLease, type WorkHistoryDocument } from "./work-cli";
|
|
13
13
|
import historySchema from "./work-history.schema.json";
|
|
14
14
|
|
|
15
15
|
const REF = join(REPO, "reference-workspace");
|
|
16
16
|
const { expectValid } = contract(historySchema);
|
|
17
17
|
|
|
18
|
-
function work(id: string): string {
|
|
19
|
-
const data = { schema: 1, id, title: `Work ${id}`, state: "open", implements: [], needs: [], constrains: ["path:app/server.mjs"], evidence: [], opened_on: "2026-09-25", source: { kind: "workspace", member: "app" }, supersedes: [] };
|
|
18
|
+
function work(id: string, extra: Record<string, unknown> = {}): string {
|
|
19
|
+
const data = { schema: 1, id, title: `Work ${id}`, state: "open", implements: [], needs: [], constrains: ["path:app/server.mjs"], evidence: [], opened_on: "2026-09-25", source: { kind: "workspace", member: "app" }, supersedes: [], ...extra };
|
|
20
20
|
return `---\n${JSON.stringify(data, null, 2)}\n---\n\n# ${id}\n`;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -46,6 +46,7 @@ beforeAll(() => {
|
|
|
46
46
|
"design/work/work.schema.json": readFileSync(join(REF, "work", "work.schema.json"), "utf-8"),
|
|
47
47
|
"design/work/W-001-one.md": work("W-001"),
|
|
48
48
|
"design/work/W-002-two.md": work("W-002"),
|
|
49
|
+
"design/work/W-004-four.md": work("W-004", { max_attempts: 2 }),
|
|
49
50
|
});
|
|
50
51
|
git(root, "config", "user.name", "History Test");
|
|
51
52
|
git(root, "config", "user.email", "history@example.com");
|
|
@@ -88,6 +89,10 @@ describe("workspace work history (#2785)", () => {
|
|
|
88
89
|
]);
|
|
89
90
|
expect(doc.events.map((e) => e.event)).toEqual(["claim", "renew", "release", "claim", "claim"]);
|
|
90
91
|
expect(doc.summary).toEqual({ claims: 3, released: 1, held: 0, expired: 1, lost: 1, outcomes: { not_done: 1 } });
|
|
92
|
+
// Each of the three counts as an attempt (#3147): not_done, lost and expired, against the kind's default of 3.
|
|
93
|
+
expect(doc.claims.map((c) => c.attempt)).toEqual([true, true, true]);
|
|
94
|
+
expect(doc.attempts).toEqual({ failed: 3, limit: 3, remaining: 0, exhausted: true });
|
|
95
|
+
expect(formatWorkHistory(doc)).toContain("3 of 3 attempts used; left to people");
|
|
91
96
|
// The history file is where git would find it, under the member's prefix.
|
|
92
97
|
expect(git(root, "show", `chant/lifecycle:${doc.ledger.path}`).split("\n")).toHaveLength(5);
|
|
93
98
|
expect(formatWorkHistory(doc)).toContain("released not_done by steward/dispatch@1");
|
|
@@ -107,6 +112,37 @@ describe("workspace work history (#2785)", () => {
|
|
|
107
112
|
expect(doc.claims.map((c) => c.ended)).toEqual(["released", "held"]);
|
|
108
113
|
expect(doc.lease).toMatchObject({ holder: "worker-b", token: live.lease.token, state: "active" });
|
|
109
114
|
expect(doc.summary.outcomes).toEqual({ done: 1 });
|
|
115
|
+
expect(doc.attempts).toEqual({ failed: 0, limit: 3, remaining: 3, exhausted: false });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("outcomes that built nothing don't count as attempts, the item's max_attempts overrides the kind's, and kept attempts are listed (#3147)", async () => {
|
|
119
|
+
const now = () => new Date();
|
|
120
|
+
const tokens: string[] = [];
|
|
121
|
+
for (const outcome of ["dropped", "redraft", "ask", "waiting", "gated", "not_done"]) {
|
|
122
|
+
const c = await claimWorkLease("W-004", "worker-a", { cwd: kindDir, now });
|
|
123
|
+
if (!c.ok) throw new Error(c.message);
|
|
124
|
+
tokens.push(c.lease.token);
|
|
125
|
+
await releaseWorkLease("W-004", "worker-a", { cwd: kindDir, now, token: c.lease.token, outcome });
|
|
126
|
+
}
|
|
127
|
+
// The not_done attempt's work, kept the way a run that changes the checkout keeps it.
|
|
128
|
+
const kept = `refs/chant/kept/design/W-004/${tokens[5]}`;
|
|
129
|
+
git(root, "update-ref", kept, "HEAD");
|
|
130
|
+
|
|
131
|
+
const doc = await workHistory({ id: "W-004", cwd: root });
|
|
132
|
+
expectValid(doc);
|
|
133
|
+
if ("error" in doc) throw new Error(doc.error.message);
|
|
134
|
+
expect(doc.claims.map((c) => c.attempt)).toEqual([false, false, false, false, false, true]);
|
|
135
|
+
expect(doc.attempts).toEqual({ failed: 1, limit: 2, remaining: 1, exhausted: false });
|
|
136
|
+
expect(doc.claims.map((c) => c.kept)).toEqual([null, null, null, null, null, kept]);
|
|
137
|
+
expect(doc.kept).toEqual([{ token: tokens[5], ref: kept, commit: git(root, "rev-parse", "HEAD").trim() }]);
|
|
138
|
+
expect(formatWorkHistory(doc)).toContain(`kept: ${kept}`);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("a release outside the closed list of outcomes is refused (#3147)", async () => {
|
|
142
|
+
await expect(releaseWorkLease("W-002", "worker-b", { cwd: kindDir, outcome: "skipped" })).rejects.toThrow(/not a work lease outcome/);
|
|
143
|
+
const doc = await workLease({ verb: "release", id: "W-002", holder: "worker-b", cwd: root, outcome: "skipped" });
|
|
144
|
+
expect(doc).toMatchObject({ error: { code: "write-usage-invalid" } });
|
|
145
|
+
expect((doc as { error: { message: string } }).error.message).toMatch(/done, not_done, abandoned, gated, waiting, dropped, redraft, ask/);
|
|
110
146
|
});
|
|
111
147
|
|
|
112
148
|
test("an item never claimed has no claims; an unknown item is an error", async () => {
|
|
@@ -142,12 +178,19 @@ describe("claimsOf", () => {
|
|
|
142
178
|
});
|
|
143
179
|
|
|
144
180
|
test("a release by someone closing out an expired lease keeps the holder and records who released it", () => {
|
|
145
|
-
const claims = claimsOf([e("claim", "a"), e("release", "a", { by: "janitor", outcome: "
|
|
181
|
+
const claims = claimsOf([e("claim", "a"), e("release", "a", { by: "janitor", outcome: "abandoned" })], null);
|
|
146
182
|
expect(claims).toEqual([
|
|
147
|
-
{ token: "a", holder: "h-a", acquiredAt: "2026-09-25T00:00:00.000Z", expiresAt: "2026-09-25T00:10:00.000Z", renewals: 0, ended: "released", release: { by: "janitor", at: "2026-09-25T00:00:00.000Z", outcome: "
|
|
183
|
+
{ token: "a", holder: "h-a", acquiredAt: "2026-09-25T00:00:00.000Z", expiresAt: "2026-09-25T00:10:00.000Z", renewals: 0, ended: "released", release: { by: "janitor", at: "2026-09-25T00:00:00.000Z", outcome: "abandoned", note: null }, attempt: true, kept: null },
|
|
148
184
|
]);
|
|
149
185
|
});
|
|
150
186
|
|
|
187
|
+
test("a release with free text from before the outcomes were closed counts as an attempt, and one with no outcome too", () => {
|
|
188
|
+
expect(claimsOf([e("claim", "a"), e("release", "a", { outcome: "skipped" })], null)[0].attempt).toBe(true);
|
|
189
|
+
expect(claimsOf([e("claim", "a"), e("release", "a")], null)[0].attempt).toBe(true);
|
|
190
|
+
expect(claimsOf([e("claim", "a"), e("release", "a", { outcome: "done" })], null)[0].attempt).toBe(false);
|
|
191
|
+
expect(claimsOf([e("claim", "a")], { token: "a", state: "active" })[0].attempt).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
|
|
151
194
|
test("the live ref decides between held and expired for the newest claim", () => {
|
|
152
195
|
expect(claimsOf([e("claim", "a")], { token: "a", state: "active" })[0].ended).toBe("held");
|
|
153
196
|
expect(claimsOf([e("claim", "a")], { token: "a", state: "expired" })[0].ended).toBe("expired");
|