devcontour-harness 0.0.0-stage → 0.1.0-alpha.6
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/LICENSE +21 -0
- package/README.md +183 -2
- package/docs/architecture.md +473 -0
- package/docs/compatibility-versions.md +56 -0
- package/docs/compatibility.md +192 -0
- package/docs/connectors.md +323 -0
- package/docs/contracts.md +603 -0
- package/docs/integrations/hindsight.md +148 -0
- package/docs/quickstart.md +182 -0
- package/docs/release-notes/0.1.0-alpha.6.md +238 -0
- package/docs/review-probes.md +120 -0
- package/docs/review-protocol.md +251 -0
- package/docs/toolchains.md +167 -0
- package/docs/turbo-starter.md +269 -0
- package/docs/upgrade.md +202 -0
- package/examples/README.md +27 -0
- package/examples/external-connector/README.md +19 -0
- package/examples/external-connector/connector.mjs +55 -0
- package/examples/files-only/README.md +28 -0
- package/examples/files-only/context/norms/rules.md +4 -0
- package/examples/files-only/graph.json +23 -0
- package/examples/files-only/policy.json +30 -0
- package/examples/one-vendor/README.md +19 -0
- package/examples/one-vendor/policy.json +27 -0
- package/examples/single-task/README.md +18 -0
- package/examples/single-task/graph.json +27 -0
- package/examples/single-task/policy-same-vendor.json +55 -0
- package/examples/single-task/policy.json +52 -0
- package/examples/single-task/src/.gitkeep +0 -0
- package/examples/single-task/test/run.js +19 -0
- package/examples/toolchains/README.md +32 -0
- package/examples/toolchains/go/bad/label/label.go +9 -0
- package/examples/toolchains/go/good/label/label.go +9 -0
- package/examples/toolchains/go/policy.json +79 -0
- package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/go/repo/_gitignore +1 -0
- package/examples/toolchains/go/repo/go.mod +5 -0
- package/examples/toolchains/go/repo/go.sum +2 -0
- package/examples/toolchains/go/repo/label/label.go +9 -0
- package/examples/toolchains/go/repo/label/label_test.go +27 -0
- package/examples/toolchains/go/repo/label/version.go +9 -0
- package/examples/toolchains/go/task.json +25 -0
- package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/policy.json +126 -0
- package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
- package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-go/task.json +25 -0
- package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/policy.json +121 -0
- package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
- package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
- package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
- package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
- package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-python/task.json +25 -0
- package/examples/toolchains/npm/bad/src/label.js +4 -0
- package/examples/toolchains/npm/good/src/label.js +4 -0
- package/examples/toolchains/npm/policy.json +82 -0
- package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/npm/repo/_gitignore +4 -0
- package/examples/toolchains/npm/repo/package-lock.json +22 -0
- package/examples/toolchains/npm/repo/package.json +13 -0
- package/examples/toolchains/npm/repo/src/label.js +4 -0
- package/examples/toolchains/npm/repo/test/label.test.js +13 -0
- package/examples/toolchains/npm/task.json +25 -0
- package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/policy.json +85 -0
- package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/pnpm/repo/_gitignore +4 -0
- package/examples/toolchains/pnpm/repo/package.json +10 -0
- package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
- package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
- package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/pnpm/task.json +25 -0
- package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/policy.json +80 -0
- package/examples/toolchains/python/repo/.python-version +1 -0
- package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/python/repo/_gitignore +5 -0
- package/examples/toolchains/python/repo/pyproject.toml +19 -0
- package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/repo/tests/test_label.py +13 -0
- package/examples/toolchains/python/repo/uv.lock +108 -0
- package/examples/toolchains/python/task.json +25 -0
- package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/policy.json +110 -0
- package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/turbo/repo/_gitignore +4 -0
- package/examples/toolchains/turbo/repo/package.json +13 -0
- package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
- package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
- package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/turbo/repo/turbo.json +7 -0
- package/examples/toolchains/turbo/task.json +25 -0
- package/examples/turbo-starter/README.md +16 -0
- package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
- package/examples/turbo-starter/changes/issued-at.patch +130 -0
- package/examples/turbo-starter/cleanup.mjs +58 -0
- package/examples/turbo-starter/graph.json +32 -0
- package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
- package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
- package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
- package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
- package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
- package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
- package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
- package/examples/turbo-starter/harness/env/backend.env.template +7 -0
- package/examples/turbo-starter/harness/env/compose.env.template +6 -0
- package/examples/turbo-starter/policy.json +109 -0
- package/examples/turbo-starter/policy.lifecycle.json +114 -0
- package/examples/turbo-starter/setup.mjs +352 -0
- package/examples/two-vendors/policy.json +30 -0
- package/lib/agents/cli-adapter.d.ts +48 -0
- package/lib/agents/cli-adapter.js +386 -0
- package/lib/agents/inspect.d.ts +6 -0
- package/lib/agents/inspect.js +46 -0
- package/lib/agents/probe-server.d.ts +2 -0
- package/lib/agents/probe-server.js +13 -0
- package/lib/agents/review-probe.d.ts +295 -0
- package/lib/agents/review-probe.js +872 -0
- package/lib/agents/runtime-events.d.ts +11 -0
- package/lib/agents/runtime-events.js +21 -0
- package/lib/agents/schemas.d.ts +217 -0
- package/lib/agents/schemas.js +124 -0
- package/lib/agents/usage.d.ts +8 -0
- package/lib/agents/usage.js +83 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.js +491 -0
- package/lib/connectors/files.d.ts +108 -0
- package/lib/connectors/files.js +133 -0
- package/lib/contracts/checks.d.ts +307 -0
- package/lib/contracts/checks.js +181 -0
- package/lib/contracts/cli.d.ts +3895 -0
- package/lib/contracts/cli.js +664 -0
- package/lib/contracts/context.d.ts +135 -0
- package/lib/contracts/context.js +129 -0
- package/lib/contracts/digest.d.ts +9 -0
- package/lib/contracts/digest.js +22 -0
- package/lib/contracts/errors.d.ts +81 -0
- package/lib/contracts/errors.js +70 -0
- package/lib/contracts/events.d.ts +827 -0
- package/lib/contracts/events.js +258 -0
- package/lib/contracts/execution.d.ts +3216 -0
- package/lib/contracts/execution.js +872 -0
- package/lib/contracts/failure.d.ts +67 -0
- package/lib/contracts/failure.js +127 -0
- package/lib/contracts/index.d.ts +18 -0
- package/lib/contracts/index.js +18 -0
- package/lib/contracts/policy.d.ts +1080 -0
- package/lib/contracts/policy.js +544 -0
- package/lib/contracts/ports.d.ts +417 -0
- package/lib/contracts/ports.js +1 -0
- package/lib/contracts/primitives.d.ts +63 -0
- package/lib/contracts/primitives.js +73 -0
- package/lib/contracts/profiles.d.ts +336 -0
- package/lib/contracts/profiles.js +109 -0
- package/lib/contracts/published.d.ts +3237 -0
- package/lib/contracts/published.js +34 -0
- package/lib/contracts/result.d.ts +1280 -0
- package/lib/contracts/result.js +311 -0
- package/lib/contracts/review.d.ts +441 -0
- package/lib/contracts/review.js +477 -0
- package/lib/contracts/toolchain.d.ts +96 -0
- package/lib/contracts/toolchain.js +89 -0
- package/lib/contracts/version.d.ts +17 -0
- package/lib/contracts/version.js +17 -0
- package/lib/contracts/work.d.ts +173 -0
- package/lib/contracts/work.js +178 -0
- package/lib/control/base-move.d.ts +44 -0
- package/lib/control/base-move.js +90 -0
- package/lib/control/doctor.d.ts +50 -0
- package/lib/control/doctor.js +113 -0
- package/lib/control/harness.d.ts +1125 -0
- package/lib/control/harness.js +741 -0
- package/lib/control/provenance.d.ts +17 -0
- package/lib/control/provenance.js +25 -0
- package/lib/control/recovery.d.ts +237 -0
- package/lib/control/recovery.js +236 -0
- package/lib/control/review.d.ts +62 -0
- package/lib/control/review.js +178 -0
- package/lib/control/workflow.d.ts +247 -0
- package/lib/control/workflow.js +259 -0
- package/lib/engine/budget.d.ts +345 -0
- package/lib/engine/budget.js +278 -0
- package/lib/engine/classify.d.ts +8 -0
- package/lib/engine/classify.js +32 -0
- package/lib/engine/engine.d.ts +1527 -0
- package/lib/engine/engine.js +2259 -0
- package/lib/engine/failure.d.ts +1 -0
- package/lib/engine/failure.js +3 -0
- package/lib/engine/joint-runner.d.ts +257 -0
- package/lib/engine/joint-runner.js +254 -0
- package/lib/engine/measured.d.ts +15 -0
- package/lib/engine/measured.js +82 -0
- package/lib/engine/prompt.d.ts +66 -0
- package/lib/engine/prompt.js +131 -0
- package/lib/engine/property-recovery.d.ts +50 -0
- package/lib/engine/property-recovery.js +171 -0
- package/lib/engine/repair.d.ts +33 -0
- package/lib/engine/repair.js +82 -0
- package/lib/engine/result.d.ts +9 -0
- package/lib/engine/result.js +218 -0
- package/lib/engine/reuse.d.ts +80 -0
- package/lib/engine/reuse.js +102 -0
- package/lib/engine/runner.d.ts +360 -0
- package/lib/engine/runner.js +1836 -0
- package/lib/engine/standalone.d.ts +6 -0
- package/lib/engine/standalone.js +48 -0
- package/lib/engine/usage.d.ts +87 -0
- package/lib/engine/usage.js +165 -0
- package/lib/environment/isolation.d.ts +110 -0
- package/lib/environment/isolation.js +238 -0
- package/lib/environment/lifecycle.d.ts +40 -0
- package/lib/environment/lifecycle.js +197 -0
- package/lib/environment/live-calls.d.ts +14 -0
- package/lib/environment/live-calls.js +73 -0
- package/lib/environment/os-tools.d.ts +16 -0
- package/lib/environment/os-tools.js +35 -0
- package/lib/environment/process.d.ts +32 -0
- package/lib/environment/process.js +369 -0
- package/lib/environment/redaction.d.ts +22 -0
- package/lib/environment/redaction.js +102 -0
- package/lib/environment/resources.d.ts +31 -0
- package/lib/environment/resources.js +120 -0
- package/lib/index.d.ts +65 -0
- package/lib/index.js +67 -0
- package/lib/integrations/connector/commands.d.ts +358 -0
- package/lib/integrations/connector/commands.js +428 -0
- package/lib/integrations/connector/config.d.ts +215 -0
- package/lib/integrations/connector/config.js +214 -0
- package/lib/integrations/connector/delivery.d.ts +107 -0
- package/lib/integrations/connector/delivery.js +591 -0
- package/lib/integrations/connector/fake.d.ts +291 -0
- package/lib/integrations/connector/fake.js +786 -0
- package/lib/integrations/connector/history.d.ts +124 -0
- package/lib/integrations/connector/history.js +497 -0
- package/lib/integrations/connector/index.d.ts +16 -0
- package/lib/integrations/connector/index.js +16 -0
- package/lib/integrations/connector/redact.d.ts +19 -0
- package/lib/integrations/connector/redact.js +91 -0
- package/lib/integrations/connector/registry.d.ts +15 -0
- package/lib/integrations/connector/registry.js +43 -0
- package/lib/integrations/connector/snapshot.d.ts +131 -0
- package/lib/integrations/connector/snapshot.js +422 -0
- package/lib/integrations/connector/source.d.ts +37 -0
- package/lib/integrations/connector/source.js +73 -0
- package/lib/integrations/connector/steps.d.ts +71 -0
- package/lib/integrations/connector/steps.js +188 -0
- package/lib/integrations/connector/store.d.ts +140 -0
- package/lib/integrations/connector/store.js +277 -0
- package/lib/integrations/connector/summary.d.ts +38 -0
- package/lib/integrations/connector/summary.js +59 -0
- package/lib/integrations/connector/testing-worker.d.ts +1 -0
- package/lib/integrations/connector/testing-worker.js +81 -0
- package/lib/integrations/connector/testing.d.ts +205 -0
- package/lib/integrations/connector/testing.js +1615 -0
- package/lib/integrations/connector/transport.d.ts +240 -0
- package/lib/integrations/connector/transport.js +28 -0
- package/lib/integrations/memory/context.d.ts +120 -0
- package/lib/integrations/memory/context.js +239 -0
- package/lib/integrations/memory/index.d.ts +8 -0
- package/lib/integrations/memory/index.js +8 -0
- package/lib/integrations/memory/provider.d.ts +79 -0
- package/lib/integrations/memory/provider.js +22 -0
- package/lib/integrations/memory/sink.d.ts +56 -0
- package/lib/integrations/memory/sink.js +116 -0
- package/lib/integrations/memory/testing.d.ts +44 -0
- package/lib/integrations/memory/testing.js +61 -0
- package/lib/integrations/relay-v1/index.d.ts +122 -0
- package/lib/integrations/relay-v1/index.js +860 -0
- package/lib/integrations/relay-v2/index.d.ts +145 -0
- package/lib/integrations/relay-v2/index.js +752 -0
- package/lib/integrations/relay-v2/process.d.ts +32 -0
- package/lib/integrations/relay-v2/process.js +112 -0
- package/lib/integrations/relay-v2/protocol.d.ts +172 -0
- package/lib/integrations/relay-v2/protocol.js +142 -0
- package/lib/package.d.ts +2 -0
- package/lib/package.js +3 -0
- package/lib/profiles/resolve.d.ts +190 -0
- package/lib/profiles/resolve.js +273 -0
- package/lib/storage/document.d.ts +1234 -0
- package/lib/storage/document.js +80 -0
- package/lib/storage/sqlite.d.ts +35 -0
- package/lib/storage/sqlite.js +260 -0
- package/lib/testing/index.d.ts +5 -0
- package/lib/testing/index.js +5 -0
- package/lib/testing/store-contract.d.ts +8 -0
- package/lib/testing/store-contract.js +167 -0
- package/lib/toolchains/index.d.ts +9 -0
- package/lib/toolchains/index.js +9 -0
- package/lib/toolchains/inspect.d.ts +105 -0
- package/lib/toolchains/inspect.js +831 -0
- package/lib/toolchains/manifests.d.ts +67 -0
- package/lib/toolchains/manifests.js +238 -0
- package/lib/toolchains/probe.d.ts +28 -0
- package/lib/toolchains/probe.js +54 -0
- package/lib/toolchains/recipes.d.ts +33 -0
- package/lib/toolchains/recipes.js +51 -0
- package/lib/validate.d.ts +36 -0
- package/lib/validate.js +175 -0
- package/lib/verification/acceptance.d.ts +284 -0
- package/lib/verification/acceptance.js +670 -0
- package/lib/verification/checks.d.ts +72 -0
- package/lib/verification/checks.js +190 -0
- package/lib/verification/confirm.d.ts +125 -0
- package/lib/verification/confirm.js +411 -0
- package/lib/verification/corpus.d.ts +1303 -0
- package/lib/verification/corpus.js +744 -0
- package/lib/verification/dependencies.d.ts +66 -0
- package/lib/verification/dependencies.js +144 -0
- package/lib/verification/gates.d.ts +160 -0
- package/lib/verification/gates.js +600 -0
- package/lib/verification/joint.d.ts +63 -0
- package/lib/verification/joint.js +121 -0
- package/lib/verification/proof.d.ts +54 -0
- package/lib/verification/proof.js +96 -0
- package/lib/verification/property.d.ts +86 -0
- package/lib/verification/property.js +214 -0
- package/lib/verification/requirements.d.ts +25 -0
- package/lib/verification/requirements.js +69 -0
- package/lib/verification/self-check.d.ts +29 -0
- package/lib/verification/self-check.js +99 -0
- package/lib/verification/spike.d.ts +79 -0
- package/lib/verification/spike.js +124 -0
- package/package.json +100 -4
- package/profiles/expo-mobile.json +15 -0
- package/profiles/go-api.json +15 -0
- package/profiles/go-gotestsum.json +21 -0
- package/profiles/mobile-maestro.json +29 -0
- package/profiles/nest-api.json +26 -0
- package/profiles/next-product.json +72 -0
- package/profiles/node-checks.json +77 -0
- package/profiles/npm-ci.json +22 -0
- package/profiles/pnpm-frozen.json +24 -0
- package/profiles/python-api.json +32 -0
- package/profiles/python-uv.json +26 -0
- package/profiles/react-native.json +50 -0
- package/profiles/react-vite-admin.json +71 -0
- package/schemas/context-snapshot.schema.json +231 -0
- package/schemas/contract-document.schema.json +385 -0
- package/schemas/execution-document.schema.json +3695 -0
- package/schemas/execution-policy.schema.json +2196 -0
- package/schemas/joint-verification.schema.json +617 -0
- package/schemas/result-envelope.schema.json +1652 -0
- package/schemas/review-record.schema.json +177 -0
- package/schemas/run-event.schema.json +2458 -0
- package/schemas/run-result.schema.json +1570 -0
- package/schemas/stack-profile.schema.json +535 -0
- package/schemas/work-graph.schema.json +381 -0
- package/schemas/work-order.schema.json +256 -0
- package/skills/harness/SKILL.md +64 -0
- package/templates/AGENTS.md +13 -0
- package/templates/controller-mode/AGENTS.controller.md +58 -0
- package/templates/controller-mode/README.md +44 -0
- package/templates/graph.json +22 -0
- package/templates/policy.json +28 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# Договоры devcontour-harness
|
|
2
|
+
|
|
3
|
+
Источник истины — Zod-схемы в `src/contracts`. TypeScript-типы экспортируются
|
|
4
|
+
из `devcontour-harness` и `devcontour-harness/contracts`.
|
|
5
|
+
|
|
6
|
+
## JSON Schema и семантическая проверка
|
|
7
|
+
|
|
8
|
+
`schemas/<имя>.schema.json` генерируется из тех же схем (`npm run schemas`);
|
|
9
|
+
`npm run check` падает, если закоммиченные файлы устарели, а тест паритета
|
|
10
|
+
сверяет вердикты Zod и JSON Schema (Ajv, draft 2020-12) на положительных и
|
|
11
|
+
отрицательных примерах.
|
|
12
|
+
|
|
13
|
+
Harness не нормализует значения: строки вроде `title`, `goal`, критериев и
|
|
14
|
+
значений ресурсов обязаны быть уже без пробелов по краям — правило выражено
|
|
15
|
+
регулярным выражением и одинаково в Zod и JSON Schema.
|
|
16
|
+
|
|
17
|
+
Программная проверка доступна из `devcontour-harness`: `validateInputs`
|
|
18
|
+
(то же, что `harness validate`) и отдельные функции ниже.
|
|
19
|
+
|
|
20
|
+
JSON Schema выражает всё, что относится к одному значению: типы,
|
|
21
|
+
обязательность, закрытость объектов, пределы, регулярные выражения путей и
|
|
22
|
+
refs, варианты исходов. Связи **между** значениями проверяются только
|
|
23
|
+
функциями пакета и `harness validate`:
|
|
24
|
+
|
|
25
|
+
| Функция | Что проверяет |
|
|
26
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `graphIssues` | Повтор ID, неизвестная зависимость, цикл графа |
|
|
28
|
+
| `policyIssues` | Циклы компонентов и gates, test gate у репозитория, ресурсы, профили инструментов, `effort`, `fixture`, пары writer/reviewer |
|
|
29
|
+
| `crossIssues` | Связь поручений с политикой: роль, ресурсы, область записи и доказательства, требования, потребители, предпосылки |
|
|
30
|
+
| `contextIssues` | Содержимое снимка контекста совпадает с digests и пределами |
|
|
31
|
+
| `reviewIssues` | Ответ reviewer согласован с историей находок предмета |
|
|
32
|
+
|
|
33
|
+
Опубликованы: `work-order`, `work-graph`, `execution-policy`,
|
|
34
|
+
`context-snapshot`, `contract-document`, `run-result`, `result-envelope`,
|
|
35
|
+
`run-event`, `review-record`, `joint-verification`, `execution-document`.
|
|
36
|
+
|
|
37
|
+
## Версии
|
|
38
|
+
|
|
39
|
+
| Версия | Значение | Поле / константа |
|
|
40
|
+
| ------------- | ---------------------------------- | --------------------------- |
|
|
41
|
+
| Пакет | `0.1.0-alpha.N` до стабильного API | `HARNESS_VERSION` |
|
|
42
|
+
| Публичный API | `devcontour-harness/v1alpha1` | `apiVersion`, `API_VERSION` |
|
|
43
|
+
| Политика | `1` | `policyVersion` |
|
|
44
|
+
| Состояние | `1` | `stateVersion` |
|
|
45
|
+
|
|
46
|
+
Версии независимы. Пакет читает только перечисленные в
|
|
47
|
+
`SUPPORTED_*_VERSIONS`; неизвестная версия входа, политики или состояния
|
|
48
|
+
отклоняется до любой мутации и до выдачи claim. Для `0.x`: patch — совместимые
|
|
49
|
+
исправления, minor — отдельно описанные изменения договора, включая
|
|
50
|
+
несовместимые. Выпущенная версия неизменяема.
|
|
51
|
+
|
|
52
|
+
Digests (`workGraphDigest`, `policyDigest`, `sourceDigest`, `findingId`) —
|
|
53
|
+
SHA-256 канонического JSON (`canonicalJson`: ключи по порядку, `undefined`
|
|
54
|
+
опускается). Формула — часть договора; тесты закрепляют эталонные значения.
|
|
55
|
+
|
|
56
|
+
## Входы
|
|
57
|
+
|
|
58
|
+
### WorkOrder
|
|
59
|
+
|
|
60
|
+
Исполняемое поручение — снимок постановки, а не редактируемая задача. Лишние
|
|
61
|
+
поля отклоняются: поручение не несёт статуса, результата или согласования.
|
|
62
|
+
|
|
63
|
+
| Поле | Смысл |
|
|
64
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
65
|
+
| `apiVersion`, `id` | Версия договора и ID |
|
|
66
|
+
| `source` | `{connector, ref, revision}` — откуда и какая редакция |
|
|
67
|
+
| `title`, `goal` | Название и цель |
|
|
68
|
+
| `acceptance[]` | Критерии приёмки (1–30) |
|
|
69
|
+
| `role` | Роль из политики |
|
|
70
|
+
| `repositoryId` | Репозиторий из политики; `relatedRepositories[]` — поручение уровня workspace (минимум два) |
|
|
71
|
+
| `writeScope[]` | Область записи: относительные пути без glob, `.`/`..`; пересекается с областью роли; `["."]` — весь репозиторий (только как единственный элемент; защищённые, генерируемые пути и область роли по-прежнему ограничивают) |
|
|
72
|
+
| `dependsOn[]` | Поручения графа или подтверждённые предпосылки |
|
|
73
|
+
| `gates[]` | Область доказательства: gates и группы `@имя`, замкнута по `dependsOn`, содержит test gate; нет поля — все gates |
|
|
74
|
+
| `consumers[]` | Потребители (зависят от репозитория поручения) и их gates |
|
|
75
|
+
| `properties[]` | Свойства договора проверки, подтверждаемые сейчас |
|
|
76
|
+
| `resources[]` | Ресурсы политики |
|
|
77
|
+
| `requirements[]` | Требование: текст, его SHA-256, test gate из области, testcase |
|
|
78
|
+
| `contracts[]` | `{id, digest}` закреплённых контрактов |
|
|
79
|
+
| `context[]` | ID обязательных источников контекста |
|
|
80
|
+
|
|
81
|
+
### WorkGraph
|
|
82
|
+
|
|
83
|
+
`{apiVersion, id, source, orders[], prerequisites[]}` — неизменяемый снимок
|
|
84
|
+
состава и зависимостей одного согласования; `workGraphDigest` закрепляет
|
|
85
|
+
согласование. Предпосылка — `{id, repositoryId, resultSha, receipt}`,
|
|
86
|
+
`receipt` — `{kind: 'engine', runId}` или `{kind: 'trusted', issuer, digest}`.
|
|
87
|
+
Доверие к `trusted` решает `WorkSource.trusts`: `Harness.run({ source })`
|
|
88
|
+
спрашивает источник графа (его `id` обязан совпасть с `graph.source.connector`);
|
|
89
|
+
без источника доверенных receipt нет. В обоих случаях движок проверяет, что
|
|
90
|
+
result SHA доступен в target ref.
|
|
91
|
+
|
|
92
|
+
### ExecutionPolicy
|
|
93
|
+
|
|
94
|
+
| Поле | Смысл |
|
|
95
|
+
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
96
|
+
| `policyVersion`, `mode` | `1`; `live` или `fixture` (runtime `fixture` только в нём) |
|
|
97
|
+
| `repositories[]` | ID, путь, `targetRef` по правилам `git check-ref-format`, `dependsOn`, gates (`test` с обязательным JUnit внутри worktree, `check`), группы gates (≤100), защищённые и генерируемые пути, среда, lifecycle, шаги подготовки, сборки зависимостей и preflight |
|
|
98
|
+
| `workspaceGates[]`, `verificationMode`, `workspaceLifecycle` | Gates совместной проверки комбинации репозиториев; `all` или `affected`; окружение совместной проверки |
|
|
99
|
+
| `roles{}` | `writer`, `writePaths`, своё правило `review` кода, `requiresContract` |
|
|
100
|
+
| `review.code / plan / contract` | `{reviewer, vendor}`; reviewer задан явно |
|
|
101
|
+
| `approvalMode` | `agent` или `operator` для технического согласования |
|
|
102
|
+
| `isolation` | `{mode: 'os' \| 'none', domains[]}`, по умолчанию `os` |
|
|
103
|
+
| `toolProfiles{}`, `environment`, `lifecycle`, `resources[]` | Инструменты (у профиля — встроенные инструменты claude, shell и сеть codex, MCP-серверы `mcp{}`: stdio-команда или http-адрес, только перечисленные `tools`, учётные данные — именами переменных `env`/`bearerTokenEnv`, передаются CLI по имени), среда, ресурсы (порты 1024–65535) |
|
|
104
|
+
| `concurrency`, `leaseMs`, `runTimeoutMs`, `reviewProbes` | Пределы исполнения |
|
|
105
|
+
| `maxAttempts`, `repairBudget`, `reuseImplementation` | Повторы и повторное использование кандидата |
|
|
106
|
+
| `reviewProtocolRetries` | Необязательное: дополнительные вызовы reviewer кода при ошибке протокола ответа (0–2; нет поля — 1, умолчание не подставляется и digest политики не меняет), [review-protocol.md](review-protocol.md) |
|
|
107
|
+
| `budgets{work, group, total, onUnknown}`, `prices[]` | Пределы USD и/или времени; тарифы |
|
|
108
|
+
|
|
109
|
+
Переменные `HARNESS_*` и `DEVCONTOUR_*` политика задать не может.
|
|
110
|
+
|
|
111
|
+
`policyDigest(policy)` — digest загруженной политики целиком: им сверяются
|
|
112
|
+
применённая политика (`control.appliedPolicy`) и запрос операции
|
|
113
|
+
`control.reconfigure`. `executionDigest(policy)` — digest исполнительной
|
|
114
|
+
части без `budgets` и `prices`: основание согласования графа
|
|
115
|
+
(`GraphState.policyDigest`) и fencing попыток (`AttemptState.policyDigest`
|
|
116
|
+
у standalone-хоста). Поднятый предел бюджета поэтому согласования не
|
|
117
|
+
сбрасывает.
|
|
118
|
+
|
|
119
|
+
Хост, который строит политику из собственной конфигурации, может передать
|
|
120
|
+
движку своё тождество применённой политики (`EngineOptions.policyIdentity`,
|
|
121
|
+
digest по формуле хоста — например, файла конфигурации). Тогда применённая
|
|
122
|
+
политика и запрос операции сверяются с ним, а не с `policyDigest(policy)`;
|
|
123
|
+
изменение политики в памяти после создания движка по-прежнему проверяется по
|
|
124
|
+
её содержимому.
|
|
125
|
+
|
|
126
|
+
`EngineOptions.recordPolicyOnLead: false` — хост сам записывает применённую
|
|
127
|
+
политику при запуске своего планировщика; получение роли controller (в том
|
|
128
|
+
числе для прямой выдачи попытки) её тогда не записывает.
|
|
129
|
+
|
|
130
|
+
Автор (`--author`): `codex`, `claude`, `fixture` или `external` — человек или
|
|
131
|
+
инструмент вне harness; вендор `external` не совпадает ни с одним runtime.
|
|
132
|
+
|
|
133
|
+
**Выбор reviewer** — только `selectReviewer(policy, kind, writer, role)`:
|
|
134
|
+
`different-vendor` (умолчание) отклоняет reviewer того же вендора
|
|
135
|
+
(`REVIEWER_SAME_VENDOR`), `same-vendor-allowed` разрешает его. Неявного
|
|
136
|
+
«противоположного runtime» нет. Проверка входов отклоняет такую политику
|
|
137
|
+
целиком; хост, ведущий движок без неё, получает блокер
|
|
138
|
+
`REVIEWER_SAME_VENDOR` только у поручений этой роли — остальная очередь
|
|
139
|
+
выдаётся.
|
|
140
|
+
|
|
141
|
+
Правило может перечислить запасных reviewer (`alternates`, по порядку):
|
|
142
|
+
берётся первый из `[reviewer, ...alternates]`, допустимый правилом вендора
|
|
143
|
+
для этого автора. Так хост явно задаёт «reviewer другого вендора, чем
|
|
144
|
+
автор», не полагаясь на неявный выбор. Запасные reviewer проверяются
|
|
145
|
+
`policyIssues` так же, как основной.
|
|
146
|
+
|
|
147
|
+
**Раунд технического ревью** плана или контракта — `technicalReview(engine,
|
|
148
|
+
policy, adapters, input)`: та же реализация, что у `Harness.review`. Хост
|
|
149
|
+
передаёт предмет (ID, digest, автор), свои разделы запроса, рабочий каталог
|
|
150
|
+
reviewer и учёт вызова; harness выбирает reviewer, вызывает его под
|
|
151
|
+
бюджетом, требует состояние каждой прежней открытой находки и записывает
|
|
152
|
+
`ReviewRecord`. Предел раундов (`maxRounds`) задаёт вызывающий:
|
|
153
|
+
`Harness.review` — `2 × maxAttempts`.
|
|
154
|
+
Хост, который вёл раунды предмета до harness и хранит их сам, передаёт их
|
|
155
|
+
как `history: {rounds, findings[]}`: пока у предмета нет раундов в движке,
|
|
156
|
+
первый раунд получает номер `rounds + 1`, а находки последнего прежнего
|
|
157
|
+
раунда — прежние открытые находки, состояние которых reviewer обязан назвать.
|
|
158
|
+
Это только история: прежним раундам не приписываются digest, назначение
|
|
159
|
+
reviewer или одобрение. Дальше нумерация идёт подряд от первого раунда
|
|
160
|
+
движка, и `history` больше не учитывается.
|
|
161
|
+
|
|
162
|
+
### ContextSnapshot
|
|
163
|
+
|
|
164
|
+
`{apiVersion, sources[], missing[]}`. Источник —
|
|
165
|
+
`{id, kind, version, repositoryId?, revision?, required, files[], references[], digest, hostDigest?}`;
|
|
166
|
+
файл — `{path, digest, bytes, content: {encoding: 'utf8' | 'base64', data}}`.
|
|
167
|
+
Содержимое передаётся в снимке: источник может не быть Git, и движок обязан
|
|
168
|
+
получить ровно те байты, на которые выдан digest. `contextIssues` сверяет
|
|
169
|
+
SHA-256 и размер каждого файла и `sourceDigest` источника; `pinnedBytes`
|
|
170
|
+
отдаёт байты только после проверки. Пределы: 2 МиБ на файл, 16 МиБ на снимок.
|
|
171
|
+
Снимок попытки сохраняется по digest (`context-snapshots`) и используется
|
|
172
|
+
после рестарта без повторного чтения источника.
|
|
173
|
+
|
|
174
|
+
### ContractDocument
|
|
175
|
+
|
|
176
|
+
`{apiVersion, id, repositoryId?, title, content, artifacts?, checks?}` — вход
|
|
177
|
+
`review-contract`. `artifacts` — закреплённые файлы контракта (`{path, blob}`,
|
|
178
|
+
Git blob в репозитории `repositoryId`); `checks` — договор проверки
|
|
179
|
+
(`checkDeclarationSchema`, `version: 1`): gate, обязательства по property ID
|
|
180
|
+
(требования, тип обещания, область входов, правила ответа, способ проверки и
|
|
181
|
+
его файлы, семейства и минимальные выборки, корпус) и политика расширения
|
|
182
|
+
корпуса. Прошедший ревью документ хранится по digest (`contract-documents`):
|
|
183
|
+
из него движок строит манифест генеративного gate поручения.
|
|
184
|
+
|
|
185
|
+
## Модель исполнения
|
|
186
|
+
|
|
187
|
+
Схемы в `execution.ts` — то, что `ExecutionStore` хранит транзакционно:
|
|
188
|
+
|
|
189
|
+
| Запись | Содержание |
|
|
190
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
191
|
+
| `GraphState` | Граф, его digest, digest политики, техническое согласование (с `approval.context` — снимок контекста, который видел reviewer плана; только он исполняется и принимается) |
|
|
192
|
+
| `WorkState` | Закреплённое поручение, статус, попытки, результат, класс отказа, согласованные digests, удержание, блок бюджета, версия корпуса, эпизод восстановления по свойству |
|
|
193
|
+
| `AttemptState` | Владение (`token`, `owner`, `leaseUntil`), runtime и reviewer, фаза, SHA, evidence, раскрытые gates, потребители и что у них проверено, версия проверок, контекст, зависимости и свежесть, основание и источник reuse, черновик, выбор из очереди, замеры, `engineVersion`, `consumerVersion` |
|
|
194
|
+
| `EvidenceRecord` | Фаза, SHA, gate, исход, команда, лог, digest, testcases, отчёт свойств, осмотр ревью, версия проверок |
|
|
195
|
+
| `ControlState` | Пауза и её причина, классы отказов, ожидания, применённая политика, reconfigure |
|
|
196
|
+
| `ControllerLease` | Единственный действующий controller; `engineVersion` (с 0.1.0-alpha.2) — версия движка процесса: роль другой версии или без версии не перенимается, пока она жива |
|
|
197
|
+
| `CallRecord` | Вызов модели: стадия, runtime, сообщённая модель, версия, исход, процесс, монотонное время, закреплённая атрибуция (`workId`, `groupId`, `workIds`), вид предмета (`subjectKind`: поручение, группа, прочее), счётчики, стоимость и её источник |
|
|
198
|
+
| `ReviewRecord` | Раунд ревью плана/контракта: предмет, digest, номер раунда, вердикт, назначение reviewer, digest закреплённого контекста плана, все находки предмета со статусами `open/closed/withdrawn` |
|
|
199
|
+
|
|
200
|
+
Локальные записи адресуются `(namespace, owner, key)`; пространства и их
|
|
201
|
+
схемы — `localSchemas` (`usage`, `context-snapshots`, `run-keys`, `delivery`,
|
|
202
|
+
`reviews`, `check-suites` — корпус подтверждённых случаев, `workflow-jobs` —
|
|
203
|
+
техническая очередь ведущего, `contract-documents` — документы контрактов,
|
|
204
|
+
прошедшие ревью, по digest, `spikes` — эксперименты выполнимости
|
|
205
|
+
репозитория, `reproductions` — реестр воспроизведений из находок ревью по
|
|
206
|
+
поручениям). `owner` — репозиторий или `@workspace`.
|
|
207
|
+
|
|
208
|
+
## Ответы исполнителей
|
|
209
|
+
|
|
210
|
+
Runtime возвращает сырой ответ; движок разбирает его
|
|
211
|
+
`implementationResultSchema` и `reviewResultSchema`. Ответ вне схемы — отказ,
|
|
212
|
+
а не самооценка writer. Reviewer называет состояние каждой прежней открытой
|
|
213
|
+
находки (`previous[]`); `reviewIssues` отклоняет `approved` при блокирующей
|
|
214
|
+
находке, в том числе прежней открытой, неназванную прежнюю находку и ссылку на
|
|
215
|
+
неизвестную. Идентичность находки плана/контракта — `findingId(subject, {rule, message})`;
|
|
216
|
+
невалидный ответ раунд не применяет (переходы и новые находки не записываются).
|
|
217
|
+
|
|
218
|
+
Ревью кода ведёт историю находок поручения с ID, выданными controller
|
|
219
|
+
(`codeReviewHistory`, `checkCodeReview`): reviewer называет ровно один переход
|
|
220
|
+
каждой открытой находки, ошибка протокола (`REVIEW_PROTOCOL_INVALID`,
|
|
221
|
+
причина и путь поля, например `previous[0].id`) отделена от содержательного
|
|
222
|
+
отказа (`REVIEW_REJECTED`) и даёт ограниченный повтор только reviewer
|
|
223
|
+
(`reviewProtocolRetries`, 0–2, по умолчанию 1). Evidence ревью несёт
|
|
224
|
+
аддитивное поле `reviewRound`, находки — `id`/`status`, ссылки результата —
|
|
225
|
+
`review`. Правила — [docs/review-protocol.md](review-protocol.md).
|
|
226
|
+
|
|
227
|
+
## Выходы
|
|
228
|
+
|
|
229
|
+
### RunResult
|
|
230
|
+
|
|
231
|
+
Варианты по `outcome`:
|
|
232
|
+
|
|
233
|
+
- `accepted` — `shas{base, candidate, integration, result}` все обязательны
|
|
234
|
+
(result = integration; он уже в target ref);
|
|
235
|
+
- `rejected | blocked | cancelled | stopped` — `stopReason{code, message}` с
|
|
236
|
+
кодом из договора ошибок; result SHA нет.
|
|
237
|
+
|
|
238
|
+
Общие поля: `workOrderId`, `graphId`, `source`, `runId`, `attempt`,
|
|
239
|
+
`repositoryId`, `targetRef`, `inputs` (версии harness и потребителя, версия
|
|
240
|
+
состояния, digests поручения, графа, политики, контекста, версия проверок),
|
|
241
|
+
`checked` (снимки зависимостей, их свежесть, проверенная комбинация каждого
|
|
242
|
+
потребителя), `evidence[]`, `findings[]`, `limitations[]`, `finishedAt`.
|
|
243
|
+
Свежесть записывается, а не запрещает приёмку. Необязательные поля
|
|
244
|
+
доказательства: `inputs.corpus` (закреплённая версия корпуса),
|
|
245
|
+
`inputs.requiredGates` (раскрытые при выдаче gates), `inputs.writer` (writer
|
|
246
|
+
попытки), у ссылки на evidence —
|
|
247
|
+
`checks` (версия проверок записи), `property{level, manifest}` (уровень и
|
|
248
|
+
манифест генеративного gate), `tests[]`/`testsTruncated` (выполненные тесты
|
|
249
|
+
собственной проверки интеграции — доказательство названного testcase).
|
|
250
|
+
Получатель проверяет результат `resultProblems(result, context)` /
|
|
251
|
+
`assertResult`. Всё, что результат утверждает о поручении, области, входах и
|
|
252
|
+
ревью, сверяется с тем, что получатель знает сам, а не с другими полями того
|
|
253
|
+
же результата: согласованная сама с собой подделка иначе проходила бы.
|
|
254
|
+
|
|
255
|
+
**Контекст получателя** (`ReceiverContext`):
|
|
256
|
+
|
|
257
|
+
- `order` — постановка поручения у получателя; `graphId` — граф, в котором
|
|
258
|
+
он её держит; `contracts` — документы договоров поручения;
|
|
259
|
+
- `policy` — политика получателя (`repositories`, `roles`, `review`): по ней
|
|
260
|
+
раскрываются область поручения и потребителей, замыкания зависимостей,
|
|
261
|
+
target ref, writer роли и назначенный reviewer с правилом вендора;
|
|
262
|
+
- `contextDigest` — снимок контекста, закреплённый согласованием графа
|
|
263
|
+
(`null` — без контекста);
|
|
264
|
+
- `suite`, `checkVersion` — корпус по копии получателя и закреплённая за
|
|
265
|
+
поручением версия (`null` — без корпуса; у поручения с договором проверки
|
|
266
|
+
обязательна); `specDigest` — digest согласованной постановки (по
|
|
267
|
+
умолчанию digest поручения);
|
|
268
|
+
- `unobserved` — результат прежнего формата хоста, в котором входы попытки
|
|
269
|
+
не наблюдались: `dependencies` — нет снимков собственных зависимостей и их
|
|
270
|
+
свежести, `consumers` — нет свежести потребителей. Такие пустые списки не
|
|
271
|
+
сверяются с замыканием (их нет, и проверке они не подлежат); непустые
|
|
272
|
+
списки, снимки зависимостей потребителя и провайдер сверяются как обычно.
|
|
273
|
+
Какой результат имеет прежний формат, решает хост по своим правилам формата.
|
|
274
|
+
- `assignment` — чем подтверждено ревью: `current` (по умолчанию) — writer и
|
|
275
|
+
reviewer назначены текущей политикой получателя; `recorded` — результат
|
|
276
|
+
несёт своё назначение, и хост перепроверяет его позже, когда назначение
|
|
277
|
+
ролей могло смениться: writer и reviewer — записанные, оба должны быть
|
|
278
|
+
runtime политики получателя, правило вендора роли соблюдено.
|
|
279
|
+
|
|
280
|
+
Чего нет в контексте (репозиторий, потребитель, зависимость или роль не
|
|
281
|
+
описаны в политике получателя), — отказ, а не PASS. Результат прежнего
|
|
282
|
+
формата (без версии проверок, области и writer) читается на прежнем уровне
|
|
283
|
+
только у поручения без договора проверки.
|
|
284
|
+
|
|
285
|
+
**Модель доверия** — категория каждого поля принятого результата
|
|
286
|
+
(`receiptTrust` в `src/verification/acceptance.ts`):
|
|
287
|
+
|
|
288
|
+
- _ожидание получателя_ — сверяется с ожиданием, вычисленным из контекста;
|
|
289
|
+
- _согласованность_ — сверяется с другими полями результата (SHA фаз,
|
|
290
|
+
свежесть со снимками, уникальность записей);
|
|
291
|
+
- _сведение_ — ничего не доказывает, вердикт на него не опирается;
|
|
292
|
+
- _схема_ — значение фиксировано схемой.
|
|
293
|
+
|
|
294
|
+
Подлинность SHA, деревьев, artifacts и записей (их наличие в Git и в
|
|
295
|
+
хранилище исполнителя) получатель не удостоверяет — это транспорт хоста.
|
|
296
|
+
Таблица — проверяемое утверждение: <!-- repo-only -->`tests/receipt-trust.test.ts`<!-- /repo-only --> по JSON
|
|
297
|
+
Schema строит подделку каждого поля (другое значение, удаление
|
|
298
|
+
необязательного поля, пустой массив, повтор и удаление элемента) на двух
|
|
299
|
+
фикстурах и требует отказа для первых двух категорий и того же вердикта для
|
|
300
|
+
сведений; тест сверяет и эту таблицу с кодом.
|
|
301
|
+
|
|
302
|
+
| Поле | Категория | Правило |
|
|
303
|
+
| ------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
304
|
+
| `apiVersion` | схема | литерал версии API |
|
|
305
|
+
| `outcome` | ожидание получателя | только accepted подтверждает приёмку |
|
|
306
|
+
| `workOrderId` | ожидание получателя | ID поручения получателя |
|
|
307
|
+
| `graphId` | ожидание получателя | граф поручения у получателя |
|
|
308
|
+
| `source.connector` | ожидание получателя | источник поручения получателя |
|
|
309
|
+
| `source.ref` | ожидание получателя | источник поручения получателя |
|
|
310
|
+
| `source.revision` | ожидание получателя | редакция поручения получателя |
|
|
311
|
+
| `runId` | сведение | идентификатор попытки у исполнителя |
|
|
312
|
+
| `attempt` | сведение | номер попытки у исполнителя |
|
|
313
|
+
| `repositoryId` | ожидание получателя | репозиторий поручения |
|
|
314
|
+
| `targetRef` | ожидание получателя | target ref репозитория в политике получателя |
|
|
315
|
+
| `inputs.harnessVersion` | сведение | версия исполнителя |
|
|
316
|
+
| `inputs.consumerVersion` | сведение | версия хоста исполнителя |
|
|
317
|
+
| `inputs.stateVersion` | схема | литерал версии состояния |
|
|
318
|
+
| `inputs.workOrderDigest` | ожидание получателя | digest поручения получателя |
|
|
319
|
+
| `inputs.graphDigest` | сведение | граф мог получить новую редакцию при неизменном поручении; привязка — digest поручения и его источник |
|
|
320
|
+
| `inputs.policyDigest` | согласованность | входит в вычисление версии проверок |
|
|
321
|
+
| `inputs.contextDigest` | ожидание получателя | снимок контекста согласования у получателя |
|
|
322
|
+
| `inputs.checks` | ожидание получателя | версия проверок, вычисленная получателем |
|
|
323
|
+
| `inputs.corpus.suite` | ожидание получателя | корпус, закреплённый за поручением у получателя |
|
|
324
|
+
| `inputs.corpus.number` | ожидание получателя | номер этой версии в корпусе получателя |
|
|
325
|
+
| `inputs.corpus.digest` | ожидание получателя | версия корпуса, закреплённая у получателя |
|
|
326
|
+
| `inputs.corpus` | ожидание получателя | привязка к корпусу, закреплённому у получателя |
|
|
327
|
+
| `inputs.requiredGates` | ожидание получателя | область поручения, раскрытая по политике получателя; без поля — область получателя |
|
|
328
|
+
| `inputs.requiredGates[]` | ожидание получателя | ровно эта область, без повторов |
|
|
329
|
+
| `inputs.writer` | ожидание получателя | writer роли поручения; без поля — writer роли получателя |
|
|
330
|
+
| `inputs.writer.runtime` | ожидание получателя | writer роли поручения в политике получателя |
|
|
331
|
+
| `inputs.writer.model` | сведение | модель writer |
|
|
332
|
+
| `checked.dependencies` | ожидание получателя | замыкание зависимостей репозитория по политике получателя |
|
|
333
|
+
| `checked.dependencies[]` | ожидание получателя | ровно один снимок каждой зависимости замыкания |
|
|
334
|
+
| `checked.dependencies[].repositoryId` | ожидание получателя | зависимость из замыкания |
|
|
335
|
+
| `checked.dependencies[].sha` | согласованность | совпадает со снимком в свежести |
|
|
336
|
+
| `checked.dependencies[].tree` | сведение | подлинность дерева — Git хоста |
|
|
337
|
+
| `checked.dependencies[].artifacts` | сведение | подлинность artifacts — Git хоста |
|
|
338
|
+
| `checked.dependencies[].artifacts[]` | сведение | подлинность artifacts — Git хоста |
|
|
339
|
+
| `checked.dependencies[].artifacts[].path` | сведение | подлинность artifacts — Git хоста |
|
|
340
|
+
| `checked.dependencies[].artifacts[].digest` | сведение | подлинность artifacts — Git хоста |
|
|
341
|
+
| `checked.freshness` | ожидание получателя | свежесть каждой зависимости замыкания |
|
|
342
|
+
| `checked.freshness[]` | ожидание получателя | ровно одна запись на зависимость |
|
|
343
|
+
| `checked.freshness[].repositoryId` | ожидание получателя | зависимость из замыкания |
|
|
344
|
+
| `checked.freshness[].snapshot` | согласованность | совпадает со снимком зависимости |
|
|
345
|
+
| `checked.freshness[].head` | согласованность | fresh ⇔ head = snapshot; значение головы — наблюдение |
|
|
346
|
+
| `checked.freshness[].fresh` | согласованность | fresh ⇔ head = snapshot |
|
|
347
|
+
| `checked.consumers` | ожидание получателя | объявленные потребители поручения |
|
|
348
|
+
| `checked.consumers[]` | ожидание получателя | ровно одно описание каждого объявленного потребителя |
|
|
349
|
+
| `checked.consumers[].repositoryId` | ожидание получателя | объявленный потребитель |
|
|
350
|
+
| `checked.consumers[].gates` | ожидание получателя | область потребителя, раскрытая по политике получателя |
|
|
351
|
+
| `checked.consumers[].gates[]` | ожидание получателя | ровно эта область, без повторов |
|
|
352
|
+
| `checked.consumers[].sha` | согласованность | совпадает со снимком потребителя в его свежести |
|
|
353
|
+
| `checked.consumers[].tree` | сведение | подлинность дерева — Git хоста |
|
|
354
|
+
| `checked.consumers[].dependencies` | ожидание получателя | замыкание зависимостей потребителя по политике получателя |
|
|
355
|
+
| `checked.consumers[].dependencies[]` | ожидание получателя | ровно один снимок каждой зависимости замыкания |
|
|
356
|
+
| `checked.consumers[].dependencies[].repositoryId` | ожидание получателя | зависимость из замыкания |
|
|
357
|
+
| `checked.consumers[].dependencies[].sha` | согласованность | у провайдера — result SHA; у прочих — снимок в свежести |
|
|
358
|
+
| `checked.consumers[].dependencies[].tree` | сведение | подлинность дерева — Git хоста |
|
|
359
|
+
| `checked.consumers[].dependencies[].artifacts` | сведение | подлинность artifacts — Git хоста |
|
|
360
|
+
| `checked.consumers[].dependencies[].artifacts[]` | сведение | подлинность artifacts — Git хоста |
|
|
361
|
+
| `checked.consumers[].dependencies[].artifacts[].path` | сведение | подлинность artifacts — Git хоста |
|
|
362
|
+
| `checked.consumers[].dependencies[].artifacts[].digest` | сведение | подлинность artifacts — Git хоста |
|
|
363
|
+
| `checked.consumers[].freshness` | ожидание получателя | свежесть каждого входа потребителя, кроме провайдера, и его самого |
|
|
364
|
+
| `checked.consumers[].freshness[]` | ожидание получателя | ровно одна запись на вход |
|
|
365
|
+
| `checked.consumers[].freshness[].repositoryId` | ожидание получателя | вход потребителя |
|
|
366
|
+
| `checked.consumers[].freshness[].snapshot` | согласованность | совпадает со снимком входа |
|
|
367
|
+
| `checked.consumers[].freshness[].head` | согласованность | fresh ⇔ head = snapshot; значение головы — наблюдение |
|
|
368
|
+
| `checked.consumers[].freshness[].fresh` | согласованность | fresh ⇔ head = snapshot |
|
|
369
|
+
| `evidence` | ожидание получателя | решающие записи всех обязательных проверок обеих фаз |
|
|
370
|
+
| `evidence[]` | согласованность | записи уникальны по ID |
|
|
371
|
+
| `evidence[].id` | согласованность | уникален |
|
|
372
|
+
| `evidence[].kind` | согласованность | согласован с gate (ревью ⇔ independent-review) и с потребителем |
|
|
373
|
+
| `evidence[].phase` | согласованность | SHA записи — SHA её фазы |
|
|
374
|
+
| `evidence[].gate` | ожидание получателя | обязательная проверка поручения, потребителя или ревью |
|
|
375
|
+
| `evidence[].sha` | согласованность | SHA фазы: candidate или result |
|
|
376
|
+
| `evidence[].passed` | ожидание получателя | решающая запись каждой обязательной проверки — PASS |
|
|
377
|
+
| `evidence[].digest` | сведение | подлинность записи — хранилище исполнителя |
|
|
378
|
+
| `evidence[].summary` | сведение | описание записи |
|
|
379
|
+
| `evidence[].consumer` | ожидание получателя | объявленный потребитель |
|
|
380
|
+
| `evidence[].checks` | ожидание получателя | версия проверок, вычисленная получателем, у каждой записи |
|
|
381
|
+
| `evidence[].tests` | ожидание получателя | доказательство названного testcase решающей записью |
|
|
382
|
+
| `evidence[].tests[]` | ожидание получателя | элемент названного testcase; прочие элементы — сведения |
|
|
383
|
+
| `evidence[].tests[].id` | ожидание получателя | ID названного testcase |
|
|
384
|
+
| `evidence[].tests[].status` | ожидание получателя | названный testcase прошёл |
|
|
385
|
+
| `evidence[].tests[].opaque` | ожидание получателя | имя названного testcase не скрыто |
|
|
386
|
+
| `evidence[].testsTruncated` | ожидание получателя | список решающей записи полон |
|
|
387
|
+
| `evidence[].property` | ожидание получателя | доказательство договора проверки; у записи потребителя — только legacy без манифеста |
|
|
388
|
+
| `evidence[].property.level` | ожидание получателя | уровень manifest; у записи потребителя — legacy |
|
|
389
|
+
| `evidence[].property.manifest` | ожидание получателя | манифест договора поручения |
|
|
390
|
+
| `evidence[].property.manifest.digest` | ожидание получателя | манифест, вычисленный получателем |
|
|
391
|
+
| `evidence[].property.manifest.properties` | ожидание получателя | свойства поручения |
|
|
392
|
+
| `evidence[].property.manifest.properties[]` | ожидание получателя | свойства поручения |
|
|
393
|
+
| `evidence[].property.manifest.corpus` | ожидание получателя | корпус закреплённой версии |
|
|
394
|
+
| `evidence[].property.manifest.corpus.digest` | ожидание получателя | версия корпуса у получателя |
|
|
395
|
+
| `evidence[].property.manifest.corpus.cases` | ожидание получателя | число случаев этой версии |
|
|
396
|
+
| `evidence[].reviewer` | ожидание получателя | reviewer, назначенный политикой получателя |
|
|
397
|
+
| `evidence[].reviewer.runtime` | ожидание получателя | reviewer роли в политике получателя |
|
|
398
|
+
| `evidence[].reviewer.model` | сведение | модель reviewer |
|
|
399
|
+
| `evidence[].reviewer.sameVendor` | согласованность | вендоры writer и reviewer |
|
|
400
|
+
| `evidence[].review` | сведение | раунд протокола ревью кода |
|
|
401
|
+
| `evidence[].review.round` | сведение | раунд протокола ревью кода |
|
|
402
|
+
| `evidence[].review.call` | сведение | раунд протокола ревью кода |
|
|
403
|
+
| `evidence[].review.protocol` | сведение | раунд протокола ревью кода |
|
|
404
|
+
| `evidence[].review.issues` | сведение | раунд протокола ревью кода |
|
|
405
|
+
| `evidence[].review.issues[]` | сведение | раунд протокола ревью кода |
|
|
406
|
+
| `evidence[].review.issues[].path` | сведение | раунд протокола ревью кода |
|
|
407
|
+
| `evidence[].review.issues[].reason` | сведение | раунд протокола ревью кода |
|
|
408
|
+
| `evidence[].review.issues[].message` | сведение | раунд протокола ревью кода |
|
|
409
|
+
| `evidence[].review.transitions` | сведение | раунд протокола ревью кода |
|
|
410
|
+
| `evidence[].review.transitions[]` | сведение | раунд протокола ревью кода |
|
|
411
|
+
| `evidence[].review.transitions[].id` | сведение | раунд протокола ревью кода |
|
|
412
|
+
| `evidence[].review.transitions[].from` | сведение | раунд протокола ревью кода |
|
|
413
|
+
| `evidence[].review.transitions[].to` | сведение | раунд протокола ревью кода |
|
|
414
|
+
| `findings` | сведение | сводка находок может относиться к отклонённым раундам |
|
|
415
|
+
| `findings[]` | сведение | сводка находок |
|
|
416
|
+
| `findings[].severity` | сведение | сводка находок |
|
|
417
|
+
| `findings[].message` | сведение | сводка находок |
|
|
418
|
+
| `findings[].path` | сведение | сводка находок |
|
|
419
|
+
| `findings[].line` | сведение | сводка находок |
|
|
420
|
+
| `findings[].rule` | сведение | сводка находок |
|
|
421
|
+
| `findings[].id` | сведение | сводка находок |
|
|
422
|
+
| `findings[].status` | сведение | сводка находок |
|
|
423
|
+
| `limitations` | сведение | чего результат не доказывает |
|
|
424
|
+
| `limitations[]` | сведение | чего результат не доказывает |
|
|
425
|
+
| `finishedAt` | сведение | время окончания |
|
|
426
|
+
| `shas.base` | сведение | база кандидата; подлинность — Git хоста |
|
|
427
|
+
| `shas.candidate` | согласованность | SHA решающих записей кандидата |
|
|
428
|
+
| `shas.integration` | согласованность | равен result SHA |
|
|
429
|
+
| `shas.result` | согласованность | SHA решающих записей интеграции и снимка провайдера у потребителей |
|
|
430
|
+
|
|
431
|
+
### DeliveryState и ResultEnvelope
|
|
432
|
+
|
|
433
|
+
Доставка — отдельно от исхода: `{sink, key, revision, status: pending |
|
|
434
|
+
delivered | failed | conflict, attempts, lastError?, currentRevision?,
|
|
435
|
+
receipt?, updatedAt}`. `harness result` выдаёт `{apiVersion, result,
|
|
436
|
+
delivery[]}`.
|
|
437
|
+
|
|
438
|
+
### JointVerification
|
|
439
|
+
|
|
440
|
+
Совместная проверка закреплённой комбинации SHA нескольких репозиториев:
|
|
441
|
+
`{id, status, policyDigest, specDigest, workIds[], manifest{repo: {sha, tree}},
|
|
442
|
+
manifestDigest, impact?, evidence[], error?}`. Смена любого SHA делает
|
|
443
|
+
результат устаревшим; атомарность продвижения нескольких репозиториев не
|
|
444
|
+
заявляется. Продуктовое принятие комбинации решает хост. Пока manifest не
|
|
445
|
+
закреплён, `impact` может нести только ссылку на базовую проверку
|
|
446
|
+
(`baseline`), выбранную хостом для режима `affected`.
|
|
447
|
+
|
|
448
|
+
### RunEvent
|
|
449
|
+
|
|
450
|
+
`{apiVersion, seq, at, type, graphId?, workId?, runId?, attempt?, payload}`.
|
|
451
|
+
`seq` строго возрастает. Нагрузка каждого из типов (`eventPayloads`) — закрытая
|
|
452
|
+
схема: лишних полей нет, поэтому токен владения, секрет или объект попытки в
|
|
453
|
+
событие не попадает.
|
|
454
|
+
|
|
455
|
+
`transactionKinds` — имена транзакций исполнения; совпадают с сохранёнными
|
|
456
|
+
типами событий журнала хоста (`run.claimed`, `task.done`, `run.failed`,
|
|
457
|
+
`scheduler.error`, …). `workflow.updated` пишет только локальные записи
|
|
458
|
+
технической очереди (`workflow-jobs`) и событий журнала не создаёт.
|
|
459
|
+
`usage.recorded` пишет только локальные записи учёта вызовов (`usage`): начало
|
|
460
|
+
вызова вместе с проверкой бюджетов, ход и итог вызова, закрытие прерванных,
|
|
461
|
+
закрепление атрибуции прежних записей; событий журнала не создаёт.
|
|
462
|
+
`checks.recorded` пишет только локальные записи корпуса (`check-suites`):
|
|
463
|
+
начало, продление и завершение операции подтверждения, решение и новую
|
|
464
|
+
версию. `checks.spike` пишет только локальную запись эксперимента
|
|
465
|
+
выполнимости (`spikes`). `checks.adopted`, `checks.awaiting-operator` и
|
|
466
|
+
`checks.adoption-abandoned` меняют принятую поручением версию корпуса и
|
|
467
|
+
удержание выдачи (`work.held`, `corpus.adopted`). Эпизод по свойству меняется
|
|
468
|
+
транзакциями `recovery.*`, отказом и выдачей (`work.recovery`).
|
|
469
|
+
`workspace.verification.started`, `workspace.manifest`, `workspace.evidence`,
|
|
470
|
+
`workspace.verified`, `workspace.failed` — транзакции совместной проверки
|
|
471
|
+
(`joint.started`, `joint.finished`). `config.started`, `config.reconfigure-*`
|
|
472
|
+
и `config.reconfigured` меняют применённую политику и запрос операции
|
|
473
|
+
(`policy.applied`, `policy.reconfigure`). `base.moved` — проверка владения
|
|
474
|
+
операцией и CAS-сдвиг ref базы; записей и событий не создаёт.
|
|
475
|
+
|
|
476
|
+
## Порты
|
|
477
|
+
|
|
478
|
+
| Порт | Договор |
|
|
479
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
480
|
+
| `ExecutionStore` | `transact(kind, fn)`: синхронная сериализуемая транзакция; исключение откатывает изменения и события; вложенная видит несохранённые изменения внешней, её исключение откатывает только её часть, а изменения обеих сохраняются; событиями становятся только `emit`, возвращаемое значение в журнал не попадает; событие фиксируется и в транзакции без изменения записей модели; `heartbeat` без события; единственный внешний эффект — CAS update-ref при приёмке до фиксации |
|
|
481
|
+
| `ExecutionView` / `ExecutionTransaction` | Чтение и запись записей модели, типизированных локальных записей, событий |
|
|
482
|
+
| `BasisProvider` | Digest постановки, области проверок и политики поручения; движок сравнивает, но не вычисляет основания хоста. Необязательный `checksDigest(work, policyDigest, view)` — версия проверок попытки по формуле хоста (по умолчанию `effectiveChecks` harness); `ReceiverContext.checksDigest` — та же формула у получателя. Необязательные `jointPolicyDigest(view)` и `jointSpecDigest(workIds, view, verificationId?)` — digest политики и основание совместной проверки по формуле хоста (по умолчанию формулы harness). Необязательный `episodeBasis(work, view)` — основание эпизода разбора по свойству по формуле хоста (по умолчанию `episodeBasis` harness): им подписаны прежние эпизоды и попытки хоста. Необязательный `suiteBasis(contract)` — нормативное основание корпуса договора проверки по формуле хоста (по умолчанию `suiteBasis` harness): им записано основание прежних корпусов хоста, их выбор (`CorpusStore.suiteFor`), привязка версии к поручению при новой редакции и у получателя (`ReceiverContext.suiteBasis`) |
|
|
483
|
+
| `HostGuards` | `claimable`, `claimBarrier`, `current`, `beforeAccept` — дополнительные запреты хоста в той же транзакции; необязательный `busy(view)` — работы хоста (поставка, preview), которых применение новой политики дожидается так же, как попыток; необязательный `joint(verification, view, kind)` — продуктовые условия совместной проверки в каждой её записи, кроме продления срока |
|
|
484
|
+
| `ContractApprovals` (необязательный `ExecutionHost.contracts`) | `approved({id, digest}, view)` — хост, ведущий согласование контрактов сам, подтверждает редакцию этого digest (`null`) или называет причину; без порта согласованием служит одобренный последний раунд технического ревью этого digest при текущем назначении reviewer. Записи ревью из сведений хоста не создаются |
|
|
485
|
+
| `ExecutionHost.readyAt` (необязательный) | `readyAt(work, view)` — когда поручение стало готово к выдаче (согласовано и дождалось зависимостей) по сведениям хоста; движок пишет его в `wait.readyAt` новой попытки в транзакции выдачи. Нет порта или `undefined` — время неизвестно и не выдумывается |
|
|
486
|
+
| `BudgetScopes` | Группа поручения, её состав, атрибуция прежних записей вызовов |
|
|
487
|
+
| `RuntimeAdapter` | `capabilities()`, `invoke(request, signal)`: сессия `fresh` для reviewer и planner (`continue` — только writer той же попытки), JSON Schema ответа, сообщённая модель и версия runtime, usage, диагностика, отмена дерева процессов; необязательный `probe` — сервер проверок reviewer кода (команда, имена переменных окружения, предел команды), адаптер подключает его как MCP-сервер `devcontour_probe` |
|
|
488
|
+
| `WorkSource` | `fetch(ref)` с редакцией; `revision(ref)`; `trusts(prerequisite)`, по умолчанию нет |
|
|
489
|
+
| `ContextSource` | `snapshot(ids, at)` — `ContextSnapshot` с содержимым |
|
|
490
|
+
| `ResultSink` | `deliver({key, result})` идемпотентно по ключу: `delivered` или `conflict` с текущей редакцией |
|
|
491
|
+
|
|
492
|
+
`RuntimeRequest.subject` (необязательно) — поручение, попытка и фаза вызова
|
|
493
|
+
исполнения: адаптер хоста находит по нему свои сведения; в запросе модели их нет.
|
|
494
|
+
|
|
495
|
+
`Runner` принимает от хоста: `context(work)` — снимок контекста, в том числе
|
|
496
|
+
асинхронно; `stateDirFor(repositoryId)` — каталог рабочих деревьев,
|
|
497
|
+
артефактов и снимков попыток репозитория (без него — `stateDir`);
|
|
498
|
+
`hooks` — точки расширения, которые добавляют сведения хоста, но не решают
|
|
499
|
+
приёмку: `prepared({work, attempt, baseSha})` — база известна, работа не
|
|
500
|
+
начата (отказ — отказ попытки, `BlockedError` — отказ окружения);
|
|
501
|
+
`notes({work, attempt, review})` — дополнения запроса writer или reviewer;
|
|
502
|
+
`implemented({attempt, output, sha})` — отчёт writer закоммичен кандидатом;
|
|
503
|
+
`failed({attempt, kind, message})` — отказ записан движком. `settled()` ждёт
|
|
504
|
+
выданные попытки — хост ведёт свой цикл поверх `tick`. `Engine.expire(at)`
|
|
505
|
+
снимает владение, истекающее к моменту `at`. Попытка записывает замеры стадий
|
|
506
|
+
(`implementation`, `<фаза>-test:<gate>`, `<фаза>-consumer:<репозиторий>:<gate>`,
|
|
507
|
+
`<фаза>-review`, `<фаза>-environment:<шаг>`, `integration-wait`) и сохраняет
|
|
508
|
+
снимок контекста артефактом `implementation/context.json`. Отказ приёмки с
|
|
509
|
+
кодом `GATE_FAILED`, `REVIEW_REJECTED`, `REVIEW_PROTOCOL_INVALID`,
|
|
510
|
+
`SCOPE_VIOLATION` или `BUDGET_EXHAUSTED` записывается классом отказа этого
|
|
511
|
+
правила.
|
|
512
|
+
|
|
513
|
+
Хост, ведущий движок поверх своего хранилища, собирает исполнение из
|
|
514
|
+
экспортов корня пакета: `Engine`, `Runner`, `WorkflowQueue`, `JointRunner`,
|
|
515
|
+
`moveBase`/`fencedRefMove`, `runGate`/`runCheck` (и разбор отчёта
|
|
516
|
+
`junitSummary`, `prepareReportPath`, `sandboxBlockedHosts`), `unprovenReason`,
|
|
517
|
+
`ReviewProbes`, маскирование (`redactor`, `redactDeep`, `redactError`),
|
|
518
|
+
корпус (`CorpusStore`, подтверждение случая `submitCase` с `ConfirmContext`),
|
|
519
|
+
ограниченный разбор по свойству (`analyzeRecovery`, `applyCases`,
|
|
520
|
+
`recoveryBrief`; назначение хоста — модель и профиль ведущего — передаётся
|
|
521
|
+
`binding`, его дополнительные границы — `boundary`), проверка
|
|
522
|
+
переносимого результата (`resultProblems`), классы и правила отказов
|
|
523
|
+
(`BlockedError`, `TaskFailure`, `classifyFailure`, `failureFingerprint`,
|
|
524
|
+
`repairPolicy`, `repairDecision`), раунд технического ревью
|
|
525
|
+
(`technicalReview`), точка сбоя подтверждения корпуса для тестов
|
|
526
|
+
(`caseHooks`). Глубокие импорты `lib/...` не поддерживаются.
|
|
527
|
+
|
|
528
|
+
Очередь технических заданий хоста — `new WorkflowQueue(store, policy, now,
|
|
529
|
+
subjects)`: `subjects.input(kind, id, view)` задаёт digest входа и владельца
|
|
530
|
+
задания для предметов хоста (доска, набор изменений); задание хранится за
|
|
531
|
+
этим владельцем, недопустимый вход (`HarnessError`) отклоняет постановку его
|
|
532
|
+
текстом и делает поставленное задание устаревшим, смена владельца — тоже.
|
|
533
|
+
Число стадий задаёт `finish(job, wait, stages)`.
|
|
534
|
+
|
|
535
|
+
## Ошибки и exit codes
|
|
536
|
+
|
|
537
|
+
`HarnessError {code, class, message, issues[{path, message}]}`; класс задаёт
|
|
538
|
+
exit code CLI.
|
|
539
|
+
|
|
540
|
+
| Exit | Класс | Коды |
|
|
541
|
+
| ---- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
542
|
+
| 0 | успех | — |
|
|
543
|
+
| 2 | `input` | `INVALID_INPUT`, `UNSUPPORTED_COMMAND`, `UNSUPPORTED_VERSION`, `GRAPH_*`, `GATE_*`, `REVIEWER_*` |
|
|
544
|
+
| 3 | `refused` | `APPROVAL_STALE`, `APPROVAL_REQUIRED`, `LEASE_STALE`, `CONTROLLER_BUSY`, `PAUSED`, `NOT_READY`, `SCOPE_VIOLATION`, `GATE_FAILED`, `REVIEW_REJECTED`, `BUDGET_EXHAUSTED`, `BUDGET_UNKNOWN`, `ATTEMPTS_EXHAUSTED`, `REVISION_CONFLICT`, `CANCELLED`, `NOT_FOUND` |
|
|
545
|
+
| 4 | `infrastructure` | `STATE_VERSION_UNSUPPORTED`, `RUNTIME_UNAVAILABLE`, `REVIEW_PROTOCOL_INVALID`, `SANDBOX_UNAVAILABLE`, `GIT_FAILED`, `STORAGE_FAILED`, `DELIVERY_FAILED`, `INTERNAL` |
|
|
546
|
+
|
|
547
|
+
Exit 1 не используется: им Node завершает процесс при необработанном
|
|
548
|
+
исключении.
|
|
549
|
+
|
|
550
|
+
### StackProfile
|
|
551
|
+
|
|
552
|
+
Переносимый профиль стека (`schemas/stack-profile.schema.json`):
|
|
553
|
+
`{id, version, extends[], capabilities[], gates[], prepare[], environment?, lifecycle?, protectedPaths[], generatedPaths[], concurrency?, runTimeoutMs?, roles{}, contextPacks[]}`.
|
|
554
|
+
`extends` — встроенный ID (`profiles/<id>.json` пакета) или относительный
|
|
555
|
+
`./file.json` внутри репозитория; не глубже 16 слоёв и не больше 32 файлов,
|
|
556
|
+
без symlink и выхода за корень, файл до 128 KiB. `resolveProfile` только
|
|
557
|
+
читает манифесты: gates, подготовка, возможности и пути складываются,
|
|
558
|
+
окружение и lifecycle задаёт один слой (иначе конфликт), параллельность —
|
|
559
|
+
наименьшая, время попытки — наибольшее, роли и `contextPacks` — по ID.
|
|
560
|
+
Итог обязан иметь test gate с JUnit; `requirement-source` зарезервирован.
|
|
561
|
+
Файлы локальных слоёв становятся защищёнными путями. Digest: один встроенный
|
|
562
|
+
файл — sha256 его байтов (так закреплены прежние потребители, встроенные
|
|
563
|
+
профили перенесены побайтно), иначе — sha256 замыкания `[{ref, digest}]`.
|
|
564
|
+
`repositoryFromProfile` собирает описание репозитория политики (собственные
|
|
565
|
+
значения сильнее, переопределённые поля названы в `shadowed`),
|
|
566
|
+
`profileRoles` — роли в форме политики. `contextPacks` — инструкции стека для
|
|
567
|
+
хоста: harness их не читает, закрепляет их `ContextSource`. Встроенные
|
|
568
|
+
профили сохраняют имена скриптов проекта, которые закреплены у прежних
|
|
569
|
+
потребителей (например, `npm run test:devcontour`); для другого проекта
|
|
570
|
+
подходит локальный профиль.
|
|
571
|
+
|
|
572
|
+
## CLI
|
|
573
|
+
|
|
574
|
+
stdout — один JSON `CliEnvelope`: `{apiVersion, command, ok: true, data}` или
|
|
575
|
+
`{apiVersion, command, ok: false, error}`. `data` каждой команды проверяется
|
|
576
|
+
её схемой (`cliDataSchemas`) перед выводом. Диагностика — stderr. Команды
|
|
577
|
+
получают явные пути; `--state <каталог>` создают только пишущие команды,
|
|
578
|
+
читающие на отсутствующем каталоге отвечают `NOT_FOUND` и ничего не создают.
|
|
579
|
+
Бинарник не хранит настроек проекта и не помнит «последний активный проект».
|
|
580
|
+
|
|
581
|
+
| Команда | Аргументы | Пишет | `data` | Повтор |
|
|
582
|
+
| ----------------- | ----------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
583
|
+
| `validate` | `--graph F --policy F [--context F]` | нет | digests, число поручений | Чистая функция входов |
|
|
584
|
+
| `review-plan` | `--state D --graph F --policy F --author A [--context F]` | да | `ReviewRecord` | Тот же digest и автор, уже согласованные, — тот же раунд без вызова модели; автор, не допускаемый правилом вендора, — `REVIEWER_SAME_VENDOR` до вызова |
|
|
585
|
+
| `review-contract` | `--state D --contract F --policy F --author A` | да | `ReviewRecord` | Как `review-plan` |
|
|
586
|
+
| `approve` | `--state D --subject ID --digest H` | да | subject, digest, at | Тот же digest — без изменений; только `approvalMode: operator` |
|
|
587
|
+
| `run` | `--state D --graph F --policy F [--context F] [--sink file:D] [--once]` | да | граф, поручения и их блокеры, задание `workflow` | Та же редакция продолжает работу; другой digest той же редакции — `REVISION_CONFLICT` |
|
|
588
|
+
| `status` | `--state D [--graph ID]` | нет | очередь, графы, поручения с блокерами, бюджеты | Только чтение |
|
|
589
|
+
| `events` | `--state D [--after N] [--limit 1–500]` | нет | события, `next` | Только чтение |
|
|
590
|
+
| `pause` | `--state D` | да | `ControlState` | Без изменений |
|
|
591
|
+
| `resume` | `--state D` | да | `ControlState` | Решение человека: снимает паузу оператора, штатной остановки и отказа runtime вместе с её классами; паузу операции reconfigure — `PAUSED` |
|
|
592
|
+
| `cancel` | `--state D --work ID [--reason T]` | да | статус поручения | Отменённое — без изменений; это не retry |
|
|
593
|
+
| `retry` | `--state D --work ID [--reset --reason T]` | да | статус поручения | В пределах `maxAttempts` и бюджета; `--reset` с причиной сбрасывает счётчик попыток, но не учёт расходов |
|
|
594
|
+
| `result` | `--state D --work ID` | нет | `ResultEnvelope` | Только чтение |
|
|
595
|
+
| `deliver` | `--state D --work ID --sink file:D` | да | `ResultEnvelope` | Доставленное не доставляется повторно; моделей и интеграции нет |
|
|
596
|
+
| `profile` | `--profile ID\|./F [--repository D]` | нет | закрепление (`pin`) и разрешённый профиль | Чистая функция файлов профиля; команды проекта не исполняются |
|
|
597
|
+
| `doctor` | `[--state D] [--policy F]` | нет | версии, runtime, sandbox, совместимость состояния и версии движка в нём | Без live-вызова модели |
|
|
598
|
+
| `--version` | — | нет | версия пакета и API | — |
|
|
599
|
+
|
|
600
|
+
Полная форма каждой команды — `cliCommands` (аргументы, обязательность,
|
|
601
|
+
идемпотентность, отказы exit 3). Все команды реализованы. `run` принимает `--author` (по умолчанию `external`) — автора графа для ревью плана. `HARNESS_CODEX_BIN` и `HARNESS_CLAUDE_BIN` подменяют исполняемые файлы runtime (fixture executables в тестах).
|
|
602
|
+
После приёмки договора имена и параметры меняются только совместимо или
|
|
603
|
+
отдельным согласованным изменением.
|