deviatdd 2.20.0__tar.gz → 2.20.1__tar.gz
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.
- {deviatdd-2.20.0 → deviatdd-2.20.1}/CHANGELOG.md +2 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/PKG-INFO +1 -1
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pyproject.toml +1 -1
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/DeviaTDD-api.md +25 -20
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/DeviaTDD-architecture.md +21 -10
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/meso.py +39 -7
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/micro.py +52 -27
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/validation.py +52 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/plan.md +6 -3
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-plan.md +5 -2
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_meso_contracts.py +6 -5
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_validation.py +43 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_resume.py +11 -10
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_run.py +170 -5
- {deviatdd-2.20.0 → deviatdd-2.20.1}/uv.lock +1 -1
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/.gitignore +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/config.toml +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/evaluations/deviate-flows-skill-2026-06-26.json +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.env.example +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.gitattributes +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.githooks/pre-commit +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.githooks/pre-push +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/workflows/ci.yml +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.gitignore +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.opencode/.gitignore +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.opencode/opencode.json +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/005-acceptance-gates/002-task-acceptance-traceability/.env.example +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/adhoc/012-rpc-streaming-tui-renderer/.env.example +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/adhoc/014-cwe-mapping-security-findings/.env.example +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/work/.env.example +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/AGENTS.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/CLAUDE.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/CODE_OF_CONDUCT.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/CONTRIBUTING.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/LICENSE +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/README.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/SECURITY.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/deviatdd.png +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/mise.toml +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat/001-deviate-cli-python/008-meso-macro-automated-orchestration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat/adhoc/006-context-cli-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-001-cli-initialization-governance-provisioning-pr-11.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-003-meso-layer-specification-task-decomposition.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-004-micro-layer-tdd-sandbox-execution.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-005-cli-architecture-realignment-skill-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-007-macro-meso-parity-backward-compatibility.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-001-foundation-cli-infrastructure.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-003-fast-path-commands.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-004-governance-inspection.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-adhoc-001-streaming-pipeline-monitor.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-adhoc-008-ast-phase-prioritization.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat_002-deviatdd-gap-analysis_001-foundation-cli-infrastructure.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/scripts/benchmark_lmstudio.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/scripts/verify_install.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t001.json +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t002.json +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t004.json +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/002-macro-layer-state-ledger-management/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/002-macro-layer-state-ledger-management/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/003-meso-layer-specification-task-decomposition/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/003-meso-layer-specification-task-decomposition/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/005-cli-architecture-realignment-skill-integration/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/005-cli-architecture-realignment-skill-integration/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/007-macro-meso-parity-backward-compatibility/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/007-macro-meso-parity-backward-compatibility/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/data-model.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/design.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/001-cli-initialization-governance-provisioning.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/002-macro-layer-state-ledger-management.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/003-meso-layer-specification-task-decomposition.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/004-micro-layer-tdd-sandbox-execution.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/005-cli-architecture-realignment-skill-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/006-state-persistence-concurrency-safety.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/007-macro-meso-parity-backward-compatibility.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/008-meso-macro-automated-orchestration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/data-model.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/design.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/001-foundation-cli-infrastructure.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/002-context-pipeline.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/003-fast-path-commands.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/004-governance-inspection.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/005-micro-layer-integrity.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/plan-tdd-integration-gap.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/003-graphite-cli-integration/explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/004-per-task-security-profile/issues/001-security-profile-and-judge-checks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/data-model.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/design.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/001-verification-mode-metadata.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/002-task-acceptance-traceability.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/003-micro-phase-gates-red-green.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/004-refactor-regression-gate.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/005-prompt-spec-alignment.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/architecture.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/domain-model.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/flows-product.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/flows-streaming.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/index.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-current-system.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-gap-register.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-git-state-model.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-rewrite.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-rust-tui-requirements.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/release-next.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/spec.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/tasks.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/015-narrow-product-flow-scope/plan.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/015-narrow-product-flow-scope/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/001-streaming-pipeline-monitor.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/002-aider-agent-backend-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/003-meso-layer-restructuring.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/004-deviate-review-skill.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/005-per-phase-model-configuration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/006-context-cli-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/007-graphite-cli.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/008-ast-phase-prioritization.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/009-pi-agent-backend-integration.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/010-deviate-setup-product-layer.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/012-rpc-streaming-tui-renderer.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/013-flow-ledger-canonical-source-of-truth.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/014-cwe-mapping-security-findings.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/015-narrow-product-flow-scope.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/constitution.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/ast-tree-sitter.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/flow-ledger.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/graphite-cli.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/pi-agent-backend.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/product-layer.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/rpc-streaming-tui.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/rpc-streaming.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/security-hardening-cwe.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/implementation-gap.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/issues.jsonl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_common.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_html.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_safe_commands.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/adhoc.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/constitution.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/feature.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/flow_commands.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/init.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/inspect.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/macro.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/review.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/walkthrough.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/_shared.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/agent.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/cache_discipline.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/commands.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/commit.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/complexity.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/constitution.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/contract.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/convention.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/epic.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/issues.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/prd.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/profile.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/repo.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/run_logger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/tasks_ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/worktree.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/architecture.html.tmpl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/domain-model.html.tmpl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/flows.html.tmpl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/plan.html.tmpl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/prd.html.tmpl +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/main.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/assembly.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/execute.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/green.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/judge.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/red.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/refactor.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/research.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/shard.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/specify.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-adhoc.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-architecture.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-constitution.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-e2e.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-execute.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-explore.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-flows.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-green.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-hotfix.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-html.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-init.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-judge.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-merge.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-pr.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-prd.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-prune.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-red.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-refactor.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-release.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-research.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-review.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-shard.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-tasks.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-triage.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-walkthrough.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/constitution_seed.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/core.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/lifecycle-auto.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/lifecycle-manual.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/macro-shared.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/meso-shared.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/micro-shared.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/product-shared.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/style-ste.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/extras/deviate-pr-graphite-routing.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/agents_seed.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/claudemd_seed.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/graphite_seed.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/libref_seed.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/skills/deviatdd/SKILL.md +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/config.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/monitor.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/pipeline.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/render.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/visual/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/conftest.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/test_agent.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/test_smart_stall.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/e2e/test_macro_workflow.bats +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_adhoc.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_common.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_constitution.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_feature.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_flows_sync.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_help.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_html.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_init.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_inspect.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_macro_contracts.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_main_entrypoint.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_merge.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_meso.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_micro.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_real_descendant_kill.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_review.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_safe_commands.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_test_command_resolution.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_timeout_safe_command.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_top_level_run.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_agent.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_cache_discipline.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_commands.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_commit.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_complexity.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_constitution.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_contract.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_convention.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_epic.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_flow_confirmation.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_issues.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_prd.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_profile.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_repo.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_run_logger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_tasks_ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_worktree.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_init.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/conftest.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_command_installation.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_init_export_cycle.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_full_cycle.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_layer.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_orchestration.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_layer.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_orchestration.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_task_ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_parity.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_skill_installation.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_explore.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_macro_model_routing.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_macro_orchestration.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_prd.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_research.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_shard.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_auto_prompt_templates.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_model_routing.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_orchestration.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_plan_structure_injection.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_prompt_assembly.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_specify.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_tasks.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/conftest.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_commit_failure.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_e2e.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_execute.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_green.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_hotfix.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_judge.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_orchestration.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_output_filter.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_red.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_refactor.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_rollback_safety.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_task_label.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_config.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_ledger.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_security_profile.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_session.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/__init__.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_monitor.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_pipeline.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_render.py +0 -0
- {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_visual_demo/test_tsk_001_01.py +0 -0
|
@@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
36
36
|
- **`/deviate-merge` no longer auto-pushes after the squash-merge commit; the push gate runs inline and the network push is opt-in.** The slash command previously ran `git push` as its final step. As of v2.4.0 the squash-merge commit lands on `main`, then a new `push_gate` step inlines the body of `.githooks/pre-push` (lint + format-check + testmon-driven affected tests with the warm-cache / full-suite fallback — bash 3.2 portable, `GIT_DIR` reset + trap preserved) so the safety net fires even though no `git push` happens yet. After the gate passes the skill asks the operator whether to `git push` (which fires the real `pre-push` hook and re-runs the same gate) or stop and push manually. The squash-merge commit and the ledger transition inside it are durable on `main` regardless of the push outcome — only the network push is deferred. New failure states: `Push_Gate_Failed` (inline gate non-zero), `Push_Failed` (`git push` non-zero, raw stderr surfaced), `Push_Deferred` (user chose "Stop — I'll push manually"). Inline gate body and `.githooks/pre-push` body must stay byte-equivalent; divergence is pinned by `tests/test_meso/test_auto_prompt_templates.py::TestMergePromptPushGate::test_hook_and_prompt_agree_on_gate_body` (which compares non-blank non-comment lines in both bodies and fails on drift in either direction) plus 3 supporting assertions on the upstream-first logic, the testmon fallback, and the prompt structure. Prompt: `src/deviate/prompts/commands/deviate-merge.md` (v2.3.0 → v2.4.0). Spec mirrors updated: `specs/DeviaTDD-architecture.md` (Merge bullet, new `**Push gate + opt-in push (v2.4.0)**` sub-bullet) and `specs/DeviaTDD-api.md` (new `**/deviate-merge push behavior (v2.4.0)**` entry under the `deviate merge` reference).
|
|
37
37
|
|
|
38
38
|
### Fixed
|
|
39
|
+
- **Language-agnostic test discovery: the RED gate no longer globs Python-only `tests/**/test_*.py`.** `_find_test_files` returned `[]` for non-Python projects, so `_run_red_phase` rejected a correctly authored Elixir test (`test/integration/tailwind_pipeline_test.exs`) with "RED phase produced no test files" before any command ran — blocking every task on an Elixir/Phoenix repo. The RED gate now trusts the resolved test command (`_test_command_candidates`: task `verification` → constitution `test_command` → `mise run test` → manifest table `mix.exs`→`mix test` / `Cargo.toml`→`cargo test` / `go.mod`→`go test ./...` / `package.json`→`npm test` / `pyproject.toml`→`pytest`), and a project with no resolvable command (returncode 127) routes to the same JUDGE adjudication as pytest's exit-5 no-tests case instead of dying. `deviate red post`, `deviate green post`, and `deviate refactor post` switched their `TEST_NOT_FOUND`/`NO_TESTS_TO_CHECK` gates from the Python glob to the same resolved-command check. `_find_test_files` remains only as the Python fallback signal. Pinned by `tests/test_micro/test_run.py::TestRunCommand::test_run_elixir_repo_red_accepts_exs_test` (fails on the old gate, passes after).
|
|
39
40
|
- **Manifest schema recovery now drops out-of-enum fields instead of aborting the phase (GH-52, GH-55).** `AgentBackend.parse_output` re-constructed a `HandoverManifest` with the offending value intact after a `ValidationError`, so an out-of-enum `failure_kind` (RED) or `next_action` (JUDGE COMPLIANCE_PASS) re-raised the identical error unguarded and the phase died with a misleading `agent returned no manifest`. Recovery now deletes every top-level field that failed validation (the model default `None` applies); the JUDGE runner's existing `_coerce_judge_action` then routes an unknown `next_action` through the legacy pass path. Pinned by `test_recovery_drops_invalid_failure_kind` / `test_recovery_drops_invalid_next_action` in `tests/test_core/test_agent.py`.
|
|
40
41
|
- **`deviate micro run` dedupes latest task records by `(issue_id, task_id)` so a same-numbered task in another issue no longer shadows the active issue's ledger.** `_collect_latest_task_records` previously keyed the latest record by task ID alone. Since every issue reuses the same `TSK-NNN-NN` numbering, a later-sorting ledger (e.g. `specs/adhoc/*` after `specs/005-*`) shadowed the active issue's records — bare `deviate micro run` reported `no ledger entry` against a committed ledger and explicit `<tid>` dispatch hit the wrong issue's task. Latest records are now keyed per issue, and `_find_task_record` prefers the record owned by the current worktree's branch issue. Pinned by `test_find_task_record_prefers_branch_issue` in `tests/test_micro/test_e2e.py`.
|
|
41
42
|
- **`deviate micro run` re-keys a stale worktree session issue to the branch's issue (GH-54).** A freshly claimed worktree could carry the previous issue's id in `.deviate/session.json` while its branch pointed at the new issue; `_resolve_task_context` trusted the stale id, found no tasks board for it in the checkout, and emitted `NO_PENDING_TASKS` exit 0 for a queue that existed. Resolution now prefers the branch-derived issue whenever the session issue differs from it and has no tasks board in the checkout. Pinned by `test_stale_session_issue_rekeys_to_branch_issue` in `tests/test_cli/test_micro.py`.
|
|
@@ -56,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
56
57
|
- **`deviate shard post` now reliably commits the per-epic `issues/` directory alongside `specs/issues.jsonl`.** When the manifest omits `epic_slug` (or only passes it via `--epic`), the post-script now derives the epic from the first issue's `source_file` and uses a recursive `**/*.md` glob, so the slash command `/deviate-shard` (and its `shard`/`/shard` aliases) commits every shard issue file even if the LLM forgot to write `epic_slug` into the manifest. Missing `issues/` directories and unresolvable epics now emit a visible `SHARD_WARNING` instead of silently producing a ledger-only commit. Implementation lives in `shard_post` (`src/deviate/cli/macro.py`); the pre-script behavior is unchanged. Pinned by `tests/test_integration/test_macro_layer.py::TestShardPost::test_shard_post_commits_issues_directory`.
|
|
57
58
|
- **`mise publish` no longer fails because a stray `.venv-tmp` directory leaks into the source distribution.** Hatchling's hard-coded sdist exclusion list covers `.venv` but not every venv variant, so a `.venv-tmp` left on disk (with its absolute `bin/python` symlink to `/usr/local/bin/python3.13`) was packaged into `dist/deviatdd-*.tar.gz` and `uv build` aborted with `Invalid tar file ... external symlinks are not allowed`. `pyproject.toml` now adds an explicit `[tool.hatch.build.targets.sdist]` exclude of `/.venv-tmp/`, making the build deterministic regardless of hatchling's built-in directory list. The wheel target already scoped packaging to `src/deviate`.
|
|
58
59
|
- **JUDGE feedback commit now passes `--no-verify`.** `_commit_judge_feedback_and_advance` (`src/deviate/cli/micro.py`) issues the docs-only `docs(<tid>): add judge feedback for retry` commit with `--no-verify` so a repository pre-commit hook running the full test suite cannot deadlock the micro loop against a still-broken next-task deliverable. Mirrors the `no_verify=True` pattern already enforced at the RED / GREEN / REFACTOR micro-loop commit sites. Pinned by `tests/test_cli/test_micro.py::TestJudgeTrainRollback::test_commit_judge_feedback_and_advance_uses_no_verify`.
|
|
60
|
+
- **`deviate plan post` / `deviate meso tasks pre` / meso-run resume now auto-fill a missing `**Verification Mode**` line instead of rejecting the plan.** When a plan's acceptance contract fails *only* because scenarios lack the `**Verification Mode**:` line, `_validate_or_repair_plan` (`src/deviate/cli/meso.py`) injects the default `automated` value into each affected scenario body and persists the repaired `plan.md` with a `PLAN_MODE_REPAIR` banner on the console. An existing — even invalid or duplicated — mode literal is never touched, so `invalid Verification Mode` / `duplicate Verification Mode lines` still block with `PLAN_ACCEPTANCE_CONTRACT_INVALID` / `MESO_PLAN_INVALID`. The manual `/deviate-plan` prompt template (`src/deviate/prompts/commands/deviate-plan.md`) now also requires the mode line (per-scenario field 6, canonical example, forbidden patterns, and a pre-write self-check step), matching `src/deviate/prompts/auto/plan.md`. Pinned by `tests/test_core/test_validation.py::TestRepairMissingVerificationMode`, the rewritten `tests/test_meso/test_meso_resume.py::TestMesoIdempotentResume::test_modeless_contract_is_repaired_on_resume`, and `tests/test_cli/test_meso_contracts.py::TestMesoContracts::test_tasks_pre_repairs_missing_verification_mode`.
|
|
59
61
|
## [2.15.0] - 2026-07-29
|
|
60
62
|
|
|
61
63
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: deviatdd
|
|
3
|
-
Version: 2.20.
|
|
3
|
+
Version: 2.20.1
|
|
4
4
|
Summary: DeviaTDD CLI — agent orchestration framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/wernerbisschoff/deviatdd
|
|
6
6
|
Project-URL: Repository, https://github.com/wernerbisschoff/deviatdd
|
|
@@ -425,13 +425,13 @@ accepts `--json` (emit JSON contract to stdout) and `--quiet` (suppress output).
|
|
|
425
425
|
5. **Given / When / Then** — exactly three bold-labelled clauses in this order: `**Given**:`, `**When**:`, `**Then**:`. Each clause is a single imperative sentence and MUST NOT embed additional `**Given**` / `**When**` / `**Then**` markers. The `**Then**` clause MUST state a verifiable observable outcome.
|
|
426
426
|
* **Required sections in canonical order**: `## Plan Summary` → `## Product Layer Anchors` → `## Acceptance Contract` → `## Workstation Mapping` → `## Implementation Strategy` → `## Data Flow Analysis` → `## Risk Assessment` → `## Security Profile` → `## Integration Points` → `## Constitutional Alignment`.
|
|
427
427
|
* **Acceptance Coverage Invariant:** Every AO from the issue's `## Acceptance Outline` MUST appear as the Source Outline of at least one AC-PLAN scenario. Behavioural coverage that does not map cleanly to a single AO (e.g. an HMAC failure, an RLS isolation invariant, a defensive boundary) belongs under an existing AO's Error Category or Boundary Category. If no existing AO fits, the issue's outline is incomplete — halt with `INCOMPLETE_ISSUE_OUTLINE` and request that shard/adhoc regenerate the issue.
|
|
428
|
-
* **Forbidden patterns** (any one triggers `PLAN_ACCEPTANCE_CONTRACT_INVALID` from `deviate plan post`): Source Outline labelled `Edge Cases`, `Boundary`, `Constitutional §…`, `RLS`, `Tenant Isolation`, `Hardening`, `Security`, or any non-AO string; missing `**Source Outline**` / `**Upstream Traceability**` / `**Current-Code Evidence**` / any of `**Given**` / `**When**` / `**Then**`;
|
|
428
|
+
* **Forbidden patterns** (any one triggers `PLAN_ACCEPTANCE_CONTRACT_INVALID` from `deviate plan post`): Source Outline labelled `Edge Cases`, `Boundary`, `Constitutional §…`, `RLS`, `Tenant Isolation`, `Hardening`, `Security`, or any non-AO string; missing `**Source Outline**` / `**Upstream Traceability**` / `**Current-Code Evidence**` / any of `**Given**` / `**When**` / `**Then**`; a repeated or illegal `**Verification Mode**: <automated|manual|deferred>` literal (a scenario MUST carry exactly one legal mode line; an empty or non-alphabetic value is treated as missing); an issue AO not used by any AC-PLAN scenario; duplicate or non-sequential `AC-PLAN-NNN` identifiers; wrapping the plan body in any XML tag / code fence / preamble. A *missing* mode line is not a stopping error: the meso gates auto-fill the default `automated` value into the scenario body (see `deviate plan post`). The validator lives at `src/deviate/core/validation.py::validate_acceptance_contract`; the repair helper is `repair_missing_verification_mode`.
|
|
429
429
|
* **Input Parameters:** `--issue`, `--force`, `--dry-run`; common `--json` / `--quiet` wrappers apply.
|
|
430
430
|
* **Session:** force-transitions to PLAN with `active_issue_id` set.
|
|
431
431
|
|
|
432
432
|
#### `deviate plan post [--force] [--issue-id]`
|
|
433
433
|
|
|
434
|
-
Validates plan.md exists, is non-empty, and contains a valid Acceptance Contract; auto-renders HTML when changed, commits with convention-aware messaging, and transitions to TASKS. Missing/malformed contracts fail as `PLAN_ACCEPTANCE_CONTRACT_MISSING` / invalid contract diagnostics.
|
|
434
|
+
Validates plan.md exists, is non-empty, and contains a valid Acceptance Contract; auto-renders HTML when changed, commits with convention-aware messaging, and transitions to TASKS. Missing/malformed contracts fail as `PLAN_ACCEPTANCE_CONTRACT_MISSING` / invalid contract diagnostics. When the contract fails *only* because scenarios lack the `**Verification Mode**:` line, the gate auto-fills `automated` into each affected scenario body, persists the repaired `plan.md` (`PLAN_MODE_REPAIR` banner), and proceeds; an existing invalid or duplicated mode literal still blocks with `PLAN_ACCEPTANCE_CONTRACT_INVALID`.
|
|
435
435
|
|
|
436
436
|
#### `deviate tasks pre [--force] [--dry-run]`
|
|
437
437
|
|
|
@@ -439,7 +439,7 @@ Validates plan.md exists, is non-empty, and contains a valid Acceptance Contract
|
|
|
439
439
|
* **Two-source input:** `spec_path` supplies macro intent; `plan_path` supplies strategy and authoritative scenarios. Plan wins over legacy issue/spec Gherkin.
|
|
440
440
|
* **Contract:** detects worktree/branch, resolves constitution commands, and emits `spec_path`, `plan_path`, `tasks_target`, worktree metadata, status, and flags. The issue is resolved from `session.active_issue_id`, falling back to a branch-derived lookup via the `feat/{epic}/{issue}` regex against `specs/issues.jsonl`.
|
|
441
441
|
* **Plan digest:** TASKS receives a bounded 16 KiB UTF-8 `plan_digest` plus `plan_path`; truncation inserts `PLAN_DIGEST_TRUNCATED`, requiring a full read.
|
|
442
|
-
* **Validation:** reports PLAN_NOT_FOUND, PLAN_ACCEPTANCE_CONTRACT_MISSING, or PLAN_ACCEPTANCE_CONTRACT_INVALID; no Gherkin fallback.
|
|
442
|
+
* **Validation:** reports PLAN_NOT_FOUND, PLAN_ACCEPTANCE_CONTRACT_MISSING, or PLAN_ACCEPTANCE_CONTRACT_INVALID; no Gherkin fallback. A contract that fails only for a missing `**Verification Mode**:` line is auto-repaired in place (default `automated`) before the status is computed.
|
|
443
443
|
* **Common Flags:** `--json`, `--quiet`.
|
|
444
444
|
|
|
445
445
|
#### `deviate tasks post [--force] [--issue-id]`
|
|
@@ -538,17 +538,21 @@ accepts `--json` and `--quiet`. `pre` emits a JSON contract describing the envir
|
|
|
538
538
|
#### `deviate red post`
|
|
539
539
|
|
|
540
540
|
* **Source:** `src/deviate/cli/micro.py`
|
|
541
|
-
* **Description:** Runs
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
541
|
+
* **Description:** Runs the project's resolved test command (language-agnostic: `mix test`,
|
|
542
|
+
`cargo test`, `npm test`, `go test ./...`, or `pytest` chosen via the `_test_command_candidates`
|
|
543
|
+
resolution order — task `verification`, constitution `test_command`, `mise run test`, manifest
|
|
544
|
+
table, Python fallback). Validates the test fails explicitly (ASSERTION_FAILURE, not PASS or
|
|
545
|
+
SYNTAX_ERROR), runs the test command, and reports whether the test failed as expected.
|
|
546
|
+
`deviate micro run`'s internal RED phase (`_run_red_phase`) applies the same contract: when the
|
|
547
|
+
test command exits 0 (all tests passed), collects no tests (pytest exit 5), or resolves to no
|
|
548
|
+
command at all (returncode 127), it does NOT die — it routes the decision to JUDGE
|
|
549
|
+
(``failure_kind: no_failing_test``), which either rules the behavior already exists (task
|
|
550
|
+
COMPLETED, the uncommitted passing test discarded) or rules the test wrong (``revert_before``,
|
|
551
|
+
RED re-authors a genuinely failing test). The RED gate does not require a Python
|
|
552
|
+
``tests/**/test_*.py`` glob — test discovery follows the project's own convention (e.g.
|
|
553
|
+
``test/**/*_test.exs`` for Elixir). On a genuine failing test it appends the RED status
|
|
554
|
+
transition to the task ledger, forces session to RED, and commits with
|
|
555
|
+
`test({scope}): RED phase - failing test`.
|
|
552
556
|
Commit messages are convention-aware: when the project declares an emoji convention in
|
|
553
557
|
``CONTRIBUTING.md`` / ``.commit-convention.md``, the appropriate gitmoji is prepended
|
|
554
558
|
automatically. RED phase `test:` commits are prefixed with 🚨 to flag the failing test (see
|
|
@@ -564,8 +568,9 @@ accepts `--json` and `--quiet`. `pre` emits a JSON contract describing the envir
|
|
|
564
568
|
#### `deviate green post`
|
|
565
569
|
|
|
566
570
|
* **Source:** `src/deviate/cli/micro.py`
|
|
567
|
-
* **Description:** Verifies a RED transition exists for the active issue. Runs
|
|
568
|
-
|
|
571
|
+
* **Description:** Verifies a RED transition exists for the active issue. Runs the project's
|
|
572
|
+
resolved test command (language-agnostic, e.g. `mix test` / `cargo test` / `pytest`), requires
|
|
573
|
+
returncode 0. Appends GREEN transition to ledger, forces session to GREEN,
|
|
569
574
|
commits with `feat({scope}): GREEN phase - implementation passes tests`.
|
|
570
575
|
|
|
571
576
|
#### `deviate judge pre`
|
|
@@ -584,9 +589,9 @@ accepts `--json` and `--quiet`. `pre` emits a JSON contract describing the envir
|
|
|
584
589
|
|
|
585
590
|
* **Source:** `src/deviate/cli/micro.py`
|
|
586
591
|
* **Description:** Verifies a GREEN transition exists. Appends REFACTOR transition, runs
|
|
587
|
-
AST-based return type mismatch check, runs
|
|
588
|
-
On regression, restores via `git restore .` and halts.
|
|
589
|
-
`refactor({scope}): REFACTOR phase - code cleanup`.
|
|
592
|
+
the AST-based return type mismatch check (Python only), runs the resolved test command
|
|
593
|
+
before/after to detect regression. On regression, restores via `git restore .` and halts.
|
|
594
|
+
Commits with `refactor({scope}): REFACTOR phase - code cleanup`.
|
|
590
595
|
|
|
591
596
|
#### `deviate execute pre [--task <id>]`
|
|
592
597
|
|
|
@@ -944,7 +949,7 @@ accepts `--json` and `--quiet`. `pre` emits a JSON contract describing the envir
|
|
|
944
949
|
* Valid `plan.md` and no `tasks.md`: emit `MESO_RESUME`, skip Plan, and run Tasks.
|
|
945
950
|
* Valid `plan.md` and non-empty `tasks.md`: emit `MESO_ALREADY_COMPLETE`, skip both agents,
|
|
946
951
|
preserve ledger progress, and return the current worktree path.
|
|
947
|
-
* Existing invalid `plan.md
|
|
952
|
+
* Existing `plan.md` valid only after repair: when the contract fails solely for a missing `**Verification Mode**:` line, it is auto-filled (`PLAN_MODE_REPAIR`) and treated as valid; a genuinely invalid `plan.md` (missing clauses, bad AO traceability, illegal/duplicated mode) emits `MESO_PLAN_INVALID` and stops without overwrite.
|
|
948
953
|
* Existing empty `tasks.md`: emit `MESO_TASKS_INVALID` and stop without overwrite.
|
|
949
954
|
A fresh claim does not use inherited main-branch artifacts as resume evidence. It runs Plan
|
|
950
955
|
and Tasks in the new worktree.
|
|
@@ -274,7 +274,7 @@ to invoke, but model selection is delegated to the calling environment.
|
|
|
274
274
|
* **Layer discipline:** GREEN's only invariant is "make the RED test pass via the library/API surface declared in scope." It does NOT make scope, spec-drift, or HITL-routing judgments — those belong to JUDGE. When a RED test cannot be satisfied within GREEN's mechanical scope, GREEN emits `status: FAILURE` with a concrete `rationale:` naming the test path and why; `status: "ERROR"` is reserved strictly for tool/orchestration failure. The runner's `_is_hitl_escalation` is a narrow defensive fallback that ONLY promotes structured `contract_drift` / `escalates_to` / `hitl_options` dict keys to `HITL_PENDING` — loose-string `error_kind` discriminators and free-form scope-conflict text do NOT trigger HITL escalation.
|
|
275
275
|
* **Mechanical Failure → JUDGE Routing:** When GREEN emits `status: FAILURE` with a concrete `rationale:` (the mechanical scope-boundary case above), the runner routes control to JUDGE instead of raising `PhaseFailedError`. `_run_green_phase` sets `session.train_feedback = rationale` + `session.failure_kind = "mechanical"` and returns the session; `_run_judge_phase` injects a `<failure_kind>mechanical</failure_kind>` discriminator block into the JUDGE prompt that instructs the agent to emit `verdict: COMPLIANCE_PASS` + `next_action: proceed_to_refactor_no_diff` (when the slice is intrinsically RED-only and REFACTOR's no-op commit + COMPLETED transition is the right termination) OR `verdict: COMPLIANCE_VIOLATION` + one of three `next_action` values (`revert_before` / `revert_to_red` / `skip_refactor`) instead of attempting to satisfy the test itself. This closes the loop where mechanical FAILURE (e.g. slice-scope conflict, CLI-surface-out-of-sco…
|
|
276
276
|
* **Test-Defect Failure → JUDGE Routing:** A second routable failure class, parallel to mechanical but pre-decided. When GREEN observes that the RED test itself is wrong (it asserts behavior the spec does not require, exercises the wrong abstraction, or encodes an assumption that contradicts spec/data-model), GREEN emits `status: FAILURE` with a concrete `rationale:` citing the FR/AC the test contradicts, plus `failure_kind: test_defect` on the manifest (`HandoverManifest.failure_kind: Literal["mechanical", "test_defect", "already_satisfied"] | None` in `src/deviate/core/agent.py` — session mirrors the discriminator as `SessionState.failure_kind: Literal["", "mechanical", "test_defect", "no_failing_test"]` in `src/deviate/state/config.py`). `_run_green_phase` reads the manifest's discriminator, sets `session.failure_kind = "test_defect"`, and routes to JUDGE. `_run_judge_phase` injects a `<failure_kind>test_defect</failure_kind>` discriminator block that pre-decides the routing — `verdict: COMPLIANCE_VIOLATION` + `next_action: revert_before` (re-run RED with the GREEN rationale as feedback) — because test defect has only one sensible outcome: the test itself must be re-authored. The discriminator intentionally narrows the JUDGE routing vocabulary compared to mechanical (`revert_to_red` / `skip_refactor` / `proceed_to_refactor_no_diff` are NOT options in the test_defect block). Default `manifest.failure_kind = None` falls through to `"mechanical"` in the runner to preserve prior behavior.
|
|
277
|
-
* **RED No-Failing-Test → JUDGE Adjudication (RED → JUDGE direct route):** When RED completes but its test command exits 0 (all tests passed)
|
|
277
|
+
* **RED No-Failing-Test → JUDGE Adjudication (RED → JUDGE direct route):** When RED completes but its test command exits 0 (all tests passed), collects no tests (pytest exit 5), or resolves to no command at all (returncode 127 from `_run_test_cmd`), `_run_red_phase` does NOT raise a raw `PhaseFailedError` and does NOT let GREEN run against a vacuous test. It calls `_adjudicate_red_no_failing_test` (`src/deviate/cli/micro.py`), which sets `session.failure_kind = "no_failing_test"`, injects a `<failure_kind>no_failing_test</failure_kind>` discriminator block into the JUDGE prompt, and dispatches `_run_judge_phase(...)`. The judge diff spans the uncommitted RED test (the `red_baseline` parameter makes `_run_judge_phase` skip the `RED→HEAD` committed diff and surface the agent's uncommitted test through the dirty-parts scan) so JUDGE reviews what the agent actually wrote. JUDGE decides between two outcomes: `verdict: COMPLIANCE_PASS` + `next_action: skip_refactor` (or a bare PASS verdict) when the required behavior already exists — the runner discards the uncommitted passing test via `_restore_worktree_to_baseline` and marks the task COMPLETED without landing it; or `verdict: COMPLIANCE_VIOLATION` + `next_action: revert_before` (forced by the `_coerce_judge_action` runner-level override for `failure_kind` `no_failing_test`/`test_defect`) when the test is wrong — the runner resets to the RED baseline and re-dispatches RED so a fresh genuinely-failing test is authored. `--no-judge` makes the no-failing-test outcome a hard failure (adjudication disabled). Test discovery is language-agnostic: the RED gate no longer globs Python `tests/**/test_*.py` (`_find_test_files`); the project's own convention is honored through the resolved test command (e.g. `mix test` collecting `test/**/*_test.exs` for Elixir/Phoenix), so a correctly authored non-Python test is neither rejected up front nor silently conflated with "no test framework" — a project with no resolvable test command routes to the same JUDGE adjudication instead of failing. This closes the prior stall where an empty `_find_test_files` let RED silently commit a vacuous 'failing test' and GREEN die in `TRAIN_EXHAUSTED`. The RED agent may steer the adjudication by declaring `failure_kind: already_satisfied` (behavior exists) or `failure_kind: test_defect` (test wrong) with a `rationale` on its handover manifest.
|
|
278
278
|
* **JUDGE / TRAIN (The Compliance Gate) — with Green → Judge → Green loop:**
|
|
279
279
|
* **The Judge:** The CLI evaluates the committed RED-parent-to-HEAD diff against `spec.md` for invariant/security violations. If GREEN tests failed before the implementation commit, `_run_judge_phase` also appends staged/unstaged `git diff HEAD` output and per-file `git diff --no-index /dev/null <path>` output for untracked files, so JUDGE assesses the retained implementation rather than a false RED-only snapshot. This judge operates in a clean, zero-shared-history session to break recursive subjectivity. A `deviate-judge` skill (loaded from `_SKILL_NAMES["JUDGE"]`) guides the agent through supplementary compliance evaluation.
|
|
280
280
|
* **The Train (Green → Judge → Green loop):** On `COMPLIANCE_VIOLATION` or test failure, the CLI safely resets without destroying task progress. The JUDGE phase honors `HandoverManifest.next_action` (see [specs/DeviaTDD-api.md](./DeviaTDD-api.md) for the routing table). The five routes:
|
|
@@ -621,17 +621,26 @@ framework's remaining HITL gates are Gate 1 and Gate 3 (Gate 2 was removed).
|
|
|
621
621
|
|
|
622
622
|
## 7. Multi-Framework Testing Abstraction
|
|
623
623
|
|
|
624
|
-
DeviaTDD's current implementation (`src/deviate/cli/micro.py`)
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
`
|
|
624
|
+
DeviaTDD's current implementation (`src/deviate/cli/micro.py`) runs tests through the
|
|
625
|
+
language-agnostic `_run_test_cmd()` → `_test_command_candidates()` resolution: the task's
|
|
626
|
+
`verification` value, the constitution `test_command`, a `mise run test` task, or the
|
|
627
|
+
`_MANIFEST_TEST_COMMANDS` manifest table (`mix.exs` → `mix test`, `Cargo.toml` → `cargo test`,
|
|
628
|
+
`go.mod` → `go test ./...`, `package.json` → `npm test`, `pyproject.toml` → `pytest`), with a
|
|
629
|
+
Python-only fallback (`_find_test_files` globbing `tests/**/test_*.py` → `pytest`) used only
|
|
630
|
+
when no other framework is detected. Test discovery follows each project's own convention
|
|
631
|
+
(e.g. `test/**/*_test.exs` for Elixir) — the RED gate does not require a Python-style
|
|
632
|
+
`tests/**/test_*.py` file. Outcome classification is shared: a red/green phase is decided by
|
|
633
|
+
the command's exit code plus `_is_no_tests_collected` (pytest exit 5) and `_is_no_test_command`
|
|
634
|
+
(returncode 127) sentinels. `_run_pytest()` remains the Python-specific subprocess runner
|
|
635
|
+
(`tests/**/test_*.py` + `python -m pytest -v`), used where a Python command was resolved.
|
|
629
636
|
|
|
630
637
|
| Testing Framework | CLI Invocation Strategy | Success Validation | Error Parse Pattern | Scope Protection |
|
|
631
638
|
| :--- | :--- | :--- | :--- | :--- |
|
|
632
|
-
| **Python / pytest** | `python -m pytest tests/ -v` | `returncode == 0` | `_classify_pytest_outcome()`: checks `SYNTAX_ERROR` markers (SyntaxError, IndentationError, etc.), `ASSERTION_FAILURE`, `PASS`, `UNKNOWN_FAILURE`. | Reverts unauthorized test edits before running suite. |
|
|
633
|
-
| **
|
|
634
|
-
| **
|
|
639
|
+
| **Python / pytest** | `python -m pytest tests/ -v` via `_run_pytest()` | `returncode == 0` | `_classify_pytest_outcome()`: checks `SYNTAX_ERROR` markers (SyntaxError, IndentationError, etc.), `ASSERTION_FAILURE`, `PASS`, `UNKNOWN_FAILURE`. | Reverts unauthorized test edits before running suite. |
|
|
640
|
+
| **Elixir / ExUnit** | `mix test` (via `_MANIFEST_TEST_COMMANDS`) | `returncode == 0` | exit code + `_is_no_tests_collected` / `_is_no_test_command` | Same. |
|
|
641
|
+
| **Rust / cargo** | `cargo test` (via `_MANIFEST_TEST_COMMANDS`) | `returncode == 0` | exit code + `_is_no_tests_collected` / `_is_no_test_command` | Same. |
|
|
642
|
+
| **Go / testing** | `go test ./...` (via `_MANIFEST_TEST_COMMANDS`) | `returncode == 0` | exit code + `_is_no_tests_collected` / `_is_no_test_command` | Same. |
|
|
643
|
+
| **Node.js / Jest** | `npm test` (via `_MANIFEST_TEST_COMMANDS`) | `returncode == 0` | exit code + `_is_no_tests_collected` / `_is_no_test_command` | Same. |
|
|
635
644
|
|
|
636
645
|
---
|
|
637
646
|
|
|
@@ -903,7 +912,9 @@ there is no `discover_skills()` abstraction.
|
|
|
903
912
|
**Scope:** Unified Meso and Micro orchestration. The skill first invokes
|
|
904
913
|
`deviate meso run`. In a linked feature worktree, Meso validates existing
|
|
905
914
|
`plan.md` and `tasks.md`, skips completed phases, resumes at Tasks when only
|
|
906
|
-
Plan is ready,
|
|
915
|
+
Plan is ready, auto-repairs a plan whose acceptance scenarios lack the
|
|
916
|
+
`**Verification Mode**:` line (default `automated`, `PLAN_MODE_REPAIR`), and
|
|
917
|
+
stops on genuinely invalid artifacts without overwrite. After Meso
|
|
907
918
|
succeeds, the skill invokes bare `deviate micro run` one task at a time.
|
|
908
919
|
The existing failure triage and clean-slate safety flow remains. **v1.1.0 added a
|
|
909
920
|
`## Troubleshooting failed runs` section** documenting the two
|
|
@@ -35,7 +35,10 @@ from deviate.core.convention import commit_scope, format_commit_message
|
|
|
35
35
|
from deviate.core.constitution import extract_commands
|
|
36
36
|
from deviate.core.issues import claim_issue
|
|
37
37
|
from deviate.core.repo import gather_git_state
|
|
38
|
-
from deviate.core.validation import
|
|
38
|
+
from deviate.core.validation import (
|
|
39
|
+
repair_missing_verification_mode,
|
|
40
|
+
validate_acceptance_contract,
|
|
41
|
+
)
|
|
39
42
|
from deviate.core.worktree import (
|
|
40
43
|
branch_exists_on_remote,
|
|
41
44
|
create_worktree,
|
|
@@ -815,6 +818,30 @@ def _plan_pre(
|
|
|
815
818
|
print(json.dumps(contract, indent=2))
|
|
816
819
|
|
|
817
820
|
|
|
821
|
+
def _validate_or_repair_plan(content: str) -> tuple[list[str], str]:
|
|
822
|
+
"""Validate a plan contract; auto-fill a missing Verification Mode.
|
|
823
|
+
|
|
824
|
+
When the contract fails *only* because scenarios lack a ``**Verification
|
|
825
|
+
Mode**:`` line, inject the default ``automated`` value and return the
|
|
826
|
+
repaired body with empty errors. Any other failure (invalid or duplicated
|
|
827
|
+
mode, missing clauses, bad AO traceability) is returned unchanged so the
|
|
828
|
+
caller rejects it.
|
|
829
|
+
"""
|
|
830
|
+
errors = validate_acceptance_contract(content)
|
|
831
|
+
if not errors:
|
|
832
|
+
return [], content
|
|
833
|
+
if not all(e.endswith("missing Verification Mode") for e in errors):
|
|
834
|
+
return errors, content
|
|
835
|
+
repaired, count = repair_missing_verification_mode(content)
|
|
836
|
+
if count == 0:
|
|
837
|
+
return errors, content
|
|
838
|
+
console.print(
|
|
839
|
+
f"[yellow]PLAN_MODE_REPAIR[/] auto-filled {count} missing "
|
|
840
|
+
"**Verification Mode** line(s) as `automated`"
|
|
841
|
+
)
|
|
842
|
+
return validate_acceptance_contract(repaired), repaired
|
|
843
|
+
|
|
844
|
+
|
|
818
845
|
def _plan_post(force: bool = False, issue_id: str | None = None) -> None:
|
|
819
846
|
"""Validate plan.md, commit it, and advance session to TASKS."""
|
|
820
847
|
session, session_path = _load_session_accept("PLAN", force=force)
|
|
@@ -841,7 +868,7 @@ def _plan_post(force: bool = False, issue_id: str | None = None) -> None:
|
|
|
841
868
|
if not content and not force:
|
|
842
869
|
console.print("[red]PLAN_EMPTY[/] plan.md is empty")
|
|
843
870
|
raise typer.Exit(code=1)
|
|
844
|
-
acceptance_errors =
|
|
871
|
+
acceptance_errors, plan_content = _validate_or_repair_plan(content)
|
|
845
872
|
if acceptance_errors:
|
|
846
873
|
status = (
|
|
847
874
|
"PLAN_ACCEPTANCE_CONTRACT_MISSING"
|
|
@@ -850,6 +877,8 @@ def _plan_post(force: bool = False, issue_id: str | None = None) -> None:
|
|
|
850
877
|
)
|
|
851
878
|
console.print(f"[red]{status}[/] {'; '.join(acceptance_errors)}")
|
|
852
879
|
raise typer.Exit(code=1)
|
|
880
|
+
if plan_content != content:
|
|
881
|
+
plan_md.write_text(plan_content, encoding="utf-8")
|
|
853
882
|
|
|
854
883
|
epic_num = _extract_epic_num(bucket)
|
|
855
884
|
issue_num = _extract_issue_num(resolved_issue_id)
|
|
@@ -1001,9 +1030,10 @@ def _tasks_pre(force: bool = False, dry_run: bool = False) -> None:
|
|
|
1001
1030
|
"(use --force to bypass)"
|
|
1002
1031
|
)
|
|
1003
1032
|
elif plan_path and Path(plan_path).exists():
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
)
|
|
1033
|
+
plan_text = Path(plan_path).read_text(encoding="utf-8")
|
|
1034
|
+
acceptance_errors, plan_text = _validate_or_repair_plan(plan_text)
|
|
1035
|
+
if plan_text != Path(plan_path).read_text(encoding="utf-8"):
|
|
1036
|
+
Path(plan_path).write_text(plan_text, encoding="utf-8")
|
|
1007
1037
|
if acceptance_errors:
|
|
1008
1038
|
missing = acceptance_errors == ["PLAN_ACCEPTANCE_CONTRACT_MISSING"]
|
|
1009
1039
|
status = (
|
|
@@ -1527,10 +1557,12 @@ def _discover_claimable_issue() -> str | None:
|
|
|
1527
1557
|
|
|
1528
1558
|
|
|
1529
1559
|
def _resolve_meso_resume_state(plan_path: Path, tasks_path: Path) -> str:
|
|
1530
|
-
"""Return PLAN, TASKS, or COMPLETE
|
|
1560
|
+
"""Return PLAN, TASKS, or COMPLETE; auto-repair a missing Verification Mode."""
|
|
1531
1561
|
if plan_path.exists():
|
|
1532
1562
|
plan_content = plan_path.read_text(encoding="utf-8")
|
|
1533
|
-
plan_errors =
|
|
1563
|
+
plan_errors, plan_content = _validate_or_repair_plan(plan_content)
|
|
1564
|
+
if plan_content != plan_path.read_text(encoding="utf-8"):
|
|
1565
|
+
plan_path.write_text(plan_content, encoding="utf-8")
|
|
1534
1566
|
if plan_errors:
|
|
1535
1567
|
console.print(
|
|
1536
1568
|
f"[red]MESO_PLAN_INVALID[/] {plan_path}: {'; '.join(plan_errors)}"
|
|
@@ -975,6 +975,21 @@ def _resolve_task_context(task_id: str | None, root: Path) -> tuple[dict, Path]
|
|
|
975
975
|
return pending[0]
|
|
976
976
|
|
|
977
977
|
|
|
978
|
+
def _start_phase_from_status(status: str) -> str | None:
|
|
979
|
+
"""Return the phase where a task's run resumes, from its latest JSONL status.
|
|
980
|
+
|
|
981
|
+
The tracked ``specs/**/tasks.jsonl`` is authoritative for
|
|
982
|
+
RED/GREEN/REFACTOR progress; ``session.json`` is an untracked cache that
|
|
983
|
+
a ``git reset`` does not roll back. ``None`` means start the full RED
|
|
984
|
+
cycle. Terminal statuses also fall through to ``None`` — their internal
|
|
985
|
+
``_phase_already_done`` guards skip re-work."""
|
|
986
|
+
return {
|
|
987
|
+
"RED": "GREEN",
|
|
988
|
+
"GREEN": "JUDGE",
|
|
989
|
+
"JUDGE": "JUDGE",
|
|
990
|
+
}.get(status)
|
|
991
|
+
|
|
992
|
+
|
|
978
993
|
def _resolve_latest_task(
|
|
979
994
|
root: Path, issue_id: str, status: str
|
|
980
995
|
) -> tuple[dict, Path] | None:
|
|
@@ -1135,6 +1150,18 @@ def _is_no_tests_collected(proc: subprocess.CompletedProcess) -> bool:
|
|
|
1135
1150
|
return "no tests" in output
|
|
1136
1151
|
|
|
1137
1152
|
|
|
1153
|
+
def _is_no_test_command(proc: subprocess.CompletedProcess) -> bool:
|
|
1154
|
+
"""Return whether the test command could not be resolved.
|
|
1155
|
+
|
|
1156
|
+
``_run_test_cmd`` returns ``returncode == 127`` with a fixed
|
|
1157
|
+
diagnostic when no command configures and no project is detected,
|
|
1158
|
+
so the RED phase can route that to the same JUDGE adjudication as
|
|
1159
|
+
a pytest ``exit 5`` (``_is_no_tests_collected``)."""
|
|
1160
|
+
if proc.returncode != 127:
|
|
1161
|
+
return False
|
|
1162
|
+
return "no test command" in f"{proc.stderr or ''}".lower()
|
|
1163
|
+
|
|
1164
|
+
|
|
1138
1165
|
def _run_red_phase(
|
|
1139
1166
|
task: dict,
|
|
1140
1167
|
ledger_path: Path,
|
|
@@ -1195,17 +1222,12 @@ def _run_red_phase(
|
|
|
1195
1222
|
issue_id = task.get("issue_id", "")
|
|
1196
1223
|
scope = _build_scope(issue_id, tid)
|
|
1197
1224
|
|
|
1198
|
-
test_files = _find_test_files(root)
|
|
1199
|
-
if not test_files:
|
|
1200
|
-
raise PhaseFailedError(
|
|
1201
|
-
f"RED phase produced no test files for {tid} — RED must author a "
|
|
1202
|
-
"failing test in a test file the project's test command can "
|
|
1203
|
-
"collect. If the task legitimately needs no code change, take it "
|
|
1204
|
-
"through /deviate-execute (DIRECT) or re-shard via /deviate-meso."
|
|
1205
|
-
)
|
|
1206
|
-
|
|
1207
1225
|
test_result = _run_test_cmd(root)
|
|
1208
|
-
if
|
|
1226
|
+
if (
|
|
1227
|
+
test_result.returncode == 0
|
|
1228
|
+
or _is_no_tests_collected(test_result)
|
|
1229
|
+
or _is_no_test_command(test_result)
|
|
1230
|
+
):
|
|
1209
1231
|
return _adjudicate_red_no_failing_test(
|
|
1210
1232
|
task,
|
|
1211
1233
|
ledger_path,
|
|
@@ -3529,15 +3551,15 @@ def _run_single(
|
|
|
3529
3551
|
c.print(f"[yellow]TASK_ALREADY_DONE[/] {task_id} is already completed")
|
|
3530
3552
|
raise typer.Exit(code=0)
|
|
3531
3553
|
|
|
3532
|
-
|
|
3554
|
+
# RED/GREEN/REFACTOR progress is read from the tracked tasks.jsonl, not
|
|
3555
|
+
# from session.json (a git reset reverts the JSONL but not the untracked
|
|
3556
|
+
# session cache). pending_judge_feedback is honored only when the JSONL
|
|
3557
|
+
# still records the implementation the judge rejected.
|
|
3558
|
+
if session.pending_judge_feedback and status in ("RED", "GREEN"):
|
|
3533
3559
|
session = _resume_pending_judge_feedback(root, task, c, session, session_path)
|
|
3534
3560
|
start_phase = "GREEN"
|
|
3535
3561
|
else:
|
|
3536
|
-
start_phase = (
|
|
3537
|
-
session.current_phase
|
|
3538
|
-
if session.current_phase not in ("IDLE", "RED")
|
|
3539
|
-
else None
|
|
3540
|
-
)
|
|
3562
|
+
start_phase = _start_phase_from_status(status)
|
|
3541
3563
|
|
|
3542
3564
|
_dispatch_task(
|
|
3543
3565
|
task,
|
|
@@ -3567,9 +3589,14 @@ def _execute_task_with_retry(
|
|
|
3567
3589
|
SessionState.load(session_path) if session_path.exists() else SessionState()
|
|
3568
3590
|
)
|
|
3569
3591
|
start_phase: str | None = None
|
|
3592
|
+
# Honor pending_judge_feedback only when the tracked tasks.jsonl still
|
|
3593
|
+
# records the implementation the judge rejected (RED or GREEN). A git
|
|
3594
|
+
# reset that reverts the JSONL to PENDING invalidates stale feedback.
|
|
3595
|
+
status = task.get("status", "PENDING")
|
|
3570
3596
|
if (
|
|
3571
3597
|
session.pending_judge_feedback
|
|
3572
3598
|
and session.pending_judge_feedback.get("task_id") == tid
|
|
3599
|
+
and status in ("RED", "GREEN")
|
|
3573
3600
|
):
|
|
3574
3601
|
session = _resume_pending_judge_feedback(root, task, c, session, session_path)
|
|
3575
3602
|
start_phase = "GREEN"
|
|
@@ -4681,10 +4708,10 @@ def _changed_source_paths(root: Path) -> list[str]:
|
|
|
4681
4708
|
@red_app.command(name="post")
|
|
4682
4709
|
def red_post() -> None:
|
|
4683
4710
|
root = Path.cwd()
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4711
|
+
if not _test_command_candidates(root):
|
|
4712
|
+
console.print(
|
|
4713
|
+
"[red]TEST_NOT_FOUND[/] No test command configured and no test project detected"
|
|
4714
|
+
)
|
|
4688
4715
|
raise typer.Exit(code=1)
|
|
4689
4716
|
|
|
4690
4717
|
proc = _run_test_cmd(root)
|
|
@@ -4792,10 +4819,10 @@ def green_pre(
|
|
|
4792
4819
|
@green_app.command(name="post")
|
|
4793
4820
|
def green_post() -> None:
|
|
4794
4821
|
root = Path.cwd()
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4822
|
+
if not _test_command_candidates(root):
|
|
4823
|
+
console.print(
|
|
4824
|
+
"[red]TEST_NOT_FOUND[/] No test command configured and no test project detected"
|
|
4825
|
+
)
|
|
4799
4826
|
raise typer.Exit(code=1)
|
|
4800
4827
|
|
|
4801
4828
|
dot_dir = root / ".deviate"
|
|
@@ -5066,9 +5093,7 @@ def _check_return_type_mismatch(filepath: str) -> list[str]:
|
|
|
5066
5093
|
@refactor_app.command(name="post")
|
|
5067
5094
|
def refactor_post() -> None:
|
|
5068
5095
|
root = Path.cwd()
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
if not test_files:
|
|
5096
|
+
if not _test_command_candidates(root):
|
|
5072
5097
|
console.print("[yellow]NO_TESTS_TO_CHECK[/]")
|
|
5073
5098
|
raise typer.Exit(code=0)
|
|
5074
5099
|
|
|
@@ -177,6 +177,58 @@ def validate_acceptance_contract(content: str) -> list[str]:
|
|
|
177
177
|
return errors
|
|
178
178
|
|
|
179
179
|
|
|
180
|
+
def repair_missing_verification_mode(content: str) -> tuple[str, int]:
|
|
181
|
+
"""Insert a default ``automated`` Verification Mode into every AC-PLAN-NNN
|
|
182
|
+
scenario absent that line; return the repaired content and repair count.
|
|
183
|
+
|
|
184
|
+
Only a genuine absence is filled. An existing mode line — even an
|
|
185
|
+
invalid or duplicated one — is never touched, so ``validate_acceptance_contract``
|
|
186
|
+
still rejects those. Callers should gate repair on the contract failing
|
|
187
|
+
*only* for ``missing Verification Mode`` errors.
|
|
188
|
+
"""
|
|
189
|
+
lines = content.splitlines()
|
|
190
|
+
header_idx = next(
|
|
191
|
+
(i for i, ln in enumerate(lines) if ln.strip() == "## Acceptance Contract"),
|
|
192
|
+
None,
|
|
193
|
+
)
|
|
194
|
+
if header_idx is None:
|
|
195
|
+
return content, 0
|
|
196
|
+
|
|
197
|
+
sec_end = len(lines)
|
|
198
|
+
for idx in range(header_idx + 1, len(lines)):
|
|
199
|
+
if lines[idx].lstrip().startswith("## "):
|
|
200
|
+
sec_end = idx
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
insertions: list[tuple[int, str]] = []
|
|
204
|
+
i = header_idx + 1
|
|
205
|
+
while i < sec_end:
|
|
206
|
+
if lines[i].lstrip().startswith("**Scenario AC-PLAN-"):
|
|
207
|
+
k = i + 1
|
|
208
|
+
mode_present = False
|
|
209
|
+
insert_after: int | None = None
|
|
210
|
+
while k < sec_end and not lines[k].lstrip().startswith(
|
|
211
|
+
"**Scenario AC-PLAN-"
|
|
212
|
+
):
|
|
213
|
+
if re.search(r"\*\*Verification Mode\*\*", lines[k], re.IGNORECASE):
|
|
214
|
+
mode_present = True
|
|
215
|
+
if lines[k].strip():
|
|
216
|
+
insert_after = k
|
|
217
|
+
k += 1
|
|
218
|
+
if not mode_present and insert_after is not None:
|
|
219
|
+
insertions.append((insert_after, "- **Verification Mode**: automated"))
|
|
220
|
+
i = k
|
|
221
|
+
else:
|
|
222
|
+
i += 1
|
|
223
|
+
|
|
224
|
+
if not insertions:
|
|
225
|
+
return content, 0
|
|
226
|
+
result = list(lines)
|
|
227
|
+
for pos, line in sorted(insertions, key=lambda t: t[0], reverse=True):
|
|
228
|
+
result.insert(pos + 1, line)
|
|
229
|
+
return "\n".join(result), len(insertions)
|
|
230
|
+
|
|
231
|
+
|
|
180
232
|
def validate_sections(content: str | None, required: list[str]) -> list[str]:
|
|
181
233
|
if not content or not content.strip():
|
|
182
234
|
return list(required)
|
|
@@ -31,7 +31,8 @@ Identify related issues sharing FR tokens. Check recent git history for commits
|
|
|
31
31
|
</step>
|
|
32
32
|
|
|
33
33
|
<step id="acceptance_contract">
|
|
34
|
-
Reconcile every AO-NNN against current code. Emit complete `AC-PLAN-NNN` scenarios under `## Acceptance Contract`, each with Source Outline, Upstream Traceability, Current-Code Evidence,
|
|
34
|
+
Reconcile every AO-NNN against current code. Emit complete `AC-PLAN-NNN` scenarios under `## Acceptance Contract`, each with Source Outline, Upstream Traceability, Current-Code Evidence, bold Given/When/Then clauses, and exactly one `**Verification Mode**: <automated|manual|deferred>` line (see required-field 6). This contract is authoritative for Tasks, RED, and JUDGE.
|
|
35
|
+
**Self-check before writing**: enumerate every `AC-PLAN-NNN` you produced and confirm each carries exactly one `**Verification Mode**:` line with a legal literal. A scenario that maps to RED/GREEN tests MUST use `automated`. Do not emit a plan whose scenarios lack this line.
|
|
35
36
|
</step>
|
|
36
37
|
|
|
37
38
|
<step id="write_plan">
|
|
@@ -69,12 +70,13 @@ The CLI orchestrator runs `deviate plan post` after your response to validate pl
|
|
|
69
70
|
|
|
70
71
|
## Acceptance Contract
|
|
71
72
|
|
|
72
|
-
**Required fields per scenario** — every `AC-PLAN-NNN` MUST contain all
|
|
73
|
+
**Required fields per scenario** — every `AC-PLAN-NNN` MUST contain all six:
|
|
73
74
|
1. **Scenario header** — `**Scenario AC-PLAN-NNN: <observable behaviour, imperative present tense>**`. Sequential, zero-padded, unique.
|
|
74
75
|
2. **Source Outline** — `**Source Outline**: \`AO-NNN\`[, \`AO-MMM\`…]`. MUST be a literal AO token from the issue's `## Acceptance Outline`. A comma-separated list is allowed for cross-cutting scenarios. Ad-hoc labels (`Edge Cases`, `Boundary`, `Constitutional §…`, `RLS`, `Tenant Isolation`, `Hardening`, `Security`) are forbidden — `deviate plan post` rejects them with `missing Source Outline AO-NNN traceability`. Every AO from the issue MUST appear as the Source Outline of at least one AC-PLAN scenario.
|
|
75
76
|
3. **Upstream Traceability** — `**Upstream Traceability**: \`US-NNN-NN\`, \`FR-NNN-ID\`, \`AC-NNN-ID-NN\`. At minimum one `US-`, one `FR-`, and one `AC-` token, comma-separated, drawn from the issue's `## Upstream Requirement Tracing` and `## User Stories Ledger`.
|
|
76
77
|
4. **Current-Code Evidence** — `**Current-Code Evidence**: \`<relative path>:<symbol or line>\``. At least one concrete path reference grounded in the codebase scan.
|
|
77
78
|
5. **Given / When / Then** — exactly three bold-labelled clauses in this order: `**Given**:`, `**When**:`, `**Then**:`. Each clause is a single imperative sentence and MUST NOT embed additional `**Given**` / `**When**` / `**Then**` markers. The `**Then**` clause MUST state a verifiable observable outcome.
|
|
79
|
+
6. **Verification Mode** — `**Verification Mode**: <automated|manual|deferred>`. Exactly one per scenario, drawn from the three allowed literals (case-insensitive). `automated` means RED/GREEN executes the scenario as a failing-then-passing test; `manual` means a human verifies it via a documented step; `deferred` means verification is postponed to a later slice. `deviate plan post` rejects a missing, duplicate, or invalid mode literal.
|
|
78
80
|
|
|
79
81
|
**Canonical example** (the shape to copy):
|
|
80
82
|
**Scenario AC-PLAN-001: <observable behaviour>**
|
|
@@ -84,10 +86,11 @@ The CLI orchestrator runs `deviate plan post` after your response to validate pl
|
|
|
84
86
|
- **Given**: <current, implementation-aware precondition>
|
|
85
87
|
- **When**: <observable trigger>
|
|
86
88
|
- **Then**: <verifiable outcome>
|
|
89
|
+
- **Verification Mode**: automated
|
|
87
90
|
|
|
88
91
|
**Required sections in canonical order**: `## Plan Summary` → `## Product Layer Anchors` → `## Acceptance Contract` (one or more scenarios; every issue AO covered) → `## Workstation Mapping` → `## Implementation Strategy` → `## Data Flow Analysis` → `## Risk Assessment` → `## Security Profile` → `## Integration Points` → `## Constitutional Alignment`.
|
|
89
92
|
|
|
90
|
-
**Forbidden patterns** (any one triggers `PLAN_ACCEPTANCE_CONTRACT_INVALID`): non-AO Source Outline labels, missing `Source Outline` / `Upstream Traceability` / `Current-Code Evidence` / any of `Given` / `When` / `Then`, an issue AO not used by any AC-PLAN scenario, duplicate or non-sequential `AC-PLAN-NNN` identifiers, wrapping the plan body in any XML tag / code fence / preamble.
|
|
93
|
+
**Forbidden patterns** (any one triggers `PLAN_ACCEPTANCE_CONTRACT_INVALID`): non-AO Source Outline labels, missing `Source Outline` / `Upstream Traceability` / `Current-Code Evidence` / any of `Given` / `When` / `Then` / `Verification Mode`, missing or duplicate or invalid `**Verification Mode**:` literal, an issue AO not used by any AC-PLAN scenario, duplicate or non-sequential `AC-PLAN-NNN` identifiers, wrapping the plan body in any XML tag / code fence / preamble.
|
|
91
94
|
|
|
92
95
|
|
|
93
96
|
## Workstation Mapping
|
|
@@ -76,12 +76,14 @@ CRITICAL INSTRUCTION INVARIANTS:
|
|
|
76
76
|
- Every AO from the issue's `## Acceptance Outline` MUST appear as the Source Outline of at least one AC-PLAN-NNN. Unused AOs produce a validation error and the agent must re-emit the contract.
|
|
77
77
|
- Behavioural coverage that does not map cleanly to a single AO (e.g. an HMAC failure, an RLS isolation invariant, a defensive boundary) belongs under an existing AO that already covers the same behaviour, with the AO's Error Category or Boundary Category used to shape the scenario. If no existing AO fits, the issue's `## Acceptance Outline` is incomplete — halt with `INCOMPLETE_ISSUE_OUTLINE` and request that shard/adhoc regenerate the issue rather than inventing a non-AO source.
|
|
78
78
|
8. **Generate `plan.md`**: Write the planning document to the issue workspace using the schema below. `deviate plan post` rejects a missing or malformed Acceptance Contract. The required fields per scenario and per section are non-negotiable — re-read this schema before each emission.
|
|
79
|
-
**Per-scenario required fields** (every `AC-PLAN-NNN` MUST contain all
|
|
79
|
+
**Per-scenario required fields** (every `AC-PLAN-NNN` MUST contain all six):
|
|
80
80
|
1. **Scenario header** — `**Scenario AC-PLAN-NNN: <observable behaviour, imperative present tense>**`. `AC-PLAN-NNN` is zero-padded three digits, sequential, starting at `AC-PLAN-001`. Identifiers are unique and gap-free.
|
|
81
81
|
2. **Source Outline** — `**Source Outline**: \`AO-NNN\`[, \`AO-MMM\`…]`. The value MUST be an AO token literally present in the issue's `## Acceptance Outline`. A comma-separated list is permitted for cross-cutting scenarios that span multiple AOs. Ad-hoc labels (`Edge Cases`, `Boundary`, `Constitutional §…`, `RLS`, `Tenant Isolation`, `Hardening`, `Security`) are forbidden — see step 7a.
|
|
82
82
|
3. **Upstream Traceability** — `**Upstream Traceability**: \`US-NNN-NN\`, \`FR-NNN-ID\`, \`AC-NNN-ID-NN\`. At minimum one `US-`, one `FR-`, and one `AC-` token, comma-separated, all drawn from the issue's `## Upstream Requirement Tracing` and `## User Stories Ledger` sections.
|
|
83
83
|
4. **Current-Code Evidence** — `**Current-Code Evidence**: \`<relative path>:<symbol or line>\``. At least one concrete path reference grounded in the codebase scan (a module, schema, migration, or test file actually present in the workstation).
|
|
84
84
|
5. **Given / When / Then** — exactly three bold-labelled clauses, in that order: `**Given**:`, `**When**:`, `**Then**:`. Each clause is a single imperative sentence and MUST NOT embed additional `**Given**` / `**When**` / `**Then**` markers. The `**Then**` clause MUST state a verifiable observable outcome.
|
|
85
|
+
6. **Verification Mode** — `**Verification Mode**: <automated|manual|deferred>`. Exactly one per scenario, drawn from the three allowed literals (case-insensitive). `automated` means RED/GREEN executes the scenario as a failing-then-passing test; `manual` means a human verifies it via a documented step; `deferred` means verification is postponed to a later slice. `deviate plan post` rejects a missing, duplicate, or invalid mode literal.
|
|
86
|
+
**Pre-write self-check**: Before writing `plan.md`, enumerate every `AC-PLAN-NNN` you produced and confirm each one carries exactly one `**Verification Mode**:` line with a legal literal. A scenario that maps to RED/GREEN tests MUST use `automated`. Do not emit a scenario without this line — the CLI cannot rescue a plan whose scenarios lack a mode.
|
|
85
87
|
**Per-section required structure** (every `plan.md` MUST contain every section below, in this order, with the exact `##` header):
|
|
86
88
|
1. `## Plan Summary` — bullets: Issue, Implementation Strategy, Estimated Complexity, Estimated Effort.
|
|
87
89
|
2. `## Product Layer Anchors` — bullets: Flow References, Source, Release Context, Architecture Components Touched (or `None` when absent).
|
|
@@ -95,7 +97,7 @@ CRITICAL INSTRUCTION INVARIANTS:
|
|
|
95
97
|
10. `## Constitutional Alignment` — Architecture / Testing / Git Isolation / Product Layer bullets.
|
|
96
98
|
**Forbidden patterns** (any one of these causes `PLAN_ACCEPTANCE_CONTRACT_INVALID` from `deviate plan post`):
|
|
97
99
|
- Source Outline labelled `Edge Cases`, `Boundary`, `Constitutional §…`, `RLS`, `Tenant Isolation`, `Hardening`, `Security`, or any non-AO string.
|
|
98
|
-
- Scenario missing `**Source Outline**`, `**Upstream Traceability**`, `**Current-Code Evidence**`,
|
|
100
|
+
- Scenario missing `**Source Outline**`, `**Upstream Traceability**`, `**Current-Code Evidence**`, any of `**Given**` / `**When**` / `**Then**`, or the `**Verification Mode**:` line.
|
|
99
101
|
- An AO from `## Acceptance Outline` not used by any AC-PLAN-NNN.
|
|
100
102
|
- Two scenarios sharing the same `AC-PLAN-NNN` number, or gaps in the sequence.
|
|
101
103
|
- Wrapping the plan body in any XML tag, code fence, or preamble — write raw Markdown only.
|
|
@@ -140,6 +142,7 @@ Write the plan as `plan.md` in the issue workspace directory (adjacent to the is
|
|
|
140
142
|
- **Given**: <current, implementation-aware precondition>
|
|
141
143
|
- **When**: <observable trigger>
|
|
142
144
|
- **Then**: <verifiable outcome>
|
|
145
|
+
- **Verification Mode**: automated
|
|
143
146
|
|
|
144
147
|
Each `AO-NNN` MUST map to at least one complete scenario. `AC-PLAN-NNN` identifiers are the authoritative acceptance identities consumed downstream.
|
|
145
148
|
|
|
@@ -326,16 +326,17 @@ class TestMesoContracts:
|
|
|
326
326
|
|
|
327
327
|
return runner.invoke(cli, ["tasks", "pre"])
|
|
328
328
|
|
|
329
|
-
def
|
|
330
|
-
self, tmp_path: Path
|
|
331
|
-
) -> None:
|
|
329
|
+
def test_tasks_pre_repairs_missing_verification_mode(self, tmp_path: Path) -> None:
|
|
332
330
|
plan_text = self._contract_plan(mode_line=None)
|
|
333
331
|
result = self._invoke_tasks_pre_with_plan(tmp_path, plan_text)
|
|
334
332
|
|
|
335
333
|
assert result.exit_code == 0, result.output
|
|
336
334
|
contract = self._extract_contract(result.output)
|
|
337
|
-
assert contract["status"] == "
|
|
338
|
-
assert "
|
|
335
|
+
assert contract["status"] == "READY", result.output
|
|
336
|
+
assert "PLAN_MODE_REPAIR" in result.output
|
|
337
|
+
plan_path = tmp_path / "specs" / "test-epic" / "ISS-TEST-001" / "plan.md"
|
|
338
|
+
repaired = plan_path.read_text(encoding="utf-8")
|
|
339
|
+
assert "**Verification Mode**: automated" in repaired
|
|
339
340
|
|
|
340
341
|
def test_tasks_pre_blocks_on_illegal_verification_mode(
|
|
341
342
|
self, tmp_path: Path
|