code-mower 1.0.12__tar.gz → 1.0.14__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 (408) hide show
  1. {code_mower-1.0.12 → code_mower-1.0.14}/PKG-INFO +19 -5
  2. {code_mower-1.0.12 → code_mower-1.0.14}/README.md +18 -4
  3. {code_mower-1.0.12 → code_mower-1.0.14}/pyproject.toml +1 -1
  4. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/__init__.py +1 -1
  5. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/devin_api.py +9 -7
  6. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/release_campaigns.py +48 -25
  7. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  8. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/PKG-INFO +19 -5
  9. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/builder-provenance.yml.j2 +1 -1
  10. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_devin_api.py +55 -0
  11. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_release_campaigns.py +72 -0
  12. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_release_hygiene.py +48 -46
  13. {code_mower-1.0.12 → code_mower-1.0.14}/CODE_OF_CONDUCT.md +0 -0
  14. {code_mower-1.0.12 → code_mower-1.0.14}/LICENSE +0 -0
  15. {code_mower-1.0.12 → code_mower-1.0.14}/MANIFEST.in +0 -0
  16. {code_mower-1.0.12 → code_mower-1.0.14}/NOTICE +0 -0
  17. {code_mower-1.0.12 → code_mower-1.0.14}/SUPPORT.md +0 -0
  18. {code_mower-1.0.12 → code_mower-1.0.14}/requirements/requirements.txt +0 -0
  19. {code_mower-1.0.12 → code_mower-1.0.14}/setup.cfg +0 -0
  20. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/__init__.py +0 -0
  21. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/_base.py +0 -0
  22. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  23. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/gitar.py +0 -0
  24. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/greptile.py +0 -0
  25. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/adapters/qodo.py +0 -0
  26. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  27. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/antigravity_sdk_probe.py +0 -0
  28. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/audit_handoff_log.py +0 -0
  29. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/audit_labeler_lib.py +0 -0
  30. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/audit_limits.py +0 -0
  31. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/audit_progress.py +0 -0
  32. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/blind_review_artifacts.py +0 -0
  33. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/blind_review_coordinator.py +0 -0
  34. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/board.py +0 -0
  35. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/board_store.py +0 -0
  36. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/bootstrap.py +0 -0
  37. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/builder_experiment.py +0 -0
  38. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/builder_runs.py +0 -0
  39. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/__init__.py +0 -0
  40. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/arms.py +0 -0
  41. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/auto_discovery.py +0 -0
  42. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/commands.py +0 -0
  43. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/context_inputs.py +0 -0
  44. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/corpus.py +0 -0
  45. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/effect_report.py +0 -0
  46. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/evidence.py +0 -0
  47. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/evidence_report.py +0 -0
  48. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/identity.py +0 -0
  49. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/metrics.py +0 -0
  50. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/overlap.py +0 -0
  51. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/planning.py +0 -0
  52. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/policy.py +0 -0
  53. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/results.py +0 -0
  54. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/run_results.py +0 -0
  55. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/run_status.py +0 -0
  56. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/runner.py +0 -0
  57. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/truth.py +0 -0
  58. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/calibration/value_report.py +0 -0
  59. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/campaign_adapters.py +0 -0
  60. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/campaign_discovery.py +0 -0
  61. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/checks.py +0 -0
  62. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/claude_audit_pr.py +0 -0
  63. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/claude_cli_bounce.py +0 -0
  64. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/claude_cli_environment.py +0 -0
  65. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/clear_stale.py +0 -0
  66. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cli.py +0 -0
  67. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud.py +0 -0
  68. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/__init__.py +0 -0
  69. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/adoption_runs.py +0 -0
  70. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/bundle.py +0 -0
  71. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/doctor.py +0 -0
  72. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/dogfood.py +0 -0
  73. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/endpoints.py +0 -0
  74. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/errors.py +0 -0
  75. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/events.py +0 -0
  76. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/export.py +0 -0
  77. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/git_metadata.py +0 -0
  78. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/manifest.py +0 -0
  79. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/operations.py +0 -0
  80. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/pr_outcomes.py +0 -0
  81. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/productivity.py +0 -0
  82. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/reports.py +0 -0
  83. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/setup.py +0 -0
  84. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/tokens.py +0 -0
  85. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/upload.py +0 -0
  86. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/cloud_client/work_types.py +0 -0
  87. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/code_mower_calibration.py +0 -0
  88. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/code_mower_context_packs.py +0 -0
  89. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/code_mower_merge.py +0 -0
  90. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/code_mower_telemetry.py +0 -0
  91. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  92. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/codex_audit_env_preflight.py +0 -0
  93. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/codex_audit_pr.py +0 -0
  94. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  95. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  96. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/config.py +0 -0
  97. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/controller.py +0 -0
  98. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/decisions.py +0 -0
  99. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/devin_cli_audit_pr.py +0 -0
  100. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor.py +0 -0
  101. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/__init__.py +0 -0
  102. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/adoption.py +0 -0
  103. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  104. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/campaign_auth.py +0 -0
  105. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/cloud.py +0 -0
  106. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/common.py +0 -0
  107. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github.py +0 -0
  108. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions.py +0 -0
  109. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  110. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  111. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  112. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  113. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  114. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  115. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  116. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  117. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_api.py +0 -0
  118. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_branch.py +0 -0
  119. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_config.py +0 -0
  120. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_human_token.py +0 -0
  121. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_provider.py +0 -0
  122. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_repo.py +0 -0
  123. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/github_trusted_authors.py +0 -0
  124. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/groups.py +0 -0
  125. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/models.py +0 -0
  126. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/output.py +0 -0
  127. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/presets.py +0 -0
  128. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/privacy.py +0 -0
  129. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  130. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  131. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  132. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_env.py +0 -0
  133. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  134. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  135. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  136. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  137. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  138. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  139. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  140. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  141. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  142. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  143. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  144. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  145. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/providers.py +0 -0
  146. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/registry.py +0 -0
  147. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/runner.py +0 -0
  148. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/runtime.py +0 -0
  149. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  150. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
  151. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/doctor_checks/supervised_pilot.py +0 -0
  152. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/file_locks.py +0 -0
  153. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/gate_health.py +0 -0
  154. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  155. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/git_identity.py +0 -0
  156. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/grok_build_audit_pr.py +0 -0
  157. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  158. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/init.py +0 -0
  159. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/__init__.py +0 -0
  160. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/aider.py +0 -0
  161. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  162. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/claude.py +0 -0
  163. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/codex.py +0 -0
  164. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/devin.py +0 -0
  165. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/devin_cli.py +0 -0
  166. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  167. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/grok_build.py +0 -0
  168. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  169. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/local_llm.py +0 -0
  170. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_configs/muse_cli.py +0 -0
  171. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_delivery.py +0 -0
  172. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/lane_status.py +0 -0
  173. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/local_llm_audit_pr.py +0 -0
  174. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/local_llm_bakeoff.py +0 -0
  175. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/local_llm_calibration.py +0 -0
  176. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/local_llm_profiles.py +0 -0
  177. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/migration.py +0 -0
  178. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/migration_install.py +0 -0
  179. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/migration_mirror.py +0 -0
  180. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/migration_readiness.py +0 -0
  181. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/migration_rehearsal.py +0 -0
  182. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/muse_cli_audit_pr.py +0 -0
  183. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/next_steps.py +0 -0
  184. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package.py +0 -0
  185. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package_content.py +0 -0
  186. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package_manifest.py +0 -0
  187. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package_paths.py +0 -0
  188. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package_rendering.py +0 -0
  189. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/package_static.py +0 -0
  190. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/participants.py +0 -0
  191. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/plan_context.py +0 -0
  192. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/productivity_report.py +0 -0
  193. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/prompts.py +0 -0
  194. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_registry.py +0 -0
  195. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/__init__.py +0 -0
  196. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/comments.py +0 -0
  197. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/exit_codes.py +0 -0
  198. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/git.py +0 -0
  199. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/github_auth.py +0 -0
  200. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/github_pr.py +0 -0
  201. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  202. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/process.py +0 -0
  203. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/repo_paths.py +0 -0
  204. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/text_schema.py +0 -0
  205. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  206. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/provider_runners/workspace.py +0 -0
  207. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/providers/__init__.py +0 -0
  208. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/providers/local_cli.py +0 -0
  209. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/providers/provenance.py +0 -0
  210. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/release_qualify.py +0 -0
  211. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/release_readiness.py +0 -0
  212. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/reviewer_metrics.py +0 -0
  213. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/reviewer_spend.py +0 -0
  214. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/saas_reviewer_labeler.py +0 -0
  215. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/secrets.py +0 -0
  216. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/session.py +0 -0
  217. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/builder-experiment.example.json +0 -0
  218. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  219. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/calibration-corpus.json +0 -0
  220. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/code-mower.example.yml +0 -0
  221. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/context-packs.example.json +0 -0
  222. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  223. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  224. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  225. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  226. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  227. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  228. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  229. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  230. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  231. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/README.md +0 -0
  232. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/claude.md +0 -0
  233. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/codex.md +0 -0
  234. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/cursor.md +0 -0
  235. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/devin.md +0 -0
  236. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/generic.md +0 -0
  237. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
  238. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/code_mower +0 -0
  239. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  240. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  241. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  242. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  243. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/run_devin_cli_audit_pr.sh +0 -0
  244. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  245. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/product-support/status_report.py +0 -0
  246. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/providers.yml +0 -0
  247. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  248. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  249. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  250. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  251. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  252. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  253. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  254. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  255. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  256. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  257. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  258. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  259. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  260. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  261. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  262. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  263. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  264. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  265. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/trailer_comment_labeler.py +0 -0
  266. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/versioning.py +0 -0
  267. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/work_orders.py +0 -0
  268. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower/workflow_actionlint.py +0 -0
  269. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/SOURCES.txt +0 -0
  270. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/dependency_links.txt +0 -0
  271. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/entry_points.txt +0 -0
  272. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/requires.txt +0 -0
  273. {code_mower-1.0.12 → code_mower-1.0.14}/src/code_mower.egg-info/top_level.txt +0 -0
  274. {code_mower-1.0.12 → code_mower-1.0.14}/templates/builder-experiment.example.json +0 -0
  275. {code_mower-1.0.12 → code_mower-1.0.14}/templates/calibration-corpus.example.json +0 -0
  276. {code_mower-1.0.12 → code_mower-1.0.14}/templates/calibration-corpus.json +0 -0
  277. {code_mower-1.0.12 → code_mower-1.0.14}/templates/code-mower.yml.j2 +0 -0
  278. {code_mower-1.0.12 → code_mower-1.0.14}/templates/context-packs.example.json +0 -0
  279. {code_mower-1.0.12 → code_mower-1.0.14}/templates/cursor/BUGBOT.md +0 -0
  280. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/README.md +0 -0
  281. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/claude.md +0 -0
  282. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/codex.md +0 -0
  283. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/cursor.md +0 -0
  284. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/devin.md +0 -0
  285. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/generic.md +0 -0
  286. {code_mower-1.0.12 → code_mower-1.0.14}/templates/lanes/run_mac_lane.sh +0 -0
  287. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/acp_bridge.yml +0 -0
  288. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/aider.yml +0 -0
  289. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/antigravity_cli.yml +0 -0
  290. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/claude_audit.yml +0 -0
  291. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/claude_review.yml +0 -0
  292. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/coderabbit_cli.yml +0 -0
  293. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/codex.yml +0 -0
  294. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/cursor_bugbot.yml +0 -0
  295. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/cursor_cloud_agent.yml +0 -0
  296. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/devin.yml +0 -0
  297. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/devin_cli.yml +0 -0
  298. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/gemini_cli.yml +0 -0
  299. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/gitar.yml +0 -0
  300. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/greptile.yml +0 -0
  301. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/hermes_cli.yml +0 -0
  302. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/local_llm.yml +0 -0
  303. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/muse_cli.yml +0 -0
  304. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers/qodo.yml +0 -0
  305. {code_mower-1.0.12 → code_mower-1.0.14}/templates/providers.yml +0 -0
  306. {code_mower-1.0.12 → code_mower-1.0.14}/templates/reviewer-spend.example.json +0 -0
  307. {code_mower-1.0.12 → code_mower-1.0.14}/templates/reviewer-value-report.example.md +0 -0
  308. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  309. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  310. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  311. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  312. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  313. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  314. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  315. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  316. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  317. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  318. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  319. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  320. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  321. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  322. {code_mower-1.0.12 → code_mower-1.0.14}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  323. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_adoption_diagnostics.py +0 -0
  324. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_adoption_result_semantics.py +0 -0
  325. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_adoption_run_contract.py +0 -0
  326. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_antigravity_sdk_probe.py +0 -0
  327. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_audit_comment_posture.py +0 -0
  328. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_audit_limits.py +0 -0
  329. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_board.py +0 -0
  330. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_builder_experiment.py +0 -0
  331. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_builder_identity.py +0 -0
  332. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_builder_runs.py +0 -0
  333. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_calibration_effect_report.py +0 -0
  334. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_calibration_truth.py +0 -0
  335. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_campaign_adapters.py +0 -0
  336. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_campaign_discovery.py +0 -0
  337. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_campaign_retry_evidence_711.py +0 -0
  338. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_checks.py +0 -0
  339. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_claude_audit_pr.py +0 -0
  340. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_claude_cli_bounce.py +0 -0
  341. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_clear_stale.py +0 -0
  342. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_cloud_client.py +0 -0
  343. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_cloud_git_metadata.py +0 -0
  344. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_cloud_manifest.py +0 -0
  345. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_cloud_reports.py +0 -0
  346. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  347. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_codex_audit_env_preflight.py +0 -0
  348. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_codex_audit_pr.py +0 -0
  349. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_controller.py +0 -0
  350. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_decision_audit_integration.py +0 -0
  351. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_decisions.py +0 -0
  352. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_devin_builder_lane.py +0 -0
  353. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_devin_cli_audit_pr.py +0 -0
  354. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_devin_provider_contract.py +0 -0
  355. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_actions_cost_summary.py +0 -0
  356. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_actions_failure_selection.py +0 -0
  357. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_boundaries.py +0 -0
  358. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_campaign_auth.py +0 -0
  359. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_campaign_readiness.py +0 -0
  360. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_github_checks.py +0 -0
  361. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_output.py +0 -0
  362. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_privacy.py +0 -0
  363. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_provider_env_required.py +0 -0
  364. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_provider_env_tokens.py +0 -0
  365. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  366. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_provider_probe.py +0 -0
  367. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_provider_review_hygiene.py +0 -0
  368. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_registry.py +0 -0
  369. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_runtime.py +0 -0
  370. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_self_hosted_runner.py +0 -0
  371. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_doctor_supervised_pilot.py +0 -0
  372. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_file_locks.py +0 -0
  373. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_fork_pr_guard.py +0 -0
  374. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_gate_automerge.py +0 -0
  375. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_gate_health.py +0 -0
  376. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_hosted_dispatch_profile.py +0 -0
  377. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_init_actionlint.py +0 -0
  378. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_init_build_loop.py +0 -0
  379. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_lane_delivery_contract.py +0 -0
  380. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_lane_status.py +0 -0
  381. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_local_llm_github_helpers.py +0 -0
  382. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_migration_rehearsal.py +0 -0
  383. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_migration_setup_drift.py +0 -0
  384. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_next_steps.py +0 -0
  385. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_package_install_failure_taxonomy.py +0 -0
  386. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_participant_sessions.py +0 -0
  387. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_plan_context.py +0 -0
  388. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_pr_outcome_contract.py +0 -0
  389. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_productivity_metrics_contract.py +0 -0
  390. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_productivity_report.py +0 -0
  391. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_prompts.py +0 -0
  392. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_fixture_contracts.py +0 -0
  393. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_local_cli.py +0 -0
  394. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_comments.py +0 -0
  395. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_git.py +0 -0
  396. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_github_pr.py +0 -0
  397. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_pr_worktree.py +0 -0
  398. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_process.py +0 -0
  399. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_repo_paths.py +0 -0
  400. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_text_schema.py +0 -0
  401. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_provider_runners_workspace.py +0 -0
  402. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_release_qualify.py +0 -0
  403. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_reviewer_metrics_core.py +0 -0
  404. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_reviewer_spend.py +0 -0
  405. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_supervised_pilot_contract.py +0 -0
  406. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_trailer_comment_labeler.py +0 -0
  407. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_work_orders.py +0 -0
  408. {code_mower-1.0.12 → code_mower-1.0.14}/tests/test_work_type_contract.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 1.0.12
3
+ Version: 1.0.14
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/codemower-ai/code-mower
@@ -241,7 +241,7 @@ agent report its actual host posture, exact installed version, doctor result,
241
241
  Board URL, and any owner-only click-list before it mutates the repo.
242
242
 
243
243
  The current package-index announcement entry point is the tagged
244
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/docs/try-in-10-minutes.md)
244
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.14/docs/try-in-10-minutes.md)
245
245
  guide. The v1.0 supervised-pilot release includes the native Board, the
246
246
  controller dry-run and policy contract, adoption and upgrade hardening from
247
247
  recent install rehearsals, package-index release checks, provider-diversity
@@ -294,6 +294,18 @@ provider qualification prompt no longer tells the agent to create its own
294
294
  temporary directory, so it stays in the disposable workspace Code Mower
295
295
  already created, and it states the existing contract that a result's total
296
296
  `elapsed_seconds` is the sum of its step values.
297
+ The v1.0.13 patch makes automatic campaign runtime selection sandbox-safe:
298
+ when `CODE_MOWER_PYTHON` is not set, Code Mower now prefers a supported
299
+ versioned Python on `PATH` outside the user home before falling back to its
300
+ own running interpreter, so a pipx- or uv-installed CLI stops handing Claude's
301
+ strict macOS sandbox an interpreter under the denied home tree. An explicit
302
+ `CODE_MOWER_PYTHON` remains authoritative.
303
+ The v1.0.14 patch corrects hosted Devin qualification result precedence: a
304
+ valid closed structured result is accepted even while the session still
305
+ reports `running` / `waiting_for_user`, so a finished informational Devin
306
+ attempt is no longer recorded as owner-blocked. An explicit terminal API
307
+ failure and a `waiting_for_approval` session still take precedence over any
308
+ structured output.
297
309
  Package-only users can start from the public package rather than a source
298
310
  checkout.
299
311
 
@@ -326,7 +338,7 @@ Provider-contract baseline for the next release train:
326
338
 
327
339
  For release verification,
328
340
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
329
- the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
341
+ the package-index procedure for `v1.0.14` / `code-mower==1.0.14`. The
330
342
  GitHub release records the workflow and rehearsal evidence for the exact tag.
331
343
  After publication, [Release Qualification](docs/release-qualification.md)
332
344
  coordinates provider-specific install and operational checks without treating
@@ -520,8 +532,8 @@ measurement work.
520
532
 
521
533
  ## Installation Status
522
534
 
523
- The current package-index release baseline is `v1.0.12`, with pinned package
524
- install spec `code-mower==1.0.12`. Release evidence is recorded on the GitHub
535
+ The current package-index release baseline is `v1.0.14`, with pinned package
536
+ install spec `code-mower==1.0.14`. Release evidence is recorded on the GitHub
525
537
  release and in the first-user install rehearsal. The public repository is
526
538
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
527
539
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -602,6 +614,8 @@ first so local work exercises the same package entrypoint users install.
602
614
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
603
615
  - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
604
616
  - [v1.0.12 Release Notes](docs/v1012-release-notes.md)
617
+ - [v1.0.13 Release Notes](docs/v1013-release-notes.md)
618
+ - [v1.0.14 Release Notes](docs/v1014-release-notes.md)
605
619
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
606
620
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
607
621
  - [Demo Calibration Example](examples/demo-calibration/README.md)
@@ -211,7 +211,7 @@ agent report its actual host posture, exact installed version, doctor result,
211
211
  Board URL, and any owner-only click-list before it mutates the repo.
212
212
 
213
213
  The current package-index announcement entry point is the tagged
214
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/docs/try-in-10-minutes.md)
214
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.14/docs/try-in-10-minutes.md)
215
215
  guide. The v1.0 supervised-pilot release includes the native Board, the
216
216
  controller dry-run and policy contract, adoption and upgrade hardening from
217
217
  recent install rehearsals, package-index release checks, provider-diversity
@@ -264,6 +264,18 @@ provider qualification prompt no longer tells the agent to create its own
264
264
  temporary directory, so it stays in the disposable workspace Code Mower
265
265
  already created, and it states the existing contract that a result's total
266
266
  `elapsed_seconds` is the sum of its step values.
267
+ The v1.0.13 patch makes automatic campaign runtime selection sandbox-safe:
268
+ when `CODE_MOWER_PYTHON` is not set, Code Mower now prefers a supported
269
+ versioned Python on `PATH` outside the user home before falling back to its
270
+ own running interpreter, so a pipx- or uv-installed CLI stops handing Claude's
271
+ strict macOS sandbox an interpreter under the denied home tree. An explicit
272
+ `CODE_MOWER_PYTHON` remains authoritative.
273
+ The v1.0.14 patch corrects hosted Devin qualification result precedence: a
274
+ valid closed structured result is accepted even while the session still
275
+ reports `running` / `waiting_for_user`, so a finished informational Devin
276
+ attempt is no longer recorded as owner-blocked. An explicit terminal API
277
+ failure and a `waiting_for_approval` session still take precedence over any
278
+ structured output.
267
279
  Package-only users can start from the public package rather than a source
268
280
  checkout.
269
281
 
@@ -296,7 +308,7 @@ Provider-contract baseline for the next release train:
296
308
 
297
309
  For release verification,
298
310
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
299
- the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
311
+ the package-index procedure for `v1.0.14` / `code-mower==1.0.14`. The
300
312
  GitHub release records the workflow and rehearsal evidence for the exact tag.
301
313
  After publication, [Release Qualification](docs/release-qualification.md)
302
314
  coordinates provider-specific install and operational checks without treating
@@ -490,8 +502,8 @@ measurement work.
490
502
 
491
503
  ## Installation Status
492
504
 
493
- The current package-index release baseline is `v1.0.12`, with pinned package
494
- install spec `code-mower==1.0.12`. Release evidence is recorded on the GitHub
505
+ The current package-index release baseline is `v1.0.14`, with pinned package
506
+ install spec `code-mower==1.0.14`. Release evidence is recorded on the GitHub
495
507
  release and in the first-user install rehearsal. The public repository is
496
508
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
497
509
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -572,6 +584,8 @@ first so local work exercises the same package entrypoint users install.
572
584
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
573
585
  - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
574
586
  - [v1.0.12 Release Notes](docs/v1012-release-notes.md)
587
+ - [v1.0.13 Release Notes](docs/v1013-release-notes.md)
588
+ - [v1.0.14 Release Notes](docs/v1014-release-notes.md)
575
589
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
576
590
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
577
591
  - [Demo Calibration Example](examples/demo-calibration/README.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "1.0.12"
7
+ version = "1.0.14"
8
8
  description = "Multi-reviewer AI code audit orchestration"
9
9
  requires-python = ">=3.12"
10
10
  readme = "README.md"
@@ -1,3 +1,3 @@
1
1
  """Code Mower package."""
2
2
 
3
- __version__ = "1.0.12"
3
+ __version__ = "1.0.14"
@@ -238,13 +238,6 @@ def poll_devin_session(
238
238
  return "failed", None, exc.code
239
239
  status = str(data.get("status") or "")
240
240
  detail = str(data.get("status_detail") or "")
241
- if detail in {"waiting_for_user", "waiting_for_approval"}:
242
- return "owner_action", None, "devin_waiting_for_owner"
243
- if status == "exit" or detail == "finished":
244
- result = data.get("structured_output")
245
- if isinstance(result, dict):
246
- return "complete", dict(result), ""
247
- return "failed", None, "hosted_result_rejected"
248
241
  if status in {"error", "suspended"} or detail in {
249
242
  "error",
250
243
  "usage_limit_exceeded",
@@ -256,4 +249,13 @@ def poll_devin_session(
256
249
  "total_session_limit_exceeded",
257
250
  }:
258
251
  return "failed", None, "devin_session_failed"
252
+ if detail == "waiting_for_approval":
253
+ return "owner_action", None, "devin_waiting_for_owner"
254
+ result = data.get("structured_output")
255
+ if isinstance(result, dict):
256
+ return "complete", dict(result), ""
257
+ if detail == "waiting_for_user":
258
+ return "owner_action", None, "devin_waiting_for_owner"
259
+ if status == "exit" or detail == "finished":
260
+ return "failed", None, "hosted_result_rejected"
259
261
  return "running", None, ""
@@ -2348,6 +2348,30 @@ def _versioned_python_candidates(path_value: str) -> tuple[str, ...]:
2348
2348
  return tuple(f"python3.{minor}" for minor in sorted(minors, reverse=True))
2349
2349
 
2350
2350
 
2351
+ def _resolve_python_candidate(
2352
+ candidate: str,
2353
+ *,
2354
+ explicit: str,
2355
+ which_fn: Callable[[str], str | None],
2356
+ ) -> str | None:
2357
+ candidate_path = Path(candidate).expanduser()
2358
+ is_path = bool(
2359
+ os.sep in candidate
2360
+ or (os.altsep and os.altsep in candidate)
2361
+ or candidate == sys.executable
2362
+ or (candidate == explicit and candidate_path.exists())
2363
+ )
2364
+ if is_path:
2365
+ if not candidate_path.exists():
2366
+ return None
2367
+ return str(candidate_path if candidate_path.is_absolute() else candidate_path.resolve())
2368
+ resolved = which_fn(candidate)
2369
+ if not resolved:
2370
+ return None
2371
+ resolved_path = Path(resolved).expanduser()
2372
+ return str(resolved_path if resolved_path.is_absolute() else resolved_path.resolve())
2373
+
2374
+
2351
2375
  def resolve_supported_runtime(
2352
2376
  *,
2353
2377
  environ: Mapping[str, str] | None = None,
@@ -2361,43 +2385,42 @@ def resolve_supported_runtime(
2361
2385
  """
2362
2386
  env = os.environ if environ is None else environ
2363
2387
  explicit = env.get("CODE_MOWER_PYTHON", "").strip()
2388
+ which = shutil.which if which_fn is None else which_fn
2364
2389
  if explicit:
2365
- candidates = (explicit,)
2390
+ resolved = _resolve_python_candidate(explicit, explicit=explicit, which_fn=which)
2391
+ candidates = (resolved,) if resolved else ()
2366
2392
  else:
2367
2393
  discovered = _versioned_python_candidates(str(env.get("PATH", "")))
2368
- candidates = (
2369
- sys.executable,
2394
+ raw_candidates = (
2370
2395
  *discovered,
2371
- "python3.12",
2372
- "python3.13",
2373
2396
  "python3.14",
2397
+ "python3.13",
2398
+ "python3.12",
2374
2399
  "python3",
2400
+ sys.executable,
2375
2401
  )
2376
- which = shutil.which if which_fn is None else which_fn
2402
+ resolved_candidates: list[str] = []
2403
+ seen: set[str] = set()
2404
+ for candidate in raw_candidates:
2405
+ resolved = _resolve_python_candidate(candidate, explicit="", which_fn=which)
2406
+ if resolved and resolved not in seen:
2407
+ seen.add(resolved)
2408
+ resolved_candidates.append(resolved)
2409
+
2410
+ home = Path(str(env.get("HOME") or Path.home())).expanduser().resolve()
2411
+ outside_home = [
2412
+ candidate for candidate in resolved_candidates if not Path(candidate).resolve().is_relative_to(home)
2413
+ ]
2414
+ inside_home = [candidate for candidate in resolved_candidates if Path(candidate).resolve().is_relative_to(home)]
2415
+ candidates = (*outside_home, *inside_home)
2416
+
2377
2417
  run = subprocess.run if runner is None else runner
2378
2418
  for cand in candidates:
2379
2419
  if not cand:
2380
2420
  continue
2381
- cand_path = Path(cand).expanduser()
2382
- if (
2383
- os.sep in cand
2384
- or (os.altsep and os.altsep in cand)
2385
- or cand == sys.executable
2386
- or (cand == explicit and cand_path.exists())
2387
- ):
2388
- if cand_path.exists():
2389
- resolved = str(cand_path.resolve()) if not cand_path.is_absolute() else cand
2390
- else:
2391
- resolved = None
2392
- else:
2393
- resolved = which(cand)
2394
- if resolved and not Path(resolved).is_absolute():
2395
- resolved = str(Path(resolved).resolve())
2396
- if not resolved:
2397
- continue
2398
2421
  try:
2399
2422
  completed = run(
2400
- [resolved, "-c", "import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}')"],
2423
+ [cand, "-c", "import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}')"],
2401
2424
  text=True,
2402
2425
  capture_output=True,
2403
2426
  check=False,
@@ -2414,7 +2437,7 @@ def resolve_supported_runtime(
2414
2437
  except (IndexError, ValueError):
2415
2438
  continue
2416
2439
  if (major, minor) >= (3, 12):
2417
- return resolved, f"python_{major}.{minor}"
2440
+ return cand, f"python_{major}.{minor}"
2418
2441
  return None
2419
2442
 
2420
2443
 
@@ -8,7 +8,7 @@ permissions:
8
8
  contents: read
9
9
 
10
10
  env:
11
- CODE_MOWER_PACKAGE_SPEC: code-mower==1.0.12
11
+ CODE_MOWER_PACKAGE_SPEC: code-mower==1.0.14
12
12
 
13
13
  jobs:
14
14
  auto-record:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 1.0.12
3
+ Version: 1.0.14
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/codemower-ai/code-mower
@@ -241,7 +241,7 @@ agent report its actual host posture, exact installed version, doctor result,
241
241
  Board URL, and any owner-only click-list before it mutates the repo.
242
242
 
243
243
  The current package-index announcement entry point is the tagged
244
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/docs/try-in-10-minutes.md)
244
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.14/docs/try-in-10-minutes.md)
245
245
  guide. The v1.0 supervised-pilot release includes the native Board, the
246
246
  controller dry-run and policy contract, adoption and upgrade hardening from
247
247
  recent install rehearsals, package-index release checks, provider-diversity
@@ -294,6 +294,18 @@ provider qualification prompt no longer tells the agent to create its own
294
294
  temporary directory, so it stays in the disposable workspace Code Mower
295
295
  already created, and it states the existing contract that a result's total
296
296
  `elapsed_seconds` is the sum of its step values.
297
+ The v1.0.13 patch makes automatic campaign runtime selection sandbox-safe:
298
+ when `CODE_MOWER_PYTHON` is not set, Code Mower now prefers a supported
299
+ versioned Python on `PATH` outside the user home before falling back to its
300
+ own running interpreter, so a pipx- or uv-installed CLI stops handing Claude's
301
+ strict macOS sandbox an interpreter under the denied home tree. An explicit
302
+ `CODE_MOWER_PYTHON` remains authoritative.
303
+ The v1.0.14 patch corrects hosted Devin qualification result precedence: a
304
+ valid closed structured result is accepted even while the session still
305
+ reports `running` / `waiting_for_user`, so a finished informational Devin
306
+ attempt is no longer recorded as owner-blocked. An explicit terminal API
307
+ failure and a `waiting_for_approval` session still take precedence over any
308
+ structured output.
297
309
  Package-only users can start from the public package rather than a source
298
310
  checkout.
299
311
 
@@ -326,7 +338,7 @@ Provider-contract baseline for the next release train:
326
338
 
327
339
  For release verification,
328
340
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
329
- the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
341
+ the package-index procedure for `v1.0.14` / `code-mower==1.0.14`. The
330
342
  GitHub release records the workflow and rehearsal evidence for the exact tag.
331
343
  After publication, [Release Qualification](docs/release-qualification.md)
332
344
  coordinates provider-specific install and operational checks without treating
@@ -520,8 +532,8 @@ measurement work.
520
532
 
521
533
  ## Installation Status
522
534
 
523
- The current package-index release baseline is `v1.0.12`, with pinned package
524
- install spec `code-mower==1.0.12`. Release evidence is recorded on the GitHub
535
+ The current package-index release baseline is `v1.0.14`, with pinned package
536
+ install spec `code-mower==1.0.14`. Release evidence is recorded on the GitHub
525
537
  release and in the first-user install rehearsal. The public repository is
526
538
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
527
539
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -602,6 +614,8 @@ first so local work exercises the same package entrypoint users install.
602
614
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
603
615
  - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
604
616
  - [v1.0.12 Release Notes](docs/v1012-release-notes.md)
617
+ - [v1.0.13 Release Notes](docs/v1013-release-notes.md)
618
+ - [v1.0.14 Release Notes](docs/v1014-release-notes.md)
605
619
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
606
620
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
607
621
  - [Demo Calibration Example](examples/demo-calibration/README.md)
@@ -8,7 +8,7 @@ permissions:
8
8
  contents: read
9
9
 
10
10
  env:
11
- CODE_MOWER_PACKAGE_SPEC: code-mower==1.0.12
11
+ CODE_MOWER_PACKAGE_SPEC: code-mower==1.0.14
12
12
 
13
13
  jobs:
14
14
  auto-record:
@@ -172,6 +172,61 @@ class DevinApiModuleTests(unittest.TestCase):
172
172
  ("failed", None, "devin_session_failed"),
173
173
  )
174
174
 
175
+ def test_poll_accepts_structured_result_while_devin_waits_for_user(self) -> None:
176
+ result = _adoption_result()
177
+ runner = _FakeApiRunner(
178
+ [
179
+ {
180
+ "status": "running",
181
+ "status_detail": "waiting_for_user",
182
+ "structured_output": result,
183
+ }
184
+ ]
185
+ )
186
+
187
+ self.assertEqual(
188
+ devin_api.poll_devin_session(
189
+ "org-test", "devin-1", "key", api_runner=runner
190
+ ),
191
+ ("complete", result, ""),
192
+ )
193
+
194
+ def test_poll_keeps_terminal_failure_ahead_of_structured_output(self) -> None:
195
+ runner = _FakeApiRunner(
196
+ [
197
+ {
198
+ "status": "error",
199
+ "status_detail": "out_of_credits",
200
+ "structured_output": _adoption_result(),
201
+ }
202
+ ]
203
+ )
204
+
205
+ self.assertEqual(
206
+ devin_api.poll_devin_session(
207
+ "org-test", "devin-1", "key", api_runner=runner
208
+ ),
209
+ ("failed", None, "devin_session_failed"),
210
+ )
211
+
212
+ def test_poll_keeps_owner_approval_ahead_of_structured_output(self) -> None:
213
+ runner = _FakeApiRunner(
214
+ [
215
+ {
216
+ "status": "running",
217
+ "status_detail": "waiting_for_approval",
218
+ "structured_output": _adoption_result(),
219
+ }
220
+ ]
221
+ )
222
+
223
+ self.assertEqual(
224
+ devin_api.poll_devin_session(
225
+ "org-test", "devin-1", "key", api_runner=runner
226
+ ),
227
+ ("owner_action", None, "devin_waiting_for_owner"),
228
+ )
229
+
175
230
 
176
231
  class DevinCampaignApiTests(unittest.TestCase):
177
232
  def _campaign(
@@ -12756,6 +12756,78 @@ class RuntimeReadinessCampaignTests(unittest.TestCase):
12756
12756
 
12757
12757
  self.assertEqual(res, (str(python315), "python_3.15"))
12758
12758
 
12759
+ def test_resolve_supported_runtime_prefers_path_runtime_outside_home(self) -> None:
12760
+ with tempfile.TemporaryDirectory() as tmp:
12761
+ root = Path(tmp)
12762
+ home = root / "home"
12763
+ home_python = home / "pipx" / "python3.14"
12764
+ external_bin = root / "toolchain" / "bin"
12765
+ external_python = external_bin / "python3.12"
12766
+ home_python.parent.mkdir(parents=True)
12767
+ external_bin.mkdir(parents=True)
12768
+ home_python.touch()
12769
+ external_python.touch()
12770
+
12771
+ def fake_which(command: str) -> str | None:
12772
+ return str(external_python) if command == "python3.12" else None
12773
+
12774
+ def fake_runner(command: list[str], **kwargs: Any) -> subprocess.CompletedProcess[str]:
12775
+ version = "3.12.9\n" if command[0] == str(external_python) else "3.14.1\n"
12776
+ return subprocess.CompletedProcess(command, 0, stdout=version, stderr="")
12777
+
12778
+ with mock.patch.object(release_campaigns.sys, "executable", str(home_python)):
12779
+ result = release_campaigns.resolve_supported_runtime(
12780
+ environ={"HOME": str(home), "PATH": str(external_bin)},
12781
+ which_fn=fake_which,
12782
+ runner=fake_runner,
12783
+ )
12784
+
12785
+ self.assertEqual(result, (str(external_python), "python_3.12"))
12786
+
12787
+ def test_resolve_supported_runtime_falls_back_to_running_interpreter_in_home(self) -> None:
12788
+ with tempfile.TemporaryDirectory() as tmp:
12789
+ home = Path(tmp) / "home"
12790
+ home_python = home / "pipx" / "python3.14"
12791
+ home_python.parent.mkdir(parents=True)
12792
+ home_python.touch()
12793
+
12794
+ def fake_runner(command: list[str], **kwargs: Any) -> subprocess.CompletedProcess[str]:
12795
+ return subprocess.CompletedProcess(command, 0, stdout="3.14.1\n", stderr="")
12796
+
12797
+ with mock.patch.object(release_campaigns.sys, "executable", str(home_python)):
12798
+ result = release_campaigns.resolve_supported_runtime(
12799
+ environ={"HOME": str(home), "PATH": ""},
12800
+ which_fn=lambda _: None,
12801
+ runner=fake_runner,
12802
+ )
12803
+
12804
+ self.assertEqual(result, (str(home_python), "python_3.14"))
12805
+
12806
+ def test_resolve_supported_runtime_keeps_explicit_home_override_authoritative(self) -> None:
12807
+ with tempfile.TemporaryDirectory() as tmp:
12808
+ home = Path(tmp) / "home"
12809
+ explicit_python = home / "python3.12"
12810
+ external_python = Path(tmp) / "external" / "python3.14"
12811
+ explicit_python.parent.mkdir(parents=True)
12812
+ external_python.parent.mkdir(parents=True)
12813
+ explicit_python.touch()
12814
+ external_python.touch()
12815
+
12816
+ def fake_runner(command: list[str], **kwargs: Any) -> subprocess.CompletedProcess[str]:
12817
+ return subprocess.CompletedProcess(command, 0, stdout="3.12.9\n", stderr="")
12818
+
12819
+ result = release_campaigns.resolve_supported_runtime(
12820
+ environ={
12821
+ "CODE_MOWER_PYTHON": str(explicit_python),
12822
+ "HOME": str(home),
12823
+ "PATH": str(external_python.parent),
12824
+ },
12825
+ which_fn=lambda _: str(external_python),
12826
+ runner=fake_runner,
12827
+ )
12828
+
12829
+ self.assertEqual(result, (str(explicit_python), "python_3.12"))
12830
+
12759
12831
  def test_invoke_local_adapter_fails_closed_when_runtime_unavailable(self) -> None:
12760
12832
  invoked: list[str] = []
12761
12833