@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
package/src/workspace/decide.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Answers to decision points as records (ws-058, #2739).
|
|
3
3
|
*
|
|
4
4
|
* {@link askPoint} asks a point's deciders for one set of inputs and records
|
|
5
|
-
* the answer in the answer kind's records directory,
|
|
6
|
-
* records people's answer to an open question
|
|
7
|
-
*
|
|
5
|
+
* the answer in the answer kind's records directory, {@link answerPoint}
|
|
6
|
+
* records people's answer to an open question, with an optional note, and
|
|
7
|
+
* {@link retractAnswer} takes an answer back (#3351). Each writes one Markdown
|
|
8
|
+
* record or none, never commits, and goes through the checks every records write goes
|
|
8
9
|
* through (`records-write.ts`): the record is read back with the kind's schema
|
|
9
10
|
* before it is written, and no other record may become invalid.
|
|
10
11
|
*
|
|
@@ -21,12 +22,28 @@
|
|
|
21
22
|
* escalated one is asked again, since a backend may answer now, and rewritten
|
|
22
23
|
* only when the chain no longer escalates.
|
|
23
24
|
*
|
|
25
|
+
* An ad-hoc point (#3403) has no candidates of its own: each ask gives the
|
|
26
|
+
* question's text and candidates, the record keeps them as `asked`, and they
|
|
27
|
+
* are part of the inputs hash, so a question asked with other options is
|
|
28
|
+
* another question. People's answer is checked against them.
|
|
29
|
+
*
|
|
30
|
+
* An answer never changes in place. People may retract it (ws-084): the
|
|
31
|
+
* question is escalated to them again, and the answer, who gave it, when, and
|
|
32
|
+
* its note move into the record's `retractions` with who retracted it, when
|
|
33
|
+
* and why. Asking a retracted question again returns it as it stands, since
|
|
34
|
+
* people took it back from the deciders; people answer it again.
|
|
35
|
+
*
|
|
36
|
+
* Each write holds the working tree's write lock (#3173, ws-089) from the first read
|
|
37
|
+
* to the write, so two answers to one question are never both taken from the
|
|
38
|
+
* same reading of it.
|
|
39
|
+
*
|
|
24
40
|
* chant never calls a model (ws-052): the model call is the caller's
|
|
25
41
|
* {@link ModelAsk}, such as the decide Op activity (#2740), or a backend's
|
|
26
42
|
* response the caller already has (`points ask --response`).
|
|
27
43
|
*/
|
|
28
44
|
|
|
29
45
|
import { writeFileSync } from "node:fs";
|
|
46
|
+
import { noteWrites, withWriteLock, WriteLockError, WRITE_LOCK_CODES, type WriteLockWho } from "./write-lock";
|
|
30
47
|
import type { ReasonCode } from "./reason-codes";
|
|
31
48
|
import { gitRoot } from "./record-source";
|
|
32
49
|
import { loadRecordKind, normalisePrincipal, RECORD_REASON_CODES, RecordReadError, type RecordEntry, type RecordWarning } from "./records";
|
|
@@ -47,15 +64,19 @@ import {
|
|
|
47
64
|
} from "./records-write";
|
|
48
65
|
import {
|
|
49
66
|
answerId,
|
|
67
|
+
askedOf,
|
|
68
|
+
askedQuestion,
|
|
50
69
|
candidates,
|
|
51
70
|
DeciderFailed,
|
|
52
71
|
inputsHash,
|
|
72
|
+
parseAsked,
|
|
53
73
|
pointOf,
|
|
54
74
|
pointsFileOf,
|
|
55
75
|
pointVersion,
|
|
56
76
|
quorumOf,
|
|
57
77
|
readPointsThrough,
|
|
58
78
|
runChain,
|
|
79
|
+
type Asked,
|
|
59
80
|
type ChainResult,
|
|
60
81
|
type Escalation,
|
|
61
82
|
type ModelAsk,
|
|
@@ -68,14 +89,16 @@ import { AGENT_ROLE } from "./records-cli";
|
|
|
68
89
|
import type { SourceVia } from "./source-block";
|
|
69
90
|
import type { RecordSource } from "./record-source";
|
|
70
91
|
import { currentStewardTurn } from "../op/steward-turn";
|
|
92
|
+
import { IdentityError, refuseUnidentified } from "./identity";
|
|
93
|
+
import { scopeSource } from "./write-scope";
|
|
71
94
|
import { RefCASConflictError } from "../lifecycle/git";
|
|
72
95
|
import { readLedgerAnswers, refreshLedger, withLedgerAnswers, writeLedgerAnswer, type LedgerAnswers } from "./answers-ledger";
|
|
73
96
|
|
|
74
|
-
/** The version of the write documents `points ask` and `points
|
|
97
|
+
/** The version of the write documents `points ask`, `points answer` and `points retract` print. */
|
|
75
98
|
export const POINTS_WRITE_CONTRACT_VERSION = 1;
|
|
76
99
|
export const POINTS_WRITE_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/points-write/v1/points-write.schema.json";
|
|
77
100
|
|
|
78
|
-
/** Why `points ask` or `points
|
|
101
|
+
/** Why `points ask`, `points answer` or `points retract` wrote nothing. Closed: a reader may switch on it. */
|
|
79
102
|
export const POINTS_WRITE_ERROR_CODES = [
|
|
80
103
|
...LOAD_ERROR_CODES,
|
|
81
104
|
"write-usage-invalid",
|
|
@@ -99,6 +122,15 @@ export const POINTS_WRITE_ERROR_CODES = [
|
|
|
99
122
|
"record-id-taken",
|
|
100
123
|
/** The answer was given during a steward's turn (#2749): a steward never answers a question, its own or another's. */
|
|
101
124
|
"answer-in-steward-turn",
|
|
125
|
+
/** An answerer is named by a bare name, and identity.attribution at base is identified (#3163). */
|
|
126
|
+
"principal-unidentified",
|
|
127
|
+
/** `points retract` names a question that has no answer: escalated or proposed (#3351). */
|
|
128
|
+
"answer-not-answered",
|
|
129
|
+
/** The answer kind's schema copy has no `note`, `retractions`, `relayed_by` or `asked` field for what the write was given (#3351, #3402, #3403). */
|
|
130
|
+
"answer-field-unsupported",
|
|
131
|
+
/** An ad-hoc point was asked without its question and candidates, a declared point with them, or they don't fit the point's question type (#3403). */
|
|
132
|
+
"point-candidates-invalid",
|
|
133
|
+
...WRITE_LOCK_CODES,
|
|
102
134
|
...RECORD_REASON_CODES,
|
|
103
135
|
] as const satisfies readonly ReasonCode[];
|
|
104
136
|
export type PointsWriteErrorCode = (typeof POINTS_WRITE_ERROR_CODES)[number];
|
|
@@ -137,16 +169,34 @@ export interface QuestionView {
|
|
|
137
169
|
probabilities: Record<string, number> | null;
|
|
138
170
|
confidence: number | null;
|
|
139
171
|
threshold: number | null;
|
|
172
|
+
/**
|
|
173
|
+
* The model's explanation of the recorded answer (#3345): a proposal's, or a
|
|
174
|
+
* confirmed proposal's. null when a model gave none, or did not decide.
|
|
175
|
+
*/
|
|
176
|
+
reason: string | null;
|
|
140
177
|
/**
|
|
141
178
|
* Any model answer: the proposal for a proposed question, or for an
|
|
142
179
|
* escalated one the last model answer below its threshold. null when no
|
|
143
|
-
* model answered.
|
|
180
|
+
* model answered. `reason` is the model's explanation of that answer, or
|
|
181
|
+
* null when it gave none (#3345).
|
|
144
182
|
*/
|
|
145
|
-
model: { answer: string | boolean | null; confidence: number | null; threshold: number | null; model: string | null; backend: string | null; observed: boolean } | null;
|
|
183
|
+
model: { answer: string | boolean | null; confidence: number | null; threshold: number | null; model: string | null; backend: string | null; observed: boolean; reason: string | null } | null;
|
|
146
184
|
escalations: Escalation[];
|
|
147
185
|
answeredBy: string[];
|
|
148
186
|
askedOn: string | null;
|
|
149
187
|
answeredOn: string | null;
|
|
188
|
+
/** What the people who answered wrote with their answer (`points answer --note`, #3351), or null. */
|
|
189
|
+
note: string | null;
|
|
190
|
+
/** Who relayed the answer to chant for the people who gave it (`points answer --relayed-by`, #3402), or null. */
|
|
191
|
+
relayedBy: string | null;
|
|
192
|
+
/** Answers people took back, oldest first (`points retract`, #3351). Empty when none was. */
|
|
193
|
+
retractions: RetractionView[];
|
|
194
|
+
/**
|
|
195
|
+
* An ad-hoc point's question as its ask gave it (#3403): the question's text
|
|
196
|
+
* and its criteria, what each candidate means. null for a declared point's
|
|
197
|
+
* question, whose text and criteria are the point's.
|
|
198
|
+
*/
|
|
199
|
+
asked: Asked | null;
|
|
150
200
|
/**
|
|
151
201
|
* The steward whose turn asked the question (#2749), and the run it was in,
|
|
152
202
|
* or null when no steward asked it. The steward waits on the question and
|
|
@@ -165,6 +215,43 @@ export interface QuestionView {
|
|
|
165
215
|
warnings: RecordWarning[];
|
|
166
216
|
}
|
|
167
217
|
|
|
218
|
+
/** One retracted answer, as a {@link QuestionView} lists it: the answer as it was, and who took it back, when and why. */
|
|
219
|
+
export interface RetractionView {
|
|
220
|
+
answer: string | boolean | null;
|
|
221
|
+
decider: Record<string, unknown>;
|
|
222
|
+
answeredBy: string[];
|
|
223
|
+
answeredOn: string | null;
|
|
224
|
+
/** The note the answer carried, or null. */
|
|
225
|
+
answerNote: string | null;
|
|
226
|
+
/** Who relayed the answer (#3402), or null. */
|
|
227
|
+
answerRelayedBy: string | null;
|
|
228
|
+
/** Who retracted it. */
|
|
229
|
+
by: string[];
|
|
230
|
+
on: string | null;
|
|
231
|
+
/** Why it was retracted (`points retract --note`), or null. */
|
|
232
|
+
note: string | null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** The record's `retractions`, as views. */
|
|
236
|
+
function retractionsOf(d: Record<string, unknown>): RetractionView[] {
|
|
237
|
+
if (!Array.isArray(d.retractions)) return [];
|
|
238
|
+
const str = (v: unknown): string | null => (typeof v === "string" ? v : null);
|
|
239
|
+
const strs = (v: unknown): string[] => (Array.isArray(v) ? v.filter((x): x is string => typeof x === "string") : []);
|
|
240
|
+
return d.retractions
|
|
241
|
+
.filter((r): r is Record<string, unknown> => r !== null && typeof r === "object" && !Array.isArray(r))
|
|
242
|
+
.map((r) => ({
|
|
243
|
+
answer: typeof r.answer === "string" || typeof r.answer === "boolean" ? r.answer : null,
|
|
244
|
+
decider: r.decider !== null && typeof r.decider === "object" && !Array.isArray(r.decider) ? (r.decider as Record<string, unknown>) : {},
|
|
245
|
+
answeredBy: strs(r.answered_by),
|
|
246
|
+
answeredOn: str(r.answered_on),
|
|
247
|
+
answerNote: str(r.answer_note),
|
|
248
|
+
answerRelayedBy: str(r.answer_relayed_by),
|
|
249
|
+
by: strs(r.by),
|
|
250
|
+
on: str(r.on),
|
|
251
|
+
note: str(r.note),
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
|
|
168
255
|
/** The harness a steward's question names in its source block (#2749). */
|
|
169
256
|
export const STEWARD_HARNESS = "chant-steward";
|
|
170
257
|
|
|
@@ -198,10 +285,20 @@ export function questionView(entry: RecordEntry, point: Point | undefined, ledge
|
|
|
198
285
|
const answer = typeof d.answer === "string" || typeof d.answer === "boolean" ? d.answer : null;
|
|
199
286
|
let model: QuestionView["model"] = null;
|
|
200
287
|
if (decider.kind === "model") {
|
|
201
|
-
model = { answer, confidence: num(d.confidence), threshold: num(d.threshold), model: str(decider.model), backend: str(decider.backend), observed: true };
|
|
288
|
+
model = { answer, confidence: num(d.confidence), threshold: num(d.threshold), model: str(decider.model), backend: str(decider.backend), observed: true, reason: str(d.reason) };
|
|
202
289
|
} else {
|
|
203
290
|
const lean = [...escalations].reverse().find((e) => e.kind === "model" && e.answer !== undefined && e.answer !== null);
|
|
204
|
-
if (lean)
|
|
291
|
+
if (lean) {
|
|
292
|
+
model = {
|
|
293
|
+
answer: lean.answer ?? null,
|
|
294
|
+
confidence: lean.confidence ?? null,
|
|
295
|
+
threshold: lean.threshold ?? null,
|
|
296
|
+
model: lean.model ?? null,
|
|
297
|
+
backend: lean.backend ?? null,
|
|
298
|
+
observed: false,
|
|
299
|
+
reason: typeof lean.model_reason === "string" ? lean.model_reason : null,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
205
302
|
}
|
|
206
303
|
const constrains = Array.isArray(d.constrains) ? d.constrains.filter((c): c is string => typeof c === "string") : [];
|
|
207
304
|
return {
|
|
@@ -223,11 +320,16 @@ export function questionView(entry: RecordEntry, point: Point | undefined, ledge
|
|
|
223
320
|
probabilities: d.probabilities !== null && typeof d.probabilities === "object" ? (d.probabilities as Record<string, number>) : null,
|
|
224
321
|
confidence: num(d.confidence),
|
|
225
322
|
threshold: num(d.threshold),
|
|
323
|
+
reason: decider.kind === "model" ? str(d.reason) : null,
|
|
226
324
|
model,
|
|
227
325
|
escalations,
|
|
228
326
|
answeredBy: Array.isArray(d.answered_by) ? d.answered_by.filter((b): b is string => typeof b === "string") : [],
|
|
229
327
|
askedOn: str(d.asked_on),
|
|
230
328
|
answeredOn: str(d.answered_on),
|
|
329
|
+
note: str(d.note),
|
|
330
|
+
relayedBy: str(d.relayed_by),
|
|
331
|
+
retractions: retractionsOf(d),
|
|
332
|
+
asked: askedOf(d) ?? null,
|
|
231
333
|
askedBy: askedByOf(d),
|
|
232
334
|
ledger,
|
|
233
335
|
valid: entry.valid,
|
|
@@ -235,12 +337,15 @@ export function questionView(entry: RecordEntry, point: Point | undefined, ledge
|
|
|
235
337
|
};
|
|
236
338
|
}
|
|
237
339
|
|
|
238
|
-
/**
|
|
340
|
+
/** The write verbs of `points`. */
|
|
341
|
+
export type PointsWriteVerb = "ask" | "answer" | "retract";
|
|
342
|
+
|
|
343
|
+
/** What `points ask`, `points answer` and `points retract` print. */
|
|
239
344
|
export type PointsWriteDocument =
|
|
240
345
|
| {
|
|
241
346
|
$schema: string;
|
|
242
347
|
contract: number;
|
|
243
|
-
verb:
|
|
348
|
+
verb: PointsWriteVerb;
|
|
244
349
|
kind: KindView;
|
|
245
350
|
id: string;
|
|
246
351
|
path: string;
|
|
@@ -253,10 +358,10 @@ export type PointsWriteDocument =
|
|
|
253
358
|
/** With --dry-run, the text the command would write. */
|
|
254
359
|
text?: string;
|
|
255
360
|
}
|
|
256
|
-
| { $schema: string; contract: number; verb:
|
|
361
|
+
| { $schema: string; contract: number; verb: PointsWriteVerb; error: { code: PointsWriteErrorCode; message: string } };
|
|
257
362
|
|
|
258
|
-
function failure(verb:
|
|
259
|
-
if (err instanceof PointsWriteError || err instanceof RecordWriteError || err instanceof RecordReadError) {
|
|
363
|
+
function failure(verb: PointsWriteVerb, err: unknown): PointsWriteDocument {
|
|
364
|
+
if (err instanceof PointsWriteError || err instanceof RecordWriteError || err instanceof RecordReadError || err instanceof IdentityError || err instanceof WriteLockError) {
|
|
260
365
|
return { $schema: POINTS_WRITE_SCHEMA_ID, contract: POINTS_WRITE_CONTRACT_VERSION, verb, error: { code: err.code as PointsWriteErrorCode, message: err.message } };
|
|
261
366
|
}
|
|
262
367
|
if (err instanceof WorkspaceReadError) {
|
|
@@ -309,6 +414,12 @@ export interface AskPointOptions {
|
|
|
309
414
|
point: string;
|
|
310
415
|
/** The inputs, keyed by the point's declared input names. */
|
|
311
416
|
inputs: unknown;
|
|
417
|
+
/**
|
|
418
|
+
* An ad-hoc point's question and candidates (#3403), as `{ question,
|
|
419
|
+
* criteria }` in the point's question type's shape. Required for an ad-hoc
|
|
420
|
+
* point and refused for a declared one.
|
|
421
|
+
*/
|
|
422
|
+
candidates?: unknown;
|
|
312
423
|
/** What the question is about, such as a work item's id: written to `constrains`. */
|
|
313
424
|
subject?: string;
|
|
314
425
|
/** The answer kind file, or a declared kind's name. Without it, the declared answer kind whose points file declares the point. */
|
|
@@ -342,14 +453,15 @@ export interface AskPointOptions {
|
|
|
342
453
|
const today = (): string => new Date().toISOString().slice(0, 10);
|
|
343
454
|
const show = (answer: string | boolean, type: string): string => (type === "noul" ? (answer ? "yes" : "no") : String(answer));
|
|
344
455
|
|
|
345
|
-
|
|
456
|
+
/** A record's title: the point's title, or an ad-hoc question's own text (#3403), what it is about, and where it stands. */
|
|
457
|
+
function titleFor(point: Point, subject: string | undefined, state: string, answer: string | boolean | undefined, asked?: Asked): string {
|
|
346
458
|
const outcome = state === "escalated" ? "open for people" : state === "proposed" ? `${show(answer!, point.question.type)}, proposed` : show(answer!, point.question.type);
|
|
347
|
-
return `${point.title}${subject ? ` (${subject})` : ""}: ${outcome}`;
|
|
459
|
+
return `${asked ? asked.question : point.title}${subject ? ` (${subject})` : ""}: ${outcome}`;
|
|
348
460
|
}
|
|
349
461
|
|
|
350
|
-
function body(point: Point, title: string): string {
|
|
351
|
-
const q = point
|
|
352
|
-
const describe = (c: string | boolean): string => (q.type === "score" ? "" : ((q.criteria as Record<string, string>)[String(c)] ?? ""));
|
|
462
|
+
function body(point: Point, title: string, asked?: Asked): string {
|
|
463
|
+
const q = askedQuestion(point, asked);
|
|
464
|
+
const describe = (c: string | boolean): string => (q.type === "score" ? "" : ((q.criteria as Record<string, string> | undefined)?.[String(c)] ?? ""));
|
|
353
465
|
const options = candidates(q).map((c) => `- ${show(c, q.type)}${describe(c) ? `: ${describe(c)}` : ""}`);
|
|
354
466
|
return ["", `# ${title}`, "", q.instructions.trim(), "", ...options, ""].join("\n");
|
|
355
467
|
}
|
|
@@ -367,6 +479,26 @@ async function findPoint(kinds: string[], name: string, cwd: string): Promise<Op
|
|
|
367
479
|
throw new PointsWriteError("point-unknown", `no points file declares ${JSON.stringify(name)}${declared.length ? ` (the points are ${declared.join(", ")})` : ""}`);
|
|
368
480
|
}
|
|
369
481
|
|
|
482
|
+
/**
|
|
483
|
+
* An ad-hoc point's question and candidates from the ask (#3403), or
|
|
484
|
+
* undefined for a declared point. Refused when an ad-hoc point has none, a
|
|
485
|
+
* declared point is given them, they don't fit the question type, or the
|
|
486
|
+
* answer kind's schema copy has no `asked` field to keep them in.
|
|
487
|
+
*/
|
|
488
|
+
function checkAsked(name: string, point: Point, given: unknown, loaded: { kind: { name: string }; schema: Record<string, unknown> }): Asked | undefined {
|
|
489
|
+
if (!point.adhoc) {
|
|
490
|
+
if (given !== undefined) throw new PointsWriteError("point-candidates-invalid", `${name} declares its candidates, so the ask gives none: --candidates is for an ad-hoc point`);
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
if (given === undefined) throw new PointsWriteError("point-candidates-invalid", `${name} is an ad-hoc point, so each ask gives the question and its candidates: --candidates <file|-|json>`);
|
|
494
|
+
const parsed = parseAsked(point, given);
|
|
495
|
+
if ("problems" in parsed) throw new PointsWriteError("point-candidates-invalid", `the candidates for ${name}, a ${point.question.type} question: ${parsed.problems.join("; ")}`);
|
|
496
|
+
if (!answerFields(loaded.schema).asked) {
|
|
497
|
+
throw new PointsWriteError("answer-field-unsupported", `the ${loaded.kind.name} kind's schema has no asked field, so an ad-hoc question's text and candidates can't be kept: copy point-answer.schema.json from @intentius/chant anew`);
|
|
498
|
+
}
|
|
499
|
+
return parsed.asked;
|
|
500
|
+
}
|
|
501
|
+
|
|
370
502
|
function checkInputs(name: string, point: Point, inputs: unknown): Record<string, unknown> {
|
|
371
503
|
if (inputs === null || typeof inputs !== "object" || Array.isArray(inputs)) throw new PointsWriteError("point-inputs-invalid", `the inputs to ${name} must be a JSON object`);
|
|
372
504
|
const declared = Object.keys(point.inputs);
|
|
@@ -385,6 +517,8 @@ interface WriteTarget {
|
|
|
385
517
|
/** Write to the ledger rather than the tree. */
|
|
386
518
|
onLedger: boolean;
|
|
387
519
|
message: string;
|
|
520
|
+
/** Who writes, for the write journal (#3173). */
|
|
521
|
+
who: WriteLockWho;
|
|
388
522
|
}
|
|
389
523
|
|
|
390
524
|
/**
|
|
@@ -408,6 +542,7 @@ async function write(o: Opened, before: RecordEntry[], path: string, text: strin
|
|
|
408
542
|
if (!dryRun) {
|
|
409
543
|
try {
|
|
410
544
|
writeFileSync(abs(o, path), text, create ? { flag: "wx" } : undefined);
|
|
545
|
+
noteWrites(o.root, [{ path, text }], target.who);
|
|
411
546
|
} catch (err) {
|
|
412
547
|
if ((err as NodeJS.ErrnoException).code === "EEXIST") throw new PointsWriteError("record-id-taken", `${path} was written by another ask at the same time: ask again to read it`);
|
|
413
548
|
throw err;
|
|
@@ -429,10 +564,28 @@ function recordData(o: Opened, fields: Record<string, unknown>): Record<string,
|
|
|
429
564
|
return pick(clean, schemaOrder(clean, { properties: o.loaded.schema.properties }));
|
|
430
565
|
}
|
|
431
566
|
|
|
432
|
-
|
|
433
|
-
|
|
567
|
+
/**
|
|
568
|
+
* Whether an answer kind's schema copy takes the model's reason (#3345): at
|
|
569
|
+
* the top level, and in an escalation entry as `model_reason`. A workspace
|
|
570
|
+
* whose copy of point-answer.schema.json predates them keeps no reason rather
|
|
571
|
+
* than failing the write; copying the schema anew turns them on.
|
|
572
|
+
*/
|
|
573
|
+
export function reasonFields(schema: Record<string, unknown>): { top: boolean; escalation: boolean } {
|
|
574
|
+
const has = (o: unknown, key: string): boolean => o !== null && typeof o === "object" && Object.prototype.hasOwnProperty.call(o, key);
|
|
575
|
+
const defs = (schema.definitions ?? schema.$defs) as Record<string, { properties?: unknown }> | undefined;
|
|
576
|
+
return { top: has(schema.properties, "reason"), escalation: has(defs?.escalation?.properties, "model_reason") };
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** Escalations without `model_reason` when the kind's schema does not take it. */
|
|
580
|
+
function keepReasons(escalations: Escalation[], takes: { escalation: boolean }): Escalation[] {
|
|
581
|
+
return takes.escalation ? escalations : escalations.map(({ model_reason: _, ...e }) => e);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function resultFields(result: ChainResult, takes: { top: boolean; escalation: boolean }): Record<string, unknown> {
|
|
585
|
+
const escalations = result.escalations.length > 0 ? keepReasons(result.escalations, takes) : undefined;
|
|
434
586
|
if (result.status === "proposed") {
|
|
435
|
-
|
|
587
|
+
const reason = takes.top ? result.reason : undefined;
|
|
588
|
+
return { state: "proposed", answer: result.answer, decider: result.decider, probabilities: result.probabilities, confidence: result.confidence, threshold: result.threshold, reason, escalations };
|
|
436
589
|
}
|
|
437
590
|
if (result.status === "answered") return { state: "answered", answer: result.answer, decider: result.decider, escalations };
|
|
438
591
|
return { state: "escalated", decider: result.decider, escalations };
|
|
@@ -444,6 +597,14 @@ function resultFields(result: ChainResult): Record<string, unknown> {
|
|
|
444
597
|
* answered or proposed before.
|
|
445
598
|
*/
|
|
446
599
|
export async function askPoint(opts: AskPointOptions): Promise<PointsWriteDocument> {
|
|
600
|
+
try {
|
|
601
|
+
return await withWriteLock(opts.cwd, { verb: "points ask", by: opts.steward?.name ?? null }, opts.dryRun, () => askPointLocked(opts));
|
|
602
|
+
} catch (err) {
|
|
603
|
+
return failure("ask", err);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
async function askPointLocked(opts: AskPointOptions): Promise<PointsWriteDocument> {
|
|
447
608
|
try {
|
|
448
609
|
// A steward's turn (#2749): named by the caller, or this process's, as when an Op shells out to `points ask`.
|
|
449
610
|
const turn = opts.steward ? undefined : currentStewardTurn();
|
|
@@ -452,8 +613,9 @@ export async function askPoint(opts: AskPointOptions): Promise<PointsWriteDocume
|
|
|
452
613
|
const kinds = await answerKindFiles(opts.cwd, opts.kind);
|
|
453
614
|
const { o, point } = await findPoint(kinds, opts.point, opts.cwd);
|
|
454
615
|
const inputs = checkInputs(opts.point, point, opts.inputs);
|
|
616
|
+
const asked = checkAsked(opts.point, point, opts.candidates, o.loaded);
|
|
455
617
|
const version = pointVersion(point);
|
|
456
|
-
const hash = inputsHash(opts.point, version, inputs);
|
|
618
|
+
const hash = inputsHash(opts.point, version, inputs, asked);
|
|
457
619
|
const id = answerId(opts.point, hash);
|
|
458
620
|
if (toLedger && !opts.dryRun) await refreshLedger(o.loaded.file);
|
|
459
621
|
const { ledger, source: read, before } = await readWithLedger(o);
|
|
@@ -473,10 +635,12 @@ export async function askPoint(opts: AskPointOptions): Promise<PointsWriteDocume
|
|
|
473
635
|
...(extra.text !== undefined ? { text: extra.text } : {}),
|
|
474
636
|
});
|
|
475
637
|
if (existing && existing.data !== null && (existing.state === "answered" || existing.state === "proposed")) return done(existing, { reused: true, written: false });
|
|
638
|
+
// People took a retracted question back from the deciders (ws-084): they answer it again, and asking returns it as it stands.
|
|
639
|
+
if (existing && existing.data !== null && Array.isArray(existing.data.retractions) && existing.data.retractions.length > 0) return done(existing, { reused: true, written: false });
|
|
476
640
|
|
|
477
641
|
let result: ChainResult;
|
|
478
642
|
try {
|
|
479
|
-
result = await runChain(opts.point, point, inputs, opts.ask);
|
|
643
|
+
result = await runChain(opts.point, { ...point, question: askedQuestion(point, asked) }, inputs, opts.ask);
|
|
480
644
|
} catch (err) {
|
|
481
645
|
if (err instanceof DeciderFailed) throw new PointsWriteError("point-decider-failed", err.message);
|
|
482
646
|
throw err;
|
|
@@ -487,7 +651,7 @@ export async function askPoint(opts: AskPointOptions): Promise<PointsWriteDocume
|
|
|
487
651
|
const on = opts.on ?? today();
|
|
488
652
|
const state = result.status;
|
|
489
653
|
const answer = result.status === "escalated" ? undefined : result.answer;
|
|
490
|
-
const title = titleFor(point, opts.subject, state, answer);
|
|
654
|
+
const title = titleFor(point, opts.subject, state, answer, asked);
|
|
491
655
|
const modelId = result.status === "proposed" ? result.decider.model : undefined;
|
|
492
656
|
const client = steward ? { name: steward.name } : opts.client;
|
|
493
657
|
const source = {
|
|
@@ -503,21 +667,22 @@ export async function askPoint(opts: AskPointOptions): Promise<PointsWriteDocume
|
|
|
503
667
|
point: opts.point,
|
|
504
668
|
point_version: version,
|
|
505
669
|
question_type: point.question.type,
|
|
506
|
-
candidates: candidates(point
|
|
670
|
+
candidates: candidates(askedQuestion(point, asked)),
|
|
671
|
+
asked,
|
|
507
672
|
inputs,
|
|
508
673
|
inputs_hash: hash,
|
|
509
674
|
constrains: opts.subject !== undefined ? [opts.subject] : existing?.data?.constrains,
|
|
510
|
-
...resultFields(result),
|
|
675
|
+
...resultFields(result, reasonFields(o.loaded.schema)),
|
|
511
676
|
asked_on: on,
|
|
512
677
|
answered_on: state === "answered" ? on : undefined,
|
|
513
678
|
source,
|
|
514
679
|
});
|
|
515
680
|
const path = existing ? existing.path : o.dirRel === "." ? `${id}.md` : `${o.dirRel}/${id}.md`;
|
|
516
|
-
const text = renderRecord(data, body(point, title));
|
|
681
|
+
const text = renderRecord(data, body(point, title, asked));
|
|
517
682
|
// A steward's question goes on the ledger, and one already held there stays there (#2786).
|
|
518
683
|
const onLedger = toLedger || ledger.byPath.has(path);
|
|
519
684
|
const message = `Decision point ${opts.point}: ${state}${opts.subject ? ` (${opts.subject})` : ""}${steward ? `, asked by ${steward.name}` : ""}`;
|
|
520
|
-
const wrote = await write(o, before, path, text, !existing, !!opts.dryRun, { source: read, ledger, onLedger, message });
|
|
685
|
+
const wrote = await write(o, before, path, text, !existing, !!opts.dryRun, { source: read, ledger, onLedger, message, who: { verb: "points ask", by: steward?.name ?? null } });
|
|
521
686
|
const entry: RecordEntry = { ...(existing ?? emptyEntry(path)), id, path, state, data, valid: true, reasons: [], warnings: wrote.warnings };
|
|
522
687
|
return done(entry, { reused: false, written: !opts.dryRun, ledger: wrote.ledger, ...(opts.dryRun ? { text } : {}) });
|
|
523
688
|
} catch (err) {
|
|
@@ -539,11 +704,38 @@ export interface AnswerPointOptions {
|
|
|
539
704
|
answer: string | boolean;
|
|
540
705
|
/** Who answered, as the caller names them. chant does not check who they are; the trust policy says who counts. */
|
|
541
706
|
by: string[];
|
|
707
|
+
/** What the people who answered say with it, recorded as the record's `note` (#3351). */
|
|
708
|
+
note?: string;
|
|
709
|
+
/**
|
|
710
|
+
* Who carried the answer to chant for the people in `by` (#3402), such as a
|
|
711
|
+
* follower relaying a person's answer through hud, recorded as the record's
|
|
712
|
+
* `relayed_by`. The relay does not count toward the quorum.
|
|
713
|
+
*/
|
|
714
|
+
relayedBy?: string;
|
|
542
715
|
kind?: string;
|
|
543
716
|
on?: string;
|
|
544
717
|
dryRun?: boolean;
|
|
545
718
|
}
|
|
546
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Whether an answer kind's schema copy takes the fields of #3351 (`note` on an
|
|
722
|
+
* answer, and `retractions`), of #3402 (`relayed_by`) and of #3403 (`asked`).
|
|
723
|
+
* A copy of point-answer.schema.json from before them refuses a note, a
|
|
724
|
+
* retraction, a relay or an ad-hoc ask with `answer-field-unsupported`, rather
|
|
725
|
+
* than dropping what a person wrote or the question an agent asked.
|
|
726
|
+
*/
|
|
727
|
+
export function answerFields(schema: Record<string, unknown>): { note: boolean; retractions: boolean; relayedBy: boolean; asked: boolean } {
|
|
728
|
+
const props = schema.properties as Record<string, unknown> | undefined;
|
|
729
|
+
const has = (key: string): boolean => props !== undefined && props !== null && typeof props === "object" && Object.prototype.hasOwnProperty.call(props, key);
|
|
730
|
+
return { note: has("note"), retractions: has("retractions"), relayedBy: has("relayed_by"), asked: has("asked") };
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/** A note as given, trimmed, or undefined when it is empty. */
|
|
734
|
+
const noteOf = (note: string | undefined): string | undefined => {
|
|
735
|
+
const t = note?.trim();
|
|
736
|
+
return t ? t : undefined;
|
|
737
|
+
};
|
|
738
|
+
|
|
547
739
|
/** The trust policy at base, for the quorum: who holds the agent role and each role a quorum names. */
|
|
548
740
|
function policyFor(root: string): TrustPolicy {
|
|
549
741
|
if (!gitRoot(root)) return emptyPolicy(null);
|
|
@@ -593,71 +785,114 @@ export function tallyQuorum(
|
|
|
593
785
|
return { counted, left, met: counted.length >= quorum.count };
|
|
594
786
|
}
|
|
595
787
|
|
|
788
|
+
/**
|
|
789
|
+
* A steward waits on a question and never answers or retracts one (#2749), as
|
|
790
|
+
* it never clears a gate: the write has to come from a person, through hud or
|
|
791
|
+
* a shell, not from the steward's own turn or a process it started.
|
|
792
|
+
*/
|
|
793
|
+
function refuseStewardTurn(id: string, does: "answers" | "retracts"): void {
|
|
794
|
+
const turn = currentStewardTurn();
|
|
795
|
+
if (turn) {
|
|
796
|
+
throw new PointsWriteError(
|
|
797
|
+
"answer-in-steward-turn",
|
|
798
|
+
`this is the steward ${turn.steward}'s turn, and a steward never ${does} a decision point: a person ${does === "answers" ? "answers" : "retracts the answer to"} ${id} through hud or \`chant workspace points ${does === "answers" ? "answer" : "retract"}\` at a shell`,
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
interface FoundQuestion {
|
|
804
|
+
opened: OpenedPoints;
|
|
805
|
+
before: RecordEntry[];
|
|
806
|
+
read: Awaited<ReturnType<typeof readWithLedger>>;
|
|
807
|
+
target: RecordEntry & { data: Record<string, unknown> };
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/** The answer record with this id, in the answer kind `kind` names or the first declared one that has it, read with the ledger's answers laid over the tree. */
|
|
811
|
+
async function findQuestion(cwd: string, kind: string | undefined, id: string): Promise<FoundQuestion> {
|
|
812
|
+
const kinds = await answerKindFiles(cwd, kind);
|
|
813
|
+
if (kinds.length === 0) throw new PointsWriteError("points-undeclared", "no record kind with an answers block is declared: name one with --kind, or declare one in chant.workspace.json");
|
|
814
|
+
for (const k of kinds) {
|
|
815
|
+
const opened = await openAnswers(k, cwd);
|
|
816
|
+
// A question a steward asked is on the ledger (#2786), and people's answer goes back there.
|
|
817
|
+
const read = await readWithLedger(opened.o);
|
|
818
|
+
const target = read.before.find((e) => e.id === id);
|
|
819
|
+
if (target && target.data !== null) return { opened, before: read.before, read, target: target as FoundQuestion["target"] };
|
|
820
|
+
}
|
|
821
|
+
throw new PointsWriteError("record-not-found", `no answer record has id ${id}`);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/** Count `by` toward the point's quorum, or refuse with `quorum-not-met`. */
|
|
825
|
+
function meetQuorum(name: string, by: string[], quorum: { count: number; roles?: string[] }, root: string, steward: string | undefined, verb: "answer" | "retract"): { counted: string[] } {
|
|
826
|
+
const tally = tallyQuorum(by, quorum, policyFor(root), steward);
|
|
827
|
+
if (!tally.met) {
|
|
828
|
+
const got = tally.counted.length;
|
|
829
|
+
const left = tally.left.length ? `; not counted: ${tally.left.map((l) => `${l.name}, who ${l.why}`).join("; ")}` : "";
|
|
830
|
+
throw new PointsWriteError(
|
|
831
|
+
"quorum-not-met",
|
|
832
|
+
`${name} needs ${quorum.count} ${quorum.count === 1 ? "person" : "people"}${quorum.roles ? ` holding ${quorum.roles.join(" or ")}` : ""} to ${verb === "answer" ? "answer" : "retract an answer"}, and ${got} ${got === 1 ? "counts" : "count"}${got ? ` (${tally.counted.join(", ")})` : ""}${left}`,
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
return tally;
|
|
836
|
+
}
|
|
837
|
+
|
|
596
838
|
/**
|
|
597
839
|
* People answer an open question: `points answer`. A proposed question the
|
|
598
840
|
* people answer as the model did is confirmed, and keeps the model as its
|
|
599
841
|
* decider; any other answer is the quorum's, and a model's proposal moves into
|
|
600
|
-
* the escalations. The question becomes `answered
|
|
842
|
+
* the escalations. The question becomes `answered`, with the people's note
|
|
843
|
+
* when they give one (#3351).
|
|
601
844
|
*/
|
|
602
845
|
export async function answerPoint(opts: AnswerPointOptions): Promise<PointsWriteDocument> {
|
|
603
846
|
try {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
for (const k of kinds) {
|
|
620
|
-
const opened = await openAnswers(k, opts.cwd);
|
|
621
|
-
// A question a steward asked is on the ledger (#2786), and people's answer goes back there.
|
|
622
|
-
const read = await readWithLedger(opened.o);
|
|
623
|
-
const target = read.before.find((e) => e.id === opts.id);
|
|
624
|
-
if (target && target.data !== null) {
|
|
625
|
-
found = { opened, before: read.before, read, target: target as RecordEntry & { data: Record<string, unknown> } };
|
|
626
|
-
break;
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
if (!found) throw new PointsWriteError("record-not-found", `no answer record has id ${opts.id}`);
|
|
847
|
+
return await withWriteLock(opts.cwd, { verb: "points answer", by: (opts.by ?? []).join(", ") || null }, opts.dryRun, () => answerPointLocked(opts));
|
|
848
|
+
} catch (err) {
|
|
849
|
+
return failure("answer", err);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
async function answerPointLocked(opts: AnswerPointOptions): Promise<PointsWriteDocument> {
|
|
854
|
+
try {
|
|
855
|
+
refuseStewardTurn(opts.id, "answers");
|
|
856
|
+
// #3163: under identity.attribution "identified" at base, each answerer is a forge identity or a signer.
|
|
857
|
+
refuseUnidentified(scopeSource(opts.cwd), opts.by, "--by");
|
|
858
|
+
// #3402: and so is whoever relayed the answer.
|
|
859
|
+
const relayedBy = noteOf(opts.relayedBy);
|
|
860
|
+
if (relayedBy !== undefined) refuseUnidentified(scopeSource(opts.cwd), [relayedBy], "--relayed-by");
|
|
861
|
+
const found = await findQuestion(opts.cwd, opts.kind, opts.id);
|
|
630
862
|
const { opened, before, target } = found;
|
|
631
863
|
const ledger = found.read.ledger;
|
|
632
864
|
const { o } = opened;
|
|
633
865
|
const d = target.data;
|
|
634
|
-
if (target.state === "answered")
|
|
866
|
+
if (target.state === "answered") {
|
|
867
|
+
throw new PointsWriteError("record-closed", `${opts.id} is answered, and an answer never changes in place: retract it with \`points retract ${opts.id}\` and answer again, ask again with other inputs, or change the point, which asks the question anew`);
|
|
868
|
+
}
|
|
869
|
+
const note = noteOf(opts.note);
|
|
870
|
+
if (note !== undefined && !answerFields(o.loaded.schema).note) {
|
|
871
|
+
throw new PointsWriteError("answer-field-unsupported", `the ${o.loaded.kind.name} kind's schema has no note field, so ${opts.id} can't keep the note: copy point-answer.schema.json from @intentius/chant anew`);
|
|
872
|
+
}
|
|
873
|
+
if (relayedBy !== undefined && !answerFields(o.loaded.schema).relayedBy) {
|
|
874
|
+
throw new PointsWriteError("answer-field-unsupported", `the ${o.loaded.kind.name} kind's schema has no relayed_by field, so ${opts.id} can't record who relayed the answer: copy point-answer.schema.json from @intentius/chant anew`);
|
|
875
|
+
}
|
|
635
876
|
const name = String(d.point);
|
|
636
877
|
const point = pointOf(opened.points, name);
|
|
637
878
|
if (!point) throw new PointsWriteError("point-unknown", `${opts.id} answers ${name}, which ${opened.pointsFile} no longer declares`);
|
|
638
|
-
|
|
879
|
+
// An ad-hoc question is answered from the candidates it was asked with (#3403).
|
|
880
|
+
const asked = askedOf(d);
|
|
881
|
+
const allowed = asked ? candidates(askedQuestion(point, asked)) : Array.isArray(d.candidates) ? (d.candidates as (string | boolean)[]) : candidates(point.question);
|
|
639
882
|
const type = String(d.question_type);
|
|
640
883
|
const value = type === "noul" && typeof opts.answer === "string" ? ({ true: true, yes: true, false: false, no: false } as Record<string, boolean>)[opts.answer.toLowerCase()] : opts.answer;
|
|
641
884
|
if (value === undefined || !allowed.includes(value)) {
|
|
642
885
|
throw new PointsWriteError("answer-not-candidate", `${opts.id} takes one of ${allowed.map((c) => JSON.stringify(c)).join(", ")}, not ${JSON.stringify(opts.answer)}`);
|
|
643
886
|
}
|
|
644
887
|
const quorum = quorumOf(point);
|
|
645
|
-
const tally =
|
|
646
|
-
if (!tally.met) {
|
|
647
|
-
const got = tally.counted.length;
|
|
648
|
-
const left = tally.left.length ? `; not counted: ${tally.left.map((l) => `${l.name}, who ${l.why}`).join("; ")}` : "";
|
|
649
|
-
throw new PointsWriteError(
|
|
650
|
-
"quorum-not-met",
|
|
651
|
-
`${name} needs ${quorum.count} ${quorum.count === 1 ? "person" : "people"}${quorum.roles ? ` holding ${quorum.roles.join(" or ")}` : ""} to answer, and ${got} ${got === 1 ? "counts" : "count"}${got ? ` (${tally.counted.join(", ")})` : ""}${left}`,
|
|
652
|
-
);
|
|
653
|
-
}
|
|
888
|
+
const tally = meetQuorum(name, opts.by, quorum, o.root, askedByOf(d)?.steward, "answer");
|
|
654
889
|
const on = opts.on ?? today();
|
|
655
890
|
const decider = d.decider as Record<string, unknown>;
|
|
656
891
|
const confirmed = target.state === "proposed" && decider.kind === "model" && d.answer === value;
|
|
657
892
|
const escalations = Array.isArray(d.escalations) ? [...(d.escalations as Escalation[])] : [];
|
|
658
893
|
let fields: Record<string, unknown>;
|
|
659
894
|
if (confirmed) {
|
|
660
|
-
fields = { ...d, state: "answered", answered_by: tally.counted, answered_on: on };
|
|
895
|
+
fields = { ...d, state: "answered", answered_by: tally.counted, answered_on: on, note, relayed_by: relayedBy };
|
|
661
896
|
} else {
|
|
662
897
|
if (target.state === "proposed" && decider.kind === "model") {
|
|
663
898
|
escalations.push({
|
|
@@ -669,9 +904,11 @@ export async function answerPoint(opts: AnswerPointOptions): Promise<PointsWrite
|
|
|
669
904
|
...(typeof d.confidence === "number" ? { confidence: d.confidence } : {}),
|
|
670
905
|
...(typeof d.threshold === "number" ? { threshold: d.threshold } : {}),
|
|
671
906
|
reason: `proposed ${show(d.answer as string | boolean, type)}, and people answered ${show(value, type)}`,
|
|
907
|
+
// The model's own reason moves with its proposal (#3345).
|
|
908
|
+
...(typeof d.reason === "string" && reasonFields(o.loaded.schema).escalation ? { model_reason: d.reason } : {}),
|
|
672
909
|
});
|
|
673
910
|
}
|
|
674
|
-
const rest = Object.fromEntries(Object.entries(d).filter(([k]) => k !== "probabilities" && k !== "confidence" && k !== "threshold"));
|
|
911
|
+
const rest = Object.fromEntries(Object.entries(d).filter(([k]) => k !== "probabilities" && k !== "confidence" && k !== "threshold" && k !== "reason"));
|
|
675
912
|
fields = {
|
|
676
913
|
...rest,
|
|
677
914
|
state: "answered",
|
|
@@ -680,15 +917,17 @@ export async function answerPoint(opts: AnswerPointOptions): Promise<PointsWrite
|
|
|
680
917
|
escalations: escalations.length > 0 ? escalations : undefined,
|
|
681
918
|
answered_by: tally.counted,
|
|
682
919
|
answered_on: on,
|
|
920
|
+
note,
|
|
921
|
+
relayed_by: relayedBy,
|
|
683
922
|
};
|
|
684
923
|
}
|
|
685
924
|
const subject = Array.isArray(d.constrains) && typeof d.constrains[0] === "string" ? (d.constrains[0] as string) : undefined;
|
|
686
|
-
fields.title = titleFor(point, subject, "answered", value);
|
|
925
|
+
fields.title = titleFor(point, subject, "answered", value, asked);
|
|
687
926
|
const data = recordData(o, fields);
|
|
688
|
-
const text = renderRecord(data, body(point, String(fields.title)));
|
|
927
|
+
const text = renderRecord(data, body(point, String(fields.title), asked));
|
|
689
928
|
const onLedger = ledger.byPath.has(target.path);
|
|
690
|
-
const message = `Decision point ${name}: answered ${show(value, type)} by ${tally.counted.join(", ")}`;
|
|
691
|
-
const wrote = await write(o, before, target.path, text, false, !!opts.dryRun, { source: found.read.source, ledger, onLedger, message });
|
|
929
|
+
const message = `Decision point ${name}: answered ${show(value, type)} by ${tally.counted.join(", ")}${relayedBy ? `, relayed by ${relayedBy}` : ""}`;
|
|
930
|
+
const wrote = await write(o, before, target.path, text, false, !!opts.dryRun, { source: found.read.source, ledger, onLedger, message, who: { verb: "points answer", by: tally.counted.join(", ") } });
|
|
692
931
|
const entry: RecordEntry = { ...target, state: "answered", data, valid: true, reasons: [], warnings: wrote.warnings };
|
|
693
932
|
return {
|
|
694
933
|
$schema: POINTS_WRITE_SCHEMA_ID,
|
|
@@ -707,3 +946,124 @@ export async function answerPoint(opts: AnswerPointOptions): Promise<PointsWrite
|
|
|
707
946
|
return failure("answer", err);
|
|
708
947
|
}
|
|
709
948
|
}
|
|
949
|
+
|
|
950
|
+
// ── points retract ───────────────────────────────────────────────────────────
|
|
951
|
+
|
|
952
|
+
export interface RetractAnswerOptions {
|
|
953
|
+
cwd: string;
|
|
954
|
+
/** The answer record's id. */
|
|
955
|
+
id: string;
|
|
956
|
+
/** Who takes the answer back. They count toward the point's quorum as answerers do. */
|
|
957
|
+
by: string[];
|
|
958
|
+
/** Why, recorded on the retraction. */
|
|
959
|
+
note?: string;
|
|
960
|
+
kind?: string;
|
|
961
|
+
on?: string;
|
|
962
|
+
dryRun?: boolean;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* People take an answer back: `points retract` (#3351, ws-084). The answer
|
|
967
|
+
* never changes in place. The question is escalated to the point's quorum
|
|
968
|
+
* again, open for people, and the answer as it was (its value, decider, who
|
|
969
|
+
* gave it, when, and its note) moves into the record's `retractions`, with who
|
|
970
|
+
* retracted it, when and why. A model's confirmed proposal also moves into the
|
|
971
|
+
* escalations, as when people answer otherwise. Retracting needs the point's
|
|
972
|
+
* quorum, counted as an answer is, and is refused in a steward's turn. People
|
|
973
|
+
* answer the question again with `points answer`.
|
|
974
|
+
*/
|
|
975
|
+
export async function retractAnswer(opts: RetractAnswerOptions): Promise<PointsWriteDocument> {
|
|
976
|
+
try {
|
|
977
|
+
return await withWriteLock(opts.cwd, { verb: "points retract", by: (opts.by ?? []).join(", ") || null }, opts.dryRun, () => retractAnswerLocked(opts));
|
|
978
|
+
} catch (err) {
|
|
979
|
+
return failure("retract", err);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
async function retractAnswerLocked(opts: RetractAnswerOptions): Promise<PointsWriteDocument> {
|
|
984
|
+
try {
|
|
985
|
+
refuseStewardTurn(opts.id, "retracts");
|
|
986
|
+
refuseUnidentified(scopeSource(opts.cwd), opts.by, "--by");
|
|
987
|
+
const found = await findQuestion(opts.cwd, opts.kind, opts.id);
|
|
988
|
+
const { opened, before, target } = found;
|
|
989
|
+
const ledger = found.read.ledger;
|
|
990
|
+
const { o } = opened;
|
|
991
|
+
const d = target.data;
|
|
992
|
+
if (target.state !== "answered") {
|
|
993
|
+
throw new PointsWriteError("answer-not-answered", `${opts.id} is ${target.state ?? "not answered"}, so there is no answer to retract: answer it with \`points answer ${opts.id}\``);
|
|
994
|
+
}
|
|
995
|
+
if (!answerFields(o.loaded.schema).retractions) {
|
|
996
|
+
throw new PointsWriteError("answer-field-unsupported", `the ${o.loaded.kind.name} kind's schema has no retractions field, so ${opts.id} can't keep the answer it would retract: copy point-answer.schema.json from @intentius/chant anew`);
|
|
997
|
+
}
|
|
998
|
+
const name = String(d.point);
|
|
999
|
+
const point = pointOf(opened.points, name);
|
|
1000
|
+
if (!point) throw new PointsWriteError("point-unknown", `${opts.id} answers ${name}, which ${opened.pointsFile} no longer declares, so no quorum can take the answer back: ask the point as it is declared now`);
|
|
1001
|
+
const quorum = quorumOf(point);
|
|
1002
|
+
const tally = meetQuorum(name, opts.by, quorum, o.root, askedByOf(d)?.steward, "retract");
|
|
1003
|
+
const on = opts.on ?? today();
|
|
1004
|
+
const type = String(d.question_type);
|
|
1005
|
+
const decider = d.decider !== null && typeof d.decider === "object" && !Array.isArray(d.decider) ? (d.decider as Record<string, unknown>) : { kind: "quorum" };
|
|
1006
|
+
const answer = d.answer as string | boolean;
|
|
1007
|
+
const note = noteOf(opts.note);
|
|
1008
|
+
const retraction = {
|
|
1009
|
+
answer,
|
|
1010
|
+
decider,
|
|
1011
|
+
answered_by: Array.isArray(d.answered_by) && d.answered_by.length > 0 ? d.answered_by : undefined,
|
|
1012
|
+
answered_on: typeof d.answered_on === "string" ? d.answered_on : undefined,
|
|
1013
|
+
answer_note: typeof d.note === "string" ? d.note : undefined,
|
|
1014
|
+
answer_relayed_by: typeof d.relayed_by === "string" ? d.relayed_by : undefined,
|
|
1015
|
+
by: tally.counted,
|
|
1016
|
+
on,
|
|
1017
|
+
note,
|
|
1018
|
+
};
|
|
1019
|
+
const escalations = Array.isArray(d.escalations) ? [...(d.escalations as Escalation[])] : [];
|
|
1020
|
+
if (decider.kind === "model") {
|
|
1021
|
+
// The confirmed proposal goes back among the deciders that did not settle the question.
|
|
1022
|
+
escalations.push({
|
|
1023
|
+
kind: "model",
|
|
1024
|
+
backend: String(decider.backend),
|
|
1025
|
+
model: String(decider.model),
|
|
1026
|
+
answer,
|
|
1027
|
+
...(d.probabilities ? { probabilities: d.probabilities as Record<string, number> } : {}),
|
|
1028
|
+
...(typeof d.confidence === "number" ? { confidence: d.confidence } : {}),
|
|
1029
|
+
...(typeof d.threshold === "number" ? { threshold: d.threshold } : {}),
|
|
1030
|
+
reason: `proposed ${show(answer, type)}, which people confirmed and then retracted`,
|
|
1031
|
+
...(typeof d.reason === "string" && reasonFields(o.loaded.schema).escalation ? { model_reason: d.reason } : {}),
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
const gone = new Set(["answer", "answered_by", "answered_on", "note", "relayed_by", "probabilities", "confidence", "threshold", "reason"]);
|
|
1035
|
+
const rest = Object.fromEntries(Object.entries(d).filter(([k]) => !gone.has(k)));
|
|
1036
|
+
const prior = Array.isArray(d.retractions) ? (d.retractions as unknown[]) : [];
|
|
1037
|
+
const subject = Array.isArray(d.constrains) && typeof d.constrains[0] === "string" ? (d.constrains[0] as string) : undefined;
|
|
1038
|
+
const asked = askedOf(d);
|
|
1039
|
+
const title = titleFor(point, subject, "escalated", undefined, asked);
|
|
1040
|
+
const data = recordData(o, {
|
|
1041
|
+
...rest,
|
|
1042
|
+
title,
|
|
1043
|
+
state: "escalated",
|
|
1044
|
+
decider: { kind: "quorum", count: quorum.count, ...(quorum.roles ? { roles: quorum.roles } : {}) },
|
|
1045
|
+
escalations: escalations.length > 0 ? escalations : undefined,
|
|
1046
|
+
retractions: [...prior, Object.fromEntries(Object.entries(retraction).filter(([, v]) => v !== undefined))],
|
|
1047
|
+
});
|
|
1048
|
+
const text = renderRecord(data, body(point, title, asked));
|
|
1049
|
+
const onLedger = ledger.byPath.has(target.path);
|
|
1050
|
+
const message = `Decision point ${name}: ${show(answer, type)} retracted by ${tally.counted.join(", ")}`;
|
|
1051
|
+
const wrote = await write(o, before, target.path, text, false, !!opts.dryRun, { source: found.read.source, ledger, onLedger, message, who: { verb: "points retract", by: tally.counted.join(", ") } });
|
|
1052
|
+
const entry: RecordEntry = { ...target, state: "escalated", data, valid: true, reasons: [], warnings: wrote.warnings };
|
|
1053
|
+
return {
|
|
1054
|
+
$schema: POINTS_WRITE_SCHEMA_ID,
|
|
1055
|
+
contract: POINTS_WRITE_CONTRACT_VERSION,
|
|
1056
|
+
verb: "retract",
|
|
1057
|
+
kind: o.view,
|
|
1058
|
+
id: opts.id,
|
|
1059
|
+
path: target.path,
|
|
1060
|
+
reused: false,
|
|
1061
|
+
written: !opts.dryRun,
|
|
1062
|
+
dryRun: !!opts.dryRun,
|
|
1063
|
+
question: questionView(entry, point, onLedger ? (wrote.ledger ?? ledger.byPath.get(target.path)?.ledger ?? null) : null)!,
|
|
1064
|
+
...(opts.dryRun ? { text } : {}),
|
|
1065
|
+
};
|
|
1066
|
+
} catch (err) {
|
|
1067
|
+
return failure("retract", err);
|
|
1068
|
+
}
|
|
1069
|
+
}
|