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.
Files changed (393) hide show
  1. {deviatdd-2.20.0 → deviatdd-2.20.1}/CHANGELOG.md +2 -0
  2. {deviatdd-2.20.0 → deviatdd-2.20.1}/PKG-INFO +1 -1
  3. {deviatdd-2.20.0 → deviatdd-2.20.1}/pyproject.toml +1 -1
  4. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/DeviaTDD-api.md +25 -20
  5. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/DeviaTDD-architecture.md +21 -10
  6. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/meso.py +39 -7
  7. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/micro.py +52 -27
  8. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/validation.py +52 -0
  9. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/plan.md +6 -3
  10. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-plan.md +5 -2
  11. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_meso_contracts.py +6 -5
  12. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_validation.py +43 -0
  13. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_resume.py +11 -10
  14. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_run.py +170 -5
  15. {deviatdd-2.20.0 → deviatdd-2.20.1}/uv.lock +1 -1
  16. {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/.gitignore +0 -0
  17. {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/config.toml +0 -0
  18. {deviatdd-2.20.0 → deviatdd-2.20.1}/.deviate/evaluations/deviate-flows-skill-2026-06-26.json +0 -0
  19. {deviatdd-2.20.0 → deviatdd-2.20.1}/.env.example +0 -0
  20. {deviatdd-2.20.0 → deviatdd-2.20.1}/.gitattributes +0 -0
  21. {deviatdd-2.20.0 → deviatdd-2.20.1}/.githooks/pre-commit +0 -0
  22. {deviatdd-2.20.0 → deviatdd-2.20.1}/.githooks/pre-push +0 -0
  23. {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
  24. {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/ISSUE_TEMPLATE/feature.md +0 -0
  25. {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  26. {deviatdd-2.20.0 → deviatdd-2.20.1}/.github/workflows/ci.yml +0 -0
  27. {deviatdd-2.20.0 → deviatdd-2.20.1}/.gitignore +0 -0
  28. {deviatdd-2.20.0 → deviatdd-2.20.1}/.opencode/.gitignore +0 -0
  29. {deviatdd-2.20.0 → deviatdd-2.20.1}/.opencode/opencode.json +0 -0
  30. {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/005-acceptance-gates/002-task-acceptance-traceability/.env.example +0 -0
  31. {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/adhoc/012-rpc-streaming-tui-renderer/.env.example +0 -0
  32. {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/feat/adhoc/014-cwe-mapping-security-findings/.env.example +0 -0
  33. {deviatdd-2.20.0 → deviatdd-2.20.1}/.worktrees/work/.env.example +0 -0
  34. {deviatdd-2.20.0 → deviatdd-2.20.1}/AGENTS.md +0 -0
  35. {deviatdd-2.20.0 → deviatdd-2.20.1}/CLAUDE.md +0 -0
  36. {deviatdd-2.20.0 → deviatdd-2.20.1}/CODE_OF_CONDUCT.md +0 -0
  37. {deviatdd-2.20.0 → deviatdd-2.20.1}/CONTRIBUTING.md +0 -0
  38. {deviatdd-2.20.0 → deviatdd-2.20.1}/LICENSE +0 -0
  39. {deviatdd-2.20.0 → deviatdd-2.20.1}/README.md +0 -0
  40. {deviatdd-2.20.0 → deviatdd-2.20.1}/SECURITY.md +0 -0
  41. {deviatdd-2.20.0 → deviatdd-2.20.1}/deviatdd.png +0 -0
  42. {deviatdd-2.20.0 → deviatdd-2.20.1}/mise.toml +0 -0
  43. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat/001-deviate-cli-python/008-meso-macro-automated-orchestration.md +0 -0
  44. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat/adhoc/006-context-cli-integration.md +0 -0
  45. {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
  46. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-003-meso-layer-specification-task-decomposition.md +0 -0
  47. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-004-micro-layer-tdd-sandbox-execution.md +0 -0
  48. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-005-cli-architecture-realignment-skill-integration.md +0 -0
  49. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-001-deviate-cli-python-007-macro-meso-parity-backward-compatibility.md +0 -0
  50. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-001-foundation-cli-infrastructure.md +0 -0
  51. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-003-fast-path-commands.md +0 -0
  52. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-002-deviatdd-gap-analysis-004-governance-inspection.md +0 -0
  53. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-adhoc-001-streaming-pipeline-monitor.md +0 -0
  54. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat-adhoc-008-ast-phase-prioritization.md +0 -0
  55. {deviatdd-2.20.0 → deviatdd-2.20.1}/pr_descriptions/feat_002-deviatdd-gap-analysis_001-foundation-cli-infrastructure.md +0 -0
  56. {deviatdd-2.20.0 → deviatdd-2.20.1}/scripts/benchmark_lmstudio.py +0 -0
  57. {deviatdd-2.20.0 → deviatdd-2.20.1}/scripts/verify_install.py +0 -0
  58. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t001.json +0 -0
  59. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t002.json +0 -0
  60. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/manifest-t004.json +0 -0
  61. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/spec.md +0 -0
  62. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/001-cli-initialization-governance-provisioning/tasks.md +0 -0
  63. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/002-macro-layer-state-ledger-management/spec.md +0 -0
  64. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/002-macro-layer-state-ledger-management/tasks.md +0 -0
  65. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/003-meso-layer-specification-task-decomposition/spec.md +0 -0
  66. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/003-meso-layer-specification-task-decomposition/tasks.md +0 -0
  67. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/spec.md +0 -0
  68. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/tasks.jsonl +0 -0
  69. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/004-micro-layer-tdd-sandbox-execution/tasks.md +0 -0
  70. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/005-cli-architecture-realignment-skill-integration/spec.md +0 -0
  71. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/005-cli-architecture-realignment-skill-integration/tasks.md +0 -0
  72. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/007-macro-meso-parity-backward-compatibility/spec.md +0 -0
  73. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/007-macro-meso-parity-backward-compatibility/tasks.md +0 -0
  74. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/spec.md +0 -0
  75. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/tasks.jsonl +0 -0
  76. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/008-meso-macro-automated-orchestration/tasks.md +0 -0
  77. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/data-model.md +0 -0
  78. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/design.md +0 -0
  79. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/explore.md +0 -0
  80. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/001-cli-initialization-governance-provisioning.md +0 -0
  81. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/002-macro-layer-state-ledger-management.md +0 -0
  82. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/003-meso-layer-specification-task-decomposition.md +0 -0
  83. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/004-micro-layer-tdd-sandbox-execution.md +0 -0
  84. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/005-cli-architecture-realignment-skill-integration.md +0 -0
  85. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/006-state-persistence-concurrency-safety.md +0 -0
  86. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/007-macro-meso-parity-backward-compatibility.md +0 -0
  87. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/issues/008-meso-macro-automated-orchestration.md +0 -0
  88. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/001-deviate-cli-python/prd.md +0 -0
  89. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/spec.md +0 -0
  90. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/tasks.jsonl +0 -0
  91. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/001-foundation-cli-infrastructure/tasks.md +0 -0
  92. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/spec.md +0 -0
  93. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/tasks.jsonl +0 -0
  94. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/003-fast-path-commands/tasks.md +0 -0
  95. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/spec.md +0 -0
  96. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/tasks.jsonl +0 -0
  97. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/004-governance-inspection/tasks.md +0 -0
  98. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/spec.md +0 -0
  99. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/tasks.jsonl +0 -0
  100. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/005-micro-layer-integrity/tasks.md +0 -0
  101. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/data-model.md +0 -0
  102. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/design.md +0 -0
  103. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/explore.md +0 -0
  104. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/001-foundation-cli-infrastructure.md +0 -0
  105. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/002-context-pipeline.md +0 -0
  106. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/003-fast-path-commands.md +0 -0
  107. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/004-governance-inspection.md +0 -0
  108. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/issues/005-micro-layer-integrity.md +0 -0
  109. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/plan-tdd-integration-gap.md +0 -0
  110. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/002-deviatdd-gap-analysis/prd.md +0 -0
  111. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/003-graphite-cli-integration/explore.md +0 -0
  112. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/004-per-task-security-profile/issues/001-security-profile-and-judge-checks.md +0 -0
  113. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/plan.md +0 -0
  114. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/tasks.jsonl +0 -0
  115. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/001-verification-mode-metadata/tasks.md +0 -0
  116. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/data-model.md +0 -0
  117. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/design.md +0 -0
  118. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/explore.md +0 -0
  119. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/001-verification-mode-metadata.md +0 -0
  120. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/002-task-acceptance-traceability.md +0 -0
  121. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/003-micro-phase-gates-red-green.md +0 -0
  122. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/004-refactor-regression-gate.md +0 -0
  123. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/issues/005-prompt-spec-alignment.md +0 -0
  124. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/005-acceptance-gates/prd.md +0 -0
  125. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/architecture.md +0 -0
  126. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/domain-model.md +0 -0
  127. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/flows-product.md +0 -0
  128. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/flows-streaming.md +0 -0
  129. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows/index.md +0 -0
  130. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/flows.jsonl +0 -0
  131. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-current-system.md +0 -0
  132. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-gap-register.md +0 -0
  133. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-git-state-model.md +0 -0
  134. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-rewrite.md +0 -0
  135. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/guildwright-rust-tui-requirements.md +0 -0
  136. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/_product/release-next.md +0 -0
  137. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/spec.md +0 -0
  138. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/tasks.jsonl +0 -0
  139. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/001-streaming-pipeline-monitor/tasks.md +0 -0
  140. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/spec.md +0 -0
  141. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/tasks.jsonl +0 -0
  142. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/003-meso-layer-restructuring/tasks.md +0 -0
  143. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/spec.md +0 -0
  144. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/tasks.jsonl +0 -0
  145. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/004-deviate-review-skill/tasks.md +0 -0
  146. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/plan.md +0 -0
  147. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/tasks.jsonl +0 -0
  148. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/005-per-phase-model-configuration/tasks.md +0 -0
  149. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/plan.md +0 -0
  150. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/tasks.jsonl +0 -0
  151. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/006-context-cli-integration/tasks.md +0 -0
  152. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/plan.md +0 -0
  153. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/tasks.jsonl +0 -0
  154. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/007-graphite-cli/tasks.md +0 -0
  155. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/plan.md +0 -0
  156. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/tasks.jsonl +0 -0
  157. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/008-ast-phase-prioritization/tasks.md +0 -0
  158. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/plan.md +0 -0
  159. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/tasks.jsonl +0 -0
  160. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/009-pi-agent-backend-integration/tasks.md +0 -0
  161. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/plan.md +0 -0
  162. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/tasks.jsonl +0 -0
  163. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/010-deviate-setup-product-layer/tasks.md +0 -0
  164. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/plan.md +0 -0
  165. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/tasks.jsonl +0 -0
  166. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/013-flow-ledger-canonical-source-of-truth/tasks.md +0 -0
  167. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/015-narrow-product-flow-scope/plan.md +0 -0
  168. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/015-narrow-product-flow-scope/tasks.md +0 -0
  169. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/001-streaming-pipeline-monitor.md +0 -0
  170. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/002-aider-agent-backend-integration.md +0 -0
  171. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/003-meso-layer-restructuring.md +0 -0
  172. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/004-deviate-review-skill.md +0 -0
  173. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/005-per-phase-model-configuration.md +0 -0
  174. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/006-context-cli-integration.md +0 -0
  175. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/007-graphite-cli.md +0 -0
  176. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/008-ast-phase-prioritization.md +0 -0
  177. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/009-pi-agent-backend-integration.md +0 -0
  178. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/010-deviate-setup-product-layer.md +0 -0
  179. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/012-rpc-streaming-tui-renderer.md +0 -0
  180. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/013-flow-ledger-canonical-source-of-truth.md +0 -0
  181. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/014-cwe-mapping-security-findings.md +0 -0
  182. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/issues/015-narrow-product-flow-scope.md +0 -0
  183. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/adhoc/prd.md +0 -0
  184. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/constitution.md +0 -0
  185. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/ast-tree-sitter.md +0 -0
  186. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/flow-ledger.md +0 -0
  187. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/graphite-cli.md +0 -0
  188. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/pi-agent-backend.md +0 -0
  189. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/product-layer.md +0 -0
  190. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/rpc-streaming-tui.md +0 -0
  191. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/rpc-streaming.md +0 -0
  192. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/explore/security-hardening-cwe.md +0 -0
  193. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/implementation-gap.md +0 -0
  194. {deviatdd-2.20.0 → deviatdd-2.20.1}/specs/issues.jsonl +0 -0
  195. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/__init__.py +0 -0
  196. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/__init__.py +0 -0
  197. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_common.py +0 -0
  198. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_html.py +0 -0
  199. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/_safe_commands.py +0 -0
  200. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/adhoc.py +0 -0
  201. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/constitution.py +0 -0
  202. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/feature.py +0 -0
  203. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/flow_commands.py +0 -0
  204. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/init.py +0 -0
  205. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/inspect.py +0 -0
  206. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/macro.py +0 -0
  207. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/review.py +0 -0
  208. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/cli/walkthrough.py +0 -0
  209. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/__init__.py +0 -0
  210. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/_shared.py +0 -0
  211. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/agent.py +0 -0
  212. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/cache_discipline.py +0 -0
  213. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/commands.py +0 -0
  214. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/commit.py +0 -0
  215. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/complexity.py +0 -0
  216. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/constitution.py +0 -0
  217. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/contract.py +0 -0
  218. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/convention.py +0 -0
  219. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/epic.py +0 -0
  220. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/issues.py +0 -0
  221. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/prd.py +0 -0
  222. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/profile.py +0 -0
  223. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/repo.py +0 -0
  224. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/run_logger.py +0 -0
  225. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/tasks_ledger.py +0 -0
  226. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/core/worktree.py +0 -0
  227. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/__init__.py +0 -0
  228. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/architecture.html.tmpl +0 -0
  229. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/domain-model.html.tmpl +0 -0
  230. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/flows.html.tmpl +0 -0
  231. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/plan.html.tmpl +0 -0
  232. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/html_templates/prd.html.tmpl +0 -0
  233. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/main.py +0 -0
  234. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/__init__.py +0 -0
  235. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/assembly.py +0 -0
  236. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/__init__.py +0 -0
  237. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/execute.md +0 -0
  238. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/explore.md +0 -0
  239. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/green.md +0 -0
  240. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/judge.md +0 -0
  241. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/prd.md +0 -0
  242. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/red.md +0 -0
  243. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/refactor.md +0 -0
  244. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/research.md +0 -0
  245. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/shard.md +0 -0
  246. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/specify.md +0 -0
  247. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/auto/tasks.md +0 -0
  248. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-adhoc.md +0 -0
  249. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-architecture.md +0 -0
  250. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-constitution.md +0 -0
  251. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-e2e.md +0 -0
  252. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-execute.md +0 -0
  253. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-explore.md +0 -0
  254. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-flows.md +0 -0
  255. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-green.md +0 -0
  256. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-hotfix.md +0 -0
  257. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-html.md +0 -0
  258. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-init.md +0 -0
  259. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-judge.md +0 -0
  260. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-merge.md +0 -0
  261. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-pr.md +0 -0
  262. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-prd.md +0 -0
  263. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-prune.md +0 -0
  264. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-red.md +0 -0
  265. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-refactor.md +0 -0
  266. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-release.md +0 -0
  267. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-research.md +0 -0
  268. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-review.md +0 -0
  269. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-shard.md +0 -0
  270. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-tasks.md +0 -0
  271. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-triage.md +0 -0
  272. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/commands/deviate-walkthrough.md +0 -0
  273. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/constitution_seed.md +0 -0
  274. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/core.md +0 -0
  275. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/lifecycle-auto.md +0 -0
  276. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/lifecycle-manual.md +0 -0
  277. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/macro-shared.md +0 -0
  278. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/meso-shared.md +0 -0
  279. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/micro-shared.md +0 -0
  280. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/product-shared.md +0 -0
  281. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/core/style-ste.md +0 -0
  282. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/extras/deviate-pr-graphite-routing.md +0 -0
  283. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/__init__.py +0 -0
  284. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/agents_seed.md +0 -0
  285. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/claudemd_seed.md +0 -0
  286. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/graphite_seed.md +0 -0
  287. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/governance/libref_seed.md +0 -0
  288. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/prompts/skills/deviatdd/SKILL.md +0 -0
  289. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/__init__.py +0 -0
  290. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/config.py +0 -0
  291. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/state/ledger.py +0 -0
  292. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/__init__.py +0 -0
  293. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/monitor.py +0 -0
  294. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/pipeline.py +0 -0
  295. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/ui/render.py +0 -0
  296. {deviatdd-2.20.0 → deviatdd-2.20.1}/src/deviate/visual/__init__.py +0 -0
  297. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/__init__.py +0 -0
  298. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/conftest.py +0 -0
  299. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/__init__.py +0 -0
  300. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/test_agent.py +0 -0
  301. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/core/test_smart_stall.py +0 -0
  302. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/e2e/test_macro_workflow.bats +0 -0
  303. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/__init__.py +0 -0
  304. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_adhoc.py +0 -0
  305. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_common.py +0 -0
  306. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_constitution.py +0 -0
  307. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_feature.py +0 -0
  308. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_flows_sync.py +0 -0
  309. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_help.py +0 -0
  310. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_html.py +0 -0
  311. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_init.py +0 -0
  312. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_inspect.py +0 -0
  313. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_macro_contracts.py +0 -0
  314. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_main_entrypoint.py +0 -0
  315. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_merge.py +0 -0
  316. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_meso.py +0 -0
  317. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_micro.py +0 -0
  318. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_real_descendant_kill.py +0 -0
  319. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_review.py +0 -0
  320. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_safe_commands.py +0 -0
  321. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_test_command_resolution.py +0 -0
  322. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_timeout_safe_command.py +0 -0
  323. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_cli/test_top_level_run.py +0 -0
  324. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_agent.py +0 -0
  325. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_cache_discipline.py +0 -0
  326. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_commands.py +0 -0
  327. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_commit.py +0 -0
  328. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_complexity.py +0 -0
  329. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_constitution.py +0 -0
  330. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_contract.py +0 -0
  331. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_convention.py +0 -0
  332. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_epic.py +0 -0
  333. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_flow_confirmation.py +0 -0
  334. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_issues.py +0 -0
  335. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_ledger.py +0 -0
  336. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_prd.py +0 -0
  337. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_profile.py +0 -0
  338. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_repo.py +0 -0
  339. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_run_logger.py +0 -0
  340. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_tasks_ledger.py +0 -0
  341. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_core/test_worktree.py +0 -0
  342. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_init.py +0 -0
  343. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/__init__.py +0 -0
  344. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/conftest.py +0 -0
  345. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_command_installation.py +0 -0
  346. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_init_export_cycle.py +0 -0
  347. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_full_cycle.py +0 -0
  348. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_layer.py +0 -0
  349. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_macro_orchestration.py +0 -0
  350. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_layer.py +0 -0
  351. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_orchestration.py +0 -0
  352. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_meso_task_ledger.py +0 -0
  353. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_parity.py +0 -0
  354. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_integration/test_skill_installation.py +0 -0
  355. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/__init__.py +0 -0
  356. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_explore.py +0 -0
  357. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_macro_model_routing.py +0 -0
  358. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_macro_orchestration.py +0 -0
  359. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_prd.py +0 -0
  360. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_research.py +0 -0
  361. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_macro/test_shard.py +0 -0
  362. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/__init__.py +0 -0
  363. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_auto_prompt_templates.py +0 -0
  364. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_model_routing.py +0 -0
  365. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_meso_orchestration.py +0 -0
  366. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_plan_structure_injection.py +0 -0
  367. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_prompt_assembly.py +0 -0
  368. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_specify.py +0 -0
  369. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_meso/test_tasks.py +0 -0
  370. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/__init__.py +0 -0
  371. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/conftest.py +0 -0
  372. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_commit_failure.py +0 -0
  373. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_e2e.py +0 -0
  374. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_execute.py +0 -0
  375. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_green.py +0 -0
  376. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_hotfix.py +0 -0
  377. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_judge.py +0 -0
  378. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_orchestration.py +0 -0
  379. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_output_filter.py +0 -0
  380. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_red.py +0 -0
  381. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_refactor.py +0 -0
  382. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_rollback_safety.py +0 -0
  383. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_micro/test_task_label.py +0 -0
  384. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/__init__.py +0 -0
  385. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_config.py +0 -0
  386. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_ledger.py +0 -0
  387. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_security_profile.py +0 -0
  388. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_state/test_session.py +0 -0
  389. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/__init__.py +0 -0
  390. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_monitor.py +0 -0
  391. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_pipeline.py +0 -0
  392. {deviatdd-2.20.0 → deviatdd-2.20.1}/tests/test_ui/test_render.py +0 -0
  393. {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.0
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deviatdd"
3
- version = "2.20.0"
3
+ version = "2.20.1"
4
4
  description = "DeviaTDD CLI — agent orchestration framework"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -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**`; missing, repeated, or illegal `**Verification Mode**: <automated|manual|deferred>` (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. The validator lives at `src/deviate/core/validation.py::validate_acceptance_contract`.
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 `pytest -v` on all test files. Validates the test fails explicitly
542
- (ASSERTION_FAILURE, not PASS or SYNTAX_ERROR), runs the test command, and reports whether the
543
- test failed as expected. `deviate micro run`'s internal RED phase (`_run_red_phase`) applies the
544
- same contract: when the test command exits 0 (all tests passed) or collects no tests (pytest
545
- exit 5), it does NOT die — it routes the decision to JUDGE (``failure_kind: no_failing_test``),
546
- which either rules the behavior already exists (task COMPLETED, the uncommitted passing test
547
- discarded) or rules the test wrong (``revert_before``, RED re-authors a genuinely failing test).
548
- When RED produces no test files at all, `deviate micro run` raises "RED phase produced no test
549
- files" naming `/deviate-execute` (DIRECT) or `/deviate-meso` re-sharding. On a genuine failing
550
- test it appends the RED status transition to the task ledger, forces session to RED, and commits
551
- with `test({scope}): RED phase - failing test`.
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 `pytest -v`,
568
- requires returncode 0. Appends GREEN transition to ledger, forces session to GREEN,
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 pytest before/after to detect regression.
588
- On regression, restores via `git restore .` and halts. Commits with
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`: emit `MESO_PLAN_INVALID` and stop without overwrite.
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) or collects no tests (pytest exit 5), `_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). When RED produces no test files at all, `_run_red_phase` raises `PhaseFailedError("RED phase produced no test files ...")` naming `/deviate-execute` (DIRECT) or `/deviate-meso` re-sharding — closing 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.
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`) supports **pytest** as its
625
- test runner via `_run_pytest()`. The abstraction layer is designed to be extensible to other
626
- frameworks through the `_classify_pytest_outcome()` pattern, which parses stdout/stderr for
627
- syntax errors, assertion failures, and pass states. Currently, `_run_pytest()` collects all
628
- `tests/**/test_*.py` files and runs them with `python -m pytest -v`.
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
- | **Node.js / Jest** | (Not implemented) | — | — | — |
634
- | **Go / testing** | (Not implemented) | — | — | — |
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, and stops on invalid artifacts without overwrite. After Meso
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 validate_acceptance_contract
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 = validate_acceptance_contract(content)
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
- acceptance_errors = validate_acceptance_contract(
1005
- Path(plan_path).read_text(encoding="utf-8")
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 without changing existing artifacts."""
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 = validate_acceptance_contract(plan_content)
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 test_result.returncode == 0 or _is_no_tests_collected(test_result):
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
- if session.pending_judge_feedback:
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
- test_files = _find_test_files(root)
4685
-
4686
- if not test_files:
4687
- console.print("[red]TEST_NOT_FOUND[/]")
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
- test_files = _find_test_files(root)
4796
-
4797
- if not test_files:
4798
- console.print("[red]TEST_NOT_FOUND[/]")
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
- test_files = _find_test_files(root)
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, and bold Given/When/Then clauses. This contract is authoritative for Tasks, RED, and JUDGE.
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 five:
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 five):
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**`, or any of `**Given**` / `**When**` / `**Then**`.
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 test_tasks_pre_blocks_on_missing_verification_mode(
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"] == "PLAN_ACCEPTANCE_CONTRACT_INVALID", result.output
338
- assert "AC-PLAN-001: missing Verification Mode" in result.output
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