@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
|
@@ -19,12 +19,27 @@
|
|
|
19
19
|
* as well, after checking both files, so the two lists never differ.
|
|
20
20
|
* `records close` is in `records-close.ts`.
|
|
21
21
|
*
|
|
22
|
+
* Each write holds the working tree's write lock (`write-lock.ts`, #3173,
|
|
23
|
+
* ws-089) from its first read to its last write, so writes to one working
|
|
24
|
+
* tree never interleave. `amend`, `review` and `close` take `--expect
|
|
25
|
+
* <digest>`: the record's digest the caller last read. When the record has
|
|
26
|
+
* moved on since, the write is refused with record-conflict, naming the
|
|
27
|
+
* digest it has now and the last chant write of it, and the caller re-reads
|
|
28
|
+
* and tries again.
|
|
29
|
+
*
|
|
22
30
|
* `new --sign` and `amend --sign` seal the record's author (#2688), and
|
|
23
31
|
* `review --sign` seals a verdict (#2687): see `trust/seal.ts`. A record of
|
|
24
32
|
* a kind that declares `seal` gets its whole-file seal when `new` or `amend`
|
|
25
33
|
* writes it into a closed state (#2546, ws-063).
|
|
34
|
+
*
|
|
35
|
+
* `new` also writes a record of a content-addressed JSON kind (`format:
|
|
36
|
+
* "json"`, `idFrom: "sha256"`, ws-053), such as the reference workspace's
|
|
37
|
+
* evidence (ws-082): the fields as JSON, in a file named for the SHA-256 of
|
|
38
|
+
* its bytes. Such a record never changes, so amend, review and close refuse
|
|
39
|
+
* the kind.
|
|
26
40
|
*/
|
|
27
41
|
|
|
42
|
+
import { createHash } from "node:crypto";
|
|
28
43
|
import { readFileSync, statSync, writeFileSync } from "node:fs";
|
|
29
44
|
import { dirname, join, posix, relative, resolve } from "node:path";
|
|
30
45
|
import type { CommandContext } from "../cli/registry";
|
|
@@ -35,6 +50,7 @@ import {
|
|
|
35
50
|
loadRecordKind,
|
|
36
51
|
parseFrontMatter,
|
|
37
52
|
readRecords,
|
|
53
|
+
readSessionSubjects,
|
|
38
54
|
RECORD_REASON_CODES,
|
|
39
55
|
RecordReadError,
|
|
40
56
|
RECORD_SEAL_FIELD,
|
|
@@ -50,8 +66,10 @@ import { policyAtBase, resolveBase } from "./trust/provenance";
|
|
|
50
66
|
import { WorkspaceReadError } from "./declaration";
|
|
51
67
|
import { findSessionKinds, headCommit, sessionKindsFor } from "./session-kinds";
|
|
52
68
|
import { workingTree } from "./tree";
|
|
53
|
-
import { AGENT_ENV, refuseRecordWrite, WRITE_SCOPE_CODES, WriteScopeError } from "./write-scope";
|
|
69
|
+
import { AGENT_ENV, refuseRecordWrite, WRITE_SCOPE_CODES, WriteScopeError, type ScopeSource } from "./write-scope";
|
|
70
|
+
import { IDENTITY_CODES, IdentityError, refuseUnidentified } from "./identity";
|
|
54
71
|
import type { WriteVerb } from "./declaration";
|
|
72
|
+
import { lastWriteReader, noteWrites, withWriteLock, writeFileAtomic, WriteLockError, WRITE_LOCK_CODES, type LastWrite, type WriteLockWho } from "./write-lock";
|
|
55
73
|
|
|
56
74
|
// ── Contract ─────────────────────────────────────────────────────────────────
|
|
57
75
|
|
|
@@ -77,7 +95,9 @@ export const NEW_ERROR_CODES = [
|
|
|
77
95
|
"source-harvest-not-proposed",
|
|
78
96
|
"record-state-not-initial",
|
|
79
97
|
"ratify-quorum-not-met",
|
|
98
|
+
...WRITE_LOCK_CODES,
|
|
80
99
|
...WRITE_SCOPE_CODES,
|
|
100
|
+
...IDENTITY_CODES,
|
|
81
101
|
...RECORD_REASON_CODES,
|
|
82
102
|
] as const satisfies readonly ReasonCode[];
|
|
83
103
|
|
|
@@ -92,7 +112,10 @@ export const AMEND_ERROR_CODES = [
|
|
|
92
112
|
"amend-supersede-instead",
|
|
93
113
|
"record-sign-failed",
|
|
94
114
|
"ratify-quorum-not-met",
|
|
115
|
+
"record-conflict",
|
|
116
|
+
...WRITE_LOCK_CODES,
|
|
95
117
|
...WRITE_SCOPE_CODES,
|
|
118
|
+
...IDENTITY_CODES,
|
|
96
119
|
...RECORD_REASON_CODES,
|
|
97
120
|
] as const satisfies readonly ReasonCode[];
|
|
98
121
|
|
|
@@ -107,7 +130,10 @@ export const REVIEW_ERROR_CODES = [
|
|
|
107
130
|
"review-sign-failed",
|
|
108
131
|
"session-unknown",
|
|
109
132
|
"session-not-open",
|
|
133
|
+
"record-conflict",
|
|
134
|
+
...WRITE_LOCK_CODES,
|
|
110
135
|
...WRITE_SCOPE_CODES,
|
|
136
|
+
...IDENTITY_CODES,
|
|
111
137
|
...RECORD_REASON_CODES,
|
|
112
138
|
] as const satisfies readonly ReasonCode[];
|
|
113
139
|
|
|
@@ -123,12 +149,28 @@ export class RecordWriteError extends Error {
|
|
|
123
149
|
constructor(
|
|
124
150
|
readonly code: WriteErrorCode,
|
|
125
151
|
message: string,
|
|
152
|
+
/** With record-conflict: the record as it is now. */
|
|
153
|
+
readonly conflict?: RecordConflict,
|
|
126
154
|
) {
|
|
127
155
|
super(message);
|
|
128
156
|
this.name = "RecordWriteError";
|
|
129
157
|
}
|
|
130
158
|
}
|
|
131
159
|
|
|
160
|
+
/**
|
|
161
|
+
* What a record-conflict refusal says about the record (#3173): the digest
|
|
162
|
+
* the caller expected, the one it has now, and the last chant write of it
|
|
163
|
+
* when the journal knows it. The caller re-reads the record and writes again
|
|
164
|
+
* with `--expect` set to `digest`.
|
|
165
|
+
*/
|
|
166
|
+
export interface RecordConflict {
|
|
167
|
+
id: string;
|
|
168
|
+
path: string;
|
|
169
|
+
expected: string;
|
|
170
|
+
digest: string;
|
|
171
|
+
lastWrite: LastWrite | null;
|
|
172
|
+
}
|
|
173
|
+
|
|
132
174
|
export interface KindView {
|
|
133
175
|
name: string;
|
|
134
176
|
schema: string;
|
|
@@ -147,6 +189,12 @@ export interface WriteResult {
|
|
|
147
189
|
dryRun: boolean;
|
|
148
190
|
/** The written record's warnings, as `records` would report them. */
|
|
149
191
|
warnings: RecordWarning[];
|
|
192
|
+
/**
|
|
193
|
+
* The record's digest after the write, as `records --json` reports it
|
|
194
|
+
* (#3173): what the caller passes as `--expect` to its next write of the
|
|
195
|
+
* record.
|
|
196
|
+
*/
|
|
197
|
+
digest: string;
|
|
150
198
|
/** With --dry-run, the whole text the command would write. */
|
|
151
199
|
text?: string;
|
|
152
200
|
}
|
|
@@ -155,6 +203,8 @@ export interface WriteFailure<C> {
|
|
|
155
203
|
$schema: string;
|
|
156
204
|
contract: number;
|
|
157
205
|
error: { code: C; message: string };
|
|
206
|
+
/** With record-conflict (#3173): the record as it is now. */
|
|
207
|
+
conflict?: RecordConflict;
|
|
158
208
|
}
|
|
159
209
|
|
|
160
210
|
/** A record's author seal as `new` and `amend` write it with `--sign` (#2688). */
|
|
@@ -335,15 +385,26 @@ export interface Opened {
|
|
|
335
385
|
dirRel: string;
|
|
336
386
|
}
|
|
337
387
|
|
|
338
|
-
|
|
388
|
+
/** A kind `records new` writes as one JSON file named for the SHA-256 of its bytes (ws-053, ws-082). */
|
|
389
|
+
export function isContentAddressed(kind: LoadedRecordKind["kind"]): boolean {
|
|
390
|
+
return kind.format === "json" && kind.idFrom === "sha256";
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export async function open(kind: string, cwd: string, opts: { contentAddressed?: boolean } = {}): Promise<Opened> {
|
|
339
394
|
const real = realpathOr(cwd);
|
|
340
395
|
const root = gitRoot(real) ?? real;
|
|
341
396
|
const loaded = await loadRecordKind(kind, real);
|
|
342
|
-
// The writers write Markdown front matter with an id field.
|
|
343
|
-
// content-addressed kind (ws-
|
|
344
|
-
|
|
397
|
+
// The writers write Markdown front matter with an id field. `records new`
|
|
398
|
+
// also writes a content-addressed JSON kind (ws-082), whose record never
|
|
399
|
+
// changes once written, so amend, review and close never open one. A JSON
|
|
400
|
+
// kind with an id field is read by records, and written by its own tool.
|
|
401
|
+
const writable = (loaded.kind.format === "markdown-front-matter" && loaded.kind.idField !== undefined) || (!!opts.contentAddressed && isContentAddressed(loaded.kind));
|
|
402
|
+
if (!writable) {
|
|
345
403
|
const what = loaded.kind.format !== "markdown-front-matter" ? `format ${loaded.kind.format}` : `ids from ${loaded.kind.idFrom}`;
|
|
346
|
-
|
|
404
|
+
const verbs = isContentAddressed(loaded.kind)
|
|
405
|
+
? "a content-addressed record never changes once records new writes it, so amend, review and close never write one"
|
|
406
|
+
: "records new, amend and review write only Markdown front matter records with an idField, and records new a JSON record named for the sha256 of its bytes";
|
|
407
|
+
throw new RecordWriteError("write-usage-invalid", `the ${loaded.kind.name} kind has ${what}: ${verbs}`);
|
|
347
408
|
}
|
|
348
409
|
const dirRel = relative(root, loaded.dir).split("\\").join("/") || ".";
|
|
349
410
|
return {
|
|
@@ -361,8 +422,24 @@ export async function open(kind: string, cwd: string): Promise<Opened> {
|
|
|
361
422
|
* written with `verb`, by the session `agent` names (`CHANT_AGENT`) or the
|
|
362
423
|
* principal `by` names. Throws a {@link WriteScopeError}.
|
|
363
424
|
*/
|
|
364
|
-
export function refuseOutOfScope(o: Opened, verb: WriteVerb, cwd: string, writer: { agent?: string; by?: string }):
|
|
365
|
-
refuseRecordWrite(cwd, { kindName: o.loaded.kind.name, kindFile: o.loaded.file, recordsDir: o.loaded.dir, verb, agent: writer.agent, principal: writer.by });
|
|
425
|
+
export function refuseOutOfScope(o: Opened, verb: WriteVerb, cwd: string, writer: { agent?: string; by?: string }): ScopeSource {
|
|
426
|
+
const source = refuseRecordWrite(cwd, { kindName: o.loaded.kind.name, kindFile: o.loaded.file, recordsDir: o.loaded.dir, verb, agent: writer.agent, principal: writer.by });
|
|
427
|
+
// #3163: under identity.attribution "identified" at base, --by names a forge identity or a signer.
|
|
428
|
+
if (writer.by !== undefined) refuseUnidentified(source, [writer.by], "--by", { agent: writer.agent });
|
|
429
|
+
return source;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Refuse author fields (the kind's reviews.decider and proposedBy fields)
|
|
434
|
+
* that name a person by a bare name, under identity.attribution
|
|
435
|
+
* "identified" at base (#3163). `flag` is where the fields came from.
|
|
436
|
+
*/
|
|
437
|
+
function refuseUnidentifiedAuthors(source: ScopeSource, kind: Opened["loaded"]["kind"], fields: Record<string, unknown>, flag: string, agent?: string): void {
|
|
438
|
+
const names = [kind.reviews?.decider, kind.proposedBy?.field]
|
|
439
|
+
.filter((f): f is string => f !== undefined)
|
|
440
|
+
.map((f) => fields[f])
|
|
441
|
+
.filter((v): v is string => typeof v === "string" && v.trim() !== "");
|
|
442
|
+
refuseUnidentified(source, names, `${flag} author`, { agent });
|
|
366
443
|
}
|
|
367
444
|
|
|
368
445
|
/**
|
|
@@ -372,11 +449,7 @@ export function refuseOutOfScope(o: Opened, verb: WriteVerb, cwd: string, writer
|
|
|
372
449
|
*/
|
|
373
450
|
export async function readAll(o: Opened, source: RecordSource): Promise<RecordEntry[]> {
|
|
374
451
|
const assets = workingTree(o.workspaceRoot === "." ? o.root : join(o.root, ...o.workspaceRoot.split("/")));
|
|
375
|
-
|
|
376
|
-
if (o.loaded.kind.session) {
|
|
377
|
-
const subjectKind = await loadRecordKind(resolve(dirname(o.loaded.file), o.loaded.kind.session.subjects.kind), o.root);
|
|
378
|
-
subjects = { records: (await readRecords(subjectKind, { root: o.root, source })).records, reviews: subjectKind.kind.reviews?.field ?? "reviews" };
|
|
379
|
-
}
|
|
452
|
+
const subjects = await readSessionSubjects(o.loaded, o.root, source);
|
|
380
453
|
return (await readRecords(o.loaded, { root: o.root, source, assets, workspaceRoot: o.workspaceRoot, ...(subjects ? { subjects } : {}) })).records;
|
|
381
454
|
}
|
|
382
455
|
|
|
@@ -450,6 +523,35 @@ async function refuseRatifyBelowQuorum(o: Opened, written: RecordEntry, id: stri
|
|
|
450
523
|
);
|
|
451
524
|
}
|
|
452
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Refuse a write to `target` when the caller expected another digest
|
|
528
|
+
* (#3173): someone wrote the record since the caller read it. Called holding
|
|
529
|
+
* the write lock, after the records are read, so the digest compared is the
|
|
530
|
+
* one the write would build on.
|
|
531
|
+
*/
|
|
532
|
+
export function refuseStale(o: Opened, target: RecordEntry, id: string, expect: string | undefined): void {
|
|
533
|
+
if (expect === undefined || expect === target.digest) return;
|
|
534
|
+
const lastWrite = lastWriteReader(o.root)(target.path, o.source.read(target.path));
|
|
535
|
+
const who = lastWrite ? ` It was last written by chant workspace ${lastWrite.verb}${lastWrite.by ? ` for ${lastWrite.by}` : ""}${lastWrite.agent ? ` in agent session ${lastWrite.agent}` : ""} at ${lastWrite.at}.` : "";
|
|
536
|
+
throw new RecordWriteError(
|
|
537
|
+
"record-conflict",
|
|
538
|
+
`${id} has changed since the digest given with --expect (${expect}): its digest is now ${target.digest}.${who} Read it again with chant workspace records --json, and write again with --expect ${target.digest} if the change still stands`,
|
|
539
|
+
{ id, path: target.path, expected: expect, digest: target.digest, lastWrite },
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/** Refuse a --expect that is not a digest, before anything is read. */
|
|
544
|
+
function refuseExpectShape(expect: string | undefined): void {
|
|
545
|
+
if (expect !== undefined && !/^[0-9a-f]{64}$/.test(expect)) {
|
|
546
|
+
throw new RecordWriteError("write-usage-invalid", `--expect takes a record's digest, 64 lowercase hex digits as records --json prints it, not ${JSON.stringify(expect)}`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/** Who a write names, for the lock's owner file and the journal. */
|
|
551
|
+
export function writeWho(verb: string, opts: { by?: string; agent?: string }): WriteLockWho {
|
|
552
|
+
return { verb, by: opts.by ?? null, agent: opts.agent ?? null };
|
|
553
|
+
}
|
|
554
|
+
|
|
453
555
|
export function findRecord(entries: RecordEntry[], id: string, kind: string): RecordEntry & { data: Record<string, unknown> } {
|
|
454
556
|
const hits = entries.filter((e) => e.id === id);
|
|
455
557
|
if (hits.length === 0) throw new RecordWriteError("record-not-found", `no ${kind} record has id ${id}`);
|
|
@@ -628,8 +730,9 @@ function today(): string {
|
|
|
628
730
|
}
|
|
629
731
|
|
|
630
732
|
export function failure<C>(schema: string, err: unknown): WriteFailure<C> {
|
|
631
|
-
if (err instanceof RecordWriteError || err instanceof RecordReadError || err instanceof WriteScopeError) {
|
|
632
|
-
|
|
733
|
+
if (err instanceof RecordWriteError || err instanceof RecordReadError || err instanceof WriteScopeError || err instanceof IdentityError || err instanceof WriteLockError) {
|
|
734
|
+
const conflict = err instanceof RecordWriteError ? err.conflict : undefined;
|
|
735
|
+
return { $schema: schema, contract: RECORDS_WRITE_CONTRACT_VERSION, error: { code: err.code as C, message: err.message }, ...(conflict ? { conflict } : {}) };
|
|
633
736
|
}
|
|
634
737
|
throw err;
|
|
635
738
|
}
|
|
@@ -766,18 +869,28 @@ function applyChannel(o: Opened, fields: Record<string, unknown>, opts: ChannelO
|
|
|
766
869
|
return out;
|
|
767
870
|
}
|
|
768
871
|
|
|
769
|
-
/** `records new`: write one new record from validated fields, sealed by its author with `sign`. */
|
|
872
|
+
/** `records new`: write one new record from validated fields, sealed by its author with `sign`. Holds the write lock (#3173). */
|
|
770
873
|
export async function newRecord(opts: NewRecordOptions & ChannelOptions): Promise<NewDocument> {
|
|
874
|
+
try {
|
|
875
|
+
return await withWriteLock(opts.cwd, writeWho("records new", opts), opts.dryRun, () => newRecordLocked(opts));
|
|
876
|
+
} catch (err) {
|
|
877
|
+
return failure<NewErrorCode>(RECORDS_NEW_SCHEMA_ID, err);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function newRecordLocked(opts: NewRecordOptions & ChannelOptions): Promise<NewDocument> {
|
|
771
882
|
try {
|
|
772
883
|
if (opts.prefix !== undefined && !/^[A-Za-z][A-Za-z0-9]*$/.test(opts.prefix)) {
|
|
773
884
|
throw new RecordWriteError("write-usage-invalid", `--prefix takes letters and digits, starting with a letter, not ${JSON.stringify(opts.prefix)}`);
|
|
774
885
|
}
|
|
775
|
-
const o = await open(opts.kind, opts.cwd);
|
|
776
|
-
refuseOutOfScope(o, "new", opts.cwd, opts);
|
|
886
|
+
const o = await open(opts.kind, opts.cwd, { contentAddressed: true });
|
|
887
|
+
const scope = refuseOutOfScope(o, "new", opts.cwd, opts);
|
|
777
888
|
const fields = applyChannel(o, parseFields(opts.fields, "--from"), opts, true, "--from");
|
|
778
889
|
const { kind, schema } = o.loaded;
|
|
890
|
+
refuseUnidentifiedAuthors(scope, kind, fields, "--from", opts.agent);
|
|
779
891
|
refuseSealField(o, fields, "--from");
|
|
780
892
|
refuseRevisionFields(kind, fields, {}, "--from");
|
|
893
|
+
if (isContentAddressed(kind)) return await newContentAddressed(o, fields, opts);
|
|
781
894
|
const idField = kind.idField!;
|
|
782
895
|
const before = await readAll(o, o.source);
|
|
783
896
|
const given = fields[idField];
|
|
@@ -809,7 +922,10 @@ export async function newRecord(opts: NewRecordOptions & ChannelOptions): Promis
|
|
|
809
922
|
const written = await validatedEntry(o, before, path, text);
|
|
810
923
|
await refuseRatifyBelowQuorum(o, written, id);
|
|
811
924
|
const warnings = written.warnings;
|
|
812
|
-
if (!opts.dryRun)
|
|
925
|
+
if (!opts.dryRun) {
|
|
926
|
+
writeFileSync(abs(o, path), text, { flag: "wx" });
|
|
927
|
+
noteWrites(o.root, [{ path, text }], writeWho("records new", opts));
|
|
928
|
+
}
|
|
813
929
|
return {
|
|
814
930
|
$schema: RECORDS_NEW_SCHEMA_ID,
|
|
815
931
|
contract: RECORDS_WRITE_CONTRACT_VERSION,
|
|
@@ -819,6 +935,7 @@ export async function newRecord(opts: NewRecordOptions & ChannelOptions): Promis
|
|
|
819
935
|
...(seal ? { seal } : {}),
|
|
820
936
|
dryRun: !!opts.dryRun,
|
|
821
937
|
warnings,
|
|
938
|
+
digest: written.digest,
|
|
822
939
|
...(opts.dryRun ? { text } : {}),
|
|
823
940
|
};
|
|
824
941
|
} catch (err) {
|
|
@@ -826,6 +943,43 @@ export async function newRecord(opts: NewRecordOptions & ChannelOptions): Promis
|
|
|
826
943
|
}
|
|
827
944
|
}
|
|
828
945
|
|
|
946
|
+
/**
|
|
947
|
+
* `records new` on a content-addressed JSON kind (ws-053, ws-082), such as
|
|
948
|
+
* the reference workspace's evidence: the fields, in the schema's order, as
|
|
949
|
+
* JSON with two-space indents and a final newline, in a file named for the
|
|
950
|
+
* SHA-256 of those bytes. The id is that hash, so the fields give no id, and
|
|
951
|
+
* the record never changes afterwards.
|
|
952
|
+
*/
|
|
953
|
+
async function newContentAddressed(o: Opened, fields: Record<string, unknown>, opts: NewRecordOptions): Promise<NewDocument> {
|
|
954
|
+
const { kind, schema } = o.loaded;
|
|
955
|
+
if (opts.prefix !== undefined) throw new RecordWriteError("write-usage-invalid", `the ${kind.name} kind's ids are the sha256 of each record's bytes, so --prefix allocates nothing`);
|
|
956
|
+
if (opts.sign !== undefined) throw new RecordWriteError("write-usage-invalid", `the ${kind.name} kind names no author to seal: its records are named for the sha256 of their bytes`);
|
|
957
|
+
const data = pick(fields, schemaOrder(fields, schema));
|
|
958
|
+
const text = `${JSON.stringify(data, null, 2)}\n`;
|
|
959
|
+
const id = createHash("sha256").update(text, "utf-8").digest("hex");
|
|
960
|
+
const name = `${id}.json`;
|
|
961
|
+
if (!new RegExp(kind.location.match).test(name)) throw new RecordWriteError("record-path-unmatched", `the kind's location.match ${kind.location.match} does not match ${name}`);
|
|
962
|
+
const path = o.dirRel === "." ? name : `${o.dirRel}/${name}`;
|
|
963
|
+
if (o.source.list(o.dirRel)?.includes(name)) throw new RecordWriteError("record-id-taken", `${path} already exists, with the same bytes: the record is already written`);
|
|
964
|
+
const before = await readAll(o, o.source);
|
|
965
|
+
const written = await validatedEntry(o, before, path, text);
|
|
966
|
+
if (!opts.dryRun) {
|
|
967
|
+
writeFileSync(abs(o, path), text, { flag: "wx" });
|
|
968
|
+
noteWrites(o.root, [{ path, text }], writeWho("records new", opts));
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
$schema: RECORDS_NEW_SCHEMA_ID,
|
|
972
|
+
contract: RECORDS_WRITE_CONTRACT_VERSION,
|
|
973
|
+
kind: o.view,
|
|
974
|
+
path,
|
|
975
|
+
id,
|
|
976
|
+
dryRun: !!opts.dryRun,
|
|
977
|
+
warnings: written.warnings,
|
|
978
|
+
digest: written.digest,
|
|
979
|
+
...(opts.dryRun ? { text } : {}),
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
829
983
|
// ── records amend ────────────────────────────────────────────────────────────
|
|
830
984
|
|
|
831
985
|
export interface AmendRecordOptions {
|
|
@@ -839,6 +993,8 @@ export interface AmendRecordOptions {
|
|
|
839
993
|
sign?: string | true;
|
|
840
994
|
/** The agent session the write is made in (#2548). */
|
|
841
995
|
agent?: string;
|
|
996
|
+
/** The record's digest the caller last read (#3173): the write is refused with record-conflict when the record has another. */
|
|
997
|
+
expect?: string;
|
|
842
998
|
}
|
|
843
999
|
|
|
844
1000
|
/**
|
|
@@ -856,14 +1012,25 @@ export interface AmendRecordOptions {
|
|
|
856
1012
|
* `--sign` with nothing to change seals the record as it is.
|
|
857
1013
|
*/
|
|
858
1014
|
export async function amendRecord(opts: AmendRecordOptions & ChannelOptions): Promise<AmendDocument> {
|
|
1015
|
+
try {
|
|
1016
|
+
refuseExpectShape(opts.expect);
|
|
1017
|
+
return await withWriteLock(opts.cwd, writeWho("records amend", opts), opts.dryRun, () => amendRecordLocked(opts));
|
|
1018
|
+
} catch (err) {
|
|
1019
|
+
return failure<AmendErrorCode>(RECORDS_AMEND_SCHEMA_ID, err);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
async function amendRecordLocked(opts: AmendRecordOptions & ChannelOptions): Promise<AmendDocument> {
|
|
859
1024
|
try {
|
|
860
1025
|
const o = await open(opts.kind, opts.cwd);
|
|
861
|
-
refuseOutOfScope(o, "amend", opts.cwd, opts);
|
|
1026
|
+
const scope = refuseOutOfScope(o, "amend", opts.cwd, opts);
|
|
862
1027
|
const given = applyChannel(o, parseFields(opts.fields, "--set"), opts, false, "--set");
|
|
863
1028
|
const { kind } = o.loaded;
|
|
1029
|
+
refuseUnidentifiedAuthors(scope, kind, given, "--set", opts.agent);
|
|
864
1030
|
refuseSealField(o, given, "--set");
|
|
865
1031
|
const before = await readAll(o, o.source);
|
|
866
1032
|
const target = findRecord(before, opts.id, kind.name);
|
|
1033
|
+
refuseStale(o, target, opts.id, opts.expect);
|
|
867
1034
|
const old = target.data;
|
|
868
1035
|
refuseRevisionFields(kind, given, old, "--set");
|
|
869
1036
|
const isClosed = target.state !== null && (kind.closedStates ?? []).includes(target.state);
|
|
@@ -929,12 +1096,17 @@ export async function amendRecord(opts: AmendRecordOptions & ChannelOptions): Pr
|
|
|
929
1096
|
if (stableJson(old[kind.seal.field]) !== stableJson(closedSeal.data[kind.seal.field])) changed.push(kind.seal.field);
|
|
930
1097
|
}
|
|
931
1098
|
let warnings = target.warnings;
|
|
1099
|
+
let digest = target.digest;
|
|
932
1100
|
if (changed.length > 0) {
|
|
933
1101
|
const written = await validatedEntry(o, before, target.path, text);
|
|
934
1102
|
if (kind.stateField !== undefined && changed.includes(kind.stateField)) await refuseRatifyBelowQuorum(o, written, opts.id);
|
|
935
1103
|
warnings = written.warnings;
|
|
1104
|
+
digest = written.digest;
|
|
1105
|
+
}
|
|
1106
|
+
if (!opts.dryRun && changed.length > 0) {
|
|
1107
|
+
writeFileAtomic(abs(o, target.path), text);
|
|
1108
|
+
noteWrites(o.root, [{ path: target.path, text }], writeWho("records amend", opts));
|
|
936
1109
|
}
|
|
937
|
-
if (!opts.dryRun && changed.length > 0) writeFileSync(abs(o, target.path), text);
|
|
938
1110
|
return {
|
|
939
1111
|
$schema: RECORDS_AMEND_SCHEMA_ID,
|
|
940
1112
|
contract: RECORDS_WRITE_CONTRACT_VERSION,
|
|
@@ -946,6 +1118,7 @@ export async function amendRecord(opts: AmendRecordOptions & ChannelOptions): Pr
|
|
|
946
1118
|
...(sealDropped ? { sealDropped } : {}),
|
|
947
1119
|
dryRun: !!opts.dryRun,
|
|
948
1120
|
warnings,
|
|
1121
|
+
digest,
|
|
949
1122
|
...(opts.dryRun ? { text } : {}),
|
|
950
1123
|
};
|
|
951
1124
|
} catch (err) {
|
|
@@ -975,6 +1148,8 @@ export interface ReviewRecordOptions {
|
|
|
975
1148
|
sign?: string | true;
|
|
976
1149
|
/** The agent session the write is made in (#2548). */
|
|
977
1150
|
agent?: string;
|
|
1151
|
+
/** The record's digest the reviewer judged (#3173): the verdict is refused with record-conflict when the record has moved on. */
|
|
1152
|
+
expect?: string;
|
|
978
1153
|
}
|
|
979
1154
|
|
|
980
1155
|
/**
|
|
@@ -984,6 +1159,15 @@ export interface ReviewRecordOptions {
|
|
|
984
1159
|
* id, the digest, the verdict, the reviewer and the date (`trust/seal.ts`).
|
|
985
1160
|
*/
|
|
986
1161
|
export async function reviewRecord(opts: ReviewRecordOptions): Promise<ReviewDocument> {
|
|
1162
|
+
try {
|
|
1163
|
+
refuseExpectShape(opts.expect);
|
|
1164
|
+
return await withWriteLock(opts.cwd, writeWho("records review", opts), opts.dryRun, () => reviewRecordLocked(opts));
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
return failure<ReviewErrorCode>(RECORDS_REVIEW_SCHEMA_ID, err);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
async function reviewRecordLocked(opts: ReviewRecordOptions): Promise<ReviewDocument> {
|
|
987
1171
|
try {
|
|
988
1172
|
if (!(VERDICTS as readonly string[]).includes(opts.verdict)) {
|
|
989
1173
|
throw new RecordWriteError("write-usage-invalid", `--verdict takes ${VERDICTS.join(", ")}, not ${JSON.stringify(opts.verdict)}`);
|
|
@@ -999,6 +1183,7 @@ export async function reviewRecord(opts: ReviewRecordOptions): Promise<ReviewDoc
|
|
|
999
1183
|
const field = kind.reviews.field;
|
|
1000
1184
|
const before = await readAll(o, o.source);
|
|
1001
1185
|
const target = findRecord(before, opts.id, kind.name);
|
|
1186
|
+
refuseStale(o, target, opts.id, opts.expect);
|
|
1002
1187
|
if (target.state !== null && (kind.closedStates ?? []).includes(target.state)) {
|
|
1003
1188
|
throw new RecordWriteError("record-closed", `${opts.id} is ${target.state}, a closed state, so it takes no more reviews`);
|
|
1004
1189
|
}
|
|
@@ -1025,7 +1210,8 @@ export async function reviewRecord(opts: ReviewRecordOptions): Promise<ReviewDoc
|
|
|
1025
1210
|
const list = [...reviews, review];
|
|
1026
1211
|
const text = replaceFields(current, { [field]: list }, { ...target.data, [field]: list });
|
|
1027
1212
|
if (text === undefined) throw new RecordWriteError("record-unparseable", `${target.path}: the ${field} block can't be rewritten in place without changing the rest of the file`);
|
|
1028
|
-
const
|
|
1213
|
+
const writtenEntry = await validatedEntry(o, before, target.path, text);
|
|
1214
|
+
const warnings = writtenEntry.warnings;
|
|
1029
1215
|
// The same verdict on the session's own list (#2693), validated with the review in place, so the two lists never differ.
|
|
1030
1216
|
let session: { path: string; text: string; out: ReviewSession } | undefined;
|
|
1031
1217
|
if (inSession) {
|
|
@@ -1041,8 +1227,9 @@ export async function reviewRecord(opts: ReviewRecordOptions): Promise<ReviewDoc
|
|
|
1041
1227
|
session = { path: st.path, text: sText, out: { id: opts.session!, path: st.path, verdict, ...(opts.dryRun ? { text: sText } : {}) } };
|
|
1042
1228
|
}
|
|
1043
1229
|
if (!opts.dryRun) {
|
|
1044
|
-
|
|
1045
|
-
if (session)
|
|
1230
|
+
writeFileAtomic(abs(o, target.path), text);
|
|
1231
|
+
if (session) writeFileAtomic(abs(o, session.path), session.text);
|
|
1232
|
+
noteWrites(o.root, [{ path: target.path, text }, ...(session ? [{ path: session.path, text: session.text }] : [])], writeWho("records review", opts));
|
|
1046
1233
|
}
|
|
1047
1234
|
return {
|
|
1048
1235
|
$schema: RECORDS_REVIEW_SCHEMA_ID,
|
|
@@ -1054,6 +1241,7 @@ export async function reviewRecord(opts: ReviewRecordOptions): Promise<ReviewDoc
|
|
|
1054
1241
|
...(session ? { session: session.out } : {}),
|
|
1055
1242
|
dryRun: !!opts.dryRun,
|
|
1056
1243
|
warnings,
|
|
1244
|
+
digest: writtenEntry.digest,
|
|
1057
1245
|
...(opts.dryRun ? { text } : {}),
|
|
1058
1246
|
};
|
|
1059
1247
|
} catch (err) {
|
|
@@ -1108,9 +1296,9 @@ async function seal(sign: string | true, cwd: string, v: { record: string; diges
|
|
|
1108
1296
|
|
|
1109
1297
|
export const WRITE_USAGE = [
|
|
1110
1298
|
"chant workspace records new [<kind file or declared kind>] --from <file|-> [--prefix <prefix>] [--by <name>] [--sign [<key file>]] [--dry-run]",
|
|
1111
|
-
"chant workspace records amend <id> [--kind <kind file>] --set <file|-> [--sign [<key file>]] [--dry-run]",
|
|
1112
|
-
"chant workspace records review <id> [--kind <kind file>] --verdict agree|dissent|abstain --by <principal> [--note <text>] [--session <id>] [--sign [<key file>]] [--dry-run]",
|
|
1113
|
-
"chant workspace records close <session id> [--kind <session kind file>] [--dry-run]",
|
|
1299
|
+
"chant workspace records amend <id> [--kind <kind file>] --set <file|-> [--expect <digest>] [--sign [<key file>]] [--dry-run]",
|
|
1300
|
+
"chant workspace records review <id> [--kind <kind file>] --verdict agree|dissent|abstain --by <principal> [--note <text>] [--session <id>] [--expect <digest>] [--sign [<key file>]] [--dry-run]",
|
|
1301
|
+
"chant workspace records close <session id> [--kind <session kind file>] [--expect <digest>] [--dry-run]",
|
|
1114
1302
|
].join("\n");
|
|
1115
1303
|
|
|
1116
1304
|
function usage(schema: string, message: string): WriteFailure<"write-usage-invalid"> {
|
|
@@ -1204,12 +1392,13 @@ export async function runRecordsWrite(ctx: CommandContext): Promise<number> {
|
|
|
1204
1392
|
if (!id) return print(usage(RECORDS_CLOSE_SCHEMA_ID, "close needs the session's id"));
|
|
1205
1393
|
const kind = args.kind !== undefined ? resolveWriteKind(args.kind, cwd) : await declaredSessionKind(RECORDS_CLOSE_SCHEMA_ID, cwd);
|
|
1206
1394
|
if (typeof kind !== "string") return print(kind);
|
|
1207
|
-
return print(await closeRecord({ kind, id, dryRun: args.dryRun, cwd, agent }));
|
|
1395
|
+
return print(await closeRecord({ kind, id, dryRun: args.dryRun, cwd, agent, expect: args.expect }));
|
|
1208
1396
|
}
|
|
1209
1397
|
if (verb === "new") {
|
|
1210
1398
|
const named = args.extraPositional2 ?? args.kind;
|
|
1211
1399
|
const kind = named !== undefined ? resolveWriteKind(named, cwd) : declaredWriteKind(RECORDS_NEW_SCHEMA_ID, cwd, "new needs the kind file");
|
|
1212
1400
|
if (typeof kind !== "string") return print(kind);
|
|
1401
|
+
if (args.expect !== undefined) return print(usage(RECORDS_NEW_SCHEMA_ID, "--expect is not taken by new: a new record has no digest yet, and its id is allocated under the write lock"));
|
|
1213
1402
|
const input = readInput(RECORDS_NEW_SCHEMA_ID, "--from", args.migrateFrom, cwd);
|
|
1214
1403
|
if (typeof input !== "string") return print(input);
|
|
1215
1404
|
return print(await newRecord({ kind, fields: input, prefix: args.prefix, by: args.by, sign: args.sign, dryRun: args.dryRun, cwd, agent }));
|
|
@@ -1223,11 +1412,11 @@ export async function runRecordsWrite(ctx: CommandContext): Promise<number> {
|
|
|
1223
1412
|
if (args.by !== undefined) return print(usage(schema, "--by is not taken by amend: set decided_by, or a kind's proposedBy field, with --set"));
|
|
1224
1413
|
const input = readInput(schema, "--set", args.set, cwd);
|
|
1225
1414
|
if (typeof input !== "string") return print(input);
|
|
1226
|
-
return print(await amendRecord({ kind, id, fields: input, sign: args.sign, dryRun: args.dryRun, cwd, agent }));
|
|
1415
|
+
return print(await amendRecord({ kind, id, fields: input, sign: args.sign, dryRun: args.dryRun, cwd, agent, expect: args.expect }));
|
|
1227
1416
|
}
|
|
1228
1417
|
if (args.verdict === undefined) return print(usage(schema, "--verdict agree|dissent|abstain is required"));
|
|
1229
1418
|
if (args.by === undefined) return print(usage(schema, "--by <principal> is required"));
|
|
1230
1419
|
return print(
|
|
1231
|
-
await reviewRecord({ kind, id, verdict: args.verdict, by: args.by, note: args.note, session: args.session, sign: args.sign, dryRun: args.dryRun, cwd, agent }),
|
|
1420
|
+
await reviewRecord({ kind, id, verdict: args.verdict, by: args.by, note: args.note, session: args.session, sign: args.sign, dryRun: args.dryRun, cwd, agent, expect: args.expect }),
|
|
1232
1421
|
);
|
|
1233
1422
|
}
|
|
@@ -124,6 +124,14 @@
|
|
|
124
124
|
},
|
|
125
125
|
"error": false,
|
|
126
126
|
"current": { "type": "boolean", "description": "Whether superseded records were left out (--current)." },
|
|
127
|
+
"uncommitted": {
|
|
128
|
+
"type": "boolean",
|
|
129
|
+
"description": "Added in contract 1 by #3160. Whether only the records HEAD doesn't hold were listed (--uncommitted): each record's worktree is then modified or new, checkout is present, and summary's total, valid and invalid count the records listed. Absent from documents written before #3160, which read as false."
|
|
130
|
+
},
|
|
131
|
+
"checkout": {
|
|
132
|
+
"description": "Added in contract 1 by #3160, on a read of the working tree in a git repository; absent under --at and outside git. The branch, head and base the working tree is on, and the records of the kind it has deleted.",
|
|
133
|
+
"$ref": "#/$defs/checkout"
|
|
134
|
+
},
|
|
127
135
|
"trust": { "$ref": "#/$defs/trust" },
|
|
128
136
|
"records": {
|
|
129
137
|
"description": "One entry per file the kind locates, sorted by path.",
|
|
@@ -145,6 +153,42 @@
|
|
|
145
153
|
"type": "array",
|
|
146
154
|
"items": { "$ref": "#/$defs/decisionWork" }
|
|
147
155
|
}
|
|
156
|
+
},
|
|
157
|
+
"allOf": [
|
|
158
|
+
{
|
|
159
|
+
"if": { "properties": { "uncommitted": { "const": true } }, "required": ["uncommitted"] },
|
|
160
|
+
"then": {
|
|
161
|
+
"required": ["checkout"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"checkout": true,
|
|
164
|
+
"at": { "type": "null" },
|
|
165
|
+
"records": { "type": "array", "items": { "type": "object", "required": ["worktree"], "properties": { "worktree": { "enum": ["modified", "new"] } } } }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
"checkout": {
|
|
172
|
+
"type": "object",
|
|
173
|
+
"required": ["branch", "head", "base", "baseFrom", "deleted"],
|
|
174
|
+
"properties": {
|
|
175
|
+
"branch": { "type": ["string", "null"], "description": "The checked-out branch's short name, such as chant/work/w-12, or null when HEAD is detached." },
|
|
176
|
+
"head": {
|
|
177
|
+
"type": ["string", "null"],
|
|
178
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
179
|
+
"description": "The full commit id HEAD names, or null before the first commit (every record is then new). Each record's worktree is judged against it."
|
|
180
|
+
},
|
|
181
|
+
"base": {
|
|
182
|
+
"type": ["string", "null"],
|
|
183
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
184
|
+
"description": "The merge base of head and the target branch tip, the commit the branch forked from: what applying the branch would be measured against. The target is --base when given, else origin/HEAD, main or master, as for trust. Null without a head, a target, or common history."
|
|
185
|
+
},
|
|
186
|
+
"baseFrom": { "enum": ["flag", "origin/HEAD", "main", "master", null], "description": "Where the target branch was found; null when there is none." },
|
|
187
|
+
"deleted": {
|
|
188
|
+
"type": "array",
|
|
189
|
+
"items": { "type": "string" },
|
|
190
|
+
"description": "Record files of the kind that head holds and the working tree no longer has, staged or not, from the repository root with / separators, sorted. A renamed record is here under its old name and in records as new."
|
|
191
|
+
}
|
|
148
192
|
}
|
|
149
193
|
},
|
|
150
194
|
"workLink": {
|
|
@@ -155,6 +199,17 @@
|
|
|
155
199
|
"state": { "type": ["string", "null"], "description": "The linked record's state as it writes it, or null when no record has the id." }
|
|
156
200
|
}
|
|
157
201
|
},
|
|
202
|
+
"workAnswer": {
|
|
203
|
+
"type": "object",
|
|
204
|
+
"required": ["id", "point", "state", "answer", "answeredBy"],
|
|
205
|
+
"properties": {
|
|
206
|
+
"id": { "type": "string", "description": "The answer record's id: the point's name and the first 12 hex digits of its inputs hash." },
|
|
207
|
+
"point": { "type": ["string", "null"], "description": "The decision point it answers." },
|
|
208
|
+
"state": { "type": ["string", "null"], "description": "escalated, proposed or answered." },
|
|
209
|
+
"answer": { "oneOf": [{ "type": "string" }, { "type": "boolean" }, { "type": "null" }], "description": "The answer, or null while there is none." },
|
|
210
|
+
"answeredBy": { "type": "array", "items": { "type": "string" }, "description": "The people who answered or confirmed it; empty when a table or a model answered." }
|
|
211
|
+
}
|
|
212
|
+
},
|
|
158
213
|
"decisionWork": {
|
|
159
214
|
"type": "object",
|
|
160
215
|
"required": ["id", "path", "state", "supersededBy", "implementedBy"],
|
|
@@ -199,7 +254,7 @@
|
|
|
199
254
|
"items": { "$ref": "#/$defs/asset" }
|
|
200
255
|
},
|
|
201
256
|
"warnings": {
|
|
202
|
-
"description": "Added in contract 1 by #2549. Findings that leave the record valid: a pinned file that changed, went missing or did not follow a superseding decision, a supersedes link that has no effect yet, (added by #2654) an evidence list that is empty, (added by #2672) a verdict that names no digest, or (added by #2683) a work record's links and dates, or (added by #2688) a record whose author seal is not attested under a signers file at base, or (added by #2772) a work record's acceptance criteria unmet when it is done, or met by a manual verdict from its implementer. A work record never carries record-no-evidence; a done one with no evidence carries work-done-unpinned. valid and --current do not look at them.",
|
|
257
|
+
"description": "Added in contract 1 by #2549. Findings that leave the record valid: a pinned file that changed, went missing or did not follow a superseding decision, a supersedes link that has no effect yet, (added by #2654) an evidence list that is empty, (added by #2672) a verdict that names no digest, or (added by #2683) a work record's links and dates, or (added by #2688) a record whose author seal is not attested under a signers file at base, or (added by #2772) a work record's acceptance criteria unmet when it is done, or met by a manual verdict from its implementer, or (added by #3147) a work record's contract that no record has or nobody approved, or a builder tier its kind does not list. A work record never carries record-no-evidence; a done one with no evidence carries work-done-unpinned. valid and --current do not look at them.",
|
|
203
258
|
"type": "array",
|
|
204
259
|
"items": { "$ref": "#/$defs/warning" }
|
|
205
260
|
},
|
|
@@ -243,6 +298,35 @@
|
|
|
243
298
|
"description": "Added in contract 1 by #2772, on every parsed record of a work kind whose work block names acceptance criteria. How many of the record's criteria passing evidence meets: evidence naming the criterion, with result pass and the criterion's verification, and for a manual criterion a by other than the implementer. Null when the record lists no criteria, so a record without them reads as before.",
|
|
244
299
|
"oneOf": [{ "type": "null" }, { "$ref": "#/$defs/workAcceptance" }]
|
|
245
300
|
},
|
|
301
|
+
"worktree": {
|
|
302
|
+
"enum": ["committed", "modified", "new"],
|
|
303
|
+
"description": "Added in contract 1 by #3160, on every record of a read of the working tree in a git repository; absent under --at and outside git. committed when the file is as HEAD holds it, modified when it differs from HEAD, new when HEAD doesn't hold it, staged or not. modified and new are the records a person has kept and not yet committed or applied."
|
|
304
|
+
},
|
|
305
|
+
"lastWrite": {
|
|
306
|
+
"description": "Added in contract 1 by #3173, beside worktree. The last chant write of the record's file in this working tree (records new, amend, review or close, points ask or answer), from the write journal in the git directory, while the file still holds the text that write left; null when the journal doesn't know it, such as after a commit was checked out or the file was edited by hand. A UI shows it with digest, so a person sees who changed a record they are looking at. It is a cache, never a fact: the journal can be lost.",
|
|
307
|
+
"oneOf": [
|
|
308
|
+
{ "type": "null" },
|
|
309
|
+
{
|
|
310
|
+
"type": "object",
|
|
311
|
+
"required": ["verb", "by", "agent", "at"],
|
|
312
|
+
"properties": {
|
|
313
|
+
"verb": { "type": "string", "description": "The write command, such as records amend or points answer." },
|
|
314
|
+
"by": { "type": ["string", "null"], "description": "The principal the write named (--by, or the people who answered), or null when it named none." },
|
|
315
|
+
"agent": { "type": ["string", "null"], "description": "The agent session the write was made in (CHANT_AGENT), or null." },
|
|
316
|
+
"at": { "type": "string", "description": "When, as an ISO 8601 time." }
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
},
|
|
321
|
+
"contract": {
|
|
322
|
+
"description": "Added in contract 1 by #3147, on every parsed record of a work kind whose work block names a contract kind. The contract record the item builds, by the id in the work block's contract field, with that record's state now; state is null when no record of the contract kind has the id. Null when the item names no contract.",
|
|
323
|
+
"oneOf": [{ "type": "null" }, { "$ref": "#/$defs/workLink" }]
|
|
324
|
+
},
|
|
325
|
+
"answers": {
|
|
326
|
+
"description": "Added in contract 1 by #3147, on every record with an id of a work kind whose work block names an answer kind. The decision-point answers about the item: each answer record whose constrains names the item's id, in path order, joined by id and never copied onto the item. Read at the same revision; in the working tree, with the answers a steward keeps on the lifecycle ledger laid over it. Absent when the answer kind can't be read.",
|
|
327
|
+
"type": "array",
|
|
328
|
+
"items": { "$ref": "#/$defs/workAnswer" }
|
|
329
|
+
},
|
|
246
330
|
"lease": {
|
|
247
331
|
"description": "Added in contract 1 by #2732, on every record of a work kind with an id, read in the working tree (absent under --at). The item's active work lease (chant workspace work claim), or null when nobody holds one live. Read from the local lease refs, refs/chant/lease/[_members/<member>/]work/<id> and the remote's as last fetched, of the ledger owning the work kind file; records never fetches.",
|
|
248
332
|
"oneOf": [{ "type": "null" }, { "$ref": "#/$defs/workLease" }]
|
|
@@ -319,6 +403,9 @@
|
|
|
319
403
|
"work-done-gap-open",
|
|
320
404
|
"work-acceptance-unmet",
|
|
321
405
|
"work-acceptance-self-verified",
|
|
406
|
+
"work-contract-unknown",
|
|
407
|
+
"work-contract-undecided",
|
|
408
|
+
"work-tier-unknown",
|
|
322
409
|
"answer-points-unreadable",
|
|
323
410
|
"answer-point-unknown",
|
|
324
411
|
"answer-point-changed",
|