sdd-agent-platform 0.4.2 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -41
- package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js +56 -73
- package/node_modules/@sdd-agent-platform/core/dist/ai-tools.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/ingestion.js +9 -64
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/ingestion.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-evidence.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-evidence.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-result.js +17 -26
- package/node_modules/@sdd-agent-platform/core/dist/artifacts/sdd-result.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/config/init-project.d.ts +8 -7
- package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js +8 -12
- package/node_modules/@sdd-agent-platform/core/dist/config/init-project.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/config/project-config.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/config/project-config.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.d.ts +3 -4
- package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js +377 -411
- package/node_modules/@sdd-agent-platform/core/dist/config/starter-documents.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/context/build-package.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js +18 -25
- package/node_modules/@sdd-agent-platform/core/dist/context/build-package.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/context/evidence-summary.js +8 -26
- package/node_modules/@sdd-agent-platform/core/dist/context/evidence-summary.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/context/log-worker.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/context/log-worker.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/context-offload/contracts.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/contracts.d.ts +6 -1
- package/node_modules/@sdd-agent-platform/core/dist/contracts.js +5 -0
- package/node_modules/@sdd-agent-platform/core/dist/contracts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/delegation/model.d.ts +0 -3
- package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.d.ts +0 -3
- package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.js +4 -7
- package/node_modules/@sdd-agent-platform/core/dist/delegation/validation.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js +3 -13
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/document-chain.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/local-run-index.js +1 -9
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/local-run-index.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/project.js +9 -9
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/project.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/registries.js +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/registries.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js +4 -4
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-evidence.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-trust.js +24 -0
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/run-trust.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/runtime-contracts.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/doctor/checks/runtime-contracts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js +43 -180
- package/node_modules/@sdd-agent-platform/core/dist/doctor/doctor.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js +7 -14
- package/node_modules/@sdd-agent-platform/core/dist/evidence/lookup.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js +110 -0
- package/node_modules/@sdd-agent-platform/core/dist/evidence-runtime/coordination.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/execution/background-executor.js +4 -4
- package/node_modules/@sdd-agent-platform/core/dist/execution/background-executor.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/execution/foreground-subagents.js +3 -3
- package/node_modules/@sdd-agent-platform/core/dist/execution/foreground-subagents.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js +85 -86
- package/node_modules/@sdd-agent-platform/core/dist/execution/host-invocation.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js +2 -3
- package/node_modules/@sdd-agent-platform/core/dist/execution/resident-worker.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/execution/stage-team-runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/governance/policy.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/governance/policy.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/governance/policy.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/instructions.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/instructions.js +31 -67
- package/node_modules/@sdd-agent-platform/core/dist/instructions.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle/decision-gate.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle/decision-gate.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.d.ts +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js +59 -85
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle/ship.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.d.ts +159 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js +7 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/contracts.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.d.ts +16 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js +461 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph/kernel.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.d.ts +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js +3 -0
- package/node_modules/@sdd-agent-platform/core/dist/lifecycle-graph.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/orchestration/contracts.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.d.ts +2 -12
- package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js +32 -80
- package/node_modules/@sdd-agent-platform/core/dist/orchestration/runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.d.ts +2 -5
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js +27 -69
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-capability-catalog.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js +118 -34
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-registry.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/agent-runtime-static.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/capability-sources.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js +8 -15
- package/node_modules/@sdd-agent-platform/core/dist/registries/command-team-runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/eval-learning-context.js +4 -4
- package/node_modules/@sdd-agent-platform/core/dist/registries/eval-learning-context.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.d.ts +13 -0
- package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js +76 -0
- package/node_modules/@sdd-agent-platform/core/dist/registries/plan-scout-domains.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/registries/query-status.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/registries/query-status.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js +7 -7
- package/node_modules/@sdd-agent-platform/core/dist/registries/skill-capabilities.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js +4 -4
- package/node_modules/@sdd-agent-platform/core/dist/registries/tool-capabilities.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/tool-plugins.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/registries/tool-plugins.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/worker-adapters.js +11 -11
- package/node_modules/@sdd-agent-platform/core/dist/registries/worker-adapters.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js +21 -21
- package/node_modules/@sdd-agent-platform/core/dist/registries/workflow-gates.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js +2 -1
- package/node_modules/@sdd-agent-platform/core/dist/risk/consumer-diagnostics.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js +6 -6
- package/node_modules/@sdd-agent-platform/core/dist/risk/kernel.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js +11 -23
- package/node_modules/@sdd-agent-platform/core/dist/risk/legacy-adapters.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.d.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js +18 -20
- package/node_modules/@sdd-agent-platform/core/dist/risk/workflow-gates.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/agent-runtime.d.ts +0 -2
- package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/route-projection.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/routing.js +16 -48
- package/node_modules/@sdd-agent-platform/core/dist/router/routing.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js +11 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/runtime-import.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/router/runtime-validation.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.d.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js +20 -28
- package/node_modules/@sdd-agent-platform/core/dist/router/stage-route-binding.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/router.d.ts +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/router.js +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/router.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.d.ts +6 -6
- package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js +13 -124
- package/node_modules/@sdd-agent-platform/core/dist/run-state/artifacts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.d.ts +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js +5 -7
- package/node_modules/@sdd-agent-platform/core/dist/run-state/inspect-run.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state/model.d.ts +28 -28
- package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.d.ts +3 -2
- package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.js +15 -66
- package/node_modules/@sdd-agent-platform/core/dist/run-state/run-index.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js +26 -36
- package/node_modules/@sdd-agent-platform/core/dist/run-state/run-state.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.d.ts +0 -4
- package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js +5 -51
- package/node_modules/@sdd-agent-platform/core/dist/run-state/task-evidence.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state.d.ts +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state.js +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/run-state.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/build.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js +7 -16
- package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/findings.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-analysis/model.d.ts +1 -2
- package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.d.ts +0 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js +1 -4
- package/node_modules/@sdd-agent-platform/core/dist/runtime-paths.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.d.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js +11 -0
- package/node_modules/@sdd-agent-platform/core/dist/runtime-projection-p0.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js +179 -0
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/artifact-depth.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.d.ts +0 -2
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js +10 -97
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/document-hashes.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js +6 -8
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/run-binding.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.d.ts +5 -2
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js +85 -68
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-parser.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/sdd-docs/task-rendering.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js +40 -0
- package/node_modules/@sdd-agent-platform/core/dist/spec-entry.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.d.ts +12 -0
- package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/spec-manager-contracts.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.d.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js +19 -26
- package/node_modules/@sdd-agent-platform/core/dist/stage-artifacts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js +3 -6
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration-contracts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.d.ts +111 -263
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js +1272 -1124
- package/node_modules/@sdd-agent-platform/core/dist/stage-collaboration.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js +5 -5
- package/node_modules/@sdd-agent-platform/core/dist/stage-runtime/runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/status/project-status.d.ts +1 -44
- package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js +47 -170
- package/node_modules/@sdd-agent-platform/core/dist/status/project-status.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/storage/runtime-store.js +73 -73
- package/node_modules/@sdd-agent-platform/core/dist/subagents/contracts.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/subagents/runtime.js +7 -7
- package/node_modules/@sdd-agent-platform/core/dist/subagents/runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/apply.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back/inspect.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back.js +2 -0
- package/node_modules/@sdd-agent-platform/core/dist/sync-back.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.d.ts +167 -0
- package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js +377 -0
- package/node_modules/@sdd-agent-platform/core/dist/task-execution-contract.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js +329 -314
- package/node_modules/@sdd-agent-platform/core/dist/test-support/fixtures.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js +53 -7
- package/node_modules/@sdd-agent-platform/core/dist/test-support/run-state.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js +9 -12
- package/node_modules/@sdd-agent-platform/core/dist/truth-reconciliation.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.d.ts +0 -48
- package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js +1 -520
- package/node_modules/@sdd-agent-platform/core/dist/verification/goal-verify.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.d.ts +5 -5
- package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js +14 -14
- package/node_modules/@sdd-agent-platform/core/dist/verification/rendering.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js +111 -159
- package/node_modules/@sdd-agent-platform/core/dist/verification/single-task-loop.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.d.ts +49 -0
- package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js +521 -0
- package/node_modules/@sdd-agent-platform/core/dist/verification/task-evidence-judgment.js.map +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js +21 -21
- package/node_modules/@sdd-agent-platform/core/dist/verification/test-runtime.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.d.ts +0 -18
- package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js +5 -27
- package/node_modules/@sdd-agent-platform/core/dist/verification/validation-wave.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js +45 -45
- package/node_modules/@sdd-agent-platform/core/dist/verification/verify-contract.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/verification.d.ts +3 -3
- package/node_modules/@sdd-agent-platform/core/dist/verification.js +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/verification.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/work-units/contracts.d.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js +9 -227
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/evidence-packet.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js +9 -50
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/hard-checks.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js +4 -42
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/policy.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-gate/types.d.ts +2 -3
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js +2 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/dependencies.js +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.d.ts +1 -0
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js +23 -63
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.d.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js +43 -65
- package/node_modules/@sdd-agent-platform/core/dist/workflow-state/resolve.js.map +1 -1
- package/node_modules/@sdd-agent-platform/core/package.json +5 -2
- package/node_modules/@sdd-agent-platform/core/src/ai-tools.test.ts +238 -185
- package/node_modules/@sdd-agent-platform/core/src/ai-tools.ts +56 -73
- package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.test.ts +189 -227
- package/node_modules/@sdd-agent-platform/core/src/artifacts/ingestion.ts +222 -278
- package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.test.ts +28 -28
- package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-evidence.ts +301 -301
- package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.test.ts +181 -181
- package/node_modules/@sdd-agent-platform/core/src/artifacts/sdd-result.ts +231 -240
- package/node_modules/@sdd-agent-platform/core/src/artifacts/templates.ts +99 -99
- package/node_modules/@sdd-agent-platform/core/src/artifacts.ts +4 -4
- package/node_modules/@sdd-agent-platform/core/src/coding-facts/contracts.ts +79 -79
- package/node_modules/@sdd-agent-platform/core/src/coding-facts.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/src/config/init-project.test.ts +314 -318
- package/node_modules/@sdd-agent-platform/core/src/config/init-project.ts +128 -123
- package/node_modules/@sdd-agent-platform/core/src/config/project-config.ts +265 -265
- package/node_modules/@sdd-agent-platform/core/src/config/project-detection.ts +147 -147
- package/node_modules/@sdd-agent-platform/core/src/config/starter-documents.ts +400 -432
- package/node_modules/@sdd-agent-platform/core/src/context/budget.ts +30 -30
- package/node_modules/@sdd-agent-platform/core/src/context/build-package.ts +304 -311
- package/node_modules/@sdd-agent-platform/core/src/context/command-summary.ts +45 -45
- package/node_modules/@sdd-agent-platform/core/src/context/context-build.test.ts +188 -189
- package/node_modules/@sdd-agent-platform/core/src/context/evidence-summary.ts +144 -163
- package/node_modules/@sdd-agent-platform/core/src/context/log-worker.ts +48 -48
- package/node_modules/@sdd-agent-platform/core/src/context/source-refs.ts +41 -41
- package/node_modules/@sdd-agent-platform/core/src/context-offload/contracts.ts +47 -47
- package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.test.ts +71 -71
- package/node_modules/@sdd-agent-platform/core/src/context-offload/runtime.ts +178 -178
- package/node_modules/@sdd-agent-platform/core/src/context-offload.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/context.ts +6 -6
- package/node_modules/@sdd-agent-platform/core/src/contracts/issues.ts +13 -13
- package/node_modules/@sdd-agent-platform/core/src/contracts.test.ts +9 -9
- package/node_modules/@sdd-agent-platform/core/src/contracts.ts +121 -116
- package/node_modules/@sdd-agent-platform/core/src/delegation/delegation.test.ts +183 -183
- package/node_modules/@sdd-agent-platform/core/src/delegation/model.ts +23 -26
- package/node_modules/@sdd-agent-platform/core/src/delegation/queue.ts +58 -58
- package/node_modules/@sdd-agent-platform/core/src/delegation/run-state.ts +14 -14
- package/node_modules/@sdd-agent-platform/core/src/delegation/state-machine.ts +90 -90
- package/node_modules/@sdd-agent-platform/core/src/delegation/validation.ts +124 -127
- package/node_modules/@sdd-agent-platform/core/src/delegation.ts +26 -26
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/ai-entries.ts +28 -28
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/document-chain.ts +104 -112
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/local-run-index.ts +19 -27
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/project.ts +84 -84
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/registries.ts +252 -251
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-evidence.ts +330 -330
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-records.ts +79 -79
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/run-trust.ts +128 -107
- package/node_modules/@sdd-agent-platform/core/src/doctor/checks/runtime-contracts.ts +300 -300
- package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.test.ts +628 -755
- package/node_modules/@sdd-agent-platform/core/src/doctor/doctor.ts +301 -453
- package/node_modules/@sdd-agent-platform/core/src/doctor/model.ts +13 -13
- package/node_modules/@sdd-agent-platform/core/src/doctor/summary.ts +11 -11
- package/node_modules/@sdd-agent-platform/core/src/doctor.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/evidence/lookup.ts +80 -88
- package/node_modules/@sdd-agent-platform/core/src/evidence-runtime/contracts.ts +48 -48
- package/node_modules/@sdd-agent-platform/core/src/evidence-runtime.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/src/execution/agent-execution-records.ts +195 -195
- package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.test.ts +187 -235
- package/node_modules/@sdd-agent-platform/core/src/execution/background-executor.ts +305 -305
- package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.test.ts +97 -106
- package/node_modules/@sdd-agent-platform/core/src/execution/foreground-subagents.ts +453 -453
- package/node_modules/@sdd-agent-platform/core/src/execution/host-invocation.ts +225 -226
- package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.test.ts +132 -143
- package/node_modules/@sdd-agent-platform/core/src/execution/resident-worker.ts +436 -437
- package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.test.ts +102 -102
- package/node_modules/@sdd-agent-platform/core/src/execution/stage-team-runtime.ts +271 -271
- package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.test.ts +111 -121
- package/node_modules/@sdd-agent-platform/core/src/execution/wave-executor.ts +231 -231
- package/node_modules/@sdd-agent-platform/core/src/execution.ts +5 -5
- package/node_modules/@sdd-agent-platform/core/src/governance/policy.test.ts +57 -65
- package/node_modules/@sdd-agent-platform/core/src/governance/policy.ts +175 -175
- package/node_modules/@sdd-agent-platform/core/src/governance.ts +1 -1
- package/node_modules/@sdd-agent-platform/core/src/instructions.test.ts +80 -64
- package/node_modules/@sdd-agent-platform/core/src/instructions.ts +32 -68
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.test.ts +174 -174
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/decision-gate.ts +373 -373
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/rendering.ts +29 -29
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/risk-signals.ts +146 -146
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.test.ts +47 -47
- package/node_modules/@sdd-agent-platform/core/src/lifecycle/ship.ts +255 -280
- package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/contracts.ts +179 -0
- package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph/kernel.ts +522 -0
- package/node_modules/@sdd-agent-platform/core/src/lifecycle-graph.ts +2 -0
- package/node_modules/@sdd-agent-platform/core/src/lifecycle.ts +4 -4
- package/node_modules/@sdd-agent-platform/core/src/orchestration/contracts.ts +50 -50
- package/node_modules/@sdd-agent-platform/core/src/orchestration/index.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/orchestration/runtime.ts +331 -394
- package/node_modules/@sdd-agent-platform/core/src/path-safety.test.ts +22 -22
- package/node_modules/@sdd-agent-platform/core/src/phase8-contracts.test.ts +243 -242
- package/node_modules/@sdd-agent-platform/core/src/phase8-projection-compat.test.ts +152 -153
- package/node_modules/@sdd-agent-platform/core/src/phase8-risk-kernel.test.ts +277 -277
- package/node_modules/@sdd-agent-platform/core/src/phase9-lifecycle-graph.test.ts +103 -0
- package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.test.ts +88 -88
- package/node_modules/@sdd-agent-platform/core/src/planning/task-graph.ts +222 -222
- package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.test.ts +79 -79
- package/node_modules/@sdd-agent-platform/core/src/planning/wave-plan.ts +160 -160
- package/node_modules/@sdd-agent-platform/core/src/planning.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/registries/agent-capability-catalog.ts +426 -473
- package/node_modules/@sdd-agent-platform/core/src/registries/agent-registry.ts +230 -146
- package/node_modules/@sdd-agent-platform/core/src/registries/agent-runtime-static.ts +142 -142
- package/node_modules/@sdd-agent-platform/core/src/registries/capability-sources.ts +253 -253
- package/node_modules/@sdd-agent-platform/core/src/registries/command-team-runtime.ts +302 -309
- package/node_modules/@sdd-agent-platform/core/src/registries/eval-learning-context.ts +246 -246
- package/node_modules/@sdd-agent-platform/core/src/registries/plan-scout-domains.ts +89 -0
- package/node_modules/@sdd-agent-platform/core/src/registries/query-status.ts +119 -119
- package/node_modules/@sdd-agent-platform/core/src/registries/registries.test.ts +454 -445
- package/node_modules/@sdd-agent-platform/core/src/registries/skill-capabilities.ts +37 -37
- package/node_modules/@sdd-agent-platform/core/src/registries/tool-capabilities.ts +135 -135
- package/node_modules/@sdd-agent-platform/core/src/registries/tool-plugins.ts +132 -132
- package/node_modules/@sdd-agent-platform/core/src/registries/worker-adapters.ts +144 -144
- package/node_modules/@sdd-agent-platform/core/src/registries/workflow-gates.ts +111 -111
- package/node_modules/@sdd-agent-platform/core/src/registries.ts +42 -42
- package/node_modules/@sdd-agent-platform/core/src/risk/consumer-diagnostics.ts +98 -97
- package/node_modules/@sdd-agent-platform/core/src/risk/contracts.ts +63 -63
- package/node_modules/@sdd-agent-platform/core/src/risk/kernel.ts +233 -233
- package/node_modules/@sdd-agent-platform/core/src/risk/legacy-adapters.ts +251 -263
- package/node_modules/@sdd-agent-platform/core/src/risk/workflow-gates.ts +203 -205
- package/node_modules/@sdd-agent-platform/core/src/risk.ts +5 -5
- package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime-config.ts +327 -327
- package/node_modules/@sdd-agent-platform/core/src/router/agent-runtime.ts +388 -390
- package/node_modules/@sdd-agent-platform/core/src/router/profile-resolution.ts +154 -154
- package/node_modules/@sdd-agent-platform/core/src/router/risk-policy.ts +33 -33
- package/node_modules/@sdd-agent-platform/core/src/router/route-cache.ts +100 -100
- package/node_modules/@sdd-agent-platform/core/src/router/route-projection.ts +356 -356
- package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.test.ts +428 -665
- package/node_modules/@sdd-agent-platform/core/src/router/route-sdd-task.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/router/routing-rules.ts +73 -73
- package/node_modules/@sdd-agent-platform/core/src/router/routing.ts +189 -223
- package/node_modules/@sdd-agent-platform/core/src/router/runtime-import.ts +464 -453
- package/node_modules/@sdd-agent-platform/core/src/router/runtime-inspection.ts +124 -124
- package/node_modules/@sdd-agent-platform/core/src/router/runtime-registry.ts +123 -123
- package/node_modules/@sdd-agent-platform/core/src/router/runtime-validation.ts +277 -277
- package/node_modules/@sdd-agent-platform/core/src/router/stage-route-binding.ts +273 -279
- package/node_modules/@sdd-agent-platform/core/src/router/team-mode.ts +170 -170
- package/node_modules/@sdd-agent-platform/core/src/router.ts +5 -6
- package/node_modules/@sdd-agent-platform/core/src/run-state/artifacts.ts +126 -240
- package/node_modules/@sdd-agent-platform/core/src/run-state/events.ts +27 -27
- package/node_modules/@sdd-agent-platform/core/src/run-state/inspect-run.ts +172 -172
- package/node_modules/@sdd-agent-platform/core/src/run-state/invocation-ledger.ts +109 -109
- package/node_modules/@sdd-agent-platform/core/src/run-state/model.ts +252 -253
- package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.test.ts +80 -52
- package/node_modules/@sdd-agent-platform/core/src/run-state/run-index.ts +301 -352
- package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.test.ts +70 -118
- package/node_modules/@sdd-agent-platform/core/src/run-state/run-state.ts +406 -416
- package/node_modules/@sdd-agent-platform/core/src/run-state/task-evidence.ts +198 -252
- package/node_modules/@sdd-agent-platform/core/src/run-state/timing.ts +146 -146
- package/node_modules/@sdd-agent-platform/core/src/run-state.ts +8 -9
- package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/build.ts +60 -60
- package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/findings.ts +249 -256
- package/node_modules/@sdd-agent-platform/core/src/runtime-analysis/model.ts +139 -140
- package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.test.ts +65 -66
- package/node_modules/@sdd-agent-platform/core/src/runtime-analysis.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/runtime-paths.ts +249 -253
- package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.test.ts +101 -96
- package/node_modules/@sdd-agent-platform/core/src/runtime-projection-p0.ts +314 -292
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.test.ts +380 -0
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/artifact-depth.ts +207 -0
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/context.ts +111 -111
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/document-hashes.ts +207 -306
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/run-binding.ts +95 -97
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-inspection.ts +39 -39
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.test.ts +467 -523
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-parser.ts +738 -709
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs/task-rendering.ts +81 -81
- package/node_modules/@sdd-agent-platform/core/src/sdd-docs.ts +5 -5
- package/node_modules/@sdd-agent-platform/core/src/spec-manager-contracts.ts +13 -0
- package/node_modules/@sdd-agent-platform/core/src/stage-artifacts.ts +435 -450
- package/node_modules/@sdd-agent-platform/core/src/stage-collaboration-contracts.ts +316 -322
- package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.test.ts +2963 -2902
- package/node_modules/@sdd-agent-platform/core/src/stage-collaboration.ts +5856 -5831
- package/node_modules/@sdd-agent-platform/core/src/stage-runtime/contracts.ts +40 -40
- package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.test.ts +209 -209
- package/node_modules/@sdd-agent-platform/core/src/stage-runtime/runtime.ts +360 -360
- package/node_modules/@sdd-agent-platform/core/src/stage-runtime.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/status/project-status.test.ts +288 -511
- package/node_modules/@sdd-agent-platform/core/src/status/project-status.ts +651 -851
- package/node_modules/@sdd-agent-platform/core/src/status.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/storage/json-io.ts +10 -10
- package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.test.ts +489 -681
- package/node_modules/@sdd-agent-platform/core/src/storage/runtime-store.ts +1981 -1981
- package/node_modules/@sdd-agent-platform/core/src/subagents/contracts.ts +45 -45
- package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.test.ts +232 -232
- package/node_modules/@sdd-agent-platform/core/src/subagents/runtime.ts +307 -307
- package/node_modules/@sdd-agent-platform/core/src/subagents.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.test.ts +141 -0
- package/node_modules/@sdd-agent-platform/core/src/task-execution-contract.ts +566 -0
- package/node_modules/@sdd-agent-platform/core/src/task-risk-profile.ts +193 -193
- package/node_modules/@sdd-agent-platform/core/src/test-support/fixtures.ts +413 -398
- package/node_modules/@sdd-agent-platform/core/src/test-support/run-state.ts +102 -56
- package/node_modules/@sdd-agent-platform/core/src/test-support.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.test.ts +72 -72
- package/node_modules/@sdd-agent-platform/core/src/truth-reconciliation.ts +9 -12
- package/node_modules/@sdd-agent-platform/core/src/verification/rendering.ts +137 -137
- package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.test.ts +77 -84
- package/node_modules/@sdd-agent-platform/core/src/verification/review-gate.ts +77 -77
- package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.ts +455 -506
- package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.test.ts → task-evidence-judgment.test.ts} +261 -261
- package/node_modules/@sdd-agent-platform/core/src/verification/{goal-verify.ts → task-evidence-judgment.ts} +619 -619
- package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.ts +1190 -1190
- package/node_modules/@sdd-agent-platform/core/src/verification/validation-cache.ts +106 -106
- package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.ts +513 -556
- package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.ts +334 -334
- package/node_modules/@sdd-agent-platform/core/src/verification.ts +8 -8
- package/node_modules/@sdd-agent-platform/core/src/work-units/contracts.ts +26 -26
- package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.test.ts +88 -88
- package/node_modules/@sdd-agent-platform/core/src/work-units/runtime.ts +112 -112
- package/node_modules/@sdd-agent-platform/core/src/work-units.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/evidence-packet.ts +190 -425
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.test.ts +169 -507
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/hard-checks.ts +136 -182
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.test.ts +135 -174
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/policy.ts +153 -194
- package/node_modules/@sdd-agent-platform/core/src/workflow-gate/types.ts +111 -115
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/affected-file-conflicts.ts +95 -93
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.test.ts +32 -32
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/dependencies.ts +114 -114
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/latest-eligible-run.ts +184 -224
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/migration-recovery.ts +158 -158
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/repair-contract.ts +77 -77
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve-task-run.ts +114 -114
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.test.ts +969 -956
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/resolve.ts +967 -992
- package/node_modules/@sdd-agent-platform/core/src/workflow-state/runtime-projections.ts +712 -712
- package/node_modules/@sdd-agent-platform/core/src/workflow-state.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/src/worktree/isolation.ts +130 -130
- package/node_modules/@sdd-agent-platform/core/src/worktree/lifecycle.ts +269 -269
- package/node_modules/@sdd-agent-platform/core/src/worktree/worktree.test.ts +150 -150
- package/node_modules/@sdd-agent-platform/core/src/worktree.ts +2 -2
- package/node_modules/@sdd-agent-platform/core/tsconfig.json +15 -15
- package/package.json +2 -2
- package/packages/cli/dist/args.js +2 -2
- package/packages/cli/dist/args.js.map +1 -1
- package/packages/cli/dist/commands/ai-tools.js +2 -13
- package/packages/cli/dist/commands/ai-tools.js.map +1 -1
- package/packages/cli/dist/commands/{verifies.d.ts → artifact.d.ts} +1 -1
- package/packages/cli/dist/commands/artifact.js +168 -0
- package/packages/cli/dist/commands/artifact.js.map +1 -0
- package/packages/cli/dist/commands/context.js +1 -1
- package/packages/cli/dist/commands/context.js.map +1 -1
- package/packages/cli/dist/commands/evidence.js.map +1 -0
- package/packages/cli/dist/commands/execution.js +127 -49
- package/packages/cli/dist/commands/execution.js.map +1 -1
- package/packages/cli/dist/commands/governance.js +1 -1
- package/packages/cli/dist/commands/governance.js.map +1 -1
- package/packages/cli/dist/commands/init.js +1 -6
- package/packages/cli/dist/commands/init.js.map +1 -1
- package/packages/cli/dist/commands/instructions.d.ts +1 -1
- package/packages/cli/dist/commands/instructions.js +15 -1
- package/packages/cli/dist/commands/instructions.js.map +1 -1
- package/packages/cli/dist/commands/registry/runtime.js +63 -40
- package/packages/cli/dist/commands/registry/runtime.js.map +1 -1
- package/packages/cli/dist/commands/run.js +13 -52
- package/packages/cli/dist/commands/run.js.map +1 -1
- package/packages/cli/dist/commands/stage-close.d.ts +60 -0
- package/packages/cli/dist/commands/stage-close.js +270 -41
- package/packages/cli/dist/commands/stage-close.js.map +1 -1
- package/packages/cli/dist/commands/status.js +9 -68
- package/packages/cli/dist/commands/status.js.map +1 -1
- package/packages/cli/dist/commands/tasks.js.map +1 -1
- package/packages/cli/dist/dispatch.js +6 -26
- package/packages/cli/dist/dispatch.js.map +1 -1
- package/packages/cli/dist/help.js +153 -159
- package/packages/cli/dist/help.js.map +1 -1
- package/packages/cli/dist/renderers/artifacts.d.ts +5 -0
- package/packages/cli/dist/renderers/artifacts.js +43 -0
- package/packages/cli/dist/renderers/artifacts.js.map +1 -0
- package/packages/cli/dist/renderers/doctor.js +1 -2
- package/packages/cli/dist/renderers/doctor.js.map +1 -1
- package/packages/cli/dist/renderers/execution.js +1 -1
- package/packages/cli/dist/renderers/execution.js.map +1 -1
- package/packages/cli/dist/renderers/json.d.ts +0 -1
- package/packages/cli/dist/renderers/json.js +0 -3
- package/packages/cli/dist/renderers/json.js.map +1 -1
- package/packages/cli/dist/renderers/registry-runtime.d.ts +1 -2
- package/packages/cli/dist/renderers/registry-runtime.js +0 -20
- package/packages/cli/dist/renderers/registry-runtime.js.map +1 -1
- package/packages/cli/dist/renderers/router.js +1 -1
- package/packages/cli/dist/renderers/router.js.map +1 -1
- package/packages/cli/dist/renderers/workflow.d.ts +53 -0
- package/packages/cli/dist/renderers/workflow.js +93 -34
- package/packages/cli/dist/renderers/workflow.js.map +1 -1
- package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/cli/package.json +2 -2
- package/packages/core/dist/ai-tools.js +56 -73
- package/packages/core/dist/ai-tools.js.map +1 -1
- package/packages/core/dist/artifacts/ingestion.js +9 -64
- package/packages/core/dist/artifacts/ingestion.js.map +1 -1
- package/packages/core/dist/artifacts/sdd-evidence.js +1 -1
- package/packages/core/dist/artifacts/sdd-evidence.js.map +1 -1
- package/packages/core/dist/artifacts/sdd-result.js +17 -26
- package/packages/core/dist/artifacts/sdd-result.js.map +1 -1
- package/packages/core/dist/config/init-project.d.ts +8 -7
- package/packages/core/dist/config/init-project.js +8 -12
- package/packages/core/dist/config/init-project.js.map +1 -1
- package/packages/core/dist/config/project-config.d.ts +1 -1
- package/packages/core/dist/config/project-config.js +1 -1
- package/packages/core/dist/config/project-config.js.map +1 -1
- package/packages/core/dist/config/starter-documents.d.ts +3 -4
- package/packages/core/dist/config/starter-documents.js +377 -411
- package/packages/core/dist/config/starter-documents.js.map +1 -1
- package/packages/core/dist/context/build-package.d.ts +1 -1
- package/packages/core/dist/context/build-package.js +18 -25
- package/packages/core/dist/context/build-package.js.map +1 -1
- package/packages/core/dist/context/evidence-summary.js +8 -26
- package/packages/core/dist/context/evidence-summary.js.map +1 -1
- package/packages/core/dist/context/log-worker.js +2 -2
- package/packages/core/dist/context/log-worker.js.map +1 -1
- package/packages/core/dist/context-offload/contracts.d.ts +1 -1
- package/packages/core/dist/contracts.d.ts +6 -1
- package/packages/core/dist/contracts.js +5 -0
- package/packages/core/dist/contracts.js.map +1 -1
- package/packages/core/dist/delegation/model.d.ts +0 -3
- package/packages/core/dist/delegation/validation.d.ts +0 -3
- package/packages/core/dist/delegation/validation.js +4 -7
- package/packages/core/dist/delegation/validation.js.map +1 -1
- package/packages/core/dist/doctor/checks/document-chain.js +3 -13
- package/packages/core/dist/doctor/checks/document-chain.js.map +1 -1
- package/packages/core/dist/doctor/checks/local-run-index.js +1 -9
- package/packages/core/dist/doctor/checks/local-run-index.js.map +1 -1
- package/packages/core/dist/doctor/checks/project.js +9 -9
- package/packages/core/dist/doctor/checks/project.js.map +1 -1
- package/packages/core/dist/doctor/checks/registries.js +1 -0
- package/packages/core/dist/doctor/checks/registries.js.map +1 -1
- package/packages/core/dist/doctor/checks/run-evidence.js +4 -4
- package/packages/core/dist/doctor/checks/run-evidence.js.map +1 -1
- package/packages/core/dist/doctor/checks/run-trust.js +24 -0
- package/packages/core/dist/doctor/checks/run-trust.js.map +1 -1
- package/packages/core/dist/doctor/checks/runtime-contracts.js +2 -2
- package/packages/core/dist/doctor/checks/runtime-contracts.js.map +1 -1
- package/packages/core/dist/doctor/doctor.js +43 -180
- package/packages/core/dist/doctor/doctor.js.map +1 -1
- package/packages/core/dist/evidence/lookup.d.ts +1 -1
- package/packages/core/dist/evidence/lookup.js +7 -14
- package/packages/core/dist/evidence/lookup.js.map +1 -1
- package/packages/core/dist/evidence-runtime/coordination.js +110 -0
- package/packages/core/dist/evidence-runtime/coordination.js.map +1 -0
- package/packages/core/dist/execution/background-executor.js +4 -4
- package/packages/core/dist/execution/background-executor.js.map +1 -1
- package/packages/core/dist/execution/foreground-subagents.js +3 -3
- package/packages/core/dist/execution/foreground-subagents.js.map +1 -1
- package/packages/core/dist/execution/host-invocation.js +85 -86
- package/packages/core/dist/execution/host-invocation.js.map +1 -1
- package/packages/core/dist/execution/resident-worker.js +2 -3
- package/packages/core/dist/execution/resident-worker.js.map +1 -1
- package/packages/core/dist/execution/stage-team-runtime.js +2 -2
- package/packages/core/dist/execution/stage-team-runtime.js.map +1 -1
- package/packages/core/dist/governance/policy.d.ts +1 -1
- package/packages/core/dist/governance/policy.js +1 -1
- package/packages/core/dist/governance/policy.js.map +1 -1
- package/packages/core/dist/instructions.d.ts +1 -1
- package/packages/core/dist/instructions.js +31 -67
- package/packages/core/dist/instructions.js.map +1 -1
- package/packages/core/dist/lifecycle/decision-gate.js +1 -1
- package/packages/core/dist/lifecycle/decision-gate.js.map +1 -1
- package/packages/core/dist/lifecycle/ship.d.ts +0 -1
- package/packages/core/dist/lifecycle/ship.js +59 -85
- package/packages/core/dist/lifecycle/ship.js.map +1 -1
- package/packages/core/dist/lifecycle-graph/contracts.d.ts +159 -0
- package/packages/core/dist/lifecycle-graph/contracts.js +7 -0
- package/packages/core/dist/lifecycle-graph/contracts.js.map +1 -0
- package/packages/core/dist/lifecycle-graph/kernel.d.ts +16 -0
- package/packages/core/dist/lifecycle-graph/kernel.js +461 -0
- package/packages/core/dist/lifecycle-graph/kernel.js.map +1 -0
- package/packages/core/dist/lifecycle-graph.d.ts +2 -0
- package/packages/core/dist/lifecycle-graph.js +3 -0
- package/packages/core/dist/lifecycle-graph.js.map +1 -0
- package/packages/core/dist/orchestration/contracts.d.ts +1 -1
- package/packages/core/dist/orchestration/runtime.d.ts +2 -12
- package/packages/core/dist/orchestration/runtime.js +32 -80
- package/packages/core/dist/orchestration/runtime.js.map +1 -1
- package/packages/core/dist/registries/agent-capability-catalog.d.ts +2 -5
- package/packages/core/dist/registries/agent-capability-catalog.js +27 -69
- package/packages/core/dist/registries/agent-capability-catalog.js.map +1 -1
- package/packages/core/dist/registries/agent-registry.js +118 -34
- package/packages/core/dist/registries/agent-registry.js.map +1 -1
- package/packages/core/dist/registries/agent-runtime-static.js +1 -1
- package/packages/core/dist/registries/agent-runtime-static.js.map +1 -1
- package/packages/core/dist/registries/capability-sources.js +1 -1
- package/packages/core/dist/registries/command-team-runtime.d.ts +1 -1
- package/packages/core/dist/registries/command-team-runtime.js +8 -15
- package/packages/core/dist/registries/command-team-runtime.js.map +1 -1
- package/packages/core/dist/registries/eval-learning-context.js +4 -4
- package/packages/core/dist/registries/eval-learning-context.js.map +1 -1
- package/packages/core/dist/registries/plan-scout-domains.d.ts +13 -0
- package/packages/core/dist/registries/plan-scout-domains.js +76 -0
- package/packages/core/dist/registries/plan-scout-domains.js.map +1 -0
- package/packages/core/dist/registries/query-status.js +2 -2
- package/packages/core/dist/registries/query-status.js.map +1 -1
- package/packages/core/dist/registries/skill-capabilities.js +7 -7
- package/packages/core/dist/registries/skill-capabilities.js.map +1 -1
- package/packages/core/dist/registries/tool-capabilities.js +4 -4
- package/packages/core/dist/registries/tool-capabilities.js.map +1 -1
- package/packages/core/dist/registries/tool-plugins.js +2 -2
- package/packages/core/dist/registries/tool-plugins.js.map +1 -1
- package/packages/core/dist/registries/worker-adapters.js +11 -11
- package/packages/core/dist/registries/worker-adapters.js.map +1 -1
- package/packages/core/dist/registries/workflow-gates.d.ts +1 -1
- package/packages/core/dist/registries/workflow-gates.js +21 -21
- package/packages/core/dist/registries/workflow-gates.js.map +1 -1
- package/packages/core/dist/risk/consumer-diagnostics.js +2 -1
- package/packages/core/dist/risk/consumer-diagnostics.js.map +1 -1
- package/packages/core/dist/risk/kernel.js +6 -6
- package/packages/core/dist/risk/kernel.js.map +1 -1
- package/packages/core/dist/risk/legacy-adapters.js +11 -23
- package/packages/core/dist/risk/legacy-adapters.js.map +1 -1
- package/packages/core/dist/risk/workflow-gates.d.ts +2 -2
- package/packages/core/dist/risk/workflow-gates.js +18 -20
- package/packages/core/dist/risk/workflow-gates.js.map +1 -1
- package/packages/core/dist/router/agent-runtime.d.ts +0 -2
- package/packages/core/dist/router/route-projection.js +1 -1
- package/packages/core/dist/router/route-projection.js.map +1 -1
- package/packages/core/dist/router/routing.js +16 -48
- package/packages/core/dist/router/routing.js.map +1 -1
- package/packages/core/dist/router/runtime-import.js +11 -1
- package/packages/core/dist/router/runtime-import.js.map +1 -1
- package/packages/core/dist/router/runtime-validation.js +2 -2
- package/packages/core/dist/router/runtime-validation.js.map +1 -1
- package/packages/core/dist/router/stage-route-binding.d.ts +2 -2
- package/packages/core/dist/router/stage-route-binding.js +20 -28
- package/packages/core/dist/router/stage-route-binding.js.map +1 -1
- package/packages/core/dist/router.d.ts +0 -1
- package/packages/core/dist/router.js +0 -1
- package/packages/core/dist/router.js.map +1 -1
- package/packages/core/dist/run-state/artifacts.d.ts +6 -6
- package/packages/core/dist/run-state/artifacts.js +13 -124
- package/packages/core/dist/run-state/artifacts.js.map +1 -1
- package/packages/core/dist/run-state/inspect-run.d.ts +2 -0
- package/packages/core/dist/run-state/inspect-run.js +5 -7
- package/packages/core/dist/run-state/inspect-run.js.map +1 -1
- package/packages/core/dist/run-state/model.d.ts +28 -28
- package/packages/core/dist/run-state/run-index.d.ts +3 -2
- package/packages/core/dist/run-state/run-index.js +15 -66
- package/packages/core/dist/run-state/run-index.js.map +1 -1
- package/packages/core/dist/run-state/run-state.js +26 -36
- package/packages/core/dist/run-state/run-state.js.map +1 -1
- package/packages/core/dist/run-state/task-evidence.d.ts +0 -4
- package/packages/core/dist/run-state/task-evidence.js +5 -51
- package/packages/core/dist/run-state/task-evidence.js.map +1 -1
- package/packages/core/dist/run-state.d.ts +0 -1
- package/packages/core/dist/run-state.js +0 -1
- package/packages/core/dist/run-state.js.map +1 -1
- package/packages/core/dist/runtime-analysis/build.js +1 -1
- package/packages/core/dist/runtime-analysis/build.js.map +1 -1
- package/packages/core/dist/runtime-analysis/findings.js +7 -16
- package/packages/core/dist/runtime-analysis/findings.js.map +1 -1
- package/packages/core/dist/runtime-analysis/model.d.ts +1 -2
- package/packages/core/dist/runtime-paths.d.ts +0 -1
- package/packages/core/dist/runtime-paths.js +1 -4
- package/packages/core/dist/runtime-paths.js.map +1 -1
- package/packages/core/dist/runtime-projection-p0.d.ts +2 -2
- package/packages/core/dist/runtime-projection-p0.js +11 -0
- package/packages/core/dist/runtime-projection-p0.js.map +1 -1
- package/packages/core/dist/sdd-docs/artifact-depth.d.ts +14 -0
- package/packages/core/dist/sdd-docs/artifact-depth.js +179 -0
- package/packages/core/dist/sdd-docs/artifact-depth.js.map +1 -0
- package/packages/core/dist/sdd-docs/document-hashes.d.ts +0 -2
- package/packages/core/dist/sdd-docs/document-hashes.js +10 -97
- package/packages/core/dist/sdd-docs/document-hashes.js.map +1 -1
- package/packages/core/dist/sdd-docs/run-binding.d.ts +1 -1
- package/packages/core/dist/sdd-docs/run-binding.js +6 -8
- package/packages/core/dist/sdd-docs/run-binding.js.map +1 -1
- package/packages/core/dist/sdd-docs/task-parser.d.ts +5 -2
- package/packages/core/dist/sdd-docs/task-parser.js +85 -68
- package/packages/core/dist/sdd-docs/task-parser.js.map +1 -1
- package/packages/core/dist/sdd-docs/task-rendering.js +2 -2
- package/packages/core/dist/sdd-docs/task-rendering.js.map +1 -1
- package/packages/core/dist/spec-entry.js +40 -0
- package/packages/core/dist/spec-entry.js.map +1 -0
- package/packages/core/dist/spec-manager-contracts.d.ts +12 -0
- package/packages/core/dist/spec-manager-contracts.js +2 -0
- package/packages/core/dist/spec-manager-contracts.js.map +1 -0
- package/packages/core/dist/stage-artifacts.d.ts +2 -2
- package/packages/core/dist/stage-artifacts.js +19 -26
- package/packages/core/dist/stage-artifacts.js.map +1 -1
- package/packages/core/dist/stage-collaboration-contracts.d.ts +1 -1
- package/packages/core/dist/stage-collaboration-contracts.js +3 -6
- package/packages/core/dist/stage-collaboration-contracts.js.map +1 -1
- package/packages/core/dist/stage-collaboration.d.ts +111 -263
- package/packages/core/dist/stage-collaboration.js +1272 -1124
- package/packages/core/dist/stage-collaboration.js.map +1 -1
- package/packages/core/dist/stage-runtime/runtime.js +5 -5
- package/packages/core/dist/stage-runtime/runtime.js.map +1 -1
- package/packages/core/dist/status/project-status.d.ts +1 -44
- package/packages/core/dist/status/project-status.js +47 -170
- package/packages/core/dist/status/project-status.js.map +1 -1
- package/packages/core/dist/storage/runtime-store.js +73 -73
- package/packages/core/dist/subagents/contracts.d.ts +1 -1
- package/packages/core/dist/subagents/runtime.js +7 -7
- package/packages/core/dist/subagents/runtime.js.map +1 -1
- package/packages/core/dist/sync-back/apply.d.ts +1 -0
- package/packages/core/dist/sync-back/apply.js +2 -0
- package/packages/core/dist/sync-back/apply.js.map +1 -0
- package/packages/core/dist/sync-back/inspect.d.ts +1 -0
- package/packages/core/dist/sync-back/inspect.js +2 -0
- package/packages/core/dist/sync-back/inspect.js.map +1 -0
- package/packages/core/dist/sync-back.d.ts +1 -0
- package/packages/core/dist/sync-back.js +2 -0
- package/packages/core/dist/sync-back.js.map +1 -0
- package/packages/core/dist/task-execution-contract.d.ts +167 -0
- package/packages/core/dist/task-execution-contract.js +377 -0
- package/packages/core/dist/task-execution-contract.js.map +1 -0
- package/packages/core/dist/test-support/fixtures.js +329 -314
- package/packages/core/dist/test-support/fixtures.js.map +1 -1
- package/packages/core/dist/test-support/run-state.d.ts +1 -0
- package/packages/core/dist/test-support/run-state.js +53 -7
- package/packages/core/dist/test-support/run-state.js.map +1 -1
- package/packages/core/dist/truth-reconciliation.js +9 -12
- package/packages/core/dist/truth-reconciliation.js.map +1 -1
- package/packages/core/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/core/dist/verification/goal-verify.d.ts +0 -48
- package/packages/core/dist/verification/goal-verify.js +1 -520
- package/packages/core/dist/verification/goal-verify.js.map +1 -1
- package/packages/core/dist/verification/rendering.d.ts +5 -5
- package/packages/core/dist/verification/rendering.js +14 -14
- package/packages/core/dist/verification/rendering.js.map +1 -1
- package/packages/core/dist/verification/single-task-loop.d.ts +1 -0
- package/packages/core/dist/verification/single-task-loop.js +111 -159
- package/packages/core/dist/verification/single-task-loop.js.map +1 -1
- package/packages/core/dist/verification/task-evidence-judgment.d.ts +49 -0
- package/packages/core/dist/verification/task-evidence-judgment.js +521 -0
- package/packages/core/dist/verification/task-evidence-judgment.js.map +1 -0
- package/packages/core/dist/verification/test-runtime.js +21 -21
- package/packages/core/dist/verification/test-runtime.js.map +1 -1
- package/packages/core/dist/verification/validation-wave.d.ts +0 -18
- package/packages/core/dist/verification/validation-wave.js +5 -27
- package/packages/core/dist/verification/validation-wave.js.map +1 -1
- package/packages/core/dist/verification/verify-contract.js +45 -45
- package/packages/core/dist/verification/verify-contract.js.map +1 -1
- package/packages/core/dist/verification.d.ts +3 -3
- package/packages/core/dist/verification.js +2 -2
- package/packages/core/dist/verification.js.map +1 -1
- package/packages/core/dist/work-units/contracts.d.ts +1 -1
- package/packages/core/dist/workflow-gate/evidence-packet.js +9 -227
- package/packages/core/dist/workflow-gate/evidence-packet.js.map +1 -1
- package/packages/core/dist/workflow-gate/hard-checks.js +9 -50
- package/packages/core/dist/workflow-gate/hard-checks.js.map +1 -1
- package/packages/core/dist/workflow-gate/policy.js +4 -42
- package/packages/core/dist/workflow-gate/policy.js.map +1 -1
- package/packages/core/dist/workflow-gate/types.d.ts +2 -3
- package/packages/core/dist/workflow-state/affected-file-conflicts.d.ts +1 -0
- package/packages/core/dist/workflow-state/affected-file-conflicts.js +2 -1
- package/packages/core/dist/workflow-state/affected-file-conflicts.js.map +1 -1
- package/packages/core/dist/workflow-state/dependencies.js +1 -1
- package/packages/core/dist/workflow-state/latest-eligible-run.d.ts +1 -0
- package/packages/core/dist/workflow-state/latest-eligible-run.js +23 -63
- package/packages/core/dist/workflow-state/latest-eligible-run.js.map +1 -1
- package/packages/core/dist/workflow-state/resolve.d.ts +2 -2
- package/packages/core/dist/workflow-state/resolve.js +43 -65
- package/packages/core/dist/workflow-state/resolve.js.map +1 -1
- package/packages/core/package.json +5 -2
- package/tsconfig.build.json +6 -7
- package/node_modules/@sdd-agent-platform/core/src/verification/single-task-loop.test.ts +0 -269
- package/node_modules/@sdd-agent-platform/core/src/verification/test-runtime.test.ts +0 -492
- package/node_modules/@sdd-agent-platform/core/src/verification/validation-wave.test.ts +0 -383
- package/node_modules/@sdd-agent-platform/core/src/verification/verify-contract.test.ts +0 -188
- package/packages/cli/dist/commands/lifecycle.d.ts +0 -6
- package/packages/cli/dist/commands/lifecycle.js +0 -125
- package/packages/cli/dist/commands/lifecycle.js.map +0 -1
- package/packages/cli/dist/commands/test.d.ts +0 -6
- package/packages/cli/dist/commands/test.js +0 -373
- package/packages/cli/dist/commands/test.js.map +0 -1
- package/packages/cli/dist/commands/verifies.js +0 -87
- package/packages/cli/dist/commands/verifies.js.map +0 -1
- package/packages/cli/dist/commands/verify.d.ts +0 -6
- package/packages/cli/dist/commands/verify.js +0 -330
- package/packages/cli/dist/commands/verify.js.map +0 -1
|
@@ -7,18 +7,18 @@ import { createRun } from './run-state/run-state.js';
|
|
|
7
7
|
import { normalizePortablePath } from './path-safety.js';
|
|
8
8
|
import { getBranchStageEvidenceDir, normalizeBranchStageEvidenceRef, toBranchStageEvidenceRef } from './runtime-paths.js';
|
|
9
9
|
import { resolveSddContext } from './sdd-docs/context.js';
|
|
10
|
+
import { evaluatePlanArtifactDepth, evaluateSpecArtifactDepth, formatArtifactDepthBlockingIssues } from './sdd-docs/artifact-depth.js';
|
|
10
11
|
import { hashDocumentContent, hashSemanticDocument, hashTasksContract } from './sdd-docs/document-hashes.js';
|
|
11
12
|
import { parseSddTasksMarkdown } from './sdd-docs/task-parser.js';
|
|
13
|
+
import { EXECUTION_LANE_PROJECTION_TYPE, TASK_DEPENDENCY_GRAPH_PROJECTION_TYPE, TASK_UNIT_PROJECTION_TYPE, executionLaneScopeKey, readTaskDependencyGraphProjection, taskDependencyGraphScopeKey } from './task-execution-contract.js';
|
|
12
14
|
import { readWorkflowHandoffProjection, recordStageRunProjection, recordWorkflowHandoffProjection, STAGE_RUN_PROJECTION_TYPE, stageRunScopeKey, WORKFLOW_HANDOFF_PROJECTION_TYPE, workflowHandoffScopeKey } from './stage-runtime/runtime.js';
|
|
13
15
|
import { listRuntimeProjections, recordRuntimeArtifactPayload, recordRuntimeProjectionEnvelope, recordRuntimeStageArtifact, recordRuntimeStageCollaborationContract, runtimeScopedId } from './storage/runtime-store.js';
|
|
14
16
|
import { readMarkdownArtifact, validateStageArtifactFrontmatter } from './stage-artifacts.js';
|
|
15
17
|
import { readStageCollaborationContract, validateStageCollaborationContractFrontmatter } from './stage-collaboration-contracts.js';
|
|
16
|
-
import { inspectVerifyContract } from './verification/verify-contract.js';
|
|
17
18
|
export const SPEC_STAGE_MANAGER = 'spec-manager';
|
|
18
|
-
export const SPEC_STAGE_DRAFTER_AGENT = 'spec-drafter';
|
|
19
19
|
export const SPEC_STAGE_REVIEW_AGENT = 'spec-reviewer';
|
|
20
20
|
export const SPEC_STAGE_SCOUT_AGENT = 'scout';
|
|
21
|
-
export const SPEC_STAGE_AGENT_TEAM = [
|
|
21
|
+
export const SPEC_STAGE_AGENT_TEAM = [SPEC_STAGE_SCOUT_AGENT, SPEC_STAGE_REVIEW_AGENT];
|
|
22
22
|
export const SPEC_STAGE_REQUIRED_CAPABILITIES = ['norm_discovery', 'uncertainty_resolution'];
|
|
23
23
|
export const SPEC_STAGE_OPTIONAL_CAPABILITIES = ['context_curation', 'solution-design', 'frontend-engineering', 'security-engineering', 'ui-ux-product-design'];
|
|
24
24
|
export const SPEC_STAGE_MATERIAL_PACKS = ['project-norms', 'uncertainty-map', 'baseline-solution-design', 'baseline-frontend-engineering', 'baseline-security-engineering', 'baseline-ui-ux-product-design'];
|
|
@@ -26,32 +26,26 @@ export const STAGE_COLLABORATION_RUNTIME_PRODUCER_VERSION = 'phase9.1-stage-coll
|
|
|
26
26
|
export const SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_1_spec_collaboration_adjudication';
|
|
27
27
|
export const PLAN_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_2_plan_collaboration_adjudication';
|
|
28
28
|
export const PLAN_STAGE_MANAGER = 'plan-manager';
|
|
29
|
-
export const
|
|
30
|
-
export const PLAN_STAGE_REVIEW_AGENT = 'plan-
|
|
29
|
+
export const PLAN_STAGE_SCOUT_AGENT = 'plan-scout';
|
|
30
|
+
export const PLAN_STAGE_REVIEW_AGENT = 'plan-review-agent';
|
|
31
|
+
export const PLAN_STAGE_AGENT_TEAM = [PLAN_STAGE_SCOUT_AGENT, PLAN_STAGE_REVIEW_AGENT];
|
|
32
|
+
export const PLAN_SCOUT_DOMAINS = ['architecture-runtime', 'backend-api', 'frontend-ui', 'database-migration', 'security', 'performance', 'testing-validation'];
|
|
33
|
+
export const PLAN_STAGE_REQUIRED_CAPABILITIES = ['plan-strategy', 'plan-pressure-review'];
|
|
34
|
+
export const PLAN_STAGE_OPTIONAL_CAPABILITIES = [...PLAN_SCOUT_DOMAINS];
|
|
35
|
+
export const PLAN_STAGE_MATERIAL_PACKS = ['project-norms', 'plan-section-rubric', 'plan-scout-domain-packs'];
|
|
31
36
|
export const TASKS_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_3_tasks_collaboration_adjudication';
|
|
32
37
|
export const TASKS_STAGE_MANAGER = 'tasks-manager';
|
|
33
|
-
export const
|
|
34
|
-
export const TASKS_STAGE_REVIEW_AGENT = 'tasks-reviewer';
|
|
38
|
+
export const TASKS_STAGE_REVIEW_AGENT = 'task-review-agent';
|
|
35
39
|
export const TASKS_STAGE_SLICER_AGENT = 'task-slicer';
|
|
36
|
-
export const
|
|
37
|
-
export const
|
|
38
|
-
export const
|
|
39
|
-
export const
|
|
40
|
-
export const
|
|
41
|
-
export const
|
|
42
|
-
export const
|
|
43
|
-
export const
|
|
44
|
-
export const
|
|
45
|
-
export const DO_STAGE_DEBUGGER_AGENT = 'debugger';
|
|
46
|
-
export const TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_6_test_collaboration_adjudication';
|
|
47
|
-
export const TEST_STAGE_MANAGER = 'test-manager';
|
|
48
|
-
export const TEST_STAGE_RUNNER_AGENT = 'test-runner';
|
|
49
|
-
export const TEST_STAGE_VALIDATOR_AGENT = 'validator';
|
|
50
|
-
export const TEST_STAGE_REVIEW_AGENT = 'test-reviewer';
|
|
51
|
-
export const GOAL_VERIFY_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_7_goal_verify_collaboration_adjudication';
|
|
52
|
-
export const GOAL_VERIFY_STAGE_MANAGER = 'goal-verify-manager';
|
|
53
|
-
export const GOAL_VERIFY_STAGE_VALIDATOR_AGENT = 'goal-validator';
|
|
54
|
-
export const GOAL_VERIFY_STAGE_REVIEW_AGENT = 'goal-reviewer';
|
|
40
|
+
export const EXECUTE_IMPLEMENTER_AGENT = 'implementer';
|
|
41
|
+
export const EXECUTE_CODE_REVIEW_AGENT = 'code-reviewer';
|
|
42
|
+
export const EXECUTE_DEBUGGER_AGENT = 'debugger';
|
|
43
|
+
export const EXECUTE_TEST_RUNNER_AGENT = 'test-runner';
|
|
44
|
+
export const EXECUTE_VALIDATOR_AGENT = 'validator';
|
|
45
|
+
export const EXECUTE_TEST_REVIEW_AGENT = 'test-reviewer';
|
|
46
|
+
export const EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase10_execute_collaboration_adjudication';
|
|
47
|
+
export const EXECUTE_EVIDENCE_JUDGMENT_VALIDATOR_AGENT = 'evidence-validator';
|
|
48
|
+
export const EXECUTE_EVIDENCE_JUDGMENT_REVIEW_AGENT = 'evidence-reviewer';
|
|
55
49
|
export const TRUTH_ALIGNMENT_PROJECTION_TYPE = 'phase9_12_truth_alignment';
|
|
56
50
|
export const TRUTH_ALIGNMENT_CONTRACT = 'sdd-truth-alignment-v1';
|
|
57
51
|
export const SHIP_COLLABORATION_ADJUDICATION_PROJECTION_TYPE = 'phase9_9_ship_collaboration_adjudication';
|
|
@@ -60,7 +54,7 @@ export const SHIP_STAGE_VALIDATOR_AGENT = 'ship-validator';
|
|
|
60
54
|
export const SHIP_STAGE_REVIEW_AGENT = 'release-reviewer';
|
|
61
55
|
const TRUTH_ALIGNMENT_STATUSES = ['aligned', 'drift_detected', 'update_required', 'blocked'];
|
|
62
56
|
const TRUTH_ALIGNMENT_SEMANTIC_IMPACTS = ['none', 'bounded', 'material'];
|
|
63
|
-
const TRUTH_ALIGNMENT_OWNER_STAGES = ['spec', 'plan', 'tasks', '
|
|
57
|
+
const TRUTH_ALIGNMENT_OWNER_STAGES = ['spec', 'plan', 'tasks', 'execute', 'ship'];
|
|
64
58
|
export function deriveSpecCollaborationProfile(decision, generatedAt = new Date().toISOString()) {
|
|
65
59
|
const required = decision.requiredStages.includes('spec');
|
|
66
60
|
const intensity = specIntensity(decision, required);
|
|
@@ -92,9 +86,7 @@ export function buildSpecStageWorkOrder(profile, profileRef, generatedAt = new D
|
|
|
92
86
|
scope: profile.scope,
|
|
93
87
|
profileRef,
|
|
94
88
|
authorityCeiling: 'proposal_input',
|
|
95
|
-
requiredOutputKinds: profile.
|
|
96
|
-
? ['scout_context', 'spec_review', 'manager_closure_request']
|
|
97
|
-
: ['spec_review', 'manager_closure_request'],
|
|
89
|
+
requiredOutputKinds: specRequiredOutputKinds(profile.intensity),
|
|
98
90
|
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
99
91
|
stageManager: SPEC_STAGE_MANAGER,
|
|
100
92
|
agentTeam: profile.agentTeam,
|
|
@@ -109,7 +101,8 @@ export function buildSpecStageWorkOrder(profile, profileRef, generatedAt = new D
|
|
|
109
101
|
export function planCollaborationScopeKey(scope) {
|
|
110
102
|
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'plan'].join(':');
|
|
111
103
|
}
|
|
112
|
-
export function buildPlanStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString()) {
|
|
104
|
+
export function buildPlanStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString(), intensity = 'scout-first') {
|
|
105
|
+
const collaborationPlan = planCollaborationPlan(intensity);
|
|
113
106
|
return {
|
|
114
107
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
115
108
|
workOrderId: stableId('plan-work-order', scope),
|
|
@@ -117,14 +110,16 @@ export function buildPlanStageWorkOrder(scope, profileRef, inputRefs, generatedA
|
|
|
117
110
|
scope,
|
|
118
111
|
profileRef,
|
|
119
112
|
authorityCeiling: 'proposal_input',
|
|
120
|
-
requiredOutputKinds:
|
|
113
|
+
requiredOutputKinds: planRequiredOutputKinds(intensity),
|
|
121
114
|
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
122
115
|
inputRefs,
|
|
123
116
|
stageManager: PLAN_STAGE_MANAGER,
|
|
124
|
-
agentTeam:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
117
|
+
agentTeam: planMemberAgents(intensity),
|
|
118
|
+
planScoutDomains: planScoutDomains(intensity),
|
|
119
|
+
requiredCapabilities: planRequiredCapabilities(intensity),
|
|
120
|
+
optionalCapabilities: planOptionalCapabilities(intensity),
|
|
121
|
+
materialPackIds: planMaterialPackIds(intensity),
|
|
122
|
+
collaborationPlan,
|
|
128
123
|
generatedAt
|
|
129
124
|
};
|
|
130
125
|
}
|
|
@@ -143,98 +138,32 @@ export function buildTasksStageWorkOrder(scope, profileRef, inputRefs, generated
|
|
|
143
138
|
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
144
139
|
inputRefs,
|
|
145
140
|
stageManager: TASKS_STAGE_MANAGER,
|
|
146
|
-
agentTeam: [TASKS_STAGE_SLICER_AGENT,
|
|
141
|
+
agentTeam: [TASKS_STAGE_SLICER_AGENT, TASKS_STAGE_REVIEW_AGENT],
|
|
147
142
|
requiredCapabilities: ['task-decomposition', 'acceptance-mapping'],
|
|
148
143
|
optionalCapabilities: ['dependency-analysis', 'parallelization-planning'],
|
|
149
144
|
materialPackIds: ['project-norms', 'baseline-task-slicing', 'baseline-acceptance-mapping'],
|
|
150
145
|
generatedAt
|
|
151
146
|
};
|
|
152
147
|
}
|
|
153
|
-
export function
|
|
154
|
-
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', '
|
|
148
|
+
export function executeCollaborationScopeKey(scope) {
|
|
149
|
+
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'execute'].join(':');
|
|
155
150
|
}
|
|
156
|
-
export function
|
|
151
|
+
export function buildExecuteStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString()) {
|
|
157
152
|
return {
|
|
158
153
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
159
|
-
workOrderId: stableId('
|
|
160
|
-
stage: '
|
|
154
|
+
workOrderId: stableId('execute-work-order', scope),
|
|
155
|
+
stage: 'execute',
|
|
161
156
|
scope,
|
|
162
157
|
profileRef,
|
|
163
158
|
authorityCeiling: 'proposal_input',
|
|
164
|
-
requiredOutputKinds: ['
|
|
159
|
+
requiredOutputKinds: ['implementation_evidence', 'code_review', 'validation_evidence', 'checkpoint_decision', 'evidence_judgment', 'manager_closure_request'],
|
|
165
160
|
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
166
161
|
inputRefs,
|
|
167
|
-
stageManager:
|
|
168
|
-
agentTeam: [
|
|
169
|
-
requiredCapabilities: ['
|
|
170
|
-
optionalCapabilities: ['
|
|
171
|
-
materialPackIds: ['
|
|
172
|
-
generatedAt
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
export function doCollaborationScopeKey(scope) {
|
|
176
|
-
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'do'].join(':');
|
|
177
|
-
}
|
|
178
|
-
export function buildDoStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString()) {
|
|
179
|
-
return {
|
|
180
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
181
|
-
workOrderId: stableId('do-work-order', scope),
|
|
182
|
-
stage: 'do',
|
|
183
|
-
scope,
|
|
184
|
-
profileRef,
|
|
185
|
-
authorityCeiling: 'proposal_input',
|
|
186
|
-
requiredOutputKinds: ['implementation_evidence', 'code_review', 'manager_closure_request'],
|
|
187
|
-
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
188
|
-
inputRefs,
|
|
189
|
-
stageManager: DO_STAGE_MANAGER,
|
|
190
|
-
agentTeam: [DO_STAGE_IMPLEMENTER_AGENT, DO_STAGE_CODE_REVIEW_AGENT, DO_STAGE_DEBUGGER_AGENT],
|
|
191
|
-
requiredCapabilities: ['implementation', 'code-review'],
|
|
192
|
-
optionalCapabilities: ['debugging', 'security-engineering', 'frontend-engineering'],
|
|
193
|
-
materialPackIds: ['project-norms', 'baseline-implementation', 'baseline-code-review'],
|
|
194
|
-
generatedAt
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
export function testCollaborationScopeKey(scope) {
|
|
198
|
-
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'test'].join(':');
|
|
199
|
-
}
|
|
200
|
-
export function buildTestStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString()) {
|
|
201
|
-
return {
|
|
202
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
203
|
-
workOrderId: stableId('test-work-order', scope),
|
|
204
|
-
stage: 'test',
|
|
205
|
-
scope,
|
|
206
|
-
profileRef,
|
|
207
|
-
authorityCeiling: 'proposal_input',
|
|
208
|
-
requiredOutputKinds: ['test_execution', 'validation_evidence', 'test_review', 'manager_closure_request'],
|
|
209
|
-
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
210
|
-
inputRefs,
|
|
211
|
-
stageManager: TEST_STAGE_MANAGER,
|
|
212
|
-
agentTeam: [TEST_STAGE_RUNNER_AGENT, TEST_STAGE_VALIDATOR_AGENT, TEST_STAGE_REVIEW_AGENT],
|
|
213
|
-
requiredCapabilities: ['test-execution', 'validation-evidence'],
|
|
214
|
-
optionalCapabilities: ['flaky-test-analysis', 'frontend-validation', 'security-testing'],
|
|
215
|
-
materialPackIds: ['project-norms', 'baseline-test-execution', 'baseline-validation-evidence'],
|
|
216
|
-
generatedAt
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
export function goalVerifyCollaborationScopeKey(scope) {
|
|
220
|
-
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'goal-verify'].join(':');
|
|
221
|
-
}
|
|
222
|
-
export function buildGoalVerifyStageWorkOrder(scope, profileRef, inputRefs, generatedAt = new Date().toISOString()) {
|
|
223
|
-
return {
|
|
224
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
225
|
-
workOrderId: stableId('goal-verify-work-order', scope),
|
|
226
|
-
stage: 'goal-verify',
|
|
227
|
-
scope,
|
|
228
|
-
profileRef,
|
|
229
|
-
authorityCeiling: 'proposal_input',
|
|
230
|
-
requiredOutputKinds: ['goal_verification', 'goal_review', 'manager_closure_request'],
|
|
231
|
-
forbiddenActions: ['stage_pass', 'risk_decision', 'gate_pass', 'ship_ready', 'truth_alignment_approved'],
|
|
232
|
-
inputRefs,
|
|
233
|
-
stageManager: GOAL_VERIFY_STAGE_MANAGER,
|
|
234
|
-
agentTeam: [GOAL_VERIFY_STAGE_VALIDATOR_AGENT, GOAL_VERIFY_STAGE_REVIEW_AGENT],
|
|
235
|
-
requiredCapabilities: ['goal-verification', 'acceptance-coverage'],
|
|
236
|
-
optionalCapabilities: ['gap-analysis', 'regression-risk-review'],
|
|
237
|
-
materialPackIds: ['project-norms', 'baseline-goal-verification', 'baseline-acceptance-coverage'],
|
|
162
|
+
stageManager: 'execute-manager',
|
|
163
|
+
agentTeam: [EXECUTE_IMPLEMENTER_AGENT, EXECUTE_CODE_REVIEW_AGENT, EXECUTE_DEBUGGER_AGENT, EXECUTE_TEST_RUNNER_AGENT, EXECUTE_VALIDATOR_AGENT, EXECUTE_TEST_REVIEW_AGENT, EXECUTE_EVIDENCE_JUDGMENT_VALIDATOR_AGENT, EXECUTE_EVIDENCE_JUDGMENT_REVIEW_AGENT],
|
|
164
|
+
requiredCapabilities: ['implementation', 'code-review', 'validation', 'evidence-judgment'],
|
|
165
|
+
optionalCapabilities: ['debugging', 'checkpoint-review', 'frontend-engineering', 'security-engineering'],
|
|
166
|
+
materialPackIds: ['accepted-task-contract', 'execute-lane-contract', 'validation-contract', 'checkpoint-policy', 'evidence-judgment-policy'],
|
|
238
167
|
generatedAt
|
|
239
168
|
};
|
|
240
169
|
}
|
|
@@ -242,11 +171,11 @@ export function truthAlignmentScopeKey(scope) {
|
|
|
242
171
|
return [scope.branch, scope.taskId ?? 'all', scope.runId ?? 'none', scope.changeRef ?? 'none', 'truth-alignment'].join(':');
|
|
243
172
|
}
|
|
244
173
|
function buildTruthAlignmentProjection(scope, input) {
|
|
245
|
-
const acceptedRealityRefs = uniqueRuntimeRefs([input.
|
|
174
|
+
const acceptedRealityRefs = uniqueRuntimeRefs([input.acceptedEvidenceJudgmentRef, ...input.artifactRefs].filter((ref) => ref !== null));
|
|
246
175
|
return {
|
|
247
176
|
contract: TRUTH_ALIGNMENT_CONTRACT,
|
|
248
177
|
branch: scope.branch,
|
|
249
|
-
sourceStage: '
|
|
178
|
+
sourceStage: 'execute',
|
|
250
179
|
declaredTruthRefs: uniqueRuntimeRefs(input.declaredTruthRefs),
|
|
251
180
|
acceptedRealityRefs,
|
|
252
181
|
status: input.status,
|
|
@@ -316,46 +245,13 @@ export async function recordTasksCollaborationAdjudicationProjection(projectRoot
|
|
|
316
245
|
payload: result
|
|
317
246
|
});
|
|
318
247
|
}
|
|
319
|
-
export async function
|
|
320
|
-
return recordRuntimeProjectionEnvelope(projectRoot, {
|
|
321
|
-
projectionType: VERIFIES_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
|
|
322
|
-
scopeKey: verifiesCollaborationScopeKey(result.scope),
|
|
323
|
-
inputHash: stableHash(JSON.stringify(result)),
|
|
324
|
-
producer: 'phase9.4-verifies-stage-collaboration-runtime',
|
|
325
|
-
producerVersion: 'phase9.4-verifies-stage-collaboration-runtime-v1',
|
|
326
|
-
generatedAt: result.createdAt,
|
|
327
|
-
payload: result
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
export async function recordDoCollaborationAdjudicationProjection(projectRoot, result) {
|
|
248
|
+
export async function recordExecuteCollaborationAdjudicationProjection(projectRoot, result) {
|
|
331
249
|
return recordRuntimeProjectionEnvelope(projectRoot, {
|
|
332
|
-
projectionType:
|
|
333
|
-
scopeKey:
|
|
250
|
+
projectionType: EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
|
|
251
|
+
scopeKey: executeCollaborationScopeKey(result.scope),
|
|
334
252
|
inputHash: stableHash(JSON.stringify(result)),
|
|
335
|
-
producer: '
|
|
336
|
-
producerVersion: '
|
|
337
|
-
generatedAt: result.createdAt,
|
|
338
|
-
payload: result
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
export async function recordTestCollaborationAdjudicationProjection(projectRoot, result) {
|
|
342
|
-
return recordRuntimeProjectionEnvelope(projectRoot, {
|
|
343
|
-
projectionType: TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
|
|
344
|
-
scopeKey: testCollaborationScopeKey(result.scope),
|
|
345
|
-
inputHash: stableHash(JSON.stringify(result)),
|
|
346
|
-
producer: 'phase9.6-test-stage-collaboration-runtime',
|
|
347
|
-
producerVersion: 'phase9.6-test-stage-collaboration-runtime-v1',
|
|
348
|
-
generatedAt: result.createdAt,
|
|
349
|
-
payload: result
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
export async function recordGoalVerifyCollaborationAdjudicationProjection(projectRoot, result) {
|
|
353
|
-
return recordRuntimeProjectionEnvelope(projectRoot, {
|
|
354
|
-
projectionType: GOAL_VERIFY_COLLABORATION_ADJUDICATION_PROJECTION_TYPE,
|
|
355
|
-
scopeKey: goalVerifyCollaborationScopeKey(result.scope),
|
|
356
|
-
inputHash: stableHash(JSON.stringify(result)),
|
|
357
|
-
producer: 'phase9.7-goal-verify-stage-collaboration-runtime',
|
|
358
|
-
producerVersion: 'phase9.7-goal-verify-stage-collaboration-runtime-v1',
|
|
253
|
+
producer: 'phase10-execute-stage-collaboration-runtime',
|
|
254
|
+
producerVersion: 'phase10-execute-stage-collaboration-runtime-v1',
|
|
359
255
|
generatedAt: result.createdAt,
|
|
360
256
|
payload: result
|
|
361
257
|
});
|
|
@@ -406,13 +302,15 @@ export async function reconcileSpecCollaborationClosure(projectRoot, input) {
|
|
|
406
302
|
const profile = deriveSpecCollaborationProfile(decision, generatedAt);
|
|
407
303
|
const profileRef = { kind: 'projection', ref: `${SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${specCollaborationScopeKey(profile.scope)}:profile` };
|
|
408
304
|
const workOrder = profile.stageManager ? buildSpecStageWorkOrder(profile, profileRef, generatedAt) : null;
|
|
409
|
-
const registeredCollaborationContracts =
|
|
305
|
+
const registeredCollaborationContracts = input.collaborationContractRefs && input.collaborationContractRefs.length > 0
|
|
306
|
+
? await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'spec', workOrder, input.collaborationContractRefs, generatedAt)
|
|
307
|
+
: [];
|
|
410
308
|
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
411
309
|
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
412
310
|
const registeredArtifacts = await registerSpecStageArtifacts(projectRoot, context.rawBranch, profile, input.artifactRefs, run.runId, generatedAt);
|
|
413
311
|
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
414
|
-
const
|
|
415
|
-
const closureRequest = input.closureRequest ??
|
|
312
|
+
const outputClosure = await buildOutputCenteredSpecClosureRequest(projectRoot, profile, workOrder, context.partition, input.outputCloseRequest, generatedAt);
|
|
313
|
+
const closureRequest = input.closureRequest ?? outputClosure;
|
|
416
314
|
const coordination = input.coordination ?? deriveRegisteredSpecManagerCoordination(profile, workOrder, registeredArtifacts, generatedAt);
|
|
417
315
|
const candidate = closureRequest?.candidate ?? null;
|
|
418
316
|
const reviews = closureRequest?.reviewResults ?? [];
|
|
@@ -519,10 +417,11 @@ export async function reconcilePlanCollaborationClosure(projectRoot, input) {
|
|
|
519
417
|
const workOrderInputRefs = acceptedSpecHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
520
418
|
const profileRef = { kind: 'projection', ref: `${PLAN_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${planCollaborationScopeKey(decision.scope)}:profile` };
|
|
521
419
|
const workOrder = planRequired && !blocked ? buildPlanStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
522
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'plan',
|
|
420
|
+
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'plan', null, input.collaborationContractRefs, generatedAt);
|
|
523
421
|
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
524
422
|
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
525
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'plan', input.artifactRefs,
|
|
423
|
+
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'plan', input.artifactRefs, false, run.runId, generatedAt);
|
|
424
|
+
const closureRequest = await buildOutputCenteredPlanClosureRequest(projectRoot, decision.scope, workOrder, context.partition, acceptedSpecHandoffEnvelope?.payload ?? null, input.outputCloseRequest, generatedAt);
|
|
526
425
|
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
527
426
|
const lifecycleRiskProjectionRef = {
|
|
528
427
|
kind: 'projection',
|
|
@@ -535,7 +434,8 @@ export async function reconcilePlanCollaborationClosure(projectRoot, input) {
|
|
|
535
434
|
blocked,
|
|
536
435
|
registeredArtifacts,
|
|
537
436
|
registeredCollaborationContracts,
|
|
538
|
-
acceptedSpecHandoff: acceptedSpecHandoffEnvelope?.payload ?? null
|
|
437
|
+
acceptedSpecHandoff: acceptedSpecHandoffEnvelope?.payload ?? null,
|
|
438
|
+
closureRequest,
|
|
539
439
|
});
|
|
540
440
|
const health = planAcceptance.planAcceptanceStatus === 'accepted'
|
|
541
441
|
? 'ready_for_tasks'
|
|
@@ -556,11 +456,14 @@ export async function reconcilePlanCollaborationClosure(projectRoot, input) {
|
|
|
556
456
|
kind: 'projection',
|
|
557
457
|
ref: `${STAGE_RUN_PROJECTION_TYPE}:${stageRunScopeKey(stageRun.scope, stageRun.stage)}`
|
|
558
458
|
};
|
|
459
|
+
const acceptedSpecRef = acceptedSpecRefFromHandoff(context.partition, acceptedSpecHandoffEnvelope?.payload ?? null);
|
|
460
|
+
const handoffOutputRefs = [planAcceptance.acceptedPlanRef].filter((ref) => ref !== null);
|
|
461
|
+
const handoffRequiredInputRefs = [acceptedSpecRef, planAcceptance.acceptedPlanRef].filter((ref) => ref !== null);
|
|
559
462
|
const handoff = planAcceptance.planAcceptanceStatus === 'accepted'
|
|
560
463
|
? buildPlanWorkflowHandoff(decision.scope, decision, {
|
|
561
|
-
outputRefs,
|
|
562
|
-
requiredInputRefs:
|
|
563
|
-
evidenceRefs:
|
|
464
|
+
outputRefs: handoffOutputRefs,
|
|
465
|
+
requiredInputRefs: handoffRequiredInputRefs,
|
|
466
|
+
evidenceRefs: [],
|
|
564
467
|
riskDecisionRef: lifecycleRiskProjectionRef,
|
|
565
468
|
generatedAt
|
|
566
469
|
})
|
|
@@ -599,7 +502,7 @@ export async function reconcilePlanCollaborationClosure(projectRoot, input) {
|
|
|
599
502
|
scope: decision.scope,
|
|
600
503
|
status: health === 'ready_for_tasks' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
601
504
|
health,
|
|
602
|
-
acceptedDecisionRefs:
|
|
505
|
+
acceptedDecisionRefs: [planAcceptance.acceptedPlanRef, adjudicationProjectionRef].filter((ref) => ref !== null),
|
|
603
506
|
advisoryRefs: [],
|
|
604
507
|
capabilityRefs: artifactRefs.filter((ref) => ref.ref.includes('context') || ref.ref.includes('capability')),
|
|
605
508
|
blockingReasons: health === 'ready_for_tasks' || health === 'no-op' ? [] : planAcceptance.reasons,
|
|
@@ -648,10 +551,11 @@ export async function reconcileTasksCollaborationClosure(projectRoot, input) {
|
|
|
648
551
|
const workOrderInputRefs = acceptedPlanHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
649
552
|
const profileRef = { kind: 'projection', ref: `${TASKS_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${tasksCollaborationScopeKey(decision.scope)}:profile` };
|
|
650
553
|
const workOrder = tasksRequired && !blocked ? buildTasksStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
651
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'tasks',
|
|
554
|
+
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'tasks', null, input.collaborationContractRefs, generatedAt);
|
|
652
555
|
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
653
556
|
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
654
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'tasks', input.artifactRefs,
|
|
557
|
+
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'tasks', input.artifactRefs, false, run.runId, generatedAt);
|
|
558
|
+
const closureRequest = await buildOutputCenteredTasksClosureRequest(projectRoot, decision.scope, workOrder, context.partition, acceptedPlanHandoffEnvelope?.payload ?? null, input.outputCloseRequest, generatedAt);
|
|
655
559
|
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
656
560
|
const lifecycleRiskProjectionRef = {
|
|
657
561
|
kind: 'projection',
|
|
@@ -664,10 +568,11 @@ export async function reconcileTasksCollaborationClosure(projectRoot, input) {
|
|
|
664
568
|
blocked,
|
|
665
569
|
registeredArtifacts,
|
|
666
570
|
registeredCollaborationContracts,
|
|
667
|
-
acceptedPlanHandoff: acceptedPlanHandoffEnvelope?.payload ?? null
|
|
571
|
+
acceptedPlanHandoff: acceptedPlanHandoffEnvelope?.payload ?? null,
|
|
572
|
+
closureRequest
|
|
668
573
|
});
|
|
669
574
|
const health = tasksAcceptance.tasksAcceptanceStatus === 'accepted'
|
|
670
|
-
? '
|
|
575
|
+
? 'ready_for_execute'
|
|
671
576
|
: !tasksRequired
|
|
672
577
|
? 'no-op'
|
|
673
578
|
: blocked
|
|
@@ -726,17 +631,17 @@ export async function reconcileTasksCollaborationClosure(projectRoot, input) {
|
|
|
726
631
|
decisionId: stableId('tasks-stage-decision', decision.scope, run.runId, generatedAt),
|
|
727
632
|
stage: 'tasks',
|
|
728
633
|
scope: decision.scope,
|
|
729
|
-
status: health === '
|
|
634
|
+
status: health === 'ready_for_execute' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
730
635
|
health,
|
|
731
636
|
acceptedDecisionRefs: outputRefs,
|
|
732
637
|
advisoryRefs: [],
|
|
733
638
|
capabilityRefs: artifactRefs.filter((ref) => ref.ref.includes('context') || ref.ref.includes('capability')),
|
|
734
|
-
blockingReasons: health === '
|
|
639
|
+
blockingReasons: health === 'ready_for_execute' || health === 'no-op' ? [] : tasksAcceptance.reasons,
|
|
735
640
|
createdAt: generatedAt
|
|
736
641
|
},
|
|
737
642
|
handoffPacket: handoff,
|
|
738
643
|
rejection,
|
|
739
|
-
nextActions: buildStageRuntimeNextActions('tasks', decision.scope, generatedAt, health === '
|
|
644
|
+
nextActions: buildStageRuntimeNextActions('tasks', decision.scope, generatedAt, health === 'ready_for_execute' ? ['stage_ready', 'handoff_ready'] : rejection ? [rejectionReasonToNextActionReason(rejection.reasonCode)] : ['report_only']),
|
|
740
645
|
closureRefs,
|
|
741
646
|
createdAt: generatedAt
|
|
742
647
|
};
|
|
@@ -758,7 +663,7 @@ export async function reconcileTasksCollaborationClosure(projectRoot, input) {
|
|
|
758
663
|
acceptedTasksRef: tasksAcceptance.acceptedTasksRef
|
|
759
664
|
};
|
|
760
665
|
}
|
|
761
|
-
export async function
|
|
666
|
+
export async function reconcileExecuteCollaborationClosure(projectRoot, input) {
|
|
762
667
|
const generatedAt = input.generatedAt ?? new Date().toISOString();
|
|
763
668
|
const context = await resolveSddContext(projectRoot, { branch: input.decision.scope.branch, branchSource: 'cli_option' });
|
|
764
669
|
const decision = {
|
|
@@ -771,504 +676,122 @@ export async function reconcileVerifiesCollaborationClosure(projectRoot, input)
|
|
|
771
676
|
lifecycleDecision: runLifecycleDecisionRecord(decision)
|
|
772
677
|
});
|
|
773
678
|
const runRef = { kind: 'run', ref: run.runId };
|
|
774
|
-
const
|
|
775
|
-
const blocked = decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' || decision.blockedStages.includes('
|
|
776
|
-
const acceptedTasksHandoffEnvelope = await readWorkflowHandoffProjection(projectRoot, decision.scope, 'tasks', '
|
|
679
|
+
const executeRequired = decision.requiredStages.includes('execute');
|
|
680
|
+
const blocked = decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' || decision.blockedStages.includes('execute');
|
|
681
|
+
const acceptedTasksHandoffEnvelope = await readWorkflowHandoffProjection(projectRoot, decision.scope, 'tasks', 'execute');
|
|
777
682
|
const workOrderInputRefs = acceptedTasksHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
778
|
-
const profileRef = { kind: 'projection', ref: `${
|
|
779
|
-
const workOrder =
|
|
780
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, '
|
|
683
|
+
const profileRef = { kind: 'projection', ref: `${EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${executeCollaborationScopeKey(decision.scope)}:profile` };
|
|
684
|
+
const workOrder = executeRequired && !blocked ? buildExecuteStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
685
|
+
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'execute', workOrder, input.collaborationContractRefs, generatedAt);
|
|
781
686
|
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
782
687
|
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
783
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, '
|
|
688
|
+
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'execute', input.artifactRefs, Boolean(workOrder), run.runId, generatedAt);
|
|
784
689
|
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
785
690
|
const lifecycleRiskProjectionRef = {
|
|
786
691
|
kind: 'projection',
|
|
787
692
|
ref: `${LIFECYCLE_RISK_DECISION_PROJECTION_TYPE}:${lifecycleRiskDecisionScopeKey(decision.scope)}`
|
|
788
693
|
};
|
|
789
|
-
const adjudicationProjectionRef =
|
|
790
|
-
const
|
|
694
|
+
const adjudicationProjectionRef = executeAdjudicationProjectionRef(decision.scope);
|
|
695
|
+
const executeAcceptance = await validateAcceptedExecuteArtifact(projectRoot, {
|
|
791
696
|
partition: context.partition,
|
|
792
|
-
required:
|
|
697
|
+
required: executeRequired,
|
|
793
698
|
blocked,
|
|
794
699
|
registeredArtifacts,
|
|
795
700
|
registeredCollaborationContracts,
|
|
796
701
|
acceptedTasksHandoff: acceptedTasksHandoffEnvelope?.payload ?? null
|
|
797
702
|
});
|
|
798
|
-
const health =
|
|
799
|
-
? '
|
|
800
|
-
: !
|
|
801
|
-
? 'no-op'
|
|
802
|
-
: blocked
|
|
803
|
-
? 'blocked'
|
|
804
|
-
: 'rejected';
|
|
805
|
-
const outputRefs = [verifyAcceptance.acceptedVerifyRef, adjudicationProjectionRef, collaborationContractRef, ...artifactRefs].filter((ref) => ref !== null);
|
|
806
|
-
const stageRun = buildVerifiesClosureStageRun(decision.scope, run.runId, workOrder, health, {
|
|
807
|
-
outputRefs,
|
|
808
|
-
decisionRefs: [lifecycleRiskProjectionRef, adjudicationProjectionRef],
|
|
809
|
-
inputRefs: acceptedTasksHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs,
|
|
810
|
-
generatedAt,
|
|
811
|
-
rejectionReason: verifyAcceptance.rejectionIssue?.explanation ?? null
|
|
812
|
-
});
|
|
813
|
-
const stageRunProjectionRef = {
|
|
814
|
-
kind: 'projection',
|
|
815
|
-
ref: `${STAGE_RUN_PROJECTION_TYPE}:${stageRunScopeKey(stageRun.scope, stageRun.stage)}`
|
|
816
|
-
};
|
|
817
|
-
const handoff = verifyAcceptance.verifyAcceptanceStatus === 'accepted'
|
|
818
|
-
? buildVerifiesWorkflowHandoff(decision.scope, decision, {
|
|
819
|
-
outputRefs,
|
|
820
|
-
requiredInputRefs: verifyAcceptance.acceptedVerifyRef ? [verifyAcceptance.acceptedVerifyRef] : [],
|
|
821
|
-
evidenceRefs: artifactRefs,
|
|
822
|
-
riskDecisionRef: lifecycleRiskProjectionRef,
|
|
823
|
-
generatedAt
|
|
824
|
-
})
|
|
825
|
-
: null;
|
|
826
|
-
const workflowHandoffProjectionRef = handoff
|
|
827
|
-
? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(handoff.scope, handoff.fromStage, handoff.toStage)}` }
|
|
828
|
-
: undefined;
|
|
829
|
-
const rejection = verifyAcceptance.rejectionIssue
|
|
830
|
-
? buildStageRejection('verifies', decision.scope, null, verifyAcceptance.rejectionIssue.reasonCode, verifyAcceptance.rejectionIssue.explanation, verifyAcceptance.rejectionIssue.requiredNextAction, verifyAcceptance.rejectionIssue.fallbackRoute, generatedAt, true)
|
|
831
|
-
: null;
|
|
832
|
-
const closureRefs = {
|
|
833
|
-
runRef,
|
|
834
|
-
acceptedVerifyRef: verifyAcceptance.acceptedVerifyRef,
|
|
835
|
-
verifyAcceptanceStatus: verifyAcceptance.verifyAcceptanceStatus,
|
|
836
|
-
verifyHash: verifyAcceptance.verifyHash,
|
|
837
|
-
verifyContractHash: verifyAcceptance.verifyContractHash,
|
|
838
|
-
acceptedTasksHandoffRef: acceptedTasksHandoffEnvelope ? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(decision.scope, 'tasks', 'verifies')}` } : null,
|
|
839
|
-
artifactRefs,
|
|
840
|
-
collaborationContractRef,
|
|
841
|
-
lifecycleRiskProjectionRef,
|
|
842
|
-
adjudicationProjectionRef,
|
|
843
|
-
stageRunProjectionRef,
|
|
844
|
-
workflowHandoffProjectionRef,
|
|
845
|
-
reasons: verifyAcceptance.reasons
|
|
846
|
-
};
|
|
847
|
-
const adjudication = {
|
|
848
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
849
|
-
adjudicationId: stableId('verifies-adjudication', decision.scope, health, generatedAt),
|
|
850
|
-
stage: 'verifies',
|
|
851
|
-
scope: decision.scope,
|
|
852
|
-
health,
|
|
853
|
-
stageDecision: {
|
|
854
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
855
|
-
decisionId: stableId('verifies-stage-decision', decision.scope, run.runId, generatedAt),
|
|
856
|
-
stage: 'verifies',
|
|
857
|
-
scope: decision.scope,
|
|
858
|
-
status: health === 'ready_for_do' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
859
|
-
health,
|
|
860
|
-
acceptedDecisionRefs: outputRefs,
|
|
861
|
-
advisoryRefs: [],
|
|
862
|
-
capabilityRefs: artifactRefs.filter((ref) => ref.ref.includes('context') || ref.ref.includes('capability')),
|
|
863
|
-
blockingReasons: health === 'ready_for_do' || health === 'no-op' ? [] : verifyAcceptance.reasons,
|
|
864
|
-
createdAt: generatedAt
|
|
865
|
-
},
|
|
866
|
-
handoffPacket: handoff,
|
|
867
|
-
rejection,
|
|
868
|
-
nextActions: buildStageRuntimeNextActions('verifies', decision.scope, generatedAt, health === 'ready_for_do' ? ['stage_ready', 'handoff_ready'] : rejection ? [rejectionReasonToNextActionReason(rejection.reasonCode)] : ['report_only']),
|
|
869
|
-
closureRefs,
|
|
870
|
-
createdAt: generatedAt
|
|
871
|
-
};
|
|
872
|
-
await recordLifecycleRiskDecisionProjection(projectRoot, decision);
|
|
873
|
-
await recordStageRunProjection(projectRoot, stageRun);
|
|
874
|
-
if (handoff) {
|
|
875
|
-
await recordWorkflowHandoffProjection(projectRoot, handoff);
|
|
876
|
-
}
|
|
877
|
-
const projection = await recordVerifiesCollaborationAdjudicationProjection(projectRoot, adjudication);
|
|
878
|
-
return {
|
|
879
|
-
runId: run.runId,
|
|
880
|
-
branch: context.rawBranch,
|
|
881
|
-
workOrder,
|
|
882
|
-
adjudication,
|
|
883
|
-
projectionRef: { kind: 'projection', ref: `${projection.envelope.projectionType}:${projection.envelope.scopeKey}` },
|
|
884
|
-
artifactRefs,
|
|
885
|
-
registeredArtifacts,
|
|
886
|
-
registeredCollaborationContracts,
|
|
887
|
-
acceptedVerifyRef: verifyAcceptance.acceptedVerifyRef
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
export async function reconcileDoCollaborationClosure(projectRoot, input) {
|
|
891
|
-
const generatedAt = input.generatedAt ?? new Date().toISOString();
|
|
892
|
-
const context = await resolveSddContext(projectRoot, { branch: input.decision.scope.branch, branchSource: 'cli_option' });
|
|
893
|
-
const decision = {
|
|
894
|
-
...input.decision,
|
|
895
|
-
scope: { ...input.decision.scope, branch: context.rawBranch }
|
|
896
|
-
};
|
|
897
|
-
const run = await createRun(projectRoot, {
|
|
898
|
-
runId: input.runId,
|
|
899
|
-
branch: context.rawBranch,
|
|
900
|
-
lifecycleDecision: runLifecycleDecisionRecord(decision)
|
|
901
|
-
});
|
|
902
|
-
const runRef = { kind: 'run', ref: run.runId };
|
|
903
|
-
const doRequired = decision.requiredStages.includes('do');
|
|
904
|
-
const blocked = decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' || decision.blockedStages.includes('do');
|
|
905
|
-
const acceptedVerifyHandoffEnvelope = await readWorkflowHandoffProjection(projectRoot, decision.scope, 'verifies', 'do');
|
|
906
|
-
const workOrderInputRefs = acceptedVerifyHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
907
|
-
const profileRef = { kind: 'projection', ref: `${DO_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${doCollaborationScopeKey(decision.scope)}:profile` };
|
|
908
|
-
const workOrder = doRequired && !blocked ? buildDoStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
909
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'do', workOrder, input.collaborationContractRefs, generatedAt);
|
|
910
|
-
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
911
|
-
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
912
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'do', input.artifactRefs, Boolean(workOrder), run.runId, generatedAt);
|
|
913
|
-
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
914
|
-
const lifecycleRiskProjectionRef = {
|
|
915
|
-
kind: 'projection',
|
|
916
|
-
ref: `${LIFECYCLE_RISK_DECISION_PROJECTION_TYPE}:${lifecycleRiskDecisionScopeKey(decision.scope)}`
|
|
917
|
-
};
|
|
918
|
-
const adjudicationProjectionRef = doAdjudicationProjectionRef(decision.scope);
|
|
919
|
-
const implementationAcceptance = await validateAcceptedDoArtifact(projectRoot, {
|
|
920
|
-
partition: context.partition,
|
|
921
|
-
required: doRequired,
|
|
922
|
-
blocked,
|
|
923
|
-
registeredArtifacts,
|
|
924
|
-
registeredCollaborationContracts,
|
|
925
|
-
acceptedVerifyHandoff: acceptedVerifyHandoffEnvelope?.payload ?? null,
|
|
926
|
-
allowedChangedFileRefs: input.allowedChangedFileRefs
|
|
927
|
-
});
|
|
928
|
-
const health = implementationAcceptance.implementationAcceptanceStatus === 'accepted'
|
|
929
|
-
? 'ready_for_test'
|
|
930
|
-
: !doRequired
|
|
703
|
+
const health = executeAcceptance.executeAcceptanceStatus === 'accepted'
|
|
704
|
+
? 'ready_for_ship'
|
|
705
|
+
: !executeRequired
|
|
931
706
|
? 'no-op'
|
|
932
707
|
: blocked
|
|
933
708
|
? 'blocked'
|
|
934
709
|
: 'rejected';
|
|
935
|
-
const
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
decisionRefs: [lifecycleRiskProjectionRef, adjudicationProjectionRef],
|
|
939
|
-
inputRefs: acceptedVerifyHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs,
|
|
940
|
-
generatedAt,
|
|
941
|
-
rejectionReason: implementationAcceptance.rejectionIssue?.explanation ?? null
|
|
942
|
-
});
|
|
943
|
-
const stageRunProjectionRef = {
|
|
944
|
-
kind: 'projection',
|
|
945
|
-
ref: `${STAGE_RUN_PROJECTION_TYPE}:${stageRunScopeKey(stageRun.scope, stageRun.stage)}`
|
|
946
|
-
};
|
|
947
|
-
const handoff = implementationAcceptance.implementationAcceptanceStatus === 'accepted'
|
|
948
|
-
? buildDoWorkflowHandoff(decision.scope, decision, {
|
|
949
|
-
outputRefs,
|
|
950
|
-
requiredInputRefs: [implementationAcceptance.acceptedImplementationRef, ...implementationAcceptance.changedFileRefs].filter((ref) => ref !== null),
|
|
951
|
-
evidenceRefs: artifactRefs,
|
|
952
|
-
riskDecisionRef: lifecycleRiskProjectionRef,
|
|
953
|
-
generatedAt
|
|
954
|
-
})
|
|
710
|
+
const acceptedEvidenceJudgmentArtifact = latestStageArtifact(registeredArtifacts, 'evidence_judgment');
|
|
711
|
+
const acceptedEvidenceJudgmentRef = executeAcceptance.executeAcceptanceStatus === 'accepted' && acceptedEvidenceJudgmentArtifact
|
|
712
|
+
? { kind: 'artifact', ref: acceptedEvidenceJudgmentArtifact.ref, hash: acceptedEvidenceJudgmentArtifact.hash }
|
|
955
713
|
: null;
|
|
956
|
-
const
|
|
957
|
-
? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(handoff.scope, handoff.fromStage, handoff.toStage)}` }
|
|
958
|
-
: undefined;
|
|
959
|
-
const rejection = implementationAcceptance.rejectionIssue
|
|
960
|
-
? buildStageRejection('do', decision.scope, null, implementationAcceptance.rejectionIssue.reasonCode, implementationAcceptance.rejectionIssue.explanation, implementationAcceptance.rejectionIssue.requiredNextAction, implementationAcceptance.rejectionIssue.fallbackRoute, generatedAt, true)
|
|
961
|
-
: null;
|
|
962
|
-
const closureRefs = {
|
|
963
|
-
runRef,
|
|
964
|
-
acceptedImplementationRef: implementationAcceptance.acceptedImplementationRef,
|
|
965
|
-
implementationAcceptanceStatus: implementationAcceptance.implementationAcceptanceStatus,
|
|
966
|
-
implementationHash: implementationAcceptance.implementationHash,
|
|
967
|
-
changedFileRefs: implementationAcceptance.changedFileRefs,
|
|
968
|
-
acceptedVerifyHandoffRef: acceptedVerifyHandoffEnvelope ? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(decision.scope, 'verifies', 'do')}` } : null,
|
|
969
|
-
artifactRefs,
|
|
970
|
-
collaborationContractRef,
|
|
971
|
-
lifecycleRiskProjectionRef,
|
|
972
|
-
adjudicationProjectionRef,
|
|
973
|
-
stageRunProjectionRef,
|
|
974
|
-
workflowHandoffProjectionRef,
|
|
975
|
-
reasons: implementationAcceptance.reasons
|
|
976
|
-
};
|
|
977
|
-
const adjudication = {
|
|
978
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
979
|
-
adjudicationId: stableId('do-adjudication', decision.scope, health, generatedAt),
|
|
980
|
-
stage: 'do',
|
|
981
|
-
scope: decision.scope,
|
|
982
|
-
health,
|
|
983
|
-
stageDecision: {
|
|
984
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
985
|
-
decisionId: stableId('do-stage-decision', decision.scope, run.runId, generatedAt),
|
|
986
|
-
stage: 'do',
|
|
987
|
-
scope: decision.scope,
|
|
988
|
-
status: health === 'ready_for_test' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
989
|
-
health,
|
|
990
|
-
acceptedDecisionRefs: outputRefs,
|
|
991
|
-
advisoryRefs: [],
|
|
992
|
-
capabilityRefs: artifactRefs.filter((ref) => ref.ref.includes('debug') || ref.ref.includes('capability')),
|
|
993
|
-
blockingReasons: health === 'ready_for_test' || health === 'no-op' ? [] : implementationAcceptance.reasons,
|
|
994
|
-
createdAt: generatedAt
|
|
995
|
-
},
|
|
996
|
-
handoffPacket: handoff,
|
|
997
|
-
rejection,
|
|
998
|
-
nextActions: buildStageRuntimeNextActions('do', decision.scope, generatedAt, health === 'ready_for_test' ? ['stage_ready', 'handoff_ready'] : rejection ? [rejectionReasonToNextActionReason(rejection.reasonCode)] : ['report_only']),
|
|
999
|
-
closureRefs,
|
|
1000
|
-
createdAt: generatedAt
|
|
1001
|
-
};
|
|
1002
|
-
await recordLifecycleRiskDecisionProjection(projectRoot, decision);
|
|
1003
|
-
await recordStageRunProjection(projectRoot, stageRun);
|
|
1004
|
-
if (handoff) {
|
|
1005
|
-
await recordWorkflowHandoffProjection(projectRoot, handoff);
|
|
1006
|
-
}
|
|
1007
|
-
const projection = await recordDoCollaborationAdjudicationProjection(projectRoot, adjudication);
|
|
1008
|
-
return {
|
|
1009
|
-
runId: run.runId,
|
|
1010
|
-
branch: context.rawBranch,
|
|
1011
|
-
workOrder,
|
|
1012
|
-
adjudication,
|
|
1013
|
-
projectionRef: { kind: 'projection', ref: `${projection.envelope.projectionType}:${projection.envelope.scopeKey}` },
|
|
1014
|
-
artifactRefs,
|
|
1015
|
-
registeredArtifacts,
|
|
1016
|
-
registeredCollaborationContracts,
|
|
1017
|
-
acceptedImplementationRef: implementationAcceptance.acceptedImplementationRef,
|
|
1018
|
-
changedFileRefs: implementationAcceptance.changedFileRefs
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
export async function reconcileTestCollaborationClosure(projectRoot, input) {
|
|
1022
|
-
const generatedAt = input.generatedAt ?? new Date().toISOString();
|
|
1023
|
-
const context = await resolveSddContext(projectRoot, { branch: input.decision.scope.branch, branchSource: 'cli_option' });
|
|
1024
|
-
const decision = {
|
|
1025
|
-
...input.decision,
|
|
1026
|
-
scope: { ...input.decision.scope, branch: context.rawBranch }
|
|
1027
|
-
};
|
|
1028
|
-
const run = await createRun(projectRoot, {
|
|
1029
|
-
runId: input.runId,
|
|
1030
|
-
branch: context.rawBranch,
|
|
1031
|
-
lifecycleDecision: runLifecycleDecisionRecord(decision)
|
|
1032
|
-
});
|
|
1033
|
-
const runRef = { kind: 'run', ref: run.runId };
|
|
1034
|
-
const testRequired = decision.requiredStages.includes('test');
|
|
1035
|
-
const blocked = decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' || decision.blockedStages.includes('test');
|
|
1036
|
-
const acceptedDoHandoffEnvelope = await readWorkflowHandoffProjection(projectRoot, decision.scope, 'do', 'test');
|
|
1037
|
-
const workOrderInputRefs = acceptedDoHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
1038
|
-
const profileRef = { kind: 'projection', ref: `${TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${testCollaborationScopeKey(decision.scope)}:profile` };
|
|
1039
|
-
const workOrder = testRequired && !blocked ? buildTestStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
1040
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'test', workOrder, input.collaborationContractRefs, generatedAt);
|
|
1041
|
-
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
1042
|
-
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
1043
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'test', input.artifactRefs, Boolean(workOrder), run.runId, generatedAt);
|
|
1044
|
-
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
1045
|
-
const lifecycleRiskProjectionRef = {
|
|
1046
|
-
kind: 'projection',
|
|
1047
|
-
ref: `${LIFECYCLE_RISK_DECISION_PROJECTION_TYPE}:${lifecycleRiskDecisionScopeKey(decision.scope)}`
|
|
1048
|
-
};
|
|
1049
|
-
const adjudicationProjectionRef = testAdjudicationProjectionRef(decision.scope);
|
|
1050
|
-
const testAcceptance = await validateAcceptedTestArtifact(projectRoot, {
|
|
1051
|
-
partition: context.partition,
|
|
1052
|
-
required: testRequired,
|
|
1053
|
-
blocked,
|
|
1054
|
-
registeredArtifacts,
|
|
1055
|
-
registeredCollaborationContracts,
|
|
1056
|
-
acceptedDoHandoff: acceptedDoHandoffEnvelope?.payload ?? null
|
|
1057
|
-
});
|
|
1058
|
-
const health = testAcceptance.testAcceptanceStatus === 'accepted'
|
|
1059
|
-
? 'ready_for_goal_verify'
|
|
1060
|
-
: !testRequired
|
|
1061
|
-
? 'no-op'
|
|
1062
|
-
: blocked
|
|
1063
|
-
? 'blocked'
|
|
1064
|
-
: 'rejected';
|
|
1065
|
-
const outputRefs = [testAcceptance.acceptedTestEvidenceRef, adjudicationProjectionRef, collaborationContractRef, ...artifactRefs].filter((ref) => ref !== null);
|
|
1066
|
-
const stageRun = buildTestClosureStageRun(decision.scope, run.runId, workOrder, health, {
|
|
1067
|
-
outputRefs,
|
|
1068
|
-
decisionRefs: [lifecycleRiskProjectionRef, adjudicationProjectionRef],
|
|
1069
|
-
inputRefs: acceptedDoHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs,
|
|
1070
|
-
generatedAt,
|
|
1071
|
-
rejectionReason: testAcceptance.rejectionIssue?.explanation ?? null
|
|
1072
|
-
});
|
|
1073
|
-
const stageRunProjectionRef = {
|
|
1074
|
-
kind: 'projection',
|
|
1075
|
-
ref: `${STAGE_RUN_PROJECTION_TYPE}:${stageRunScopeKey(stageRun.scope, stageRun.stage)}`
|
|
1076
|
-
};
|
|
1077
|
-
const handoff = testAcceptance.testAcceptanceStatus === 'accepted'
|
|
1078
|
-
? buildTestWorkflowHandoff(decision.scope, decision, {
|
|
1079
|
-
outputRefs,
|
|
1080
|
-
requiredInputRefs: testAcceptance.acceptedTestEvidenceRef ? [testAcceptance.acceptedTestEvidenceRef] : [],
|
|
1081
|
-
evidenceRefs: artifactRefs,
|
|
1082
|
-
riskDecisionRef: lifecycleRiskProjectionRef,
|
|
1083
|
-
generatedAt
|
|
1084
|
-
})
|
|
1085
|
-
: null;
|
|
1086
|
-
const workflowHandoffProjectionRef = handoff
|
|
1087
|
-
? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(handoff.scope, handoff.fromStage, handoff.toStage)}` }
|
|
1088
|
-
: undefined;
|
|
1089
|
-
const rejection = testAcceptance.rejectionIssue
|
|
1090
|
-
? buildStageRejection('test', decision.scope, null, testAcceptance.rejectionIssue.reasonCode, testAcceptance.rejectionIssue.explanation, testAcceptance.rejectionIssue.requiredNextAction, testAcceptance.rejectionIssue.fallbackRoute, generatedAt, true)
|
|
1091
|
-
: null;
|
|
1092
|
-
const closureRefs = {
|
|
1093
|
-
runRef,
|
|
1094
|
-
acceptedTestEvidenceRef: testAcceptance.acceptedTestEvidenceRef,
|
|
1095
|
-
testAcceptanceStatus: testAcceptance.testAcceptanceStatus,
|
|
1096
|
-
testEvidenceHash: testAcceptance.testEvidenceHash,
|
|
1097
|
-
acceptedDoHandoffRef: acceptedDoHandoffEnvelope ? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(decision.scope, 'do', 'test')}` } : null,
|
|
1098
|
-
artifactRefs,
|
|
1099
|
-
collaborationContractRef,
|
|
1100
|
-
lifecycleRiskProjectionRef,
|
|
1101
|
-
adjudicationProjectionRef,
|
|
1102
|
-
stageRunProjectionRef,
|
|
1103
|
-
workflowHandoffProjectionRef,
|
|
1104
|
-
reasons: testAcceptance.reasons
|
|
1105
|
-
};
|
|
1106
|
-
const adjudication = {
|
|
1107
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
1108
|
-
adjudicationId: stableId('test-adjudication', decision.scope, health, generatedAt),
|
|
1109
|
-
stage: 'test',
|
|
1110
|
-
scope: decision.scope,
|
|
1111
|
-
health,
|
|
1112
|
-
stageDecision: {
|
|
1113
|
-
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
1114
|
-
decisionId: stableId('test-stage-decision', decision.scope, run.runId, generatedAt),
|
|
1115
|
-
stage: 'test',
|
|
1116
|
-
scope: decision.scope,
|
|
1117
|
-
status: health === 'ready_for_goal_verify' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
1118
|
-
health,
|
|
1119
|
-
acceptedDecisionRefs: outputRefs,
|
|
1120
|
-
advisoryRefs: [],
|
|
1121
|
-
capabilityRefs: artifactRefs.filter((ref) => ref.ref.includes('validation') || ref.ref.includes('capability')),
|
|
1122
|
-
blockingReasons: health === 'ready_for_goal_verify' || health === 'no-op' ? [] : testAcceptance.reasons,
|
|
1123
|
-
createdAt: generatedAt
|
|
1124
|
-
},
|
|
1125
|
-
handoffPacket: handoff,
|
|
1126
|
-
rejection,
|
|
1127
|
-
nextActions: buildStageRuntimeNextActions('test', decision.scope, generatedAt, health === 'ready_for_goal_verify' ? ['stage_ready', 'handoff_ready'] : rejection ? [rejectionReasonToNextActionReason(rejection.reasonCode)] : ['report_only']),
|
|
1128
|
-
closureRefs,
|
|
1129
|
-
createdAt: generatedAt
|
|
1130
|
-
};
|
|
1131
|
-
await recordLifecycleRiskDecisionProjection(projectRoot, decision);
|
|
1132
|
-
await recordStageRunProjection(projectRoot, stageRun);
|
|
1133
|
-
if (handoff) {
|
|
1134
|
-
await recordWorkflowHandoffProjection(projectRoot, handoff);
|
|
1135
|
-
}
|
|
1136
|
-
const projection = await recordTestCollaborationAdjudicationProjection(projectRoot, adjudication);
|
|
1137
|
-
return {
|
|
1138
|
-
runId: run.runId,
|
|
1139
|
-
branch: context.rawBranch,
|
|
1140
|
-
workOrder,
|
|
1141
|
-
adjudication,
|
|
1142
|
-
projectionRef: { kind: 'projection', ref: `${projection.envelope.projectionType}:${projection.envelope.scopeKey}` },
|
|
1143
|
-
artifactRefs,
|
|
1144
|
-
registeredArtifacts,
|
|
1145
|
-
registeredCollaborationContracts,
|
|
1146
|
-
acceptedTestEvidenceRef: testAcceptance.acceptedTestEvidenceRef
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
export async function reconcileGoalVerifyCollaborationClosure(projectRoot, input) {
|
|
1150
|
-
const generatedAt = input.generatedAt ?? new Date().toISOString();
|
|
1151
|
-
const context = await resolveSddContext(projectRoot, { branch: input.decision.scope.branch, branchSource: 'cli_option' });
|
|
1152
|
-
const decision = {
|
|
1153
|
-
...input.decision,
|
|
1154
|
-
scope: { ...input.decision.scope, branch: context.rawBranch }
|
|
1155
|
-
};
|
|
1156
|
-
const run = await createRun(projectRoot, {
|
|
1157
|
-
runId: input.runId,
|
|
1158
|
-
branch: context.rawBranch,
|
|
1159
|
-
lifecycleDecision: runLifecycleDecisionRecord(decision)
|
|
1160
|
-
});
|
|
1161
|
-
const runRef = { kind: 'run', ref: run.runId };
|
|
1162
|
-
const goalVerifyRequired = decision.requiredStages.includes('goal-verify');
|
|
1163
|
-
const blocked = decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' || decision.blockedStages.includes('goal-verify');
|
|
1164
|
-
const acceptedTestHandoffEnvelope = await readWorkflowHandoffProjection(projectRoot, decision.scope, 'test', 'goal-verify');
|
|
1165
|
-
const workOrderInputRefs = acceptedTestHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs;
|
|
1166
|
-
const profileRef = { kind: 'projection', ref: `${GOAL_VERIFY_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${goalVerifyCollaborationScopeKey(decision.scope)}:profile` };
|
|
1167
|
-
const workOrder = goalVerifyRequired && !blocked ? buildGoalVerifyStageWorkOrder(decision.scope, profileRef, workOrderInputRefs, generatedAt) : null;
|
|
1168
|
-
const registeredCollaborationContracts = await registerStageCollaborationContracts(projectRoot, context.rawBranch, 'goal-verify', workOrder, input.collaborationContractRefs, generatedAt);
|
|
1169
|
-
const validatedCollaborationContract = latestValidatedStageCollaborationContract(registeredCollaborationContracts);
|
|
1170
|
-
const collaborationContractRef = validatedCollaborationContract ? runtimeRefForStageCollaborationContract(validatedCollaborationContract) : null;
|
|
1171
|
-
const registeredArtifacts = await registerBranchStageArtifacts(projectRoot, context.rawBranch, 'goal-verify', input.artifactRefs, Boolean(workOrder), run.runId, generatedAt);
|
|
1172
|
-
const artifactRefs = registeredArtifacts.map(runtimeRefForStageArtifact);
|
|
1173
|
-
const lifecycleRiskProjectionRef = {
|
|
1174
|
-
kind: 'projection',
|
|
1175
|
-
ref: `${LIFECYCLE_RISK_DECISION_PROJECTION_TYPE}:${lifecycleRiskDecisionScopeKey(decision.scope)}`
|
|
1176
|
-
};
|
|
1177
|
-
const adjudicationProjectionRef = goalVerifyAdjudicationProjectionRef(decision.scope);
|
|
1178
|
-
const goalVerifyAcceptance = await validateAcceptedGoalVerifyArtifact(projectRoot, {
|
|
1179
|
-
partition: context.partition,
|
|
1180
|
-
required: goalVerifyRequired,
|
|
1181
|
-
blocked,
|
|
1182
|
-
registeredArtifacts,
|
|
1183
|
-
registeredCollaborationContracts,
|
|
1184
|
-
acceptedTestHandoff: acceptedTestHandoffEnvelope?.payload ?? null
|
|
1185
|
-
});
|
|
1186
|
-
const truthAlignmentObservation = goalVerifyAcceptance.truthAlignment;
|
|
1187
|
-
const truthAlignmentStatus = goalVerifyAcceptance.goalVerifyAcceptanceStatus === 'accepted'
|
|
1188
|
-
? truthAlignmentObservation?.status ?? 'aligned'
|
|
1189
|
-
: 'blocked';
|
|
1190
|
-
const declaredTruthRefs = await collectTruthAlignmentDeclaredTruthRefs(projectRoot, context.rawBranch, acceptedTestHandoffEnvelope?.payload ?? null);
|
|
1191
|
-
const truthAlignmentProjection = goalVerifyRequired
|
|
714
|
+
const truthAlignmentProjection = acceptedEvidenceJudgmentRef
|
|
1192
715
|
? buildTruthAlignmentProjection(decision.scope, {
|
|
1193
|
-
|
|
1194
|
-
declaredTruthRefs,
|
|
716
|
+
acceptedEvidenceJudgmentRef: acceptedEvidenceJudgmentRef,
|
|
717
|
+
declaredTruthRefs: await collectTruthAlignmentDeclaredTruthRefs(projectRoot, context.rawBranch, acceptedTasksHandoffEnvelope?.payload ?? null),
|
|
1195
718
|
artifactRefs,
|
|
1196
|
-
status:
|
|
1197
|
-
ownerStage:
|
|
1198
|
-
semanticImpact:
|
|
1199
|
-
staleRefs:
|
|
1200
|
-
invalidatesStages:
|
|
1201
|
-
reasons:
|
|
1202
|
-
? ['Accepted goal verification is structurally aligned with declared upstream truth refs.']
|
|
1203
|
-
: goalVerifyAcceptance.reasons,
|
|
719
|
+
status: 'aligned',
|
|
720
|
+
ownerStage: null,
|
|
721
|
+
semanticImpact: 'none',
|
|
722
|
+
staleRefs: [],
|
|
723
|
+
invalidatesStages: [],
|
|
724
|
+
reasons: ['Accepted execute evidence judgment is structurally aligned with declared upstream truth refs.'],
|
|
1204
725
|
generatedAt
|
|
1205
726
|
})
|
|
1206
727
|
: null;
|
|
1207
|
-
const goalVerifyClosureReasons = truthAlignmentProjection?.status !== 'aligned' && truthAlignmentProjection?.reasons.length ? truthAlignmentProjection.reasons : goalVerifyAcceptance.reasons;
|
|
1208
728
|
const truthAlignmentProjectionRef = truthAlignmentProjection
|
|
1209
|
-
? { kind: 'projection', ref: `${TRUTH_ALIGNMENT_PROJECTION_TYPE}:${truthAlignmentScopeKey({ branch: decision.scope.branch })}` }
|
|
1210
|
-
:
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1213
|
-
: !goalVerifyRequired
|
|
1214
|
-
? 'no-op'
|
|
1215
|
-
: blocked
|
|
1216
|
-
? 'blocked'
|
|
1217
|
-
: 'rejected';
|
|
1218
|
-
const outputRefs = [goalVerifyAcceptance.acceptedGoalVerificationRef, truthAlignmentProjectionRef, adjudicationProjectionRef, collaborationContractRef, ...artifactRefs].filter((ref) => ref !== null && ref !== undefined);
|
|
1219
|
-
const stageRun = buildGoalVerifyClosureStageRun(decision.scope, run.runId, workOrder, health, {
|
|
729
|
+
? { kind: 'projection', ref: `${TRUTH_ALIGNMENT_PROJECTION_TYPE}:${truthAlignmentScopeKey({ branch: decision.scope.branch })}` }
|
|
730
|
+
: null;
|
|
731
|
+
const outputRefs = [executeAcceptance.acceptedExecuteRef, truthAlignmentProjectionRef, adjudicationProjectionRef, collaborationContractRef, ...executeAcceptance.laneEvidenceRefs, ...artifactRefs].filter((ref) => ref !== null);
|
|
732
|
+
const stageRun = buildExecuteClosureStageRun(decision.scope, run.runId, workOrder, health, {
|
|
1220
733
|
outputRefs,
|
|
1221
734
|
decisionRefs: [lifecycleRiskProjectionRef, adjudicationProjectionRef],
|
|
1222
|
-
inputRefs:
|
|
735
|
+
inputRefs: acceptedTasksHandoffEnvelope?.payload.requiredInputRefs ?? decision.inputRefs,
|
|
1223
736
|
generatedAt,
|
|
1224
|
-
rejectionReason:
|
|
737
|
+
rejectionReason: executeAcceptance.rejectionIssue?.explanation ?? null
|
|
1225
738
|
});
|
|
1226
739
|
const stageRunProjectionRef = {
|
|
1227
740
|
kind: 'projection',
|
|
1228
741
|
ref: `${STAGE_RUN_PROJECTION_TYPE}:${stageRunScopeKey(stageRun.scope, stageRun.stage)}`
|
|
1229
742
|
};
|
|
1230
|
-
const handoff =
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
743
|
+
const handoff = executeAcceptance.executeAcceptanceStatus === 'accepted'
|
|
744
|
+
? buildExecuteWorkflowHandoff(decision.scope, decision, {
|
|
745
|
+
outputRefs,
|
|
746
|
+
requiredInputRefs: executeAcceptance.acceptedExecuteRef ? [executeAcceptance.acceptedExecuteRef, ...executeAcceptance.laneEvidenceRefs] : executeAcceptance.laneEvidenceRefs,
|
|
747
|
+
evidenceRefs: artifactRefs,
|
|
748
|
+
riskDecisionRef: lifecycleRiskProjectionRef,
|
|
749
|
+
generatedAt
|
|
750
|
+
})
|
|
751
|
+
: null;
|
|
752
|
+
const workflowHandoffProjectionRef = handoff
|
|
753
|
+
? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(handoff.scope, handoff.fromStage, handoff.toStage)}` }
|
|
754
|
+
: undefined;
|
|
755
|
+
const rejection = executeAcceptance.rejectionIssue
|
|
756
|
+
? buildStageRejection('execute', decision.scope, null, executeAcceptance.rejectionIssue.reasonCode, executeAcceptance.rejectionIssue.explanation, executeAcceptance.rejectionIssue.requiredNextAction, executeAcceptance.rejectionIssue.fallbackRoute, generatedAt, true)
|
|
1234
757
|
: null;
|
|
1235
758
|
const closureRefs = {
|
|
1236
759
|
runRef,
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
760
|
+
acceptedExecuteRef: executeAcceptance.acceptedExecuteRef,
|
|
761
|
+
executeAcceptanceStatus: executeAcceptance.executeAcceptanceStatus,
|
|
762
|
+
acceptedTasksHandoffRef: acceptedTasksHandoffEnvelope ? { kind: 'projection', ref: `${WORKFLOW_HANDOFF_PROJECTION_TYPE}:${workflowHandoffScopeKey(decision.scope, 'tasks', 'execute')}` } : null,
|
|
763
|
+
truthAlignmentProjectionRef,
|
|
764
|
+
laneEvidenceRefs: executeAcceptance.laneEvidenceRefs,
|
|
1241
765
|
artifactRefs,
|
|
1242
766
|
collaborationContractRef,
|
|
1243
767
|
lifecycleRiskProjectionRef,
|
|
1244
768
|
adjudicationProjectionRef,
|
|
1245
769
|
stageRunProjectionRef,
|
|
1246
770
|
workflowHandoffProjectionRef,
|
|
1247
|
-
|
|
1248
|
-
reasons: goalVerifyClosureReasons
|
|
771
|
+
reasons: executeAcceptance.reasons
|
|
1249
772
|
};
|
|
1250
773
|
const adjudication = {
|
|
1251
774
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
1252
|
-
adjudicationId: stableId('
|
|
1253
|
-
stage: '
|
|
775
|
+
adjudicationId: stableId('execute-adjudication', decision.scope, health, generatedAt),
|
|
776
|
+
stage: 'execute',
|
|
1254
777
|
scope: decision.scope,
|
|
1255
778
|
health,
|
|
1256
779
|
stageDecision: {
|
|
1257
780
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
1258
|
-
decisionId: stableId('
|
|
1259
|
-
stage: '
|
|
781
|
+
decisionId: stableId('execute-stage-decision', decision.scope, run.runId, generatedAt),
|
|
782
|
+
stage: 'execute',
|
|
1260
783
|
scope: decision.scope,
|
|
1261
784
|
status: health === 'ready_for_ship' ? 'completed' : health === 'no-op' ? 'skipped' : health === 'blocked' ? 'blocked' : 'rejected',
|
|
1262
785
|
health,
|
|
1263
786
|
acceptedDecisionRefs: outputRefs,
|
|
1264
787
|
advisoryRefs: [],
|
|
1265
|
-
capabilityRefs:
|
|
1266
|
-
blockingReasons: health === 'ready_for_ship' || health === 'no-op' ? [] :
|
|
788
|
+
capabilityRefs: executeAcceptance.laneEvidenceRefs,
|
|
789
|
+
blockingReasons: health === 'ready_for_ship' || health === 'no-op' ? [] : executeAcceptance.reasons,
|
|
1267
790
|
createdAt: generatedAt
|
|
1268
791
|
},
|
|
1269
792
|
handoffPacket: handoff,
|
|
1270
793
|
rejection,
|
|
1271
|
-
nextActions: buildStageRuntimeNextActions('
|
|
794
|
+
nextActions: buildStageRuntimeNextActions('execute', decision.scope, generatedAt, health === 'ready_for_ship' ? ['stage_ready', 'handoff_ready'] : rejection ? [rejectionReasonToNextActionReason(rejection.reasonCode)] : ['report_only']),
|
|
1272
795
|
closureRefs,
|
|
1273
796
|
createdAt: generatedAt
|
|
1274
797
|
};
|
|
@@ -1277,7 +800,10 @@ export async function reconcileGoalVerifyCollaborationClosure(projectRoot, input
|
|
|
1277
800
|
if (truthAlignmentProjection) {
|
|
1278
801
|
await recordTruthAlignmentProjection(projectRoot, truthAlignmentProjection);
|
|
1279
802
|
}
|
|
1280
|
-
|
|
803
|
+
if (handoff) {
|
|
804
|
+
await recordWorkflowHandoffProjection(projectRoot, handoff);
|
|
805
|
+
}
|
|
806
|
+
const projection = await recordExecuteCollaborationAdjudicationProjection(projectRoot, adjudication);
|
|
1281
807
|
return {
|
|
1282
808
|
runId: run.runId,
|
|
1283
809
|
branch: context.rawBranch,
|
|
@@ -1287,7 +813,7 @@ export async function reconcileGoalVerifyCollaborationClosure(projectRoot, input
|
|
|
1287
813
|
artifactRefs,
|
|
1288
814
|
registeredArtifacts,
|
|
1289
815
|
registeredCollaborationContracts,
|
|
1290
|
-
|
|
816
|
+
acceptedExecuteRef: executeAcceptance.acceptedExecuteRef
|
|
1291
817
|
};
|
|
1292
818
|
}
|
|
1293
819
|
export async function reconcileShipCollaborationClosure(projectRoot, input) {
|
|
@@ -1413,11 +939,8 @@ export async function reconcileShipCollaborationClosure(projectRoot, input) {
|
|
|
1413
939
|
const FULL_STAGE_CHAIN = [
|
|
1414
940
|
{ stage: 'spec', expectedHealth: 'ready_for_plan', projectionType: SPEC_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
1415
941
|
{ stage: 'plan', expectedHealth: 'ready_for_tasks', projectionType: PLAN_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
1416
|
-
{ stage: 'tasks', expectedHealth: '
|
|
1417
|
-
{ stage: '
|
|
1418
|
-
{ stage: 'do', expectedHealth: 'ready_for_test', projectionType: DO_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
1419
|
-
{ stage: 'test', expectedHealth: 'ready_for_goal_verify', projectionType: TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
1420
|
-
{ stage: 'goal-verify', expectedHealth: 'ready_for_ship', projectionType: GOAL_VERIFY_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
942
|
+
{ stage: 'tasks', expectedHealth: 'ready_for_execute', projectionType: TASKS_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
943
|
+
{ stage: 'execute', expectedHealth: 'ready_for_ship', projectionType: EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE },
|
|
1421
944
|
{ stage: 'ship', expectedHealth: 'ship_ready', projectionType: SHIP_COLLABORATION_ADJUDICATION_PROJECTION_TYPE }
|
|
1422
945
|
];
|
|
1423
946
|
export async function inspectFullStageChain(projectRoot, branch) {
|
|
@@ -1447,14 +970,14 @@ export async function inspectFullStageChain(projectRoot, branch) {
|
|
|
1447
970
|
}
|
|
1448
971
|
async function collectTruthAlignmentDeclaredTruthRefs(projectRoot, branch, testHandoff) {
|
|
1449
972
|
const projectionTypes = FULL_STAGE_CHAIN
|
|
1450
|
-
.filter((item) => item.stage !== '
|
|
973
|
+
.filter((item) => item.stage !== 'ship')
|
|
1451
974
|
.map((item) => item.projectionType);
|
|
1452
975
|
const projections = await listRuntimeProjections(projectRoot, projectionTypes);
|
|
1453
976
|
const envelopes = projections
|
|
1454
977
|
.map((projection) => projection.payload)
|
|
1455
978
|
.filter((envelope) => envelope?.payload?.scope?.branch === branch);
|
|
1456
979
|
const acceptedRefs = FULL_STAGE_CHAIN
|
|
1457
|
-
.filter((item) => item.stage !== '
|
|
980
|
+
.filter((item) => item.stage !== 'ship')
|
|
1458
981
|
.map((item) => latestStageChainEnvelope(envelopes, item.projectionType, item.stage))
|
|
1459
982
|
.map((envelope) => envelope ? acceptedRefFromAdjudication(envelope.payload.stage, envelope.payload) : null)
|
|
1460
983
|
.filter((ref) => ref !== null);
|
|
@@ -1497,10 +1020,7 @@ function acceptedRefFromAdjudication(stage, adjudication) {
|
|
|
1497
1020
|
spec: 'acceptedSpecRef',
|
|
1498
1021
|
plan: 'acceptedPlanRef',
|
|
1499
1022
|
tasks: 'acceptedTasksRef',
|
|
1500
|
-
|
|
1501
|
-
do: 'acceptedImplementationRef',
|
|
1502
|
-
test: 'acceptedTestEvidenceRef',
|
|
1503
|
-
'goal-verify': 'acceptedGoalVerificationRef',
|
|
1023
|
+
execute: 'acceptedExecuteRef',
|
|
1504
1024
|
ship: 'acceptedShipReadinessRef'
|
|
1505
1025
|
};
|
|
1506
1026
|
return runtimeRefValue(closureRefs[keyByStage[stage]]) ?? adjudication.stageDecision?.acceptedDecisionRefs[0] ?? null;
|
|
@@ -1639,6 +1159,105 @@ export function adjudicateSpecStageClosureRequest(input) {
|
|
|
1639
1159
|
nextActions: buildRuntimeNextActions(input.profile, generatedAt, ['stage_ready', 'handoff_ready'])
|
|
1640
1160
|
});
|
|
1641
1161
|
}
|
|
1162
|
+
function planMemberAgents(intensity) {
|
|
1163
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1164
|
+
return [];
|
|
1165
|
+
}
|
|
1166
|
+
if (intensity === 'lightweight') {
|
|
1167
|
+
return [PLAN_STAGE_REVIEW_AGENT];
|
|
1168
|
+
}
|
|
1169
|
+
return [PLAN_STAGE_SCOUT_AGENT, PLAN_STAGE_REVIEW_AGENT];
|
|
1170
|
+
}
|
|
1171
|
+
function planScoutDomains(intensity) {
|
|
1172
|
+
if (intensity === 'noop' || intensity === 'blocked' || intensity === 'lightweight') {
|
|
1173
|
+
return [];
|
|
1174
|
+
}
|
|
1175
|
+
if (intensity === 'scout-first') {
|
|
1176
|
+
return ['architecture-runtime', 'testing-validation'];
|
|
1177
|
+
}
|
|
1178
|
+
return ['architecture-runtime', 'backend-api', 'database-migration', 'security', 'testing-validation'];
|
|
1179
|
+
}
|
|
1180
|
+
function planRequiredOutputKinds(intensity) {
|
|
1181
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1182
|
+
return [];
|
|
1183
|
+
}
|
|
1184
|
+
if (intensity === 'lightweight') {
|
|
1185
|
+
return ['plan_review', 'manager_closure_request'];
|
|
1186
|
+
}
|
|
1187
|
+
return ['plan_context', 'plan_review', 'manager_closure_request'];
|
|
1188
|
+
}
|
|
1189
|
+
function planRequiredCapabilities(intensity) {
|
|
1190
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1191
|
+
return [];
|
|
1192
|
+
}
|
|
1193
|
+
if (intensity === 'lightweight') {
|
|
1194
|
+
return ['plan-strategy', 'plan-pressure-review'];
|
|
1195
|
+
}
|
|
1196
|
+
return ['plan-strategy', 'plan-pressure-review', ...planScoutDomains(intensity)];
|
|
1197
|
+
}
|
|
1198
|
+
function planOptionalCapabilities(intensity) {
|
|
1199
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1200
|
+
return [];
|
|
1201
|
+
}
|
|
1202
|
+
return PLAN_SCOUT_DOMAINS.filter((domain) => !planScoutDomains(intensity).includes(domain));
|
|
1203
|
+
}
|
|
1204
|
+
function planMaterialPackIds(intensity) {
|
|
1205
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1206
|
+
return [];
|
|
1207
|
+
}
|
|
1208
|
+
if (intensity === 'lightweight') {
|
|
1209
|
+
return ['project-norms', 'plan-section-rubric'];
|
|
1210
|
+
}
|
|
1211
|
+
return [...PLAN_STAGE_MATERIAL_PACKS];
|
|
1212
|
+
}
|
|
1213
|
+
function planCollaborationPlan(intensity) {
|
|
1214
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1215
|
+
return { topology: 'none', participants: [], maxParallelism: 0, fanIn: 'runtime_adjudication' };
|
|
1216
|
+
}
|
|
1217
|
+
const requiredCapabilities = planRequiredCapabilities(intensity);
|
|
1218
|
+
const optionalCapabilities = planOptionalCapabilities(intensity);
|
|
1219
|
+
const materialPackIds = planMaterialPackIds(intensity);
|
|
1220
|
+
const participants = [
|
|
1221
|
+
{ id: PLAN_STAGE_MANAGER, kind: 'agent', role: 'plan-stage-manager', required: true, capabilityDomain: 'plan-strategy', parallelGroup: null },
|
|
1222
|
+
...planMemberAgents(intensity).map((agent) => ({
|
|
1223
|
+
id: agent,
|
|
1224
|
+
kind: 'subagent',
|
|
1225
|
+
role: planAgentRole(agent),
|
|
1226
|
+
required: agent === PLAN_STAGE_REVIEW_AGENT,
|
|
1227
|
+
capabilityDomain: planAgentCapability(agent),
|
|
1228
|
+
parallelGroup: planAgentParallelGroup(agent)
|
|
1229
|
+
})),
|
|
1230
|
+
...requiredCapabilities.map((capability) => ({ id: `cap.${capability}`, kind: 'skill', role: 'required-capability-review', required: true, capabilityDomain: capability, parallelGroup: 'capability-review' })),
|
|
1231
|
+
...optionalCapabilities.map((capability) => ({ id: `cap.${capability}`, kind: 'skill', role: 'optional-capability-review', required: false, capabilityDomain: capability, parallelGroup: 'capability-review' })),
|
|
1232
|
+
...materialPackIds.map((packId) => ({ id: packId, kind: 'material-pack', role: 'capability-material', required: false, parallelGroup: 'material-pack' }))
|
|
1233
|
+
];
|
|
1234
|
+
const topology = intensity === 'lightweight' ? 'team-lite' : intensity === 'scout-first' ? 'parallel-research' : 'team-required';
|
|
1235
|
+
return { topology, participants, maxParallelism: topology === 'team-lite' ? 2 : 3, fanIn: 'runtime_adjudication' };
|
|
1236
|
+
}
|
|
1237
|
+
function planAgentRole(agent) {
|
|
1238
|
+
switch (agent) {
|
|
1239
|
+
case PLAN_STAGE_SCOUT_AGENT:
|
|
1240
|
+
return 'domain-evidence-scout';
|
|
1241
|
+
case PLAN_STAGE_REVIEW_AGENT:
|
|
1242
|
+
return 'plan-pressure-reviewer';
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function planAgentCapability(agent) {
|
|
1246
|
+
switch (agent) {
|
|
1247
|
+
case PLAN_STAGE_SCOUT_AGENT:
|
|
1248
|
+
return 'architecture-runtime';
|
|
1249
|
+
case PLAN_STAGE_REVIEW_AGENT:
|
|
1250
|
+
return 'plan-pressure-review';
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
function planAgentParallelGroup(agent) {
|
|
1254
|
+
switch (agent) {
|
|
1255
|
+
case PLAN_STAGE_SCOUT_AGENT:
|
|
1256
|
+
return 'domain-scouting';
|
|
1257
|
+
case PLAN_STAGE_REVIEW_AGENT:
|
|
1258
|
+
return 'review';
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1642
1261
|
function specIntensity(decision, required) {
|
|
1643
1262
|
if (decision.profile === 'blocked' || decision.blockedStages.includes('spec')) {
|
|
1644
1263
|
return 'blocked';
|
|
@@ -1674,9 +1293,18 @@ function specMemberAgents(intensity) {
|
|
|
1674
1293
|
return [];
|
|
1675
1294
|
}
|
|
1676
1295
|
if (intensity === 'lightweight') {
|
|
1677
|
-
return [
|
|
1296
|
+
return [SPEC_STAGE_REVIEW_AGENT];
|
|
1297
|
+
}
|
|
1298
|
+
return [SPEC_STAGE_SCOUT_AGENT, SPEC_STAGE_REVIEW_AGENT];
|
|
1299
|
+
}
|
|
1300
|
+
function specRequiredOutputKinds(intensity) {
|
|
1301
|
+
if (intensity === 'noop' || intensity === 'blocked') {
|
|
1302
|
+
return [];
|
|
1303
|
+
}
|
|
1304
|
+
if (intensity === 'lightweight') {
|
|
1305
|
+
return ['spec_review', 'manager_closure_request'];
|
|
1678
1306
|
}
|
|
1679
|
-
return [
|
|
1307
|
+
return ['scout_context', 'spec_review', 'manager_closure_request'];
|
|
1680
1308
|
}
|
|
1681
1309
|
function specRequiredCapabilities(intensity) {
|
|
1682
1310
|
if (intensity === 'noop' || intensity === 'blocked') {
|
|
@@ -1717,10 +1345,10 @@ function specCollaborationPlan(intensity) {
|
|
|
1717
1345
|
...specMemberAgents(intensity).map((agent) => ({
|
|
1718
1346
|
id: agent,
|
|
1719
1347
|
kind: 'subagent',
|
|
1720
|
-
role: agent === SPEC_STAGE_SCOUT_AGENT ? 'bounded-context-scout' :
|
|
1348
|
+
role: agent === SPEC_STAGE_SCOUT_AGENT ? 'bounded-context-scout' : 'spec-document-reviewer',
|
|
1721
1349
|
required: true,
|
|
1722
|
-
capabilityDomain: agent === SPEC_STAGE_SCOUT_AGENT ? 'context_curation' :
|
|
1723
|
-
parallelGroup: agent === SPEC_STAGE_SCOUT_AGENT ? 'discovery' :
|
|
1350
|
+
capabilityDomain: agent === SPEC_STAGE_SCOUT_AGENT ? 'context_curation' : 'uncertainty_resolution',
|
|
1351
|
+
parallelGroup: agent === SPEC_STAGE_SCOUT_AGENT ? 'discovery' : 'review'
|
|
1724
1352
|
})),
|
|
1725
1353
|
...requiredCapabilities.map((capability) => ({ id: `cap.${capability}`, kind: 'skill', role: 'required-capability-review', required: true, capabilityDomain: capability, parallelGroup: 'capability-review' })),
|
|
1726
1354
|
...optionalCapabilities.map((capability) => ({ id: `cap.${capability}`, kind: 'skill', role: 'optional-capability-review', required: false, capabilityDomain: capability, parallelGroup: 'capability-review' })),
|
|
@@ -1732,7 +1360,7 @@ function specCollaborationPlan(intensity) {
|
|
|
1732
1360
|
function validateStageClosureRequest(input) {
|
|
1733
1361
|
const request = input.closureRequest;
|
|
1734
1362
|
if (!request) {
|
|
1735
|
-
return { reasonCode: 'invalid_proposal', explanation: 'Spec stage closure requires a StageClosureRequest from spec-manager.', requiredNextAction: 'Submit spec-manager closure request with
|
|
1363
|
+
return { reasonCode: 'invalid_proposal', explanation: 'Spec stage closure requires a StageClosureRequest from spec-manager.', requiredNextAction: 'Submit spec-manager closure request with final spec ref/hash and runtime close boundary facts.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1736
1364
|
}
|
|
1737
1365
|
if (request.stage !== 'spec') {
|
|
1738
1366
|
return { reasonCode: 'unsupported_stage', explanation: `Spec runtime cannot close ${request.stage} closure requests.`, requiredNextAction: 'Route the closure request to the matching stage runtime.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
@@ -1740,32 +1368,19 @@ function validateStageClosureRequest(input) {
|
|
|
1740
1368
|
if (request.authorityAttempts.length > 0) {
|
|
1741
1369
|
return { reasonCode: 'authority_violation', explanation: `Spec stage closure attempted workflow authority: ${request.authorityAttempts.join(', ')}.`, requiredNextAction: 'Remove workflow-authority attempts from manager and agent-team outputs.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1742
1370
|
}
|
|
1743
|
-
if (
|
|
1744
|
-
return { reasonCode: 'invalid_proposal', explanation: 'Spec stage closure is missing SpecDocumentCandidate.', requiredNextAction: 'Ask spec-drafter to produce a candidate and submit its ref.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1745
|
-
}
|
|
1746
|
-
if (request.candidate.stage !== 'spec') {
|
|
1371
|
+
if (request.candidate && request.candidate.stage !== 'spec') {
|
|
1747
1372
|
return { reasonCode: 'unsupported_stage', explanation: `Spec runtime cannot close ${request.candidate.stage} candidates.`, requiredNextAction: 'Route the candidate to the matching stage runtime.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1748
1373
|
}
|
|
1749
|
-
|
|
1750
|
-
return { reasonCode: 'missing_refs', explanation: 'SpecDocumentCandidate has no input refs.', requiredNextAction: 'Attach spec request, document, or runtime projection refs before closure.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1751
|
-
}
|
|
1752
|
-
const unsupported = request.candidate.acceptedItems.find((item) => !input.profile.allowedProposalKinds.includes(item.kind));
|
|
1374
|
+
const unsupported = request.candidate?.acceptedItems.find((item) => !input.profile.allowedProposalKinds.includes(item.kind));
|
|
1753
1375
|
if (unsupported) {
|
|
1754
1376
|
return { reasonCode: 'invalid_proposal', explanation: `Spec candidate item ${unsupported.id} uses unsupported kind ${unsupported.kind}.`, requiredNextAction: 'Submit only allowed spec candidate item kinds for this profile.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1755
1377
|
}
|
|
1756
|
-
const missingItemRef = request.candidate
|
|
1378
|
+
const missingItemRef = request.candidate?.acceptedItems.find((item) => item.refs.length === 0);
|
|
1757
1379
|
if (missingItemRef) {
|
|
1758
1380
|
return { reasonCode: 'missing_refs', explanation: `Spec candidate item ${missingItemRef.id} has no refs.`, requiredNextAction: 'Attach source refs to every candidate item.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1759
1381
|
}
|
|
1760
|
-
if (request.
|
|
1761
|
-
return { reasonCode: '
|
|
1762
|
-
}
|
|
1763
|
-
const approvedReview = request.reviewResults.find((review) => review.reviewer === SPEC_STAGE_REVIEW_AGENT && review.verdict === 'approved');
|
|
1764
|
-
if (!approvedReview && request.unresolvedAmbiguityIds.length === 0) {
|
|
1765
|
-
return { reasonCode: 'missing_required_review', explanation: 'Spec stage closure has no approved spec-reviewer result.', requiredNextAction: 'Resolve review findings or submit approved spec-reviewer evidence.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1766
|
-
}
|
|
1767
|
-
if (request.evidenceRefs.length === 0) {
|
|
1768
|
-
return { reasonCode: 'missing_refs', explanation: 'Spec stage closure has no evidence refs.', requiredNextAction: 'Attach work order, candidate, review, and source evidence refs.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1382
|
+
if (request.managerRecommendation === 'close_stage' && !request.runtimeCloseBoundaryFacts) {
|
|
1383
|
+
return { reasonCode: 'missing_refs', explanation: 'Spec stage close request is missing runtime close boundary facts for the final spec.md V3.', requiredNextAction: 'Ask spec-manager to submit finalSpecRef/finalSpecHash, section close declaration, review signal presence, and blockingBeforePlanCount=0.', fallbackRoute: 'revise-proposal', retryAllowed: true };
|
|
1769
1384
|
}
|
|
1770
1385
|
return null;
|
|
1771
1386
|
}
|
|
@@ -2092,27 +1707,13 @@ async function registerSpecStageArtifacts(projectRoot, branch, profile, artifact
|
|
|
2092
1707
|
return records;
|
|
2093
1708
|
}
|
|
2094
1709
|
async function collectSpecStageEvidenceRefs(projectRoot, branch, profile, artifactRefs) {
|
|
1710
|
+
void projectRoot;
|
|
1711
|
+
void branch;
|
|
1712
|
+
void profile;
|
|
2095
1713
|
if (artifactRefs && artifactRefs.length > 0) {
|
|
2096
1714
|
return [...new Set(artifactRefs.map(normalizeBranchStageEvidenceRef))];
|
|
2097
1715
|
}
|
|
2098
|
-
|
|
2099
|
-
return [];
|
|
2100
|
-
}
|
|
2101
|
-
const dir = getBranchStageEvidenceDir(projectRoot, branch, 'spec');
|
|
2102
|
-
let files;
|
|
2103
|
-
try {
|
|
2104
|
-
files = await readdir(dir);
|
|
2105
|
-
}
|
|
2106
|
-
catch (error) {
|
|
2107
|
-
if (error.code === 'ENOENT') {
|
|
2108
|
-
return [];
|
|
2109
|
-
}
|
|
2110
|
-
throw error;
|
|
2111
|
-
}
|
|
2112
|
-
return files
|
|
2113
|
-
.filter(isSpecStageEvidenceFile)
|
|
2114
|
-
.sort(compareStageEvidenceFileNames)
|
|
2115
|
-
.map((fileName) => toBranchStageEvidenceRef(branch, 'spec', fileName));
|
|
1716
|
+
return [];
|
|
2116
1717
|
}
|
|
2117
1718
|
async function registerBranchStageArtifacts(projectRoot, branch, stage, artifactRefs, required, runId, registeredAt) {
|
|
2118
1719
|
const refs = await collectBranchStageEvidenceRefs(projectRoot, branch, stage, artifactRefs, required);
|
|
@@ -2200,95 +1801,226 @@ function runtimeRefForStageArtifact(record) {
|
|
|
2200
1801
|
function runtimeRefForStageCollaborationContract(record) {
|
|
2201
1802
|
return { kind: 'artifact', ref: record.ref, hash: record.hash };
|
|
2202
1803
|
}
|
|
2203
|
-
function
|
|
2204
|
-
|
|
2205
|
-
.filter((record) => record.status === 'validated')
|
|
2206
|
-
.sort((left, right) => stageEvidenceVersion(right.ref) - stageEvidenceVersion(left.ref) || right.registeredAt.localeCompare(left.registeredAt))[0] ?? null;
|
|
2207
|
-
}
|
|
2208
|
-
function deriveRegisteredSpecManagerCoordination(profile, workOrder, records, generatedAt) {
|
|
2209
|
-
const manager = latestStageArtifact(records, 'manager_closure_request');
|
|
2210
|
-
if (!manager || !workOrder) {
|
|
1804
|
+
async function buildOutputCenteredSpecClosureRequest(projectRoot, profile, workOrder, partition, request, generatedAt) {
|
|
1805
|
+
if (!request) {
|
|
2211
1806
|
return null;
|
|
2212
1807
|
}
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
coordinationId: stableId('spec-manager-coordination', profile.scope, manager.ref, manager.hash, generatedAt),
|
|
2216
|
-
stage: 'spec',
|
|
2217
|
-
scope: profile.scope,
|
|
2218
|
-
stageManager: SPEC_STAGE_MANAGER,
|
|
2219
|
-
workOrderRef: { kind: 'projection', ref: `spec-work-order:${workOrder.workOrderId}` },
|
|
2220
|
-
agentTeamRefs: records.filter((record) => record.ref !== manager.ref).map(runtimeRefForStageArtifact),
|
|
2221
|
-
recommendation: manager.recommendation ?? 'blocked',
|
|
2222
|
-
generatedAt
|
|
2223
|
-
};
|
|
2224
|
-
}
|
|
2225
|
-
function deriveRegisteredStageClosureRequest(profile, workOrder, records, branchPartition, generatedAt) {
|
|
2226
|
-
const manager = latestStageArtifact(records, 'manager_closure_request');
|
|
2227
|
-
if (!manager) {
|
|
1808
|
+
const expectedSpecRef = `specs/${partition}/spec.md`;
|
|
1809
|
+
if (request.finalSpecRef && request.finalSpecRef !== expectedSpecRef) {
|
|
2228
1810
|
return null;
|
|
2229
1811
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
const
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
1812
|
+
if (request.sectionCloseDeclaration !== 'present' || request.reviewSignal !== 'present' || request.blockingBeforePlanCount !== 0) {
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
const content = await readOptionalText(path.join(projectRoot, 'specs', partition, 'spec.md'));
|
|
1816
|
+
if (content === null) {
|
|
1817
|
+
return null;
|
|
1818
|
+
}
|
|
1819
|
+
const specHash = hashDocumentContent(content);
|
|
1820
|
+
const finalSpecRef = { kind: 'document', ref: expectedSpecRef, hash: specHash };
|
|
1821
|
+
const facts = {
|
|
1822
|
+
contract: 'sdd-spec-runtime-close-boundary-facts-v1',
|
|
1823
|
+
scope: profile.scope,
|
|
1824
|
+
finalSpecRef,
|
|
1825
|
+
finalSpecHash: specHash,
|
|
1826
|
+
templateContract: 'sdd-spec-doc-v3',
|
|
1827
|
+
blockingBeforePlanCount: 0,
|
|
1828
|
+
sectionCloseDeclaration: 'present',
|
|
1829
|
+
reviewSignal: 'present',
|
|
1830
|
+
runtimeTruthOwner: 'Runtime Kernel'
|
|
1831
|
+
};
|
|
1832
|
+
const acceptedItems = [{
|
|
1833
|
+
id: 'accepted-spec',
|
|
1834
|
+
kind: 'handoff_proposal',
|
|
1835
|
+
summary: 'Spec-manager submitted final spec.md V3 for runtime ref/hash acceptance.',
|
|
1836
|
+
refs: [finalSpecRef]
|
|
1837
|
+
}];
|
|
2241
1838
|
const candidate = {
|
|
2242
1839
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
2243
|
-
candidateId: stableId('spec-document-candidate', profile.scope,
|
|
1840
|
+
candidateId: stableId('spec-document-candidate', profile.scope, expectedSpecRef, specHash, generatedAt),
|
|
2244
1841
|
stage: 'spec',
|
|
2245
1842
|
scope: profile.scope,
|
|
2246
|
-
producedBy:
|
|
2247
|
-
inputRefs: profile.inputRefs
|
|
2248
|
-
evidenceRefs,
|
|
1843
|
+
producedBy: SPEC_STAGE_MANAGER,
|
|
1844
|
+
inputRefs: profile.inputRefs,
|
|
1845
|
+
evidenceRefs: [],
|
|
2249
1846
|
acceptedItems,
|
|
2250
1847
|
generatedAt
|
|
2251
1848
|
};
|
|
2252
1849
|
return {
|
|
2253
1850
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
2254
|
-
closureRequestId: stableId('spec-closure-request', profile.scope,
|
|
1851
|
+
closureRequestId: stableId('spec-closure-request', profile.scope, expectedSpecRef, specHash, generatedAt),
|
|
2255
1852
|
stage: 'spec',
|
|
2256
1853
|
scope: profile.scope,
|
|
2257
|
-
submittedBy:
|
|
1854
|
+
submittedBy: 'host-adapter',
|
|
2258
1855
|
workOrderRef: workOrder ? { kind: 'projection', ref: `spec-work-order:${workOrder.workOrderId}` } : { kind: 'projection', ref: `spec-work-order:${specCollaborationScopeKey(profile.scope)}` },
|
|
2259
|
-
coordinationRef:
|
|
2260
|
-
candidateRef,
|
|
2261
|
-
reviewRefs:
|
|
1856
|
+
coordinationRef: null,
|
|
1857
|
+
candidateRef: finalSpecRef,
|
|
1858
|
+
reviewRefs: [],
|
|
2262
1859
|
capabilityFindingRefs: [],
|
|
2263
|
-
evidenceRefs,
|
|
1860
|
+
evidenceRefs: [],
|
|
2264
1861
|
candidate,
|
|
2265
|
-
reviewResults:
|
|
1862
|
+
reviewResults: [],
|
|
2266
1863
|
capabilityFindings: [],
|
|
2267
|
-
unresolvedAmbiguityIds:
|
|
1864
|
+
unresolvedAmbiguityIds: [],
|
|
2268
1865
|
authorityAttempts: [],
|
|
2269
|
-
managerRecommendation:
|
|
1866
|
+
managerRecommendation: 'close_stage',
|
|
1867
|
+
runtimeCloseBoundaryFacts: facts,
|
|
2270
1868
|
generatedAt
|
|
2271
1869
|
};
|
|
2272
1870
|
}
|
|
2273
|
-
function
|
|
1871
|
+
async function buildOutputCenteredPlanClosureRequest(projectRoot, scope, workOrder, partition, acceptedSpecHandoff, request, generatedAt) {
|
|
1872
|
+
if (!request) {
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
const expectedPlanRef = `specs/${partition}/plan.md`;
|
|
1876
|
+
if (request.finalPlanRef && request.finalPlanRef !== expectedPlanRef) {
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
if (request.planCloseQualityEvidence !== 'present' || request.reviewSignal !== 'present' || request.blockingBeforeTasksCount !== 0) {
|
|
1880
|
+
return null;
|
|
1881
|
+
}
|
|
1882
|
+
const acceptedSpecRef = acceptedSpecRefFromHandoff(partition, acceptedSpecHandoff);
|
|
1883
|
+
if (!acceptedSpecRef) {
|
|
1884
|
+
return null;
|
|
1885
|
+
}
|
|
1886
|
+
const content = await readOptionalText(path.join(projectRoot, 'specs', partition, 'plan.md'));
|
|
1887
|
+
if (content === null) {
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
const planHash = hashDocumentContent(content);
|
|
1891
|
+
const finalPlanRef = { kind: 'document', ref: expectedPlanRef, hash: planHash };
|
|
1892
|
+
const facts = {
|
|
1893
|
+
contract: 'sdd-plan-runtime-close-boundary-facts-v1',
|
|
1894
|
+
scope,
|
|
1895
|
+
acceptedSpecRef,
|
|
1896
|
+
finalPlanRef,
|
|
1897
|
+
finalPlanHash: planHash,
|
|
1898
|
+
templateContract: 'sdd-plan-doc-v3',
|
|
1899
|
+
blockingBeforeTasksCount: 0,
|
|
1900
|
+
planCloseQualityEvidence: 'present',
|
|
1901
|
+
reviewSignal: 'present',
|
|
1902
|
+
runtimeTruthOwner: 'Runtime Kernel'
|
|
1903
|
+
};
|
|
2274
1904
|
return {
|
|
2275
1905
|
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
2276
|
-
|
|
2277
|
-
stage: '
|
|
2278
|
-
scope
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
1906
|
+
closureRequestId: stableId('plan-closure-request', scope, expectedPlanRef, planHash, generatedAt),
|
|
1907
|
+
stage: 'plan',
|
|
1908
|
+
scope,
|
|
1909
|
+
submittedBy: 'host-adapter',
|
|
1910
|
+
workOrderRef: workOrder ? { kind: 'projection', ref: `plan-work-order:${workOrder.workOrderId}` } : { kind: 'projection', ref: `plan-work-order:${planCollaborationScopeKey(scope)}` },
|
|
1911
|
+
coordinationRef: null,
|
|
1912
|
+
candidateRef: finalPlanRef,
|
|
1913
|
+
reviewRefs: [],
|
|
1914
|
+
capabilityFindingRefs: [],
|
|
1915
|
+
evidenceRefs: [],
|
|
1916
|
+
candidate: null,
|
|
1917
|
+
reviewResults: [],
|
|
1918
|
+
capabilityFindings: [],
|
|
1919
|
+
unresolvedAmbiguityIds: [],
|
|
1920
|
+
authorityAttempts: [],
|
|
1921
|
+
managerRecommendation: 'close_stage',
|
|
1922
|
+
runtimeCloseBoundaryFacts: facts,
|
|
2284
1923
|
generatedAt
|
|
2285
1924
|
};
|
|
2286
1925
|
}
|
|
2287
|
-
function
|
|
2288
|
-
if (
|
|
2289
|
-
return
|
|
1926
|
+
async function buildOutputCenteredTasksClosureRequest(projectRoot, scope, workOrder, partition, acceptedPlanHandoff, request, generatedAt) {
|
|
1927
|
+
if (!request) {
|
|
1928
|
+
return null;
|
|
1929
|
+
}
|
|
1930
|
+
const expectedTasksRef = `specs/${partition}/tasks.md`;
|
|
1931
|
+
if (request.finalTasksRef && request.finalTasksRef !== expectedTasksRef) {
|
|
1932
|
+
return null;
|
|
1933
|
+
}
|
|
1934
|
+
if (request.dependencyGraphStatus !== 'present' || request.validationSignalsStatus !== 'present' || request.reviewSignal !== 'present' || request.blockingBeforeExecuteCount !== 0) {
|
|
1935
|
+
return null;
|
|
1936
|
+
}
|
|
1937
|
+
const acceptedPlanRef = acceptedPlanRefFromHandoff(partition, acceptedPlanHandoff);
|
|
1938
|
+
const acceptedSpecRef = acceptedSpecRefFromPlanHandoff(acceptedPlanHandoff);
|
|
1939
|
+
if (!acceptedPlanRef || !acceptedSpecRef) {
|
|
1940
|
+
return null;
|
|
1941
|
+
}
|
|
1942
|
+
const content = await readOptionalText(path.join(projectRoot, 'specs', partition, 'tasks.md'));
|
|
1943
|
+
if (content === null) {
|
|
1944
|
+
return null;
|
|
1945
|
+
}
|
|
1946
|
+
const taskModel = parseSddTasksMarkdown(content, { tasksPath: expectedTasksRef });
|
|
1947
|
+
const tasksHash = hashDocumentContent(content);
|
|
1948
|
+
const finalTasksRef = { kind: 'document', ref: expectedTasksRef, hash: tasksHash };
|
|
1949
|
+
const facts = {
|
|
1950
|
+
contract: 'sdd-tasks-runtime-close-boundary-facts-v1',
|
|
1951
|
+
scope,
|
|
1952
|
+
acceptedSpecRef,
|
|
1953
|
+
acceptedPlanRef,
|
|
1954
|
+
finalTasksRef,
|
|
1955
|
+
finalTasksHash: tasksHash,
|
|
1956
|
+
templateContract: 'sdd-tasks-doc-v2',
|
|
1957
|
+
taskUnitCount: taskModel.tasks.length,
|
|
1958
|
+
blockingBeforeExecuteCount: 0,
|
|
1959
|
+
dependencyGraphStatus: 'present',
|
|
1960
|
+
validationSignalsStatus: 'present',
|
|
1961
|
+
reviewSignal: 'present',
|
|
1962
|
+
runtimeTruthOwner: 'Runtime Kernel'
|
|
1963
|
+
};
|
|
1964
|
+
return {
|
|
1965
|
+
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
1966
|
+
closureRequestId: stableId('tasks-closure-request', scope, expectedTasksRef, tasksHash, generatedAt),
|
|
1967
|
+
stage: 'tasks',
|
|
1968
|
+
scope,
|
|
1969
|
+
submittedBy: 'host-adapter',
|
|
1970
|
+
workOrderRef: workOrder ? { kind: 'projection', ref: `tasks-work-order:${workOrder.workOrderId}` } : { kind: 'projection', ref: `tasks-work-order:${tasksCollaborationScopeKey(scope)}` },
|
|
1971
|
+
coordinationRef: null,
|
|
1972
|
+
candidateRef: finalTasksRef,
|
|
1973
|
+
reviewRefs: [],
|
|
1974
|
+
capabilityFindingRefs: [],
|
|
1975
|
+
evidenceRefs: [],
|
|
1976
|
+
candidate: null,
|
|
1977
|
+
reviewResults: [],
|
|
1978
|
+
capabilityFindings: [],
|
|
1979
|
+
unresolvedAmbiguityIds: [],
|
|
1980
|
+
authorityAttempts: [],
|
|
1981
|
+
managerRecommendation: 'close_stage',
|
|
1982
|
+
runtimeCloseBoundaryFacts: facts,
|
|
1983
|
+
generatedAt
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
function acceptedSpecRefFromHandoff(partition, handoff) {
|
|
1987
|
+
const expectedSpecRef = `specs/${partition}/spec.md`;
|
|
1988
|
+
return handoff?.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedSpecRef)
|
|
1989
|
+
?? handoff?.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedSpecRef)
|
|
1990
|
+
?? null;
|
|
1991
|
+
}
|
|
1992
|
+
function acceptedPlanRefFromHandoff(partition, handoff) {
|
|
1993
|
+
const expectedPlanRef = `specs/${partition}/plan.md`;
|
|
1994
|
+
return handoff?.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedPlanRef)
|
|
1995
|
+
?? handoff?.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedPlanRef)
|
|
1996
|
+
?? null;
|
|
1997
|
+
}
|
|
1998
|
+
function acceptedSpecRefFromPlanHandoff(handoff) {
|
|
1999
|
+
return handoff?.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref.endsWith('/spec.md'))
|
|
2000
|
+
?? handoff?.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref.endsWith('/spec.md'))
|
|
2001
|
+
?? null;
|
|
2002
|
+
}
|
|
2003
|
+
function latestValidatedStageCollaborationContract(records) {
|
|
2004
|
+
return records
|
|
2005
|
+
.filter((record) => record.status === 'validated')
|
|
2006
|
+
.sort((left, right) => stageEvidenceVersion(right.ref) - stageEvidenceVersion(left.ref) || right.registeredAt.localeCompare(left.registeredAt))[0] ?? null;
|
|
2007
|
+
}
|
|
2008
|
+
function deriveRegisteredSpecManagerCoordination(profile, workOrder, records, generatedAt) {
|
|
2009
|
+
const manager = latestStageArtifact(records, 'manager_closure_request');
|
|
2010
|
+
if (!manager || !workOrder) {
|
|
2011
|
+
return null;
|
|
2290
2012
|
}
|
|
2291
|
-
return
|
|
2013
|
+
return {
|
|
2014
|
+
contract: STAGE_COLLABORATION_RUNTIME_CONTRACT_VERSION,
|
|
2015
|
+
coordinationId: stableId('spec-manager-coordination', profile.scope, manager.ref, manager.hash, generatedAt),
|
|
2016
|
+
stage: 'spec',
|
|
2017
|
+
scope: profile.scope,
|
|
2018
|
+
stageManager: SPEC_STAGE_MANAGER,
|
|
2019
|
+
workOrderRef: { kind: 'projection', ref: `spec-work-order:${workOrder.workOrderId}` },
|
|
2020
|
+
agentTeamRefs: records.filter((record) => record.ref !== manager.ref).map(runtimeRefForStageArtifact),
|
|
2021
|
+
recommendation: manager.recommendation ?? 'blocked',
|
|
2022
|
+
generatedAt
|
|
2023
|
+
};
|
|
2292
2024
|
}
|
|
2293
2025
|
function latestStageArtifact(records, kind) {
|
|
2294
2026
|
return records
|
|
@@ -2305,54 +2037,90 @@ async function validateAcceptedSpecArtifact(projectRoot, input) {
|
|
|
2305
2037
|
reasons: [`Spec artifact was not accepted because adjudication health is ${input.adjudication.health}.`]
|
|
2306
2038
|
};
|
|
2307
2039
|
}
|
|
2308
|
-
if (!input.validatedCollaborationContract) {
|
|
2309
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready spec closure must be backed by a validated spec StageCollaborationContract.', 'Ask spec-manager to write .sdd/runs/<branch>/spec/spec-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2310
|
-
}
|
|
2311
2040
|
const expectedRef = `specs/${input.partition}/spec.md`;
|
|
2312
|
-
const
|
|
2313
|
-
if (!
|
|
2314
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', '
|
|
2315
|
-
}
|
|
2316
|
-
if (manager.recommendation !== 'close_stage') {
|
|
2317
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Spec-manager recommendation ${manager.recommendation ?? 'none'} cannot accept spec for plan handoff.`, 'Ask spec-manager to submit a close_stage recommendation after review blockers are resolved.');
|
|
2041
|
+
const boundaryFacts = input.closureRequest?.runtimeCloseBoundaryFacts ?? null;
|
|
2042
|
+
if (!boundaryFacts || boundaryFacts.contract !== 'sdd-spec-runtime-close-boundary-facts-v1') {
|
|
2043
|
+
return rejectedSpecArtifact('not_accepted_wrong_ref', 'missing_refs', 'Ready spec closure must include runtime close boundary facts for the final spec.md V3.', 'Submit finalSpecRef/finalSpecHash, section close declaration, review signal presence, and blockingBeforePlanCount=0 before closure.');
|
|
2318
2044
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
: null;
|
|
2322
|
-
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2323
|
-
return rejectedSpecArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Spec-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh spec-manager closure artifact so reviewRef/reviewHash point at the registered review artifact.');
|
|
2324
|
-
}
|
|
2325
|
-
const approvedReview = findReviewForManager(input.registeredArtifacts, manager);
|
|
2326
|
-
if (!approvedReview) {
|
|
2327
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', 'missing_required_review', 'Ready spec closure must include a registered spec-reviewer artifact referenced by spec-manager.', 'Ask spec-reviewer to write .sdd/runs/<branch>/spec/spec-review-vN.md and ask spec-manager to reference that review hash.');
|
|
2328
|
-
}
|
|
2329
|
-
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2330
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', 'missing_required_review', `Spec-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept spec.`, 'Resolve review blockers and register an approved spec-reviewer artifact before closure.');
|
|
2331
|
-
}
|
|
2332
|
-
if (manager.targetRef?.kind !== 'document' || manager.targetRef.ref !== expectedRef || approvedReview.targetRef?.kind !== 'document' || approvedReview.targetRef.ref !== expectedRef) {
|
|
2333
|
-
return rejectedSpecArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready spec closure must reference reviewed ${expectedRef} as the canonical spec document.`, 'Refresh review and manager artifacts so targetRef points at specs/<branch>/spec.md.');
|
|
2045
|
+
if (!validSpecRuntimeCloseBoundaryFacts(boundaryFacts, input.partition, expectedRef)) {
|
|
2046
|
+
return rejectedSpecArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Spec runtime close boundary facts do not match the final spec.md V3 acceptance contract.', 'Refresh spec close facts so finalSpecRef/finalSpecHash, template contract, section close declaration, review signal, and blocking count match runtime requirements.');
|
|
2334
2047
|
}
|
|
2335
2048
|
const specPath = path.join(projectRoot, 'specs', input.partition, 'spec.md');
|
|
2336
2049
|
const content = await readOptionalText(specPath);
|
|
2337
2050
|
if (content === null) {
|
|
2338
|
-
return rejectedSpecArtifact('not_accepted_missing_spec', 'missing_refs', `
|
|
2051
|
+
return rejectedSpecArtifact('not_accepted_missing_spec', 'missing_refs', `Final spec.md V3 artifact is missing at ${expectedRef}.`, 'Produce specs/<branch>/spec.md before requesting runtime closure.');
|
|
2339
2052
|
}
|
|
2340
2053
|
if (isManagedStarterSpec(content)) {
|
|
2341
|
-
return rejectedSpecArtifact('not_accepted_starter_spec', 'invalid_proposal', `Canonical spec artifact at ${expectedRef} is still the managed starter spec.`, 'Replace starter spec.md with
|
|
2054
|
+
return rejectedSpecArtifact('not_accepted_starter_spec', 'invalid_proposal', `Canonical spec artifact at ${expectedRef} is still the managed starter spec.`, 'Replace starter spec.md with final semantic spec.md V3 content before closure.');
|
|
2342
2055
|
}
|
|
2343
2056
|
const specHash = hashDocumentContent(content);
|
|
2344
|
-
const expectedHashes = [
|
|
2057
|
+
const expectedHashes = [boundaryFacts.finalSpecHash, boundaryFacts.finalSpecRef.hash].filter((hash) => Boolean(hash));
|
|
2345
2058
|
const mismatchedHash = expectedHashes.find((hash) => hash !== specHash);
|
|
2346
2059
|
if (mismatchedHash) {
|
|
2347
|
-
return rejectedSpecArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `
|
|
2060
|
+
return rejectedSpecArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Final spec.md V3 hash mismatch for ${expectedRef}: expected ${mismatchedHash}, actual ${specHash}.`, 'Refresh spec close facts with the current spec.md hash before closure.');
|
|
2061
|
+
}
|
|
2062
|
+
const specV3Errors = validateSpecDocumentV3(content);
|
|
2063
|
+
if (specV3Errors.length > 0) {
|
|
2064
|
+
return rejectedSpecArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Final spec.md does not satisfy sdd-spec-doc-v3: ${specV3Errors.join('; ')}.`, 'Rewrite specs/<branch>/spec.md as final spec.md V3 with required semantic sections before closure.');
|
|
2348
2065
|
}
|
|
2349
2066
|
return {
|
|
2350
2067
|
acceptedSpecRef: { kind: 'document', ref: expectedRef, hash: specHash },
|
|
2351
2068
|
specAcceptanceStatus: 'accepted',
|
|
2352
2069
|
specHash,
|
|
2353
2070
|
specContractHash: hashSemanticDocument(content),
|
|
2354
|
-
reasons: [`Runtime accepted
|
|
2355
|
-
};
|
|
2071
|
+
reasons: [`Runtime accepted final spec.md V3 artifact ${expectedRef}.`]
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
function validSpecRuntimeCloseBoundaryFacts(facts, partition, expectedSpecRef) {
|
|
2075
|
+
return facts.contract === 'sdd-spec-runtime-close-boundary-facts-v1'
|
|
2076
|
+
&& facts.scope.branch === partition
|
|
2077
|
+
&& facts.finalSpecRef.kind === 'document'
|
|
2078
|
+
&& facts.finalSpecRef.ref === expectedSpecRef
|
|
2079
|
+
&& Boolean(facts.finalSpecRef.hash)
|
|
2080
|
+
&& facts.finalSpecHash === facts.finalSpecRef.hash
|
|
2081
|
+
&& facts.templateContract === 'sdd-spec-doc-v3'
|
|
2082
|
+
&& facts.blockingBeforePlanCount === 0
|
|
2083
|
+
&& facts.sectionCloseDeclaration === 'present'
|
|
2084
|
+
&& facts.reviewSignal === 'present'
|
|
2085
|
+
&& facts.runtimeTruthOwner === 'Runtime Kernel';
|
|
2086
|
+
}
|
|
2087
|
+
function validPlanRuntimeCloseBoundaryFacts(facts, partition, expectedPlanRef, acceptedSpecRef) {
|
|
2088
|
+
return facts.contract === 'sdd-plan-runtime-close-boundary-facts-v1'
|
|
2089
|
+
&& facts.scope.branch === partition
|
|
2090
|
+
&& facts.acceptedSpecRef.kind === acceptedSpecRef.kind
|
|
2091
|
+
&& facts.acceptedSpecRef.ref === acceptedSpecRef.ref
|
|
2092
|
+
&& facts.acceptedSpecRef.hash === acceptedSpecRef.hash
|
|
2093
|
+
&& facts.finalPlanRef.kind === 'document'
|
|
2094
|
+
&& facts.finalPlanRef.ref === expectedPlanRef
|
|
2095
|
+
&& Boolean(facts.finalPlanRef.hash)
|
|
2096
|
+
&& facts.finalPlanHash === facts.finalPlanRef.hash
|
|
2097
|
+
&& facts.templateContract === 'sdd-plan-doc-v3'
|
|
2098
|
+
&& facts.blockingBeforeTasksCount === 0
|
|
2099
|
+
&& facts.planCloseQualityEvidence === 'present'
|
|
2100
|
+
&& facts.reviewSignal === 'present'
|
|
2101
|
+
&& facts.runtimeTruthOwner === 'Runtime Kernel';
|
|
2102
|
+
}
|
|
2103
|
+
function validTasksRuntimeCloseBoundaryFacts(facts, partition, expectedTasksRef, acceptedSpecRef, acceptedPlanRef, taskUnitCount) {
|
|
2104
|
+
return facts.contract === 'sdd-tasks-runtime-close-boundary-facts-v1'
|
|
2105
|
+
&& facts.scope.branch === partition
|
|
2106
|
+
&& facts.acceptedSpecRef.kind === acceptedSpecRef.kind
|
|
2107
|
+
&& facts.acceptedSpecRef.ref === acceptedSpecRef.ref
|
|
2108
|
+
&& facts.acceptedSpecRef.hash === acceptedSpecRef.hash
|
|
2109
|
+
&& facts.acceptedPlanRef.kind === acceptedPlanRef.kind
|
|
2110
|
+
&& facts.acceptedPlanRef.ref === acceptedPlanRef.ref
|
|
2111
|
+
&& facts.acceptedPlanRef.hash === acceptedPlanRef.hash
|
|
2112
|
+
&& facts.finalTasksRef.kind === 'document'
|
|
2113
|
+
&& facts.finalTasksRef.ref === expectedTasksRef
|
|
2114
|
+
&& Boolean(facts.finalTasksRef.hash)
|
|
2115
|
+
&& facts.finalTasksHash === facts.finalTasksRef.hash
|
|
2116
|
+
&& facts.templateContract === 'sdd-tasks-doc-v2'
|
|
2117
|
+
&& facts.taskUnitCount === taskUnitCount
|
|
2118
|
+
&& facts.taskUnitCount > 0
|
|
2119
|
+
&& facts.blockingBeforeExecuteCount === 0
|
|
2120
|
+
&& facts.dependencyGraphStatus === 'present'
|
|
2121
|
+
&& facts.validationSignalsStatus === 'present'
|
|
2122
|
+
&& facts.reviewSignal === 'present'
|
|
2123
|
+
&& facts.runtimeTruthOwner === 'Runtime Kernel';
|
|
2356
2124
|
}
|
|
2357
2125
|
function rejectedSpecArtifact(specAcceptanceStatus, reasonCode, explanation, requiredNextAction) {
|
|
2358
2126
|
return {
|
|
@@ -2382,50 +2150,37 @@ async function validateAcceptedPlanArtifact(projectRoot, input) {
|
|
|
2382
2150
|
if (input.blocked) {
|
|
2383
2151
|
return rejectedPlanArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks plan closure.', 'Resolve lifecycle blockers before requesting plan-stage closure.', 'runtime-blocked');
|
|
2384
2152
|
}
|
|
2385
|
-
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2386
|
-
return rejectedPlanArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready plan closure must be backed by a validated plan StageCollaborationContract.', 'Ask plan-manager to write .sdd/runs/<branch>/plan/plan-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2387
|
-
}
|
|
2388
2153
|
const upstreamIssue = await validateAcceptedSpecHandoff(projectRoot, input.partition, input.acceptedSpecHandoff);
|
|
2389
2154
|
if (upstreamIssue) {
|
|
2390
2155
|
return rejectedPlanArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh spec-stage closure and provide a fresh spec -> plan handoff before plan closure.');
|
|
2391
2156
|
}
|
|
2392
2157
|
const expectedRef = `specs/${input.partition}/plan.md`;
|
|
2393
|
-
const
|
|
2394
|
-
if (!
|
|
2395
|
-
return rejectedPlanArtifact('
|
|
2396
|
-
}
|
|
2397
|
-
if (manager.recommendation !== 'close_stage') {
|
|
2398
|
-
return rejectedPlanArtifact('not_accepted_rejected', 'invalid_proposal', `Plan-manager recommendation ${manager.recommendation ?? 'none'} cannot accept plan for tasks handoff.`, 'Ask plan-manager to submit a close_stage recommendation after review blockers are resolved.');
|
|
2399
|
-
}
|
|
2400
|
-
const reviewByRef = manager.reviewRef
|
|
2401
|
-
? input.registeredArtifacts.find((record) => record.kind === 'plan_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2402
|
-
: null;
|
|
2403
|
-
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2404
|
-
return rejectedPlanArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Plan-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh plan-manager closure artifact so reviewRef/reviewHash point at the registered review artifact.');
|
|
2405
|
-
}
|
|
2406
|
-
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'plan_review');
|
|
2407
|
-
if (!approvedReview) {
|
|
2408
|
-
return rejectedPlanArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready plan closure must include a registered plan-reviewer artifact referenced by plan-manager.', 'Ask plan-reviewer to write .sdd/runs/<branch>/plan/plan-review-vN.md and ask plan-manager to reference that review hash.');
|
|
2158
|
+
const acceptedSpecRef = acceptedSpecRefFromHandoff(input.partition, input.acceptedSpecHandoff);
|
|
2159
|
+
if (!acceptedSpecRef) {
|
|
2160
|
+
return rejectedPlanArtifact('not_accepted_missing_upstream', 'missing_refs', 'Plan closure requires accepted spec ref/hash from runtime handoff.', 'Refresh spec-stage closure and provide a fresh spec -> plan handoff before plan closure.');
|
|
2409
2161
|
}
|
|
2410
|
-
|
|
2411
|
-
|
|
2162
|
+
const boundaryFacts = input.closureRequest?.runtimeCloseBoundaryFacts;
|
|
2163
|
+
if (!boundaryFacts || boundaryFacts.contract !== 'sdd-plan-runtime-close-boundary-facts-v1') {
|
|
2164
|
+
return rejectedPlanArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Plan close request is missing runtime boundary facts for final plan.md V3.', 'Submit finalPlanRef/finalPlanHash, acceptedSpecRef, plan close quality evidence, review signal, and blockingBeforeTasksCount=0.');
|
|
2412
2165
|
}
|
|
2413
|
-
if (
|
|
2414
|
-
return rejectedPlanArtifact('not_accepted_wrong_ref', 'invalid_proposal', `
|
|
2166
|
+
if (!validPlanRuntimeCloseBoundaryFacts(boundaryFacts, input.partition, expectedRef, acceptedSpecRef)) {
|
|
2167
|
+
return rejectedPlanArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Plan close boundary facts must reference accepted spec and final ${expectedRef}.`, 'Refresh the output close request from current runtime handoff and specs/<branch>/plan.md.');
|
|
2415
2168
|
}
|
|
2416
2169
|
const planPath = path.join(projectRoot, 'specs', input.partition, 'plan.md');
|
|
2417
2170
|
const content = await readOptionalText(planPath);
|
|
2418
2171
|
if (content === null) {
|
|
2419
|
-
return rejectedPlanArtifact('not_accepted_missing_plan', 'missing_refs', `
|
|
2172
|
+
return rejectedPlanArtifact('not_accepted_missing_plan', 'missing_refs', `Canonical plan artifact is missing at ${expectedRef}.`, 'Produce specs/<branch>/plan.md before requesting runtime closure.');
|
|
2420
2173
|
}
|
|
2421
2174
|
if (isManagedStarterSpec(content)) {
|
|
2422
|
-
return rejectedPlanArtifact('not_accepted_starter_plan', 'invalid_proposal', `Canonical plan artifact at ${expectedRef} is still the managed starter document.`, 'Replace starter plan.md with
|
|
2175
|
+
return rejectedPlanArtifact('not_accepted_starter_plan', 'invalid_proposal', `Canonical plan artifact at ${expectedRef} is still the managed starter document.`, 'Replace starter plan.md with semantic plan content before closure.');
|
|
2176
|
+
}
|
|
2177
|
+
const documentErrors = validatePlanDocumentV3(content, boundaryFacts);
|
|
2178
|
+
if (documentErrors.length > 0) {
|
|
2179
|
+
return rejectedPlanArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Canonical plan artifact at ${expectedRef} is not a valid sdd-plan-doc-v3: ${documentErrors.join('; ')}.`, 'Rewrite specs/<branch>/plan.md as plan.md V3 before requesting runtime closure.');
|
|
2423
2180
|
}
|
|
2424
2181
|
const planHash = hashDocumentContent(content);
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
if (mismatchedHash) {
|
|
2428
|
-
return rejectedPlanArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed plan hash mismatch for ${expectedRef}: expected ${mismatchedHash}, actual ${planHash}.`, 'Refresh plan-reviewer and plan-manager artifacts with the current plan.md hash before closure.');
|
|
2182
|
+
if (boundaryFacts.finalPlanHash !== planHash || boundaryFacts.finalPlanRef.hash !== planHash) {
|
|
2183
|
+
return rejectedPlanArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Final plan hash mismatch for ${expectedRef}: expected ${boundaryFacts.finalPlanHash}, actual ${planHash}.`, 'Refresh plan close request with the current plan.md hash before closure.');
|
|
2429
2184
|
}
|
|
2430
2185
|
return {
|
|
2431
2186
|
acceptedPlanRef: { kind: 'document', ref: expectedRef, hash: planHash },
|
|
@@ -2448,45 +2203,37 @@ async function validateAcceptedTasksArtifact(projectRoot, input) {
|
|
|
2448
2203
|
if (input.blocked) {
|
|
2449
2204
|
return rejectedTasksArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks tasks closure.', 'Resolve lifecycle blockers before requesting tasks-stage closure.', 'runtime-blocked');
|
|
2450
2205
|
}
|
|
2451
|
-
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2452
|
-
return rejectedTasksArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready tasks closure must be backed by a validated tasks StageCollaborationContract.', 'Ask tasks-manager to write .sdd/runs/<branch>/tasks/tasks-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2453
|
-
}
|
|
2454
2206
|
const upstreamIssue = await validateAcceptedPlanHandoff(projectRoot, input.partition, input.acceptedPlanHandoff);
|
|
2455
2207
|
if (upstreamIssue) {
|
|
2456
2208
|
return rejectedTasksArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh plan-stage closure and provide a fresh plan -> tasks handoff before tasks closure.');
|
|
2457
2209
|
}
|
|
2458
2210
|
const expectedRef = `specs/${input.partition}/tasks.md`;
|
|
2459
|
-
const
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
if (manager.recommendation !== 'close_stage') {
|
|
2464
|
-
return rejectedTasksArtifact('not_accepted_rejected', 'invalid_proposal', `Tasks-manager recommendation ${manager.recommendation ?? 'none'} cannot accept tasks for verifies handoff.`, 'Ask tasks-manager to submit a close_stage recommendation after review blockers are resolved.');
|
|
2465
|
-
}
|
|
2466
|
-
const reviewByRef = manager.reviewRef
|
|
2467
|
-
? input.registeredArtifacts.find((record) => record.kind === 'tasks_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2468
|
-
: null;
|
|
2469
|
-
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2470
|
-
return rejectedTasksArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Tasks-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh tasks-manager closure artifact so reviewRef/reviewHash point at the registered review artifact.');
|
|
2471
|
-
}
|
|
2472
|
-
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'tasks_review');
|
|
2473
|
-
if (!approvedReview) {
|
|
2474
|
-
return rejectedTasksArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready tasks closure must include a registered tasks-reviewer artifact referenced by tasks-manager.', 'Ask tasks-reviewer to write .sdd/runs/<branch>/tasks/tasks-review-vN.md and ask tasks-manager to reference that review hash.');
|
|
2475
|
-
}
|
|
2476
|
-
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2477
|
-
return rejectedTasksArtifact('not_accepted_missing_review', 'missing_required_review', `Tasks-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept tasks.`, 'Resolve review blockers and register an approved tasks-reviewer artifact before closure.');
|
|
2478
|
-
}
|
|
2479
|
-
if (manager.targetRef?.kind !== 'document' || manager.targetRef.ref !== expectedRef || approvedReview.targetRef?.kind !== 'document' || approvedReview.targetRef.ref !== expectedRef) {
|
|
2480
|
-
return rejectedTasksArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready tasks closure must reference reviewed ${expectedRef} as the canonical tasks document.`, 'Refresh review and manager artifacts so targetRef points at specs/<branch>/tasks.md.');
|
|
2211
|
+
const acceptedPlanRef = acceptedPlanRefFromHandoff(input.partition, input.acceptedPlanHandoff);
|
|
2212
|
+
const acceptedSpecRef = acceptedSpecRefFromPlanHandoff(input.acceptedPlanHandoff);
|
|
2213
|
+
if (!acceptedPlanRef || !acceptedSpecRef) {
|
|
2214
|
+
return rejectedTasksArtifact('not_accepted_missing_upstream', 'missing_refs', 'Tasks closure requires accepted spec and plan ref/hash from runtime handoff.', 'Refresh plan-stage closure and provide a fresh plan -> tasks handoff before tasks closure.');
|
|
2481
2215
|
}
|
|
2482
2216
|
const tasksPath = path.join(projectRoot, 'specs', input.partition, 'tasks.md');
|
|
2483
2217
|
const content = await readOptionalText(tasksPath);
|
|
2218
|
+
const boundaryFacts = input.closureRequest?.runtimeCloseBoundaryFacts;
|
|
2219
|
+
if (!boundaryFacts || boundaryFacts.contract !== 'sdd-tasks-runtime-close-boundary-facts-v1') {
|
|
2220
|
+
const closeEvidenceErrors = [];
|
|
2221
|
+
if (content !== null) {
|
|
2222
|
+
validateTasksDepthSignals(content, closeEvidenceErrors);
|
|
2223
|
+
}
|
|
2224
|
+
const closeEvidenceExplanation = closeEvidenceErrors.join('\n');
|
|
2225
|
+
return rejectedTasksArtifact('not_accepted_wrong_ref', 'invalid_proposal', closeEvidenceExplanation || 'Tasks close request is missing runtime boundary facts for final tasks.md V2.', 'Submit finalTasksRef/finalTasksHash, acceptedSpecRef, acceptedPlanRef, taskUnitCount, dependencyGraphStatus, validationSignalsStatus, reviewSignal, and blockingBeforeExecuteCount=0.');
|
|
2226
|
+
}
|
|
2484
2227
|
if (content === null) {
|
|
2485
2228
|
return rejectedTasksArtifact('not_accepted_missing_tasks', 'missing_refs', `Reviewed canonical tasks artifact is missing at ${expectedRef}.`, 'Produce and review specs/<branch>/tasks.md before requesting runtime closure.');
|
|
2486
2229
|
}
|
|
2487
2230
|
if (isManagedStarterSpec(content)) {
|
|
2488
2231
|
return rejectedTasksArtifact('not_accepted_starter_tasks', 'invalid_proposal', `Canonical tasks artifact at ${expectedRef} is still the managed starter document.`, 'Replace starter tasks.md with reviewed executable task contracts before closure.');
|
|
2489
2232
|
}
|
|
2233
|
+
const tasksV2Errors = validateTasksDocumentV2(content, expectedRef);
|
|
2234
|
+
if (tasksV2Errors.length > 0) {
|
|
2235
|
+
return rejectedTasksArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Final tasks.md does not satisfy sdd-tasks-doc-v2: ${tasksV2Errors.join('; ')}.`, 'Rewrite specs/<branch>/tasks.md as final tasks.md V2 with required execution topology sections before closure.');
|
|
2236
|
+
}
|
|
2490
2237
|
const taskModel = parseSddTasksMarkdown(content, { tasksPath: expectedRef });
|
|
2491
2238
|
const duplicateIdGap = taskModel.gaps.find((gap) => gap.field === 'id' && /Duplicate task id/i.test(gap.message));
|
|
2492
2239
|
if (duplicateIdGap) {
|
|
@@ -2498,11 +2245,12 @@ async function validateAcceptedTasksArtifact(projectRoot, input) {
|
|
|
2498
2245
|
if (blockingTaskGap) {
|
|
2499
2246
|
return rejectedTasksArtifact('not_accepted_invalid_task_ids', 'invalid_proposal', blockingTaskGap.message, blockingTaskGap.recommendation);
|
|
2500
2247
|
}
|
|
2501
|
-
const tasksHash = hashDocumentContent(content);
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2248
|
+
const tasksHash = hashDocumentContent(content);
|
|
2249
|
+
if (!validTasksRuntimeCloseBoundaryFacts(boundaryFacts, input.partition, expectedRef, acceptedSpecRef, acceptedPlanRef, taskModel.tasks.length)) {
|
|
2250
|
+
return rejectedTasksArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Tasks close boundary facts must reference accepted spec, accepted plan, final ${expectedRef}, and parsed task unit count.`, 'Refresh the output close request from current runtime handoff and specs/<branch>/tasks.md.');
|
|
2251
|
+
}
|
|
2252
|
+
if (boundaryFacts.finalTasksHash !== tasksHash || boundaryFacts.finalTasksRef.hash !== tasksHash) {
|
|
2253
|
+
return rejectedTasksArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Final tasks hash mismatch for ${expectedRef}: expected ${boundaryFacts.finalTasksHash}, actual ${tasksHash}.`, 'Refresh tasks close request with the current tasks.md hash before closure.');
|
|
2506
2254
|
}
|
|
2507
2255
|
const tasksContractHash = hashTasksContract(content);
|
|
2508
2256
|
if (!tasksContractHash) {
|
|
@@ -2516,76 +2264,83 @@ async function validateAcceptedTasksArtifact(projectRoot, input) {
|
|
|
2516
2264
|
reasons: [`Runtime accepted reviewed canonical tasks artifact ${expectedRef}.`]
|
|
2517
2265
|
};
|
|
2518
2266
|
}
|
|
2519
|
-
async function
|
|
2267
|
+
async function validateAcceptedExecuteArtifact(projectRoot, input) {
|
|
2520
2268
|
if (!input.required) {
|
|
2521
2269
|
return {
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
reasons: ['Verify artifact was not required by this lifecycle decision.']
|
|
2270
|
+
acceptedExecuteRef: null,
|
|
2271
|
+
executeAcceptanceStatus: 'not_required_noop',
|
|
2272
|
+
laneEvidenceRefs: [],
|
|
2273
|
+
reasons: ['Execute evidence was not required by this lifecycle decision.']
|
|
2527
2274
|
};
|
|
2528
2275
|
}
|
|
2529
2276
|
if (input.blocked) {
|
|
2530
|
-
return
|
|
2531
|
-
}
|
|
2532
|
-
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2533
|
-
return rejectedVerifyArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready verifies closure must be backed by a validated verifies StageCollaborationContract.', 'Ask verifies-manager to write .sdd/runs/<branch>/verifies/verifies-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2277
|
+
return rejectedExecuteArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks execute closure.', 'Resolve lifecycle blockers before requesting execute-stage closure.', 'runtime-blocked');
|
|
2534
2278
|
}
|
|
2535
|
-
const upstreamIssue = await
|
|
2279
|
+
const upstreamIssue = await validateAcceptedExecuteTasksHandoff(projectRoot, input.partition, input.acceptedTasksHandoff);
|
|
2536
2280
|
if (upstreamIssue) {
|
|
2537
|
-
return
|
|
2538
|
-
}
|
|
2539
|
-
const expectedRef = `specs/${input.partition}/verify.md`;
|
|
2540
|
-
const manager = latestStageArtifact(input.registeredArtifacts, 'manager_closure_request');
|
|
2541
|
-
if (!manager) {
|
|
2542
|
-
return rejectedVerifyArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready verifies closure must be backed by a registered verifies-manager closure artifact.', 'Ask verifies-manager to write .sdd/runs/<branch>/verifies/verifies-manager-vN.md and register it before closure.');
|
|
2543
|
-
}
|
|
2544
|
-
if (manager.recommendation !== 'close_stage') {
|
|
2545
|
-
return rejectedVerifyArtifact('not_accepted_rejected', 'invalid_proposal', `Verifies-manager recommendation ${manager.recommendation ?? 'none'} cannot accept verify contract for do handoff.`, 'Ask verifies-manager to submit a close_stage recommendation after review blockers are resolved.');
|
|
2546
|
-
}
|
|
2547
|
-
const reviewByRef = manager.reviewRef
|
|
2548
|
-
? input.registeredArtifacts.find((record) => record.kind === 'verifies_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2549
|
-
: null;
|
|
2550
|
-
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2551
|
-
return rejectedVerifyArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Verifies-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh verifies-manager closure artifact so reviewRef/reviewHash point at the registered review artifact.');
|
|
2552
|
-
}
|
|
2553
|
-
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'verifies_review');
|
|
2554
|
-
if (!approvedReview) {
|
|
2555
|
-
return rejectedVerifyArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready verifies closure must include a registered verifies-reviewer artifact referenced by verifies-manager.', 'Ask verifies-reviewer to write .sdd/runs/<branch>/verifies/verifies-review-vN.md and ask verifies-manager to reference that review hash.');
|
|
2556
|
-
}
|
|
2557
|
-
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2558
|
-
return rejectedVerifyArtifact('not_accepted_missing_review', 'missing_required_review', `Verifies-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept verify contract.`, 'Resolve review blockers and register an approved verifies-reviewer artifact before closure.');
|
|
2559
|
-
}
|
|
2560
|
-
if (manager.targetRef?.kind !== 'document' || manager.targetRef.ref !== expectedRef || approvedReview.targetRef?.kind !== 'document' || approvedReview.targetRef.ref !== expectedRef) {
|
|
2561
|
-
return rejectedVerifyArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready verifies closure must reference reviewed ${expectedRef} as the canonical verify contract.`, 'Refresh review and manager artifacts so targetRef points at specs/<branch>/verify.md.');
|
|
2562
|
-
}
|
|
2563
|
-
const verifyPath = path.join(projectRoot, 'specs', input.partition, 'verify.md');
|
|
2564
|
-
const content = await readOptionalText(verifyPath);
|
|
2565
|
-
if (content === null) {
|
|
2566
|
-
return rejectedVerifyArtifact('not_accepted_missing_verify', 'missing_refs', `Reviewed canonical verify artifact is missing at ${expectedRef}.`, 'Produce and review specs/<branch>/verify.md before requesting runtime closure.');
|
|
2567
|
-
}
|
|
2568
|
-
if (isManagedStarterSpec(content)) {
|
|
2569
|
-
return rejectedVerifyArtifact('not_accepted_starter_verify', 'invalid_proposal', `Canonical verify artifact at ${expectedRef} is still the managed starter document.`, 'Replace starter verify.md with a reviewed verification contract before closure.');
|
|
2570
|
-
}
|
|
2571
|
-
const verifyHash = hashDocumentContent(content);
|
|
2572
|
-
const expectedHashes = [manager.targetHash, approvedReview.targetHash, manager.targetRef.hash, approvedReview.targetRef.hash].filter((hash) => Boolean(hash));
|
|
2573
|
-
const mismatchedHash = expectedHashes.find((hash) => hash !== verifyHash);
|
|
2574
|
-
if (mismatchedHash) {
|
|
2575
|
-
return rejectedVerifyArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed verify hash mismatch for ${expectedRef}: expected ${mismatchedHash}, actual ${verifyHash}.`, 'Refresh verifies-reviewer and verifies-manager artifacts with the current verify.md hash before closure.');
|
|
2576
|
-
}
|
|
2577
|
-
const inspection = await inspectVerifyContract(projectRoot, { branch: input.partition, branchSource: 'cli_option' });
|
|
2578
|
-
const blockingIssue = inspection.issues.find((issue) => issue.level === 'FAIL')
|
|
2579
|
-
?? inspection.issues.find((issue) => issue.field === 'tasks');
|
|
2580
|
-
if (blockingIssue) {
|
|
2581
|
-
return rejectedVerifyArtifact('not_accepted_incomplete_coverage', 'invalid_proposal', blockingIssue.message, blockingIssue.action);
|
|
2281
|
+
return rejectedExecuteArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh tasks-stage closure and provide a fresh tasks -> execute handoff before execute closure.');
|
|
2582
2282
|
}
|
|
2283
|
+
return validateExecuteProjectionReadiness(projectRoot, input.partition, input.acceptedTasksHandoff);
|
|
2284
|
+
}
|
|
2285
|
+
async function validateExecuteProjectionReadiness(projectRoot, partition, acceptedTasksHandoff) {
|
|
2286
|
+
const acceptedTasksRef = acceptedTasksRefFromExecuteHandoff(acceptedTasksHandoff);
|
|
2287
|
+
if (!acceptedTasksRef?.hash) {
|
|
2288
|
+
return rejectedExecuteArtifact('not_accepted_missing_upstream', 'missing_refs', 'Execute close requires a tasks -> execute handoff carrying accepted tasks ref/hash.', 'Refresh tasks-stage closure before requesting execute close.');
|
|
2289
|
+
}
|
|
2290
|
+
const [projectionRecords, dependencyGraphEnvelope] = await Promise.all([
|
|
2291
|
+
listRuntimeProjections(projectRoot, [TASK_UNIT_PROJECTION_TYPE, EXECUTION_LANE_PROJECTION_TYPE]),
|
|
2292
|
+
readTaskDependencyGraphProjection(projectRoot, partition)
|
|
2293
|
+
]);
|
|
2294
|
+
if (!dependencyGraphEnvelope || dependencyGraphEnvelope.payload.tasksHash !== acceptedTasksRef.hash) {
|
|
2295
|
+
return rejectedExecuteArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Execute dependency graph must be derived from accepted ${acceptedTasksRef.ref}.`, 'Rebuild execute task projections from the accepted tasks ref/hash before closing execute.');
|
|
2296
|
+
}
|
|
2297
|
+
const taskUnits = projectionRecords
|
|
2298
|
+
.filter((record) => record.projectionType === TASK_UNIT_PROJECTION_TYPE && record.scopeKey.startsWith(`${partition}:`))
|
|
2299
|
+
.map((record) => runtimeProjectionPayload(record.payload))
|
|
2300
|
+
.filter((unit) => Boolean(unit))
|
|
2301
|
+
.filter((unit) => unit.sourceRef.ref === acceptedTasksRef.ref && unit.sourceRef.hash === acceptedTasksRef.hash);
|
|
2302
|
+
if (taskUnits.length === 0) {
|
|
2303
|
+
return rejectedExecuteArtifact('not_accepted_wrong_ref', 'missing_refs', `No TaskUnitProjection records match accepted ${acceptedTasksRef.ref}.`, 'Rebuild execute task projections from the accepted tasks ref/hash before closing execute.');
|
|
2304
|
+
}
|
|
2305
|
+
const executionLanes = projectionRecords
|
|
2306
|
+
.filter((record) => record.projectionType === EXECUTION_LANE_PROJECTION_TYPE && record.scopeKey.startsWith(`${partition}:`))
|
|
2307
|
+
.map((record) => runtimeProjectionPayload(record.payload))
|
|
2308
|
+
.filter((lane) => Boolean(lane));
|
|
2309
|
+
const laneEvidenceRefs = executionLanes.map((lane) => ({ kind: 'projection', ref: `${EXECUTION_LANE_PROJECTION_TYPE}:${executionLaneScopeKey(partition, lane.laneId)}` }));
|
|
2310
|
+
const invalidTaskIds = uniqueStrings([...dependencyGraphEnvelope.payload.invalidTaskIds, ...taskUnits.filter((unit) => unit.dependencyState === 'invalid').map((unit) => unit.taskId)]);
|
|
2311
|
+
if (invalidTaskIds.length > 0) {
|
|
2312
|
+
return rejectedExecuteArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Execute task projections contain invalid task units: ${invalidTaskIds.join(', ')}.`, 'Repair accepted tasks.md and rebuild task projections before closing execute.');
|
|
2313
|
+
}
|
|
2314
|
+
const implementationUnits = taskUnits.filter((unit) => unit.unit.agentRouting.board === 'implementation');
|
|
2315
|
+
const validationUnits = taskUnits.filter((unit) => unit.unit.agentRouting.board === 'validation');
|
|
2316
|
+
if (implementationUnits.length === 0) {
|
|
2317
|
+
return rejectedExecuteArtifact('not_accepted_missing_implementation', 'missing_refs', 'Execute close requires at least one implementation-board task unit from accepted tasks.md.', 'Route accepted implementation tasks before closing execute.');
|
|
2318
|
+
}
|
|
2319
|
+
if (validationUnits.length === 0) {
|
|
2320
|
+
return rejectedExecuteArtifact('not_accepted_missing_validation', 'missing_refs', 'Execute close requires at least one validation-board task unit from accepted tasks.md.', 'Route implementation validation and goal validation tasks before closing execute.');
|
|
2321
|
+
}
|
|
2322
|
+
const incompleteImplementation = implementationUnits.filter((unit) => !isImplementationComplete(unit)).map((unit) => unit.taskId);
|
|
2323
|
+
if (incompleteImplementation.length > 0) {
|
|
2324
|
+
return rejectedExecuteArtifact('not_accepted_missing_implementation', 'missing_refs', `Implementation board is not complete for task units: ${incompleteImplementation.join(', ')}.`, 'Run implementation/review/debug lanes until implementation task units are implemented or validated before execute close.');
|
|
2325
|
+
}
|
|
2326
|
+
const openCheckpointIds = taskUnits.filter((unit) => unit.checkpointState === 'open' || unit.checkpointState === 'locked').map((unit) => `${unit.taskId}:checkpoint`);
|
|
2327
|
+
if (openCheckpointIds.length > 0) {
|
|
2328
|
+
return rejectedExecuteArtifact('not_accepted_missing_checkpoint', 'invalid_proposal', `Execute checkpoints are still open: ${openCheckpointIds.join(', ')}.`, 'Satisfy or resolve execute checkpoints before closing execute.');
|
|
2329
|
+
}
|
|
2330
|
+
const incompleteValidation = validationUnits.filter((unit) => !isValidationComplete(unit)).map((unit) => unit.taskId);
|
|
2331
|
+
if (incompleteValidation.length > 0) {
|
|
2332
|
+
return rejectedExecuteArtifact('not_accepted_missing_validation', 'missing_refs', `Validation board is not complete for task units: ${incompleteValidation.join(', ')}.`, 'Run validation and goal-validation lanes until validation task units are validated before execute close.');
|
|
2333
|
+
}
|
|
2334
|
+
const acceptedExecuteRef = {
|
|
2335
|
+
kind: 'projection',
|
|
2336
|
+
ref: `${TASK_DEPENDENCY_GRAPH_PROJECTION_TYPE}:${taskDependencyGraphScopeKey(partition)}`,
|
|
2337
|
+
hash: dependencyGraphEnvelope.payload.tasksHash
|
|
2338
|
+
};
|
|
2583
2339
|
return {
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
reasons: [`Runtime accepted reviewed canonical verify artifact ${expectedRef}.`]
|
|
2340
|
+
acceptedExecuteRef,
|
|
2341
|
+
executeAcceptanceStatus: 'accepted',
|
|
2342
|
+
laneEvidenceRefs,
|
|
2343
|
+
reasons: [`Runtime accepted execute task/lane projections for ${acceptedTasksRef.ref}.`]
|
|
2589
2344
|
};
|
|
2590
2345
|
}
|
|
2591
2346
|
async function validateAcceptedDoArtifact(projectRoot, input) {
|
|
@@ -2599,46 +2354,46 @@ async function validateAcceptedDoArtifact(projectRoot, input) {
|
|
|
2599
2354
|
};
|
|
2600
2355
|
}
|
|
2601
2356
|
if (input.blocked) {
|
|
2602
|
-
return rejectedDoArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks
|
|
2357
|
+
return rejectedDoArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks execute closure.', 'Resolve lifecycle blockers before requesting execute closure.', 'runtime-blocked');
|
|
2603
2358
|
}
|
|
2604
2359
|
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2605
|
-
return rejectedDoArtifact('not_accepted_wrong_ref', 'missing_refs', 'Ready
|
|
2360
|
+
return rejectedDoArtifact('not_accepted_wrong_ref', 'missing_refs', 'Ready execute implementation closure must be backed by a validated execute StageCollaborationContract.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/execute-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2606
2361
|
}
|
|
2607
|
-
const upstreamIssue = await
|
|
2362
|
+
const upstreamIssue = await validateAcceptedTasksExecuteHandoff(projectRoot, input.partition, input.acceptedTasksHandoff);
|
|
2608
2363
|
if (upstreamIssue) {
|
|
2609
|
-
return rejectedDoArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh
|
|
2364
|
+
return rejectedDoArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh tasks closure and provide a fresh tasks -> execute handoff before execute closure.');
|
|
2610
2365
|
}
|
|
2611
2366
|
const implementation = latestStageArtifact(input.registeredArtifacts, 'implementation_evidence');
|
|
2612
2367
|
if (!implementation) {
|
|
2613
|
-
return rejectedDoArtifact('not_accepted_missing_implementation', 'missing_refs', 'Ready
|
|
2368
|
+
return rejectedDoArtifact('not_accepted_missing_implementation', 'missing_refs', 'Ready execute implementation closure must be backed by a registered implementer evidence artifact.', 'Ask implementer to write .sdd/runs/<branch>/execute/implementation-vN.md and register it before closure.');
|
|
2614
2369
|
}
|
|
2615
2370
|
const manager = latestStageArtifact(input.registeredArtifacts, 'manager_closure_request');
|
|
2616
2371
|
if (!manager) {
|
|
2617
|
-
return rejectedDoArtifact('not_accepted_wrong_ref', 'missing_refs', 'Ready
|
|
2372
|
+
return rejectedDoArtifact('not_accepted_wrong_ref', 'missing_refs', 'Ready execute implementation closure must be backed by a registered execute-manager closure artifact.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/execute-manager-vN.md and register it before closure.');
|
|
2618
2373
|
}
|
|
2619
2374
|
if (manager.recommendation !== 'close_stage') {
|
|
2620
|
-
return rejectedDoArtifact('not_accepted_rejected', 'invalid_proposal', `
|
|
2375
|
+
return rejectedDoArtifact('not_accepted_rejected', 'invalid_proposal', `Execute-manager recommendation ${manager.recommendation ?? 'none'} cannot accept implementation state for execute validation handoff.`, 'Ask execute-manager to submit a close_stage recommendation after review blockers are resolved.');
|
|
2621
2376
|
}
|
|
2622
2377
|
const reviewByRef = manager.reviewRef
|
|
2623
2378
|
? input.registeredArtifacts.find((record) => record.kind === 'code_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2624
2379
|
: null;
|
|
2625
2380
|
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2626
|
-
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `
|
|
2381
|
+
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Execute-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh execute-manager closure artifact so reviewRef/reviewHash point at the registered code review artifact.');
|
|
2627
2382
|
}
|
|
2628
2383
|
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'code_review');
|
|
2629
2384
|
if (!approvedReview) {
|
|
2630
|
-
return rejectedDoArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready
|
|
2385
|
+
return rejectedDoArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready execute implementation closure must include a registered code-reviewer artifact referenced by execute-manager.', 'Ask code-reviewer to write .sdd/runs/<branch>/execute/code-review-vN.md and ask execute-manager to reference that review hash.');
|
|
2631
2386
|
}
|
|
2632
2387
|
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2633
2388
|
return rejectedDoArtifact('not_accepted_missing_review', 'missing_required_review', `Code-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept implementation state.`, 'Resolve review blockers and register an approved code-reviewer artifact before closure.');
|
|
2634
2389
|
}
|
|
2635
2390
|
if (manager.targetRef?.kind !== 'artifact' || manager.targetRef.ref !== implementation.ref || approvedReview.targetRef?.kind !== 'artifact' || approvedReview.targetRef.ref !== implementation.ref) {
|
|
2636
|
-
return rejectedDoArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready
|
|
2391
|
+
return rejectedDoArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready execute implementation closure must reference reviewed ${implementation.ref} as the implementation evidence artifact.`, 'Refresh code-reviewer and execute-manager artifacts so targetRef points at the implementation evidence artifact.');
|
|
2637
2392
|
}
|
|
2638
2393
|
const expectedHashes = [manager.targetHash, approvedReview.targetHash, manager.targetRef.hash, approvedReview.targetRef.hash].filter((hash) => Boolean(hash));
|
|
2639
2394
|
const mismatchedHash = expectedHashes.find((hash) => hash !== implementation.hash);
|
|
2640
2395
|
if (mismatchedHash) {
|
|
2641
|
-
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed implementation evidence hash mismatch for ${implementation.ref}: expected ${mismatchedHash}, actual ${implementation.hash}.`, 'Refresh code-reviewer and
|
|
2396
|
+
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed implementation evidence hash mismatch for ${implementation.ref}: expected ${mismatchedHash}, actual ${implementation.hash}.`, 'Refresh code-reviewer and execute-manager artifacts with the current implementation evidence hash before closure.');
|
|
2642
2397
|
}
|
|
2643
2398
|
const changedFileParse = parseImplementationChangedFileRefs(implementation);
|
|
2644
2399
|
if (changedFileParse.issue) {
|
|
@@ -2647,11 +2402,11 @@ async function validateAcceptedDoArtifact(projectRoot, input) {
|
|
|
2647
2402
|
const changedFileRefs = changedFileParse.refs;
|
|
2648
2403
|
const boundaryIssue = validateAllowedChangedFileRefs(changedFileRefs, input.allowedChangedFileRefs);
|
|
2649
2404
|
if (boundaryIssue) {
|
|
2650
|
-
return rejectedDoArtifact('not_accepted_boundary_violation', 'invalid_proposal', boundaryIssue, 'Restrict
|
|
2405
|
+
return rejectedDoArtifact('not_accepted_boundary_violation', 'invalid_proposal', boundaryIssue, 'Restrict execute implementation evidence to the task boundary or update the allowed changed-file refs.');
|
|
2651
2406
|
}
|
|
2652
2407
|
const changedFileHashIssue = await validateChangedFileHashes(projectRoot, changedFileRefs);
|
|
2653
2408
|
if (changedFileHashIssue) {
|
|
2654
|
-
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', changedFileHashIssue, 'Refresh implementation, code-reviewer, and
|
|
2409
|
+
return rejectedDoArtifact('not_accepted_hash_mismatch', 'invalid_proposal', changedFileHashIssue, 'Refresh implementation, code-reviewer, and execute-manager artifacts with current changed-file hashes before closure.');
|
|
2655
2410
|
}
|
|
2656
2411
|
return {
|
|
2657
2412
|
acceptedImplementationRef: { kind: 'artifact', ref: implementation.ref, hash: implementation.hash },
|
|
@@ -2671,146 +2426,146 @@ async function validateAcceptedTestArtifact(projectRoot, input) {
|
|
|
2671
2426
|
};
|
|
2672
2427
|
}
|
|
2673
2428
|
if (input.blocked) {
|
|
2674
|
-
return rejectedTestArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks
|
|
2429
|
+
return rejectedTestArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks execute validation closure.', 'Resolve lifecycle blockers before requesting execute validation closure.', 'runtime-blocked');
|
|
2675
2430
|
}
|
|
2676
2431
|
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2677
|
-
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready
|
|
2432
|
+
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready execute validation closure must be backed by a validated execute StageCollaborationContract.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/validation-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2678
2433
|
}
|
|
2679
2434
|
const upstreamIssue = await validateAcceptedDoHandoff(projectRoot, input.partition, input.acceptedDoHandoff);
|
|
2680
2435
|
if (upstreamIssue) {
|
|
2681
|
-
return rejectedTestArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh
|
|
2436
|
+
return rejectedTestArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh execute implementation closure before execute validation closure.');
|
|
2682
2437
|
}
|
|
2683
2438
|
const execution = latestStageArtifact(input.registeredArtifacts, 'test_execution');
|
|
2684
2439
|
if (!execution) {
|
|
2685
|
-
return rejectedTestArtifact('not_accepted_missing_execution', 'missing_refs', 'Ready
|
|
2440
|
+
return rejectedTestArtifact('not_accepted_missing_execution', 'missing_refs', 'Ready execute validation closure must be backed by a registered validation execution artifact.', 'Ask validator to write .sdd/runs/<branch>/execute/test-execution-vN.md and register it before closure.');
|
|
2686
2441
|
}
|
|
2687
2442
|
const validation = latestStageArtifact(input.registeredArtifacts, 'validation_evidence');
|
|
2688
2443
|
if (!validation) {
|
|
2689
|
-
return rejectedTestArtifact('not_accepted_missing_validation', 'missing_refs', 'Ready
|
|
2444
|
+
return rejectedTestArtifact('not_accepted_missing_validation', 'missing_refs', 'Ready execute validation closure must be backed by a registered validator evidence artifact.', 'Ask validator to write .sdd/runs/<branch>/execute/validation-vN.md and register it before closure.');
|
|
2690
2445
|
}
|
|
2691
2446
|
const executionStatus = execution.frontmatter.status;
|
|
2692
2447
|
const executionExitCode = execution.frontmatter.exitCode;
|
|
2693
2448
|
if (executionStatus !== 'passed' || executionExitCode !== 0) {
|
|
2694
|
-
return rejectedTestArtifact('not_accepted_failed_tests', 'invalid_proposal', `
|
|
2449
|
+
return rejectedTestArtifact('not_accepted_failed_tests', 'invalid_proposal', `Validation execution ${execution.ref} status ${String(executionStatus)} with exitCode ${String(executionExitCode)} cannot close execute validation.`, 'Rerun failing validation commands and register passing validation execution evidence before closure.');
|
|
2695
2450
|
}
|
|
2696
2451
|
const validationExecutionRef = executionRefFromValidation(validation);
|
|
2697
2452
|
if (validationExecutionRef !== execution.ref) {
|
|
2698
|
-
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Validation evidence ${validation.ref} must reference execution evidence ${execution.ref}.`, 'Refresh validation evidence so executionRef points at the registered
|
|
2453
|
+
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Validation evidence ${validation.ref} must reference execution evidence ${execution.ref}.`, 'Refresh validation evidence so executionRef points at the registered validation execution artifact.');
|
|
2699
2454
|
}
|
|
2700
2455
|
const validationExecutionHash = validation.frontmatter.executionHash;
|
|
2701
2456
|
if (validationExecutionHash !== execution.hash) {
|
|
2702
|
-
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Validation evidence execution hash mismatch for ${execution.ref}: expected ${String(validationExecutionHash)}, actual ${execution.hash}.`, 'Refresh validation evidence with the current
|
|
2457
|
+
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Validation evidence execution hash mismatch for ${execution.ref}: expected ${String(validationExecutionHash)}, actual ${execution.hash}.`, 'Refresh validation evidence with the current validation execution hash before closure.');
|
|
2703
2458
|
}
|
|
2704
2459
|
if (validation.frontmatter.status !== 'passed') {
|
|
2705
|
-
return rejectedTestArtifact('not_accepted_failed_tests', 'invalid_proposal', `Validation evidence ${validation.ref} status ${String(validation.frontmatter.status)} cannot close
|
|
2460
|
+
return rejectedTestArtifact('not_accepted_failed_tests', 'invalid_proposal', `Validation evidence ${validation.ref} status ${String(validation.frontmatter.status)} cannot close execute validation.`, 'Resolve validation failures and register passing validation evidence before closure.');
|
|
2706
2461
|
}
|
|
2707
2462
|
if (validation.frontmatter.acceptanceMapped !== true) {
|
|
2708
|
-
return rejectedTestArtifact('not_accepted_unmapped_acceptance', 'invalid_proposal', `Validation evidence ${validation.ref} must declare acceptanceMapped: true.`, 'Map validation evidence to accepted task/verify criteria before requesting
|
|
2463
|
+
return rejectedTestArtifact('not_accepted_unmapped_acceptance', 'invalid_proposal', `Validation evidence ${validation.ref} must declare acceptanceMapped: true.`, 'Map validation evidence to accepted task/verify criteria before requesting execute validation closure.');
|
|
2709
2464
|
}
|
|
2710
2465
|
const manager = latestStageArtifact(input.registeredArtifacts, 'manager_closure_request');
|
|
2711
2466
|
if (!manager) {
|
|
2712
|
-
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready
|
|
2467
|
+
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready execute validation closure must be backed by a registered execute-manager closure artifact.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/validation-manager-vN.md and register it before closure.');
|
|
2713
2468
|
}
|
|
2714
2469
|
if (manager.recommendation !== 'close_stage') {
|
|
2715
|
-
return rejectedTestArtifact('not_accepted_rejected', 'invalid_proposal', `
|
|
2470
|
+
return rejectedTestArtifact('not_accepted_rejected', 'invalid_proposal', `Execute-manager recommendation ${manager.recommendation ?? 'none'} cannot accept validation evidence for execute evidence judgment.`, 'Ask execute-manager to submit a close_stage recommendation after validation blockers are resolved.');
|
|
2716
2471
|
}
|
|
2717
2472
|
const reviewByRef = manager.reviewRef
|
|
2718
2473
|
? input.registeredArtifacts.find((record) => record.kind === 'test_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2719
2474
|
: null;
|
|
2720
2475
|
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2721
|
-
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `
|
|
2476
|
+
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Execute-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh execute-manager closure artifact so reviewRef/reviewHash point at the registered validation review artifact.');
|
|
2722
2477
|
}
|
|
2723
2478
|
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'test_review');
|
|
2724
2479
|
if (!approvedReview) {
|
|
2725
|
-
return rejectedTestArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready
|
|
2480
|
+
return rejectedTestArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready execute validation closure must include a registered validation-reviewer artifact referenced by execute-manager.', 'Ask validation-reviewer to write .sdd/runs/<branch>/execute/validation-review-vN.md and ask execute-manager to reference that review hash.');
|
|
2726
2481
|
}
|
|
2727
2482
|
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2728
|
-
return rejectedTestArtifact('not_accepted_missing_review', 'missing_required_review', `
|
|
2483
|
+
return rejectedTestArtifact('not_accepted_missing_review', 'missing_required_review', `Validation-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept validation evidence.`, 'Resolve review blockers and register an approved validation-reviewer artifact before closure.');
|
|
2729
2484
|
}
|
|
2730
2485
|
if (manager.targetRef?.kind !== 'artifact' || manager.targetRef.ref !== validation.ref || approvedReview.targetRef?.kind !== 'artifact' || approvedReview.targetRef.ref !== validation.ref) {
|
|
2731
|
-
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready
|
|
2486
|
+
return rejectedTestArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready execute validation closure must reference reviewed ${validation.ref} as the validation evidence artifact.`, 'Refresh validation-reviewer and execute-manager artifacts so targetRef points at the validation evidence artifact.');
|
|
2732
2487
|
}
|
|
2733
2488
|
const expectedHashes = [manager.targetHash, approvedReview.targetHash, manager.targetRef.hash, approvedReview.targetRef.hash].filter((hash) => Boolean(hash));
|
|
2734
2489
|
const mismatchedHash = expectedHashes.find((hash) => hash !== validation.hash);
|
|
2735
2490
|
if (mismatchedHash) {
|
|
2736
|
-
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed validation evidence hash mismatch for ${validation.ref}: expected ${mismatchedHash}, actual ${validation.hash}.`, 'Refresh
|
|
2491
|
+
return rejectedTestArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed validation evidence hash mismatch for ${validation.ref}: expected ${mismatchedHash}, actual ${validation.hash}.`, 'Refresh validation-reviewer and execute-manager artifacts with the current validation evidence hash before closure.');
|
|
2737
2492
|
}
|
|
2738
2493
|
return {
|
|
2739
2494
|
acceptedTestEvidenceRef: { kind: 'artifact', ref: validation.ref, hash: validation.hash },
|
|
2740
2495
|
testAcceptanceStatus: 'accepted',
|
|
2741
2496
|
testEvidenceHash: validation.hash,
|
|
2742
|
-
reasons: [`Runtime accepted reviewed
|
|
2497
|
+
reasons: [`Runtime accepted reviewed execute validation evidence ${validation.ref}.`]
|
|
2743
2498
|
};
|
|
2744
2499
|
}
|
|
2745
|
-
async function
|
|
2500
|
+
async function validateAcceptedEvidenceJudgmentArtifact(projectRoot, input) {
|
|
2746
2501
|
if (!input.required) {
|
|
2747
2502
|
return {
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
reasons: ['
|
|
2503
|
+
acceptedEvidenceJudgmentRef: null,
|
|
2504
|
+
evidenceJudgmentAcceptanceStatus: 'not_required_noop',
|
|
2505
|
+
evidenceJudgmentHash: null,
|
|
2506
|
+
reasons: ['Evidence judgment was not required by this lifecycle decision.'],
|
|
2752
2507
|
truthAlignment: null
|
|
2753
2508
|
};
|
|
2754
2509
|
}
|
|
2755
2510
|
if (input.blocked) {
|
|
2756
|
-
return
|
|
2511
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_blocked', 'blocked_lifecycle', 'Lifecycle risk decision blocks execute evidence judgment closure.', 'Resolve lifecycle blockers before requesting execute evidence judgment closure.', 'runtime-blocked');
|
|
2757
2512
|
}
|
|
2758
2513
|
if (!latestValidatedStageCollaborationContract(input.registeredCollaborationContracts)) {
|
|
2759
|
-
return
|
|
2514
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready execute evidence judgment closure must be backed by a validated execute StageCollaborationContract.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/evidence-judgment-collaboration-contract-vN.md within StageWorkOrder constraints before closure.');
|
|
2760
2515
|
}
|
|
2761
2516
|
const upstreamIssue = await validateAcceptedTestHandoff(projectRoot, input.partition, input.acceptedTestHandoff);
|
|
2762
2517
|
if (upstreamIssue) {
|
|
2763
|
-
return
|
|
2518
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_missing_upstream', 'missing_refs', upstreamIssue, 'Refresh execute validation closure before execute evidence judgment closure.');
|
|
2764
2519
|
}
|
|
2765
|
-
const verification = latestStageArtifact(input.registeredArtifacts, '
|
|
2520
|
+
const verification = latestStageArtifact(input.registeredArtifacts, 'evidence_judgment');
|
|
2766
2521
|
if (!verification) {
|
|
2767
|
-
return
|
|
2522
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_missing_verification', 'missing_refs', 'Ready execute evidence judgment closure must be backed by a registered evidence-judgment artifact.', 'Ask evidence-judgment agent to write .sdd/runs/<branch>/execute/evidence-judgment-vN.md and register it before closure.');
|
|
2768
2523
|
}
|
|
2769
2524
|
if (verification.frontmatter.status !== 'passed') {
|
|
2770
|
-
return
|
|
2525
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_failed_verification', 'invalid_proposal', `Evidence judgment ${verification.ref} status ${String(verification.frontmatter.status)} cannot close execute evidence judgment.`, 'Resolve evidence judgment failures and register passing evidence judgment evidence before closure.');
|
|
2771
2526
|
}
|
|
2772
2527
|
if (verification.frontmatter.coverageComplete !== true) {
|
|
2773
|
-
return
|
|
2528
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_incomplete_coverage', 'invalid_proposal', `Evidence judgment ${verification.ref} must declare coverageComplete: true.`, 'Complete acceptance coverage before requesting execute evidence judgment closure.');
|
|
2774
2529
|
}
|
|
2775
2530
|
const durableGapCount = verification.frontmatter.durableGapCount;
|
|
2776
2531
|
const openGapCount = verification.frontmatter.openGapCount;
|
|
2777
2532
|
if ((typeof durableGapCount === 'number' && durableGapCount > 0) || (typeof openGapCount === 'number' && openGapCount > 0)) {
|
|
2778
|
-
return
|
|
2533
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_open_gap', 'invalid_proposal', `Evidence judgment ${verification.ref} still declares open durable gaps.`, 'Resolve durable gaps before requesting execute evidence judgment closure.');
|
|
2779
2534
|
}
|
|
2780
2535
|
const manager = latestStageArtifact(input.registeredArtifacts, 'manager_closure_request');
|
|
2781
2536
|
if (!manager) {
|
|
2782
|
-
return
|
|
2537
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_wrong_ref', 'invalid_proposal', 'Ready execute evidence judgment closure must be backed by a registered execute-manager closure artifact.', 'Ask execute-manager to write .sdd/runs/<branch>/execute/evidence-judgment-manager-vN.md and register it before closure.');
|
|
2783
2538
|
}
|
|
2784
2539
|
if (manager.recommendation !== 'close_stage') {
|
|
2785
|
-
return
|
|
2540
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_rejected', 'invalid_proposal', `Execute-manager recommendation ${manager.recommendation ?? 'none'} cannot accept evidence judgment for truthAlignment and ship readiness.`, 'Ask execute-manager to submit a close_stage recommendation after evidence judgment blockers are resolved.');
|
|
2786
2541
|
}
|
|
2787
2542
|
const reviewByRef = manager.reviewRef
|
|
2788
|
-
? input.registeredArtifacts.find((record) => record.kind === '
|
|
2543
|
+
? input.registeredArtifacts.find((record) => record.kind === 'evidence_review' && record.ref === manager.reviewRef?.ref) ?? null
|
|
2789
2544
|
: null;
|
|
2790
2545
|
if (reviewByRef && manager.reviewHash !== reviewByRef.hash) {
|
|
2791
|
-
return
|
|
2546
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Execute-manager review hash mismatch for ${reviewByRef.ref}: expected ${manager.reviewHash ?? 'none'}, actual ${reviewByRef.hash}.`, 'Refresh execute-manager closure artifact so reviewRef/reviewHash point at the registered evidence review artifact.');
|
|
2792
2547
|
}
|
|
2793
|
-
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, '
|
|
2548
|
+
const approvedReview = findStageReviewForManager(input.registeredArtifacts, manager, 'evidence_review');
|
|
2794
2549
|
if (!approvedReview) {
|
|
2795
|
-
return
|
|
2550
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_missing_review', 'missing_required_review', 'Ready execute evidence judgment closure must include a registered evidence-reviewer artifact referenced by execute-manager.', 'Ask evidence-reviewer to write .sdd/runs/<branch>/execute/evidence-review-vN.md and ask execute-manager to reference that review hash.');
|
|
2796
2551
|
}
|
|
2797
2552
|
if (approvedReview.verdict !== 'approved' || approvedReview.blockingCount !== 0) {
|
|
2798
|
-
return
|
|
2553
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_missing_review', 'missing_required_review', `Evidence-reviewer verdict ${approvedReview.verdict ?? 'none'} with ${approvedReview.blockingCount ?? 0} blockers cannot accept evidence judgment.`, 'Resolve review blockers and register an approved evidence-reviewer artifact before closure.');
|
|
2799
2554
|
}
|
|
2800
2555
|
if (manager.targetRef?.kind !== 'artifact' || manager.targetRef.ref !== verification.ref || approvedReview.targetRef?.kind !== 'artifact' || approvedReview.targetRef.ref !== verification.ref) {
|
|
2801
|
-
return
|
|
2556
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_wrong_ref', 'invalid_proposal', `Ready execute evidence judgment closure must reference reviewed ${verification.ref} as the evidence judgment artifact.`, 'Refresh evidence-reviewer and execute-manager artifacts so targetRef points at the evidence judgment artifact.');
|
|
2802
2557
|
}
|
|
2803
2558
|
const expectedHashes = [manager.targetHash, approvedReview.targetHash, manager.targetRef.hash, approvedReview.targetRef.hash].filter((hash) => Boolean(hash));
|
|
2804
2559
|
const mismatchedHash = expectedHashes.find((hash) => hash !== verification.hash);
|
|
2805
2560
|
if (mismatchedHash) {
|
|
2806
|
-
return
|
|
2561
|
+
return rejectedEvidenceJudgmentArtifact('not_accepted_hash_mismatch', 'invalid_proposal', `Reviewed evidence judgment hash mismatch for ${verification.ref}: expected ${mismatchedHash}, actual ${verification.hash}.`, 'Refresh evidence-reviewer and execute-manager artifacts with the current evidence judgment hash before closure.');
|
|
2807
2562
|
}
|
|
2808
2563
|
return {
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
reasons: [`Runtime accepted reviewed
|
|
2813
|
-
truthAlignment:
|
|
2564
|
+
acceptedEvidenceJudgmentRef: { kind: 'artifact', ref: verification.ref, hash: verification.hash },
|
|
2565
|
+
evidenceJudgmentAcceptanceStatus: 'accepted',
|
|
2566
|
+
evidenceJudgmentHash: verification.hash,
|
|
2567
|
+
reasons: [`Runtime accepted reviewed evidence judgment evidence ${verification.ref}.`],
|
|
2568
|
+
truthAlignment: parseEvidenceJudgmentTruthAlignment(verification)
|
|
2814
2569
|
};
|
|
2815
2570
|
}
|
|
2816
2571
|
async function validateAcceptedShipReadinessArtifact(projectRoot, input) {
|
|
@@ -2831,7 +2586,7 @@ async function validateAcceptedShipReadinessArtifact(projectRoot, input) {
|
|
|
2831
2586
|
}
|
|
2832
2587
|
const truthAlignmentIssue = await validateAcceptedTruthAlignment(projectRoot, input.partition, input.truthAlignment);
|
|
2833
2588
|
if (truthAlignmentIssue) {
|
|
2834
|
-
return rejectedShipReadinessArtifact('not_accepted_missing_upstream', 'missing_refs', truthAlignmentIssue, 'Refresh
|
|
2589
|
+
return rejectedShipReadinessArtifact('not_accepted_missing_upstream', 'missing_refs', truthAlignmentIssue, 'Refresh execute evidence judgment closure so runtime records an aligned truthAlignment projection before ship closure.');
|
|
2835
2590
|
}
|
|
2836
2591
|
const authorityIssue = validateNoRuntimeAuthorityAttempts(input.registeredArtifacts);
|
|
2837
2592
|
if (authorityIssue) {
|
|
@@ -2889,6 +2644,7 @@ async function validateAcceptedShipReadinessArtifact(projectRoot, input) {
|
|
|
2889
2644
|
};
|
|
2890
2645
|
}
|
|
2891
2646
|
async function validateAcceptedPlanHandoff(projectRoot, partition, handoff) {
|
|
2647
|
+
const expectedSpecRef = `specs/${partition}/spec.md`;
|
|
2892
2648
|
const expectedPlanRef = `specs/${partition}/plan.md`;
|
|
2893
2649
|
if (!handoff) {
|
|
2894
2650
|
return 'Tasks closure requires a recorded plan -> tasks handoff.';
|
|
@@ -2896,6 +2652,19 @@ async function validateAcceptedPlanHandoff(projectRoot, partition, handoff) {
|
|
|
2896
2652
|
if (handoff.fromStage !== 'plan' || handoff.toStage !== 'tasks' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2897
2653
|
return 'Tasks closure requires a non-blocking plan -> tasks handoff.';
|
|
2898
2654
|
}
|
|
2655
|
+
const acceptedSpecRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedSpecRef)
|
|
2656
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedSpecRef);
|
|
2657
|
+
if (!acceptedSpecRef?.hash) {
|
|
2658
|
+
return `Plan -> tasks handoff must carry accepted ${expectedSpecRef} with a content hash.`;
|
|
2659
|
+
}
|
|
2660
|
+
const specContent = await readOptionalText(path.join(projectRoot, 'specs', partition, 'spec.md'));
|
|
2661
|
+
if (specContent === null) {
|
|
2662
|
+
return `Accepted upstream spec artifact is missing at ${expectedSpecRef}.`;
|
|
2663
|
+
}
|
|
2664
|
+
const currentSpecHash = hashDocumentContent(specContent);
|
|
2665
|
+
if (acceptedSpecRef.hash !== currentSpecHash) {
|
|
2666
|
+
return `Accepted upstream spec hash is stale for ${expectedSpecRef}: expected ${acceptedSpecRef.hash}, actual ${currentSpecHash}.`;
|
|
2667
|
+
}
|
|
2899
2668
|
const acceptedPlanRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedPlanRef)
|
|
2900
2669
|
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedPlanRef);
|
|
2901
2670
|
if (!acceptedPlanRef?.hash) {
|
|
@@ -2911,18 +2680,55 @@ async function validateAcceptedPlanHandoff(projectRoot, partition, handoff) {
|
|
|
2911
2680
|
}
|
|
2912
2681
|
return null;
|
|
2913
2682
|
}
|
|
2683
|
+
async function validateAcceptedExecuteTasksHandoff(projectRoot, partition, handoff) {
|
|
2684
|
+
const expectedTasksRef = `specs/${partition}/tasks.md`;
|
|
2685
|
+
if (!handoff) {
|
|
2686
|
+
return 'Execute closure requires a recorded tasks -> execute handoff.';
|
|
2687
|
+
}
|
|
2688
|
+
if (handoff.fromStage !== 'tasks' || handoff.toStage !== 'execute' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2689
|
+
return 'Execute closure requires a non-blocking tasks -> execute handoff.';
|
|
2690
|
+
}
|
|
2691
|
+
const acceptedTasksRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedTasksRef)
|
|
2692
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedTasksRef);
|
|
2693
|
+
if (!acceptedTasksRef?.hash) {
|
|
2694
|
+
return `Tasks -> execute handoff must carry accepted ${expectedTasksRef} with a content hash.`;
|
|
2695
|
+
}
|
|
2696
|
+
const tasksContent = await readOptionalText(path.join(projectRoot, 'specs', partition, 'tasks.md'));
|
|
2697
|
+
if (tasksContent === null) {
|
|
2698
|
+
return `Accepted upstream tasks artifact is missing at ${expectedTasksRef}.`;
|
|
2699
|
+
}
|
|
2700
|
+
const currentTasksHash = hashDocumentContent(tasksContent);
|
|
2701
|
+
if (acceptedTasksRef.hash !== currentTasksHash) {
|
|
2702
|
+
return `Accepted upstream tasks hash is stale for ${expectedTasksRef}: expected ${acceptedTasksRef.hash}, actual ${currentTasksHash}.`;
|
|
2703
|
+
}
|
|
2704
|
+
return null;
|
|
2705
|
+
}
|
|
2706
|
+
function acceptedTasksRefFromExecuteHandoff(handoff) {
|
|
2707
|
+
if (!handoff) {
|
|
2708
|
+
return null;
|
|
2709
|
+
}
|
|
2710
|
+
return handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref.endsWith('/tasks.md'))
|
|
2711
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref.endsWith('/tasks.md'))
|
|
2712
|
+
?? null;
|
|
2713
|
+
}
|
|
2714
|
+
function isImplementationComplete(unit) {
|
|
2715
|
+
return unit.executionState === 'implemented' || unit.executionState === 'validated' || unit.evidenceState === 'accepted';
|
|
2716
|
+
}
|
|
2717
|
+
function isValidationComplete(unit) {
|
|
2718
|
+
return unit.executionState === 'validated' || unit.evidenceState === 'accepted';
|
|
2719
|
+
}
|
|
2914
2720
|
async function validateAcceptedTasksHandoff(projectRoot, partition, handoff) {
|
|
2915
2721
|
const expectedTasksRef = `specs/${partition}/tasks.md`;
|
|
2916
2722
|
if (!handoff) {
|
|
2917
|
-
return '
|
|
2723
|
+
return 'Verification-design closure requires a recorded plan -> tasks handoff.';
|
|
2918
2724
|
}
|
|
2919
|
-
if (handoff.fromStage !== '
|
|
2920
|
-
return '
|
|
2725
|
+
if (handoff.fromStage !== 'plan' || handoff.toStage !== 'tasks' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2726
|
+
return 'Verification-design closure requires a non-blocking plan -> tasks handoff.';
|
|
2921
2727
|
}
|
|
2922
2728
|
const acceptedTasksRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedTasksRef)
|
|
2923
2729
|
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedTasksRef);
|
|
2924
2730
|
if (!acceptedTasksRef?.hash) {
|
|
2925
|
-
return `
|
|
2731
|
+
return `Plan -> tasks handoff must carry accepted ${expectedTasksRef} with a content hash.`;
|
|
2926
2732
|
}
|
|
2927
2733
|
const tasksContent = await readOptionalText(path.join(projectRoot, 'specs', partition, 'tasks.md'));
|
|
2928
2734
|
if (tasksContent === null) {
|
|
@@ -2934,54 +2740,54 @@ async function validateAcceptedTasksHandoff(projectRoot, partition, handoff) {
|
|
|
2934
2740
|
}
|
|
2935
2741
|
return null;
|
|
2936
2742
|
}
|
|
2937
|
-
async function
|
|
2938
|
-
const
|
|
2743
|
+
async function validateAcceptedTasksExecuteHandoff(projectRoot, partition, handoff) {
|
|
2744
|
+
const expectedTasksRef = `specs/${partition}/tasks.md`;
|
|
2939
2745
|
if (!handoff) {
|
|
2940
|
-
return '
|
|
2746
|
+
return 'Execute closure requires a recorded tasks -> execute handoff.';
|
|
2941
2747
|
}
|
|
2942
|
-
if (handoff.fromStage !== '
|
|
2943
|
-
return '
|
|
2748
|
+
if (handoff.fromStage !== 'tasks' || handoff.toStage !== 'execute' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2749
|
+
return 'Execute closure requires a non-blocking tasks -> execute handoff.';
|
|
2944
2750
|
}
|
|
2945
|
-
const
|
|
2946
|
-
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref ===
|
|
2947
|
-
if (!
|
|
2948
|
-
return `
|
|
2751
|
+
const acceptedTasksRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'document' && inputRef.ref === expectedTasksRef)
|
|
2752
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'document' && outputRef.ref === expectedTasksRef);
|
|
2753
|
+
if (!acceptedTasksRef?.hash) {
|
|
2754
|
+
return `Tasks -> execute handoff must carry accepted ${expectedTasksRef} with a content hash.`;
|
|
2949
2755
|
}
|
|
2950
|
-
const
|
|
2951
|
-
if (
|
|
2952
|
-
return `Accepted upstream
|
|
2756
|
+
const tasksContent = await readOptionalText(path.join(projectRoot, 'specs', partition, 'tasks.md'));
|
|
2757
|
+
if (tasksContent === null) {
|
|
2758
|
+
return `Accepted upstream tasks artifact is missing at ${expectedTasksRef}.`;
|
|
2953
2759
|
}
|
|
2954
|
-
const
|
|
2955
|
-
if (
|
|
2956
|
-
return `Accepted upstream
|
|
2760
|
+
const currentTasksHash = hashDocumentContent(tasksContent);
|
|
2761
|
+
if (acceptedTasksRef.hash !== currentTasksHash) {
|
|
2762
|
+
return `Accepted upstream tasks hash is stale for ${expectedTasksRef}: expected ${acceptedTasksRef.hash}, actual ${currentTasksHash}.`;
|
|
2957
2763
|
}
|
|
2958
2764
|
return null;
|
|
2959
2765
|
}
|
|
2960
2766
|
async function validateAcceptedDoHandoff(projectRoot, partition, handoff) {
|
|
2961
2767
|
if (!handoff) {
|
|
2962
|
-
return '
|
|
2768
|
+
return 'Validation lane closure requires a recorded execute -> ship handoff.';
|
|
2963
2769
|
}
|
|
2964
|
-
if (handoff.fromStage !== '
|
|
2965
|
-
return '
|
|
2770
|
+
if (handoff.fromStage !== 'execute' || handoff.toStage !== 'ship' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2771
|
+
return 'Validation lane closure requires a non-blocking execute -> ship handoff.';
|
|
2966
2772
|
}
|
|
2967
|
-
const acceptedImplementationRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'artifact' && inputRef.ref.startsWith(`.sdd/runs/${partition}/
|
|
2968
|
-
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'artifact' && outputRef.ref.startsWith(`.sdd/runs/${partition}/
|
|
2773
|
+
const acceptedImplementationRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'artifact' && inputRef.ref.startsWith(`.sdd/runs/${partition}/execute/implementation-`))
|
|
2774
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'artifact' && outputRef.ref.startsWith(`.sdd/runs/${partition}/execute/implementation-`));
|
|
2969
2775
|
if (!acceptedImplementationRef?.hash) {
|
|
2970
|
-
return `
|
|
2776
|
+
return `Execute -> ship handoff must carry accepted .sdd/runs/${partition}/execute/implementation-vN.md with a content hash.`;
|
|
2971
2777
|
}
|
|
2972
2778
|
return validateHandoffInputHashes(projectRoot, handoff.requiredInputRefs);
|
|
2973
2779
|
}
|
|
2974
2780
|
async function validateAcceptedTestHandoff(projectRoot, partition, handoff) {
|
|
2975
2781
|
if (!handoff) {
|
|
2976
|
-
return '
|
|
2782
|
+
return 'Evidence-judgment lane closure requires a recorded execute -> ship handoff.';
|
|
2977
2783
|
}
|
|
2978
|
-
if (handoff.fromStage !== '
|
|
2979
|
-
return '
|
|
2784
|
+
if (handoff.fromStage !== 'execute' || handoff.toStage !== 'ship' || handoff.status === 'blocked' || handoff.status === 'rejected') {
|
|
2785
|
+
return 'Evidence-judgment lane closure requires a non-blocking execute -> ship handoff.';
|
|
2980
2786
|
}
|
|
2981
|
-
const acceptedTestRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'artifact' && inputRef.ref.startsWith(`.sdd/runs/${partition}/
|
|
2982
|
-
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'artifact' && outputRef.ref.startsWith(`.sdd/runs/${partition}/
|
|
2787
|
+
const acceptedTestRef = handoff.requiredInputRefs.find((inputRef) => inputRef.kind === 'artifact' && inputRef.ref.startsWith(`.sdd/runs/${partition}/execute/validation-`))
|
|
2788
|
+
?? handoff.outputRefs.find((outputRef) => outputRef.kind === 'artifact' && outputRef.ref.startsWith(`.sdd/runs/${partition}/execute/validation-`));
|
|
2983
2789
|
if (!acceptedTestRef?.hash) {
|
|
2984
|
-
return `
|
|
2790
|
+
return `Execute -> ship handoff must carry accepted .sdd/runs/${partition}/execute/validation-vN.md with a content hash.`;
|
|
2985
2791
|
}
|
|
2986
2792
|
return validateHandoffInputHashes(projectRoot, handoff.requiredInputRefs);
|
|
2987
2793
|
}
|
|
@@ -3038,12 +2844,11 @@ function rejectedTasksArtifact(tasksAcceptanceStatus, reasonCode, explanation, r
|
|
|
3038
2844
|
}
|
|
3039
2845
|
};
|
|
3040
2846
|
}
|
|
3041
|
-
function
|
|
2847
|
+
function rejectedExecuteArtifact(executeAcceptanceStatus, reasonCode, explanation, requiredNextAction, fallbackRoute = 'revise-proposal') {
|
|
3042
2848
|
return {
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
verifyContractHash: null,
|
|
2849
|
+
acceptedExecuteRef: null,
|
|
2850
|
+
executeAcceptanceStatus,
|
|
2851
|
+
laneEvidenceRefs: [],
|
|
3047
2852
|
reasons: [explanation],
|
|
3048
2853
|
rejectionIssue: {
|
|
3049
2854
|
reasonCode,
|
|
@@ -3082,11 +2887,11 @@ function rejectedTestArtifact(testAcceptanceStatus, reasonCode, explanation, req
|
|
|
3082
2887
|
}
|
|
3083
2888
|
};
|
|
3084
2889
|
}
|
|
3085
|
-
function
|
|
2890
|
+
function rejectedEvidenceJudgmentArtifact(evidenceJudgmentAcceptanceStatus, reasonCode, explanation, requiredNextAction, fallbackRoute = 'revise-proposal') {
|
|
3086
2891
|
return {
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
2892
|
+
acceptedEvidenceJudgmentRef: null,
|
|
2893
|
+
evidenceJudgmentAcceptanceStatus,
|
|
2894
|
+
evidenceJudgmentHash: null,
|
|
3090
2895
|
reasons: [explanation],
|
|
3091
2896
|
truthAlignment: null,
|
|
3092
2897
|
rejectionIssue: {
|
|
@@ -3097,7 +2902,7 @@ function rejectedGoalVerifyArtifact(goalVerifyAcceptanceStatus, reasonCode, expl
|
|
|
3097
2902
|
}
|
|
3098
2903
|
};
|
|
3099
2904
|
}
|
|
3100
|
-
function
|
|
2905
|
+
function parseEvidenceJudgmentTruthAlignment(verification) {
|
|
3101
2906
|
const status = enumFrontmatter(verification.frontmatter, 'truthAlignmentStatus', TRUTH_ALIGNMENT_STATUSES);
|
|
3102
2907
|
const semanticImpact = enumFrontmatter(verification.frontmatter, 'semanticImpact', TRUTH_ALIGNMENT_SEMANTIC_IMPACTS);
|
|
3103
2908
|
const ownerStage = enumFrontmatter(verification.frontmatter, 'ownerStage', TRUTH_ALIGNMENT_OWNER_STAGES);
|
|
@@ -3135,7 +2940,7 @@ function stageListFrontmatter(frontmatter, key) {
|
|
|
3135
2940
|
if (values.length === 0) {
|
|
3136
2941
|
return null;
|
|
3137
2942
|
}
|
|
3138
|
-
const allowed = new Set(['spec', 'plan', 'tasks', '
|
|
2943
|
+
const allowed = new Set(['spec', 'plan', 'tasks', 'execute', 'ship']);
|
|
3139
2944
|
return values.filter((value) => allowed.has(value));
|
|
3140
2945
|
}
|
|
3141
2946
|
function runtimeRefListFrontmatter(frontmatter, key) {
|
|
@@ -3202,10 +3007,10 @@ async function parseShipReleaseDocumentRef(projectRoot, partition, readiness) {
|
|
|
3202
3007
|
}
|
|
3203
3008
|
async function validateAcceptedTruthAlignment(projectRoot, partition, truthAlignment) {
|
|
3204
3009
|
if (!truthAlignment) {
|
|
3205
|
-
return 'Ship closure requires a recorded aligned truthAlignment projection from
|
|
3010
|
+
return 'Ship closure requires a recorded aligned truthAlignment projection from execute.';
|
|
3206
3011
|
}
|
|
3207
|
-
if (truthAlignment.contract !== TRUTH_ALIGNMENT_CONTRACT || truthAlignment.sourceStage !== '
|
|
3208
|
-
return 'Ship closure requires a valid
|
|
3012
|
+
if (truthAlignment.contract !== TRUTH_ALIGNMENT_CONTRACT || truthAlignment.sourceStage !== 'execute') {
|
|
3013
|
+
return 'Ship closure requires a valid execute truthAlignment projection.';
|
|
3209
3014
|
}
|
|
3210
3015
|
if (truthAlignment.status !== 'aligned') {
|
|
3211
3016
|
const reasons = truthAlignment.reasons.length > 0 ? `: ${truthAlignment.reasons.join('; ')}` : '';
|
|
@@ -3220,9 +3025,9 @@ async function validateAcceptedTruthAlignment(projectRoot, partition, truthAlign
|
|
|
3220
3025
|
if (truthAlignment.invalidatesStages.includes('ship')) {
|
|
3221
3026
|
return 'Ship closure requires truthAlignment that does not invalidate ship.';
|
|
3222
3027
|
}
|
|
3223
|
-
const
|
|
3224
|
-
if (!
|
|
3225
|
-
return `TruthAlignment must carry accepted .sdd/runs/${partition}/
|
|
3028
|
+
const acceptedEvidenceJudgmentRef = truthAlignment.acceptedRealityRefs.find((ref) => ref.kind === 'artifact' && ref.ref.startsWith(`.sdd/runs/${partition}/execute/evidence-judgment-`));
|
|
3029
|
+
if (!acceptedEvidenceJudgmentRef?.hash) {
|
|
3030
|
+
return `TruthAlignment must carry accepted .sdd/runs/${partition}/execute/evidence-judgment-vN.md with a content hash.`;
|
|
3226
3031
|
}
|
|
3227
3032
|
return validateTruthAlignmentRefHashes(projectRoot, [...truthAlignment.declaredTruthRefs, ...truthAlignment.acceptedRealityRefs]);
|
|
3228
3033
|
}
|
|
@@ -3376,7 +3181,7 @@ function validateAllowedChangedFileRefs(changedFileRefs, allowedChangedFileRefs)
|
|
|
3376
3181
|
}
|
|
3377
3182
|
}
|
|
3378
3183
|
const outsideBoundary = changedFileRefs.find((ref) => !allowedExact.has(ref.ref) && !allowedPatterns.some((pattern) => pattern.test(ref.ref)));
|
|
3379
|
-
return outsideBoundary ? `Changed file ${outsideBoundary.ref} is outside the allowed
|
|
3184
|
+
return outsideBoundary ? `Changed file ${outsideBoundary.ref} is outside the allowed execute task boundary.` : null;
|
|
3380
3185
|
}
|
|
3381
3186
|
function normalizeChangedFilePattern(value) {
|
|
3382
3187
|
const normalized = normalizePortablePath(value);
|
|
@@ -3454,7 +3259,7 @@ function buildPlanWorkflowHandoff(scope, decision, input) {
|
|
|
3454
3259
|
};
|
|
3455
3260
|
}
|
|
3456
3261
|
function buildTasksClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3457
|
-
const status = health === '
|
|
3262
|
+
const status = health === 'ready_for_execute'
|
|
3458
3263
|
? 'completed'
|
|
3459
3264
|
: health === 'no-op'
|
|
3460
3265
|
? 'skipped'
|
|
@@ -3478,94 +3283,12 @@ function buildTasksClosureStageRun(scope, runId, workOrder, health, input) {
|
|
|
3478
3283
|
function buildTasksWorkflowHandoff(scope, decision, input) {
|
|
3479
3284
|
return {
|
|
3480
3285
|
contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
|
|
3481
|
-
id: stableId('tasks-
|
|
3286
|
+
id: stableId('tasks-execute-handoff', scope, 'closure', input.generatedAt),
|
|
3482
3287
|
scope,
|
|
3483
3288
|
fromStage: 'tasks',
|
|
3484
|
-
toStage: '
|
|
3289
|
+
toStage: 'execute',
|
|
3485
3290
|
fromAgent: TASKS_STAGE_MANAGER,
|
|
3486
|
-
toAgent: '
|
|
3487
|
-
status: decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' ? 'blocked' : 'proposed',
|
|
3488
|
-
outputRefs: input.outputRefs,
|
|
3489
|
-
requiredInputRefs: input.requiredInputRefs,
|
|
3490
|
-
riskDecisionRef: input.riskDecisionRef,
|
|
3491
|
-
evidenceRefs: input.evidenceRefs,
|
|
3492
|
-
openQuestions: [],
|
|
3493
|
-
blockingGaps: [],
|
|
3494
|
-
createdAt: input.generatedAt
|
|
3495
|
-
};
|
|
3496
|
-
}
|
|
3497
|
-
function buildVerifiesClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3498
|
-
const status = health === 'ready_for_do'
|
|
3499
|
-
? 'completed'
|
|
3500
|
-
: health === 'no-op'
|
|
3501
|
-
? 'skipped'
|
|
3502
|
-
: 'blocked';
|
|
3503
|
-
return {
|
|
3504
|
-
contract: STAGE_RUN_CONTRACT_VERSION,
|
|
3505
|
-
id: stableId('stage-run-verifies', scope, runId, input.generatedAt),
|
|
3506
|
-
scope,
|
|
3507
|
-
stage: 'verifies',
|
|
3508
|
-
ownerAgent: workOrder?.stageManager ?? 'runtime',
|
|
3509
|
-
coMainAgents: workOrder?.agentTeam ?? [],
|
|
3510
|
-
status,
|
|
3511
|
-
inputRefs: input.inputRefs,
|
|
3512
|
-
outputRefs: input.outputRefs,
|
|
3513
|
-
decisionRefs: input.decisionRefs,
|
|
3514
|
-
blockingReasons: status === 'blocked' ? [input.rejectionReason ?? `Verifies adjudication health is ${health}.`] : [],
|
|
3515
|
-
createdAt: input.generatedAt,
|
|
3516
|
-
updatedAt: input.generatedAt
|
|
3517
|
-
};
|
|
3518
|
-
}
|
|
3519
|
-
function buildVerifiesWorkflowHandoff(scope, decision, input) {
|
|
3520
|
-
return {
|
|
3521
|
-
contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
|
|
3522
|
-
id: stableId('verifies-do-handoff', scope, 'closure', input.generatedAt),
|
|
3523
|
-
scope,
|
|
3524
|
-
fromStage: 'verifies',
|
|
3525
|
-
toStage: 'do',
|
|
3526
|
-
fromAgent: VERIFIES_STAGE_MANAGER,
|
|
3527
|
-
toAgent: 'do-stage-runtime',
|
|
3528
|
-
status: decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' ? 'blocked' : 'proposed',
|
|
3529
|
-
outputRefs: input.outputRefs,
|
|
3530
|
-
requiredInputRefs: input.requiredInputRefs,
|
|
3531
|
-
riskDecisionRef: input.riskDecisionRef,
|
|
3532
|
-
evidenceRefs: input.evidenceRefs,
|
|
3533
|
-
openQuestions: [],
|
|
3534
|
-
blockingGaps: [],
|
|
3535
|
-
createdAt: input.generatedAt
|
|
3536
|
-
};
|
|
3537
|
-
}
|
|
3538
|
-
function buildDoClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3539
|
-
const status = health === 'ready_for_test'
|
|
3540
|
-
? 'completed'
|
|
3541
|
-
: health === 'no-op'
|
|
3542
|
-
? 'skipped'
|
|
3543
|
-
: 'blocked';
|
|
3544
|
-
return {
|
|
3545
|
-
contract: STAGE_RUN_CONTRACT_VERSION,
|
|
3546
|
-
id: stableId('stage-run-do', scope, runId, input.generatedAt),
|
|
3547
|
-
scope,
|
|
3548
|
-
stage: 'do',
|
|
3549
|
-
ownerAgent: workOrder?.stageManager ?? 'runtime',
|
|
3550
|
-
coMainAgents: workOrder?.agentTeam ?? [],
|
|
3551
|
-
status,
|
|
3552
|
-
inputRefs: input.inputRefs,
|
|
3553
|
-
outputRefs: input.outputRefs,
|
|
3554
|
-
decisionRefs: input.decisionRefs,
|
|
3555
|
-
blockingReasons: status === 'blocked' ? [input.rejectionReason ?? `Do adjudication health is ${health}.`] : [],
|
|
3556
|
-
createdAt: input.generatedAt,
|
|
3557
|
-
updatedAt: input.generatedAt
|
|
3558
|
-
};
|
|
3559
|
-
}
|
|
3560
|
-
function buildDoWorkflowHandoff(scope, decision, input) {
|
|
3561
|
-
return {
|
|
3562
|
-
contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
|
|
3563
|
-
id: stableId('do-test-handoff', scope, 'closure', input.generatedAt),
|
|
3564
|
-
scope,
|
|
3565
|
-
fromStage: 'do',
|
|
3566
|
-
toStage: 'test',
|
|
3567
|
-
fromAgent: DO_STAGE_MANAGER,
|
|
3568
|
-
toAgent: 'test-stage-runtime',
|
|
3291
|
+
toAgent: 'execute-stage-runtime',
|
|
3569
3292
|
status: decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' ? 'blocked' : 'proposed',
|
|
3570
3293
|
outputRefs: input.outputRefs,
|
|
3571
3294
|
requiredInputRefs: input.requiredInputRefs,
|
|
@@ -3576,37 +3299,37 @@ function buildDoWorkflowHandoff(scope, decision, input) {
|
|
|
3576
3299
|
createdAt: input.generatedAt
|
|
3577
3300
|
};
|
|
3578
3301
|
}
|
|
3579
|
-
function
|
|
3580
|
-
const status = health === '
|
|
3302
|
+
function buildExecuteClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3303
|
+
const status = health === 'ready_for_ship'
|
|
3581
3304
|
? 'completed'
|
|
3582
3305
|
: health === 'no-op'
|
|
3583
3306
|
? 'skipped'
|
|
3584
3307
|
: 'blocked';
|
|
3585
3308
|
return {
|
|
3586
3309
|
contract: STAGE_RUN_CONTRACT_VERSION,
|
|
3587
|
-
id: stableId('stage-run-
|
|
3310
|
+
id: stableId('stage-run-execute', scope, runId, input.generatedAt),
|
|
3588
3311
|
scope,
|
|
3589
|
-
stage: '
|
|
3312
|
+
stage: 'execute',
|
|
3590
3313
|
ownerAgent: workOrder?.stageManager ?? 'runtime',
|
|
3591
3314
|
coMainAgents: workOrder?.agentTeam ?? [],
|
|
3592
3315
|
status,
|
|
3593
3316
|
inputRefs: input.inputRefs,
|
|
3594
3317
|
outputRefs: input.outputRefs,
|
|
3595
3318
|
decisionRefs: input.decisionRefs,
|
|
3596
|
-
blockingReasons: status === 'blocked' ? [input.rejectionReason ?? `
|
|
3319
|
+
blockingReasons: status === 'blocked' ? [input.rejectionReason ?? `Execute adjudication health is ${health}.`] : [],
|
|
3597
3320
|
createdAt: input.generatedAt,
|
|
3598
3321
|
updatedAt: input.generatedAt
|
|
3599
3322
|
};
|
|
3600
3323
|
}
|
|
3601
|
-
function
|
|
3324
|
+
function buildExecuteWorkflowHandoff(scope, decision, input) {
|
|
3602
3325
|
return {
|
|
3603
3326
|
contract: WORKFLOW_HANDOFF_CONTRACT_VERSION,
|
|
3604
|
-
id: stableId('
|
|
3327
|
+
id: stableId('execute-ship-handoff', scope, 'closure', input.generatedAt),
|
|
3605
3328
|
scope,
|
|
3606
|
-
fromStage: '
|
|
3607
|
-
toStage: '
|
|
3608
|
-
fromAgent:
|
|
3609
|
-
toAgent: '
|
|
3329
|
+
fromStage: 'execute',
|
|
3330
|
+
toStage: 'ship',
|
|
3331
|
+
fromAgent: 'execute-manager',
|
|
3332
|
+
toAgent: 'ship-stage-runtime',
|
|
3610
3333
|
status: decision.profile === 'blocked' || decision.approvalPolicy === 'blocked' ? 'blocked' : 'proposed',
|
|
3611
3334
|
outputRefs: input.outputRefs,
|
|
3612
3335
|
requiredInputRefs: input.requiredInputRefs,
|
|
@@ -3617,28 +3340,6 @@ function buildTestWorkflowHandoff(scope, decision, input) {
|
|
|
3617
3340
|
createdAt: input.generatedAt
|
|
3618
3341
|
};
|
|
3619
3342
|
}
|
|
3620
|
-
function buildGoalVerifyClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3621
|
-
const status = health === 'ready_for_ship'
|
|
3622
|
-
? 'completed'
|
|
3623
|
-
: health === 'no-op'
|
|
3624
|
-
? 'skipped'
|
|
3625
|
-
: 'blocked';
|
|
3626
|
-
return {
|
|
3627
|
-
contract: STAGE_RUN_CONTRACT_VERSION,
|
|
3628
|
-
id: stableId('stage-run-goal-verify', scope, runId, input.generatedAt),
|
|
3629
|
-
scope,
|
|
3630
|
-
stage: 'goal-verify',
|
|
3631
|
-
ownerAgent: workOrder?.stageManager ?? 'runtime',
|
|
3632
|
-
coMainAgents: workOrder?.agentTeam ?? [],
|
|
3633
|
-
status,
|
|
3634
|
-
inputRefs: input.inputRefs,
|
|
3635
|
-
outputRefs: input.outputRefs,
|
|
3636
|
-
decisionRefs: input.decisionRefs,
|
|
3637
|
-
blockingReasons: status === 'blocked' ? [input.rejectionReason ?? `Goal-verify adjudication health is ${health}.`] : [],
|
|
3638
|
-
createdAt: input.generatedAt,
|
|
3639
|
-
updatedAt: input.generatedAt
|
|
3640
|
-
};
|
|
3641
|
-
}
|
|
3642
3343
|
function buildShipClosureStageRun(scope, runId, workOrder, health, input) {
|
|
3643
3344
|
const status = health === 'ship_ready'
|
|
3644
3345
|
? 'completed'
|
|
@@ -3790,6 +3491,462 @@ function specArtifactStatusForHealth(health) {
|
|
|
3790
3491
|
function isManagedStarterSpec(content) {
|
|
3791
3492
|
return /^sdd_managed_starter:\s*true\s*$/m.test(content);
|
|
3792
3493
|
}
|
|
3494
|
+
function validateSpecDocumentV3(content) {
|
|
3495
|
+
const errors = [];
|
|
3496
|
+
if (!/contract:\s*sdd-spec-doc-v3\b/.test(content)) {
|
|
3497
|
+
errors.push('missing contract: sdd-spec-doc-v3');
|
|
3498
|
+
}
|
|
3499
|
+
const requiredSections = [
|
|
3500
|
+
'Problem Reframing / Intent Discovery',
|
|
3501
|
+
'Change Delta',
|
|
3502
|
+
'Scope',
|
|
3503
|
+
'Requirements',
|
|
3504
|
+
'Acceptance Criteria / Evidence Targets',
|
|
3505
|
+
'Definitions / Rules',
|
|
3506
|
+
'Planning Constraints / Signals',
|
|
3507
|
+
'Open Questions / Ambiguity Ledger',
|
|
3508
|
+
'Close Quality Evidence'
|
|
3509
|
+
];
|
|
3510
|
+
for (const section of requiredSections) {
|
|
3511
|
+
const escaped = escapeRegex(section).replace(/\s+/g, '\\s+');
|
|
3512
|
+
if (!new RegExp(`^##\\s+(?:\\d+\\.\\s*)?${escaped}\\s*$`, 'im').test(content)) {
|
|
3513
|
+
errors.push(`missing section: ${section}`);
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
const forbiddenSections = [/^##\s+Implementation Plan\s*$/im, /^##\s+Task List\s*$/im, /^##\s+Validation Plan\s*$/im, /^##\s+Runtime Gate Metadata\s*$/im, /^##\s+Subagent Trace\s*$/im];
|
|
3517
|
+
if (forbiddenSections.some((pattern) => pattern.test(content))) {
|
|
3518
|
+
errors.push('contains forbidden implementation/runtime/subagent section');
|
|
3519
|
+
}
|
|
3520
|
+
errors.push(...formatArtifactDepthBlockingIssues(evaluateSpecArtifactDepth(content)));
|
|
3521
|
+
return errors;
|
|
3522
|
+
}
|
|
3523
|
+
function validateSpecDepthSignals(content, errors) {
|
|
3524
|
+
const problem = extractMarkdownSection(content, 'Problem Reframing / Intent Discovery') ?? '';
|
|
3525
|
+
const changeDelta = extractMarkdownSection(content, 'Change Delta') ?? '';
|
|
3526
|
+
const requirements = extractMarkdownSection(content, 'Requirements') ?? '';
|
|
3527
|
+
const acceptance = extractMarkdownSection(content, 'Acceptance Criteria / Evidence Targets') ?? '';
|
|
3528
|
+
const definitions = extractMarkdownSection(content, 'Definitions / Rules') ?? '';
|
|
3529
|
+
const ambiguity = extractMarkdownSection(content, 'Open Questions / Ambiguity Ledger') ?? '';
|
|
3530
|
+
const closeEvidence = extractMarkdownSection(content, 'Close Quality Evidence') ?? '';
|
|
3531
|
+
if (!hasProblemReframingDepth(problem)) {
|
|
3532
|
+
errors.push('spec lacks problem reframing depth in Problem Reframing / Intent Discovery');
|
|
3533
|
+
}
|
|
3534
|
+
if (!hasChangeDeltaDepth(changeDelta)) {
|
|
3535
|
+
errors.push('spec lacks explicit current/target/delta/unchanged/non-goal depth in Change Delta');
|
|
3536
|
+
}
|
|
3537
|
+
if (!hasRequirementReasoningDepth(requirements, definitions)) {
|
|
3538
|
+
errors.push('spec lacks requirement reasoning or domain rule depth');
|
|
3539
|
+
}
|
|
3540
|
+
if (!hasAcceptanceEvidenceDepth(acceptance)) {
|
|
3541
|
+
errors.push('spec lacks acceptance evidence targets tied to requirements');
|
|
3542
|
+
}
|
|
3543
|
+
if (!hasAmbiguityRoutingDepth(ambiguity)) {
|
|
3544
|
+
errors.push('spec lacks explicit ambiguity routing for blocking decisions, researchable gaps, assumptions, or deferred items');
|
|
3545
|
+
}
|
|
3546
|
+
if (!closeEvidence) {
|
|
3547
|
+
errors.push('missing spec close quality evidence content');
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3550
|
+
const requiredEvidence = [
|
|
3551
|
+
['requirement_review_sufficient', 'spec close quality evidence must declare requirement_review_sufficient: true'],
|
|
3552
|
+
['problem_reframed', 'spec close quality evidence must declare problem_reframed: true'],
|
|
3553
|
+
['domain_rules_confirmed_or_routed', 'spec close quality evidence must declare domain_rules_confirmed_or_routed: true'],
|
|
3554
|
+
['acceptance_evidence_targets_defined', 'spec close quality evidence must declare acceptance_evidence_targets_defined: true'],
|
|
3555
|
+
['ambiguity_routed', 'spec close quality evidence must declare ambiguity_routed: true'],
|
|
3556
|
+
['ready_for_plan', 'spec close quality evidence must declare ready_for_plan: true']
|
|
3557
|
+
];
|
|
3558
|
+
for (const [key, message] of requiredEvidence) {
|
|
3559
|
+
if (!new RegExp(`${key}\\s*:\\s*` + '`?' + 'true' + '`?', 'i').test(closeEvidence)) {
|
|
3560
|
+
errors.push(message);
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
if (!/downstream_business_guesswork_remaining\s*:\s*\[\s*\]/i.test(closeEvidence)) {
|
|
3564
|
+
errors.push('spec close quality evidence must declare no downstream_business_guesswork_remaining');
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
function hasProblemReframingDepth(section) {
|
|
3568
|
+
return /surface request/i.test(section)
|
|
3569
|
+
&& /reframed problem/i.test(section)
|
|
3570
|
+
&& /inferred real intent|real intent/i.test(section)
|
|
3571
|
+
&& /observable success/i.test(section);
|
|
3572
|
+
}
|
|
3573
|
+
function hasChangeDeltaDepth(section) {
|
|
3574
|
+
return /current behavior/i.test(section)
|
|
3575
|
+
&& /target behavior|desired behavior/i.test(section)
|
|
3576
|
+
&& /delta/i.test(section)
|
|
3577
|
+
&& /unchanged behavior/i.test(section)
|
|
3578
|
+
&& /non-goals?/i.test(section);
|
|
3579
|
+
}
|
|
3580
|
+
function hasRequirementReasoningDepth(requirements, definitions) {
|
|
3581
|
+
const hasRequirement = /\bREQ-\d+\b/i.test(requirements);
|
|
3582
|
+
const hasReasoning = /reasoning|basis|source|constraint|because|why|rule|invariant|domain/i.test(`${requirements}\n${definitions}`);
|
|
3583
|
+
return hasRequirement && hasReasoning;
|
|
3584
|
+
}
|
|
3585
|
+
function hasAcceptanceEvidenceDepth(section) {
|
|
3586
|
+
return /\bAC-\d+\b/i.test(section)
|
|
3587
|
+
&& /evidence target|api|ui|sql|test|manual|runtime|stage close/i.test(section)
|
|
3588
|
+
&& /REQ-\d+/i.test(section);
|
|
3589
|
+
}
|
|
3590
|
+
function hasAmbiguityRoutingDepth(section) {
|
|
3591
|
+
return /blocking user decisions?|blocking before plan|no blocking/i.test(section)
|
|
3592
|
+
&& /researchable|resolved by scout|scout|safe assumptions?|assumptions?|deferred/i.test(section);
|
|
3593
|
+
}
|
|
3594
|
+
function validatePlanDocumentV3(content, boundaryFacts) {
|
|
3595
|
+
const errors = [];
|
|
3596
|
+
if (!/contract:\s*sdd-plan-doc-v3\b/.test(content)) {
|
|
3597
|
+
errors.push('missing contract: sdd-plan-doc-v3');
|
|
3598
|
+
}
|
|
3599
|
+
const requiredSections = [
|
|
3600
|
+
'Metadata',
|
|
3601
|
+
'Upstream Spec Trace',
|
|
3602
|
+
'Planning Problem / Strategy Framing',
|
|
3603
|
+
'Current Implementation Map',
|
|
3604
|
+
'Target Design Overview',
|
|
3605
|
+
'Change Topology / Responsibility Boundaries',
|
|
3606
|
+
'Interface / API / Schema Design',
|
|
3607
|
+
'State / Data / Concurrency Design',
|
|
3608
|
+
'Key Design Decisions',
|
|
3609
|
+
'Alternatives Considered',
|
|
3610
|
+
'Risk Controls',
|
|
3611
|
+
'Validation Strategy',
|
|
3612
|
+
'Rollout / Rollback / Compatibility',
|
|
3613
|
+
'Task-stage Constraints',
|
|
3614
|
+
'Open Questions / User Decisions',
|
|
3615
|
+
'Plan Close Quality Evidence'
|
|
3616
|
+
];
|
|
3617
|
+
for (const section of requiredSections) {
|
|
3618
|
+
const escaped = escapeRegex(section).replace(/\s+/g, '\\s+');
|
|
3619
|
+
if (!new RegExp(`^##\\s+(?:\\d+(?:\\.\\d+)*\\.?\\s+)?${escaped}\\s*$`, 'im').test(content)) {
|
|
3620
|
+
errors.push(`missing section: ${section}`);
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
const forbiddenSections = ['Task Graph', 'Task Units', 'Task Breakdown Rationale', 'Implementation Diff', 'Validation Results', 'Runtime Gate Metadata', 'Subagent Trace'];
|
|
3624
|
+
const hasForbiddenSection = forbiddenSections.some((section) => {
|
|
3625
|
+
const escaped = escapeRegex(section).replace(/\s+/g, '\\s+');
|
|
3626
|
+
return new RegExp(`^##\\s+(?:\\d+(?:\\.\\d+)*\\.?\\s+)?${escaped}\\s*$`, 'im').test(content);
|
|
3627
|
+
});
|
|
3628
|
+
const taskLeakagePatterns = [/```sdd-task\b/i, /^###\s+T\d+\b/im, /^#{3,}\s+Task\s+Units?\b/im, /^\s*sourceRequirements\s*:/im, /^\s*sourceAcceptanceCriteria\s*:/im, /^\s*taskClass\s*:/im, /^\s*suggestedExecutionLane\s*:/im, /^\s*wave\s*:/im, /^\s*dependencies\s*:/im];
|
|
3629
|
+
if (hasForbiddenSection || taskLeakagePatterns.some((pattern) => pattern.test(content))) {
|
|
3630
|
+
errors.push('contains forbidden task/runtime/subagent section');
|
|
3631
|
+
}
|
|
3632
|
+
const closeEvidence = extractMarkdownSection(content, 'Plan Close Quality Evidence');
|
|
3633
|
+
if (!closeEvidence) {
|
|
3634
|
+
errors.push('missing plan close quality evidence content');
|
|
3635
|
+
}
|
|
3636
|
+
else if (/ready_for_tasks\s*:\s*`?false`?/i.test(closeEvidence) || !/ready_for_tasks\s*:\s*`?true`?/i.test(closeEvidence)) {
|
|
3637
|
+
errors.push('plan close quality evidence must declare ready_for_tasks: true');
|
|
3638
|
+
}
|
|
3639
|
+
validatePlanDepthSignals(content, boundaryFacts, errors);
|
|
3640
|
+
errors.push(...formatArtifactDepthBlockingIssues(evaluatePlanArtifactDepth(content)));
|
|
3641
|
+
return errors;
|
|
3642
|
+
}
|
|
3643
|
+
function validatePlanDepthSignals(_content, boundaryFacts, errors) {
|
|
3644
|
+
if (boundaryFacts?.blockingBeforeTasksCount !== undefined && boundaryFacts.blockingBeforeTasksCount !== 0) {
|
|
3645
|
+
errors.push('plan close quality evidence conflicts with runtime blockingBeforeTasksCount');
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
function hasConcreteImplementationSurface(section) {
|
|
3649
|
+
if (/scout gap|needs scout|unresolved gap|not applicable|no existing surface/i.test(section)) {
|
|
3650
|
+
return true;
|
|
3651
|
+
}
|
|
3652
|
+
const namedSurfaces = section.match(/\b[A-Z][A-Za-z0-9_]*(?:Controller|Service|ServiceImpl|Mapper|Repository|Entity|DTO|VO|Request|Response|Component|Page|Config|Test)\b/g) ?? [];
|
|
3653
|
+
const fileRefs = section.match(/`[^`]+\.(?:ts|tsx|js|jsx|java|kt|go|py|rs|xml|sql|jsp|vue|md)`/g) ?? [];
|
|
3654
|
+
return namedSurfaces.length + fileRefs.length >= 2 && /reuse|change|do-not-reuse|do not reuse|owner|ownership|convention|boundary|surface/i.test(section);
|
|
3655
|
+
}
|
|
3656
|
+
function hasFieldApiSqlMapping(section) {
|
|
3657
|
+
if (/not applicable|no interface|no api|no schema/i.test(section) && /because|checked|reason/i.test(section)) {
|
|
3658
|
+
return true;
|
|
3659
|
+
}
|
|
3660
|
+
const backtickFields = section.match(/`[a-zA-Z_][\w.]*`/g) ?? [];
|
|
3661
|
+
const identifierFields = section.match(/\b[A-Za-z_][A-Za-z0-9_]*(?:Id|IDs|Hash|Ref|Refs|Count|Status|Type|Key|Keys|At|Path|Command|Query|DTO|VO|Request|Response|Mapper|Controller|Service)\b/g) ?? [];
|
|
3662
|
+
const hasApiShape = /\b(query|request|response|DTO|VO|endpoint|controller|service|mapper|SQL|MyBatis|分页|权限|错误|响应包装)\b/i.test(section);
|
|
3663
|
+
const hasMapping = /\b(source|table|mapper|SQL|field|column|join|group|aggregate|映射|字段|表|聚合|查询参数|返回字段)\b/i.test(section);
|
|
3664
|
+
return backtickFields.length + identifierFields.length >= 6 && hasApiShape && hasMapping;
|
|
3665
|
+
}
|
|
3666
|
+
function hasStateDataFailureDepth(section) {
|
|
3667
|
+
if (/not applicable|no persisted|no state/i.test(section) && /failure|rollback|stale|dirty|because|reason/i.test(section)) {
|
|
3668
|
+
return true;
|
|
3669
|
+
}
|
|
3670
|
+
const hasDataSources = /\b(table|source|asset|state|flow|idempot|transaction|rollback|failure|partial|dirty|stale|performance|limit|join|dedup|grain|表|状态|流程|失败|回滚|脏数据|性能|去重|粒度|资产池)\b/i.test(section);
|
|
3671
|
+
const identifierRules = section.match(/\b[A-Za-z_][A-Za-z0-9_]*(?:Id|Hash|Ref|Status|Type|Key|At|Path|Projection|Handoff|Stage|State|Scope|Owner|Content)\b/g) ?? [];
|
|
3672
|
+
const hasSpecificRules = (section.match(/`[^`]+`/g) ?? []).length >= 5 || identifierRules.length >= 5 || /@startuml|\|.*\|.*\|/m.test(section);
|
|
3673
|
+
const hasFailureOrLimit = /\b(fail|failure|rollback|partial|dirty|stale|limit|timeout|fallback|异常|失败|回滚|部分|脏|限制|超时|降级)\b/i.test(section);
|
|
3674
|
+
return hasDataSources && hasSpecificRules && hasFailureOrLimit;
|
|
3675
|
+
}
|
|
3676
|
+
function hasScenarioValidationMatrix(validationStrategy, riskControls) {
|
|
3677
|
+
const combined = `${validationStrategy}\n${riskControls}`;
|
|
3678
|
+
const hasScenario = /scenario|input data|user action|expected|proves|does not prove|场景|输入|预期|证明/i.test(combined);
|
|
3679
|
+
const hasEvidence = /command|evidence|manual|test|api|ui|sql|hook|artifact|证据|检查/i.test(combined);
|
|
3680
|
+
const hasRiskLink = /risk|impact|control|validation hook|task-stage constraint|风险|影响|控制/i.test(combined);
|
|
3681
|
+
return hasScenario && hasEvidence && hasRiskLink;
|
|
3682
|
+
}
|
|
3683
|
+
function hasTaskStageConstraintDepth(section) {
|
|
3684
|
+
return /boundary|constraint|rollback|ordering|dependency|validation coverage|risky seam|task-stage|atomic|边界|约束|回滚|依赖|验证/i.test(section)
|
|
3685
|
+
&& !/```sdd-task\b/i.test(section);
|
|
3686
|
+
}
|
|
3687
|
+
function hasScoutResolutionSignal(implementationMap, openQuestions, closeEvidence) {
|
|
3688
|
+
return /scout|evidence|observed|grounded|resolved|logged|no existing surface|not applicable/i.test(`${implementationMap}\n${openQuestions}\n${closeEvidence}`);
|
|
3689
|
+
}
|
|
3690
|
+
function extractMarkdownSection(content, section) {
|
|
3691
|
+
for (const sectionName of Array.isArray(section) ? section : [section]) {
|
|
3692
|
+
const escaped = escapeRegex(sectionName).replace(/\s+/g, '\\s+');
|
|
3693
|
+
const match = new RegExp(`^##\\s+(?:\\d+(?:\\.\\d+)*\\.?\\s+)?${escaped}\\s*$`, 'im').exec(content);
|
|
3694
|
+
if (!match) {
|
|
3695
|
+
continue;
|
|
3696
|
+
}
|
|
3697
|
+
const start = match.index + match[0].length;
|
|
3698
|
+
const rest = content.slice(start);
|
|
3699
|
+
const next = /^##\s+/im.exec(rest);
|
|
3700
|
+
return (next ? rest.slice(0, next.index) : rest).trim();
|
|
3701
|
+
}
|
|
3702
|
+
return null;
|
|
3703
|
+
}
|
|
3704
|
+
function validateTasksDocumentV2(content, tasksPath = 'tasks.md') {
|
|
3705
|
+
const errors = [];
|
|
3706
|
+
if (!/contract:\s*sdd-tasks-doc-v2\b/.test(content)) {
|
|
3707
|
+
errors.push('missing contract: sdd-tasks-doc-v2');
|
|
3708
|
+
}
|
|
3709
|
+
const requiredSections = [
|
|
3710
|
+
['Split Basis', 'Task Split Basis', 'Work Unit Split Basis'],
|
|
3711
|
+
['Execution Order Overview'],
|
|
3712
|
+
['Implementation Tasks', 'Implementation Work Units', 'Implementation Task Units'],
|
|
3713
|
+
['Validation Tasks', 'Validation Work Units', 'Validation Task Units'],
|
|
3714
|
+
['Task Dependencies and Handoff', 'Dependencies and Validation Handoff', 'Task Dependency and Validation Handoff'],
|
|
3715
|
+
['Coverage Check'],
|
|
3716
|
+
['Open Execution Questions', 'Open Questions', 'Execution Questions'],
|
|
3717
|
+
['Tasks Close Quality Evidence', 'Close Quality Evidence']
|
|
3718
|
+
];
|
|
3719
|
+
for (const sectionAliases of requiredSections) {
|
|
3720
|
+
if (!hasMarkdownSection(content, sectionAliases)) {
|
|
3721
|
+
errors.push(`missing section: ${sectionAliases[0]}`);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
const forbiddenSections = [/^##\s+(?:\d+(?:\.\d+)*\.?\s+)?Implementation Diff\s*$/im, /^##\s+(?:\d+(?:\.\d+)*\.?\s+)?Validation Results\s*$/im, /^##\s+(?:\d+(?:\.\d+)*\.?\s+)?Runtime Gate Metadata\s*$/im, /^##\s+(?:\d+(?:\.\d+)*\.?\s+)?Subagent Trace\s*$/im, /^##\s+(?:\d+(?:\.\d+)*\.?\s+)?Long-Term Backlog\s*$/im];
|
|
3725
|
+
if (forbiddenSections.some((pattern) => pattern.test(content)) || /\b(?:obligationMatrix|projectionPayload|runtimeGateMetadata)\b/i.test(content)) {
|
|
3726
|
+
errors.push('contains forbidden implementation/runtime/subagent section');
|
|
3727
|
+
}
|
|
3728
|
+
const parsed = parseSddTasksMarkdown(content, { tasksPath });
|
|
3729
|
+
if (parsed.tasks.length === 0) {
|
|
3730
|
+
errors.push('missing executable task units');
|
|
3731
|
+
}
|
|
3732
|
+
const taskIds = new Set(parsed.tasks.map((task) => task.id));
|
|
3733
|
+
const taskById = new Map(parsed.tasks.map((task) => [task.id, task]));
|
|
3734
|
+
let hasImplementationTask = false;
|
|
3735
|
+
let hasValidationTask = false;
|
|
3736
|
+
for (const task of parsed.tasks) {
|
|
3737
|
+
const metadata = task.rawMetadata;
|
|
3738
|
+
const taskClass = task.taskClass;
|
|
3739
|
+
const unitType = task.unitType;
|
|
3740
|
+
const dependencies = task.dependsOn;
|
|
3741
|
+
if (taskClass !== 'implementation' && taskClass !== 'validation') {
|
|
3742
|
+
errors.push(`task ${task.id} missing taskClass implementation|validation`);
|
|
3743
|
+
}
|
|
3744
|
+
if (!unitType) {
|
|
3745
|
+
errors.push(`task ${task.id} missing unitType`);
|
|
3746
|
+
}
|
|
3747
|
+
if (!Number.isInteger(task.wave) || (task.wave ?? 0) <= 0) {
|
|
3748
|
+
errors.push(`task ${task.id} missing execution wave`);
|
|
3749
|
+
}
|
|
3750
|
+
if (task.affectedFiles.length === 0) {
|
|
3751
|
+
errors.push(`task ${task.id} missing affected areas`);
|
|
3752
|
+
}
|
|
3753
|
+
for (const dependency of dependencies) {
|
|
3754
|
+
if (!taskIds.has(dependency)) {
|
|
3755
|
+
errors.push(`task ${task.id} references unknown dependency ${dependency}`);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
if (taskClass === 'implementation') {
|
|
3759
|
+
hasImplementationTask = true;
|
|
3760
|
+
const handoffTasks = task.validationHandoff;
|
|
3761
|
+
if (handoffTasks.length === 0) {
|
|
3762
|
+
errors.push(`task ${task.id} missing validation handoff`);
|
|
3763
|
+
}
|
|
3764
|
+
for (const handoffTaskId of handoffTasks) {
|
|
3765
|
+
const handoffTask = taskById.get(handoffTaskId);
|
|
3766
|
+
if (!handoffTask) {
|
|
3767
|
+
errors.push(`task ${task.id} hands off to unknown validation task ${handoffTaskId}`);
|
|
3768
|
+
}
|
|
3769
|
+
else if (handoffTask.taskClass !== 'validation') {
|
|
3770
|
+
errors.push(`task ${task.id} hands off to non-validation task ${handoffTaskId}`);
|
|
3771
|
+
}
|
|
3772
|
+
else if (Number.isInteger(task.wave) && Number.isInteger(handoffTask.wave) && (handoffTask.wave ?? 0) <= (task.wave ?? 0)) {
|
|
3773
|
+
errors.push(`task ${task.id} validation handoff ${handoffTaskId} must be in a later wave`);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
if (taskClass === 'validation') {
|
|
3778
|
+
hasValidationTask = true;
|
|
3779
|
+
const validatesTasks = metadataNamedListValue(metadata, ['validatesImplementationTasks', 'validates_implementation_tasks']);
|
|
3780
|
+
if (validatesTasks.length === 0) {
|
|
3781
|
+
errors.push(`task ${task.id} missing validatesImplementationTasks`);
|
|
3782
|
+
}
|
|
3783
|
+
for (const validatedTask of validatesTasks) {
|
|
3784
|
+
if (!taskIds.has(validatedTask)) {
|
|
3785
|
+
errors.push(`task ${task.id} validates unknown implementation task ${validatedTask}`);
|
|
3786
|
+
}
|
|
3787
|
+
const validated = taskById.get(validatedTask);
|
|
3788
|
+
if (validated && validated.taskClass !== 'implementation') {
|
|
3789
|
+
errors.push(`task ${task.id} validates non-implementation task ${validatedTask}`);
|
|
3790
|
+
}
|
|
3791
|
+
if (validated && Number.isInteger(task.wave) && Number.isInteger(validated.wave) && (task.wave ?? 0) <= (validated.wave ?? 0)) {
|
|
3792
|
+
errors.push(`task ${task.id} must run after validated implementation task ${validatedTask}`);
|
|
3793
|
+
}
|
|
3794
|
+
if (!dependencies.includes(validatedTask)) {
|
|
3795
|
+
errors.push(`task ${task.id} must depend on validated implementation task ${validatedTask}`);
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
if (!hasImplementationTask) {
|
|
3801
|
+
errors.push('missing implementation task');
|
|
3802
|
+
}
|
|
3803
|
+
if (!hasValidationTask) {
|
|
3804
|
+
errors.push('missing validation task');
|
|
3805
|
+
}
|
|
3806
|
+
errors.push(...validateTaskValidationTopology(parsed.tasks));
|
|
3807
|
+
validateTasksDepthSignals(content, errors);
|
|
3808
|
+
errors.push(...taskDependencyCycleErrors(parsed.tasks));
|
|
3809
|
+
return errors;
|
|
3810
|
+
}
|
|
3811
|
+
function validateTasksDepthSignals(content, errors) {
|
|
3812
|
+
const closeEvidence = extractMarkdownSection(content, ['Tasks Close Quality Evidence', 'Close Quality Evidence']) ?? '';
|
|
3813
|
+
if (!hasTaskReviewVerdict(closeEvidence) || !hasTaskReviewReconciliation(closeEvidence)) {
|
|
3814
|
+
errors.push('tasks close quality evidence must include task-review-agent verdict and tasks-manager review reconciliation');
|
|
3815
|
+
}
|
|
3816
|
+
if (!/downstream_execution_guesswork_remaining\s*:\s*\[\s*\]/i.test(closeEvidence)) {
|
|
3817
|
+
errors.push('tasks close quality evidence must declare downstream_execution_guesswork_remaining: []');
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
function hasTaskReviewVerdict(section) {
|
|
3821
|
+
return /task-review-agent\s+(?:verdict|review)|review(?:_|\s+)signal|reviewed by task-review-agent/i.test(section);
|
|
3822
|
+
}
|
|
3823
|
+
function hasTaskReviewReconciliation(section) {
|
|
3824
|
+
return /review(?:_|\s+)reconciliation|tasks-manager\s+(?:review\s+)?reconciliation|tasks-manager\s+(?:resolved|adjudicated)|review findings? reconciled|blocking findings resolved|task-review-agent findings resolved/i.test(section);
|
|
3825
|
+
}
|
|
3826
|
+
function hasWorkUnitContextDepth(section) {
|
|
3827
|
+
return /why this task exists|work-unit context|plan decision|design part|must not reinterpret|risk/i.test(section);
|
|
3828
|
+
}
|
|
3829
|
+
function hasUpstreamTraceDepth(section) {
|
|
3830
|
+
return /REQ-\d+/i.test(section) && /AC-\d+/i.test(section) && /planRefs|plan section|plan decision|§\d+/i.test(section);
|
|
3831
|
+
}
|
|
3832
|
+
function hasModificationBoundaryDepth(section) {
|
|
3833
|
+
return /allowed files|allowed code|allowed .*changes|forbidden files|forbidden .*scope|what not to do|modification boundary|scope exclusions/i.test(section);
|
|
3834
|
+
}
|
|
3835
|
+
function hasRollbackUnitDepth(implementationTasks, dependencies) {
|
|
3836
|
+
return /rollback unit|reverted together|rollback boundary|shared rollback/i.test(`${implementationTasks}\n${dependencies}`);
|
|
3837
|
+
}
|
|
3838
|
+
function hasDependencyRationaleDepth(dependencies, implementationTasks) {
|
|
3839
|
+
return /because|why ordering matters|dependency rationale|unlocks|must complete before|parallel/i.test(`${dependencies}\n${implementationTasks}`);
|
|
3840
|
+
}
|
|
3841
|
+
function hasCompletionEvidenceDepth(section) {
|
|
3842
|
+
return /completion evidence|done criteria|observable completion|what does not count|code review|basic code sanity/i.test(section);
|
|
3843
|
+
}
|
|
3844
|
+
function hasValidationExpectedResultDepth(section) {
|
|
3845
|
+
return /expected result|pass criteria|evidence is enough|does not prove|acceptance checks|manual inspection|test/i.test(section);
|
|
3846
|
+
}
|
|
3847
|
+
function hasFailureRouteDepth(section) {
|
|
3848
|
+
return /failure routing|failure route|return to|plan repair|spec\/user decision|environment diagnostic|tasks repair/i.test(section);
|
|
3849
|
+
}
|
|
3850
|
+
function hasMarkdownSection(content, sectionAliases) {
|
|
3851
|
+
return sectionAliases.some((section) => {
|
|
3852
|
+
const escaped = escapeRegex(section).replace(/\s+/g, '\\s+');
|
|
3853
|
+
return new RegExp(`^##\\s+(?:\\d+(?:\\.\\d+)*\\.?\\s+)?${escaped}\\s*$`, 'im').test(content);
|
|
3854
|
+
});
|
|
3855
|
+
}
|
|
3856
|
+
function validateTaskValidationTopology(tasks) {
|
|
3857
|
+
const taskIds = new Set(tasks.map((task) => task.id));
|
|
3858
|
+
if (taskIds.size !== tasks.length) {
|
|
3859
|
+
return [];
|
|
3860
|
+
}
|
|
3861
|
+
const taskById = new Map(tasks.map((task) => [task.id, task]));
|
|
3862
|
+
const errors = [];
|
|
3863
|
+
for (const task of tasks) {
|
|
3864
|
+
if (task.taskClass === 'implementation') {
|
|
3865
|
+
if (task.validationHandoff.length !== 1) {
|
|
3866
|
+
errors.push(`task ${task.id} must hand off to exactly one validation task`);
|
|
3867
|
+
continue;
|
|
3868
|
+
}
|
|
3869
|
+
const validationTask = taskById.get(task.validationHandoff[0]);
|
|
3870
|
+
const validatesTasks = validationTask ? metadataNamedListValue(validationTask.rawMetadata, ['validatesImplementationTasks', 'validates_implementation_tasks']) : [];
|
|
3871
|
+
if (validationTask && (validatesTasks.length !== 1 || validatesTasks[0] !== task.id)) {
|
|
3872
|
+
errors.push(`task ${task.id} validation handoff ${validationTask.id} must validate exactly ${task.id}`);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3875
|
+
if (task.taskClass === 'validation') {
|
|
3876
|
+
const validatesTasks = metadataNamedListValue(task.rawMetadata, ['validatesImplementationTasks', 'validates_implementation_tasks']);
|
|
3877
|
+
if (validatesTasks.length !== 1) {
|
|
3878
|
+
errors.push(`task ${task.id} must validate exactly one implementation task`);
|
|
3879
|
+
continue;
|
|
3880
|
+
}
|
|
3881
|
+
const implementationTask = taskById.get(validatesTasks[0]);
|
|
3882
|
+
if (implementationTask?.taskClass === 'implementation' && (implementationTask.validationHandoff.length !== 1 || implementationTask.validationHandoff[0] !== task.id)) {
|
|
3883
|
+
errors.push(`task ${task.id} validates ${implementationTask.id} but ${implementationTask.id} must hand off only to ${task.id}`);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
return errors;
|
|
3888
|
+
}
|
|
3889
|
+
function taskDependencyCycleErrors(tasks) {
|
|
3890
|
+
const taskIds = new Set(tasks.map((task) => task.id));
|
|
3891
|
+
const dependencies = new Map(tasks.map((task) => [task.id, task.dependsOn.filter((dependency) => taskIds.has(dependency))]));
|
|
3892
|
+
const visiting = new Set();
|
|
3893
|
+
const visited = new Set();
|
|
3894
|
+
const errors = [];
|
|
3895
|
+
const visit = (taskId, path) => {
|
|
3896
|
+
if (visited.has(taskId)) {
|
|
3897
|
+
return;
|
|
3898
|
+
}
|
|
3899
|
+
if (visiting.has(taskId)) {
|
|
3900
|
+
errors.push(`task dependency cycle: ${[...path, taskId].join(' -> ')}`);
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
visiting.add(taskId);
|
|
3904
|
+
for (const dependency of dependencies.get(taskId) ?? []) {
|
|
3905
|
+
visit(dependency, [...path, taskId]);
|
|
3906
|
+
}
|
|
3907
|
+
visiting.delete(taskId);
|
|
3908
|
+
visited.add(taskId);
|
|
3909
|
+
};
|
|
3910
|
+
for (const task of tasks) {
|
|
3911
|
+
visit(task.id, []);
|
|
3912
|
+
}
|
|
3913
|
+
return Array.from(new Set(errors));
|
|
3914
|
+
}
|
|
3915
|
+
function metadataNamedListValue(metadata, names) {
|
|
3916
|
+
for (const name of names) {
|
|
3917
|
+
const value = metadataListValue(metadata[name]);
|
|
3918
|
+
if (value.length > 0) {
|
|
3919
|
+
return value;
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
return [];
|
|
3923
|
+
}
|
|
3924
|
+
function metadataNamedScalarValue(metadata, names) {
|
|
3925
|
+
for (const name of names) {
|
|
3926
|
+
const value = metadataScalarValue(metadata[name]);
|
|
3927
|
+
if (value !== null) {
|
|
3928
|
+
return value;
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
return null;
|
|
3932
|
+
}
|
|
3933
|
+
function metadataListValue(value) {
|
|
3934
|
+
if (Array.isArray(value)) {
|
|
3935
|
+
return value.map((item) => String(item).trim()).filter((item) => item.length > 0);
|
|
3936
|
+
}
|
|
3937
|
+
const scalar = metadataScalarValue(value);
|
|
3938
|
+
return scalar ? [scalar] : [];
|
|
3939
|
+
}
|
|
3940
|
+
function metadataScalarValue(value) {
|
|
3941
|
+
if (typeof value === 'string') {
|
|
3942
|
+
const trimmed = value.trim();
|
|
3943
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
3944
|
+
}
|
|
3945
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
3946
|
+
return String(value);
|
|
3947
|
+
}
|
|
3948
|
+
return null;
|
|
3949
|
+
}
|
|
3793
3950
|
async function readOptionalText(filePath) {
|
|
3794
3951
|
try {
|
|
3795
3952
|
return await readFile(filePath, 'utf8');
|
|
@@ -3819,28 +3976,10 @@ function tasksAdjudicationProjectionRef(scope) {
|
|
|
3819
3976
|
ref: `${TASKS_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${tasksCollaborationScopeKey(scope)}`
|
|
3820
3977
|
};
|
|
3821
3978
|
}
|
|
3822
|
-
function
|
|
3979
|
+
function executeAdjudicationProjectionRef(scope) {
|
|
3823
3980
|
return {
|
|
3824
3981
|
kind: 'projection',
|
|
3825
|
-
ref: `${
|
|
3826
|
-
};
|
|
3827
|
-
}
|
|
3828
|
-
function doAdjudicationProjectionRef(scope) {
|
|
3829
|
-
return {
|
|
3830
|
-
kind: 'projection',
|
|
3831
|
-
ref: `${DO_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${doCollaborationScopeKey(scope)}`
|
|
3832
|
-
};
|
|
3833
|
-
}
|
|
3834
|
-
function testAdjudicationProjectionRef(scope) {
|
|
3835
|
-
return {
|
|
3836
|
-
kind: 'projection',
|
|
3837
|
-
ref: `${TEST_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${testCollaborationScopeKey(scope)}`
|
|
3838
|
-
};
|
|
3839
|
-
}
|
|
3840
|
-
function goalVerifyAdjudicationProjectionRef(scope) {
|
|
3841
|
-
return {
|
|
3842
|
-
kind: 'projection',
|
|
3843
|
-
ref: `${GOAL_VERIFY_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${goalVerifyCollaborationScopeKey(scope)}`
|
|
3982
|
+
ref: `${EXECUTE_COLLABORATION_ADJUDICATION_PROJECTION_TYPE}:${executeCollaborationScopeKey(scope)}`
|
|
3844
3983
|
};
|
|
3845
3984
|
}
|
|
3846
3985
|
function shipAdjudicationProjectionRef(scope) {
|
|
@@ -3852,6 +3991,9 @@ function shipAdjudicationProjectionRef(scope) {
|
|
|
3852
3991
|
function stableHash(value) {
|
|
3853
3992
|
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
3854
3993
|
}
|
|
3994
|
+
function uniqueStrings(values) {
|
|
3995
|
+
return Array.from(new Set(values.filter((value) => value.length > 0)));
|
|
3996
|
+
}
|
|
3855
3997
|
function uniqueRuntimeRefs(refs) {
|
|
3856
3998
|
const seen = new Set();
|
|
3857
3999
|
return refs.filter((ref) => {
|
|
@@ -3863,6 +4005,12 @@ function uniqueRuntimeRefs(refs) {
|
|
|
3863
4005
|
return true;
|
|
3864
4006
|
});
|
|
3865
4007
|
}
|
|
4008
|
+
function runtimeProjectionPayload(payload) {
|
|
4009
|
+
if (!payload || typeof payload !== 'object' || !('payload' in payload)) {
|
|
4010
|
+
return null;
|
|
4011
|
+
}
|
|
4012
|
+
return payload.payload;
|
|
4013
|
+
}
|
|
3866
4014
|
function stableId(prefix, scope, ...parts) {
|
|
3867
4015
|
const hash = createHash('sha256').update(JSON.stringify([scope, parts]), 'utf8').digest('hex').slice(0, 16);
|
|
3868
4016
|
return `${prefix}-${hash}`;
|