code-mower 1.0.10__tar.gz → 1.0.12__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.10 → code_mower-1.0.12}/PKG-INFO +20 -5
  2. {code_mower-1.0.10 → code_mower-1.0.12}/README.md +19 -4
  3. {code_mower-1.0.10 → code_mower-1.0.12}/pyproject.toml +1 -1
  4. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/__init__.py +1 -1
  5. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/campaign_adapters.py +93 -11
  6. code_mower-1.0.12/src/code_mower/devin_api.py +259 -0
  7. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/adoption.py +8 -4
  8. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_install.py +22 -0
  9. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_manifest.py +1 -0
  10. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_registry.py +7 -4
  11. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_campaigns.py +682 -31
  12. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_qualify.py +27 -2
  13. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/providers.yml +8 -1
  14. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  15. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/PKG-INFO +20 -5
  16. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/SOURCES.txt +2 -0
  17. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/devin.yml +8 -1
  18. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers.yml +8 -1
  19. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/builder-provenance.yml.j2 +1 -1
  20. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_adapters.py +173 -0
  21. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_retry_evidence_711.py +5 -4
  22. code_mower-1.0.12/tests/test_devin_api.py +556 -0
  23. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_provider_contract.py +13 -4
  24. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_campaign_readiness.py +16 -10
  25. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_hosted_dispatch_profile.py +52 -30
  26. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_package_install_failure_taxonomy.py +58 -0
  27. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_campaigns.py +142 -86
  28. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_hygiene.py +48 -46
  29. {code_mower-1.0.10 → code_mower-1.0.12}/CODE_OF_CONDUCT.md +0 -0
  30. {code_mower-1.0.10 → code_mower-1.0.12}/LICENSE +0 -0
  31. {code_mower-1.0.10 → code_mower-1.0.12}/MANIFEST.in +0 -0
  32. {code_mower-1.0.10 → code_mower-1.0.12}/NOTICE +0 -0
  33. {code_mower-1.0.10 → code_mower-1.0.12}/SUPPORT.md +0 -0
  34. {code_mower-1.0.10 → code_mower-1.0.12}/requirements/requirements.txt +0 -0
  35. {code_mower-1.0.10 → code_mower-1.0.12}/setup.cfg +0 -0
  36. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/__init__.py +0 -0
  37. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/_base.py +0 -0
  38. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  39. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/gitar.py +0 -0
  40. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/greptile.py +0 -0
  41. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/qodo.py +0 -0
  42. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  43. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/antigravity_sdk_probe.py +0 -0
  44. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_handoff_log.py +0 -0
  45. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_labeler_lib.py +0 -0
  46. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_limits.py +0 -0
  47. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_progress.py +0 -0
  48. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/blind_review_artifacts.py +0 -0
  49. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/blind_review_coordinator.py +0 -0
  50. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/board.py +0 -0
  51. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/board_store.py +0 -0
  52. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/bootstrap.py +0 -0
  53. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/builder_experiment.py +0 -0
  54. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/builder_runs.py +0 -0
  55. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/__init__.py +0 -0
  56. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/arms.py +0 -0
  57. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/auto_discovery.py +0 -0
  58. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/commands.py +0 -0
  59. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/context_inputs.py +0 -0
  60. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/corpus.py +0 -0
  61. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/effect_report.py +0 -0
  62. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/evidence.py +0 -0
  63. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/evidence_report.py +0 -0
  64. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/identity.py +0 -0
  65. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/metrics.py +0 -0
  66. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/overlap.py +0 -0
  67. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/planning.py +0 -0
  68. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/policy.py +0 -0
  69. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/results.py +0 -0
  70. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/run_results.py +0 -0
  71. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/run_status.py +0 -0
  72. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/runner.py +0 -0
  73. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/truth.py +0 -0
  74. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/value_report.py +0 -0
  75. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/campaign_discovery.py +0 -0
  76. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/checks.py +0 -0
  77. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_audit_pr.py +0 -0
  78. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_cli_bounce.py +0 -0
  79. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_cli_environment.py +0 -0
  80. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/clear_stale.py +0 -0
  81. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cli.py +0 -0
  82. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud.py +0 -0
  83. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/__init__.py +0 -0
  84. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/adoption_runs.py +0 -0
  85. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/bundle.py +0 -0
  86. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/doctor.py +0 -0
  87. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/dogfood.py +0 -0
  88. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/endpoints.py +0 -0
  89. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/errors.py +0 -0
  90. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/events.py +0 -0
  91. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/export.py +0 -0
  92. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/git_metadata.py +0 -0
  93. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/manifest.py +0 -0
  94. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/operations.py +0 -0
  95. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/pr_outcomes.py +0 -0
  96. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/productivity.py +0 -0
  97. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/reports.py +0 -0
  98. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/setup.py +0 -0
  99. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/tokens.py +0 -0
  100. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/upload.py +0 -0
  101. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/work_types.py +0 -0
  102. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_calibration.py +0 -0
  103. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_context_packs.py +0 -0
  104. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_merge.py +0 -0
  105. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_telemetry.py +0 -0
  106. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  107. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_env_preflight.py +0 -0
  108. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_pr.py +0 -0
  109. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  110. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  111. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/config.py +0 -0
  112. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/controller.py +0 -0
  113. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/decisions.py +0 -0
  114. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/devin_cli_audit_pr.py +0 -0
  115. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor.py +0 -0
  116. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/__init__.py +0 -0
  117. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  118. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/campaign_auth.py +0 -0
  119. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/cloud.py +0 -0
  120. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/common.py +0 -0
  121. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github.py +0 -0
  122. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions.py +0 -0
  123. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  124. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  125. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  126. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  127. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  128. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  129. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  130. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  131. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_api.py +0 -0
  132. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_branch.py +0 -0
  133. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_config.py +0 -0
  134. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_human_token.py +0 -0
  135. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_provider.py +0 -0
  136. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_repo.py +0 -0
  137. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_trusted_authors.py +0 -0
  138. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/groups.py +0 -0
  139. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/models.py +0 -0
  140. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/output.py +0 -0
  141. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/presets.py +0 -0
  142. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/privacy.py +0 -0
  143. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  144. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  145. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  146. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env.py +0 -0
  147. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  148. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  149. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  150. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  151. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  152. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  153. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  154. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  155. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  156. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  157. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  158. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  159. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/providers.py +0 -0
  160. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/registry.py +0 -0
  161. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runner.py +0 -0
  162. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runtime.py +0 -0
  163. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  164. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
  165. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/supervised_pilot.py +0 -0
  166. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/file_locks.py +0 -0
  167. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/gate_health.py +0 -0
  168. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  169. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/git_identity.py +0 -0
  170. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/grok_build_audit_pr.py +0 -0
  171. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  172. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/init.py +0 -0
  173. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/__init__.py +0 -0
  174. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/aider.py +0 -0
  175. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  176. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/claude.py +0 -0
  177. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/codex.py +0 -0
  178. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/devin.py +0 -0
  179. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/devin_cli.py +0 -0
  180. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  181. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/grok_build.py +0 -0
  182. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  183. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/local_llm.py +0 -0
  184. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/muse_cli.py +0 -0
  185. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_delivery.py +0 -0
  186. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_status.py +0 -0
  187. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_audit_pr.py +0 -0
  188. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_bakeoff.py +0 -0
  189. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_calibration.py +0 -0
  190. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_profiles.py +0 -0
  191. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration.py +0 -0
  192. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_mirror.py +0 -0
  193. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_readiness.py +0 -0
  194. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_rehearsal.py +0 -0
  195. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/muse_cli_audit_pr.py +0 -0
  196. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/next_steps.py +0 -0
  197. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package.py +0 -0
  198. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_content.py +0 -0
  199. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_paths.py +0 -0
  200. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_rendering.py +0 -0
  201. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_static.py +0 -0
  202. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/participants.py +0 -0
  203. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/plan_context.py +0 -0
  204. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/productivity_report.py +0 -0
  205. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/prompts.py +0 -0
  206. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/__init__.py +0 -0
  207. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/comments.py +0 -0
  208. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/exit_codes.py +0 -0
  209. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/git.py +0 -0
  210. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/github_auth.py +0 -0
  211. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/github_pr.py +0 -0
  212. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  213. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/process.py +0 -0
  214. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/repo_paths.py +0 -0
  215. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/text_schema.py +0 -0
  216. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  217. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/workspace.py +0 -0
  218. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/__init__.py +0 -0
  219. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/local_cli.py +0 -0
  220. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/provenance.py +0 -0
  221. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_readiness.py +0 -0
  222. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/reviewer_metrics.py +0 -0
  223. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/reviewer_spend.py +0 -0
  224. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/saas_reviewer_labeler.py +0 -0
  225. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/secrets.py +0 -0
  226. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/session.py +0 -0
  227. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/builder-experiment.example.json +0 -0
  228. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  229. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/calibration-corpus.json +0 -0
  230. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/code-mower.example.yml +0 -0
  231. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/context-packs.example.json +0 -0
  232. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  233. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  234. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  235. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  236. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  237. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  238. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  239. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  240. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  241. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/README.md +0 -0
  242. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/claude.md +0 -0
  243. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/codex.md +0 -0
  244. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/cursor.md +0 -0
  245. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/devin.md +0 -0
  246. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/generic.md +0 -0
  247. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
  248. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower +0 -0
  249. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  250. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  251. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  252. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  253. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_devin_cli_audit_pr.sh +0 -0
  254. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  255. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/status_report.py +0 -0
  256. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  257. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  258. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  259. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  260. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  261. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  262. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  263. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  264. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  265. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  266. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  267. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  268. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  269. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  270. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  271. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  272. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  273. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  274. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/trailer_comment_labeler.py +0 -0
  275. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/versioning.py +0 -0
  276. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/work_orders.py +0 -0
  277. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/workflow_actionlint.py +0 -0
  278. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/dependency_links.txt +0 -0
  279. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/entry_points.txt +0 -0
  280. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/requires.txt +0 -0
  281. {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/top_level.txt +0 -0
  282. {code_mower-1.0.10 → code_mower-1.0.12}/templates/builder-experiment.example.json +0 -0
  283. {code_mower-1.0.10 → code_mower-1.0.12}/templates/calibration-corpus.example.json +0 -0
  284. {code_mower-1.0.10 → code_mower-1.0.12}/templates/calibration-corpus.json +0 -0
  285. {code_mower-1.0.10 → code_mower-1.0.12}/templates/code-mower.yml.j2 +0 -0
  286. {code_mower-1.0.10 → code_mower-1.0.12}/templates/context-packs.example.json +0 -0
  287. {code_mower-1.0.10 → code_mower-1.0.12}/templates/cursor/BUGBOT.md +0 -0
  288. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/README.md +0 -0
  289. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/claude.md +0 -0
  290. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/codex.md +0 -0
  291. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/cursor.md +0 -0
  292. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/devin.md +0 -0
  293. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/generic.md +0 -0
  294. {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/run_mac_lane.sh +0 -0
  295. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/acp_bridge.yml +0 -0
  296. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/aider.yml +0 -0
  297. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/antigravity_cli.yml +0 -0
  298. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/claude_audit.yml +0 -0
  299. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/claude_review.yml +0 -0
  300. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/coderabbit_cli.yml +0 -0
  301. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/codex.yml +0 -0
  302. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/cursor_bugbot.yml +0 -0
  303. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/cursor_cloud_agent.yml +0 -0
  304. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/devin_cli.yml +0 -0
  305. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/gemini_cli.yml +0 -0
  306. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/gitar.yml +0 -0
  307. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/greptile.yml +0 -0
  308. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/hermes_cli.yml +0 -0
  309. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/local_llm.yml +0 -0
  310. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/muse_cli.yml +0 -0
  311. {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/qodo.yml +0 -0
  312. {code_mower-1.0.10 → code_mower-1.0.12}/templates/reviewer-spend.example.json +0 -0
  313. {code_mower-1.0.10 → code_mower-1.0.12}/templates/reviewer-value-report.example.md +0 -0
  314. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  315. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  316. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  317. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  318. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  319. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  320. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  321. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  322. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  323. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  324. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  325. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  326. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  327. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  328. {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  329. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_diagnostics.py +0 -0
  330. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_result_semantics.py +0 -0
  331. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_run_contract.py +0 -0
  332. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_antigravity_sdk_probe.py +0 -0
  333. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_audit_comment_posture.py +0 -0
  334. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_audit_limits.py +0 -0
  335. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_board.py +0 -0
  336. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_experiment.py +0 -0
  337. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_identity.py +0 -0
  338. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_runs.py +0 -0
  339. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_calibration_effect_report.py +0 -0
  340. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_calibration_truth.py +0 -0
  341. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_discovery.py +0 -0
  342. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_checks.py +0 -0
  343. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_claude_audit_pr.py +0 -0
  344. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_claude_cli_bounce.py +0 -0
  345. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_clear_stale.py +0 -0
  346. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_client.py +0 -0
  347. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_git_metadata.py +0 -0
  348. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_manifest.py +0 -0
  349. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_reports.py +0 -0
  350. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  351. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_codex_audit_env_preflight.py +0 -0
  352. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_codex_audit_pr.py +0 -0
  353. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_controller.py +0 -0
  354. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_decision_audit_integration.py +0 -0
  355. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_decisions.py +0 -0
  356. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_builder_lane.py +0 -0
  357. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_cli_audit_pr.py +0 -0
  358. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_actions_cost_summary.py +0 -0
  359. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_actions_failure_selection.py +0 -0
  360. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_boundaries.py +0 -0
  361. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_campaign_auth.py +0 -0
  362. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_github_checks.py +0 -0
  363. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_output.py +0 -0
  364. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_privacy.py +0 -0
  365. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_env_required.py +0 -0
  366. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_env_tokens.py +0 -0
  367. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  368. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_probe.py +0 -0
  369. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_review_hygiene.py +0 -0
  370. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_registry.py +0 -0
  371. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_runtime.py +0 -0
  372. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_self_hosted_runner.py +0 -0
  373. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_supervised_pilot.py +0 -0
  374. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_file_locks.py +0 -0
  375. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_fork_pr_guard.py +0 -0
  376. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_gate_automerge.py +0 -0
  377. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_gate_health.py +0 -0
  378. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_init_actionlint.py +0 -0
  379. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_init_build_loop.py +0 -0
  380. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_lane_delivery_contract.py +0 -0
  381. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_lane_status.py +0 -0
  382. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_local_llm_github_helpers.py +0 -0
  383. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_migration_rehearsal.py +0 -0
  384. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_migration_setup_drift.py +0 -0
  385. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_next_steps.py +0 -0
  386. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_participant_sessions.py +0 -0
  387. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_plan_context.py +0 -0
  388. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_pr_outcome_contract.py +0 -0
  389. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_productivity_metrics_contract.py +0 -0
  390. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_productivity_report.py +0 -0
  391. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_prompts.py +0 -0
  392. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_fixture_contracts.py +0 -0
  393. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_local_cli.py +0 -0
  394. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_comments.py +0 -0
  395. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_git.py +0 -0
  396. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_github_pr.py +0 -0
  397. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_pr_worktree.py +0 -0
  398. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_process.py +0 -0
  399. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_repo_paths.py +0 -0
  400. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_text_schema.py +0 -0
  401. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_workspace.py +0 -0
  402. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_qualify.py +0 -0
  403. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_reviewer_metrics_core.py +0 -0
  404. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_reviewer_spend.py +0 -0
  405. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_supervised_pilot_contract.py +0 -0
  406. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_trailer_comment_labeler.py +0 -0
  407. {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_work_orders.py +0 -0
  408. {code_mower-1.0.10 → code_mower-1.0.12}/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.10
3
+ Version: 1.0.12
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.10/docs/try-in-10-minutes.md)
244
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/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
@@ -285,6 +285,15 @@ provider-neutral delivery contract with bounded no-change and owner-action
285
285
  outcomes, process-group cleanup so a finished provider is not reported as a
286
286
  timeout, simpler first-run defaults, host-led participant sessions, and a
287
287
  published 20-sample provider calibration scorecard.
288
+ The v1.0.11 patch moves canonical hosted Devin release campaigns onto the
289
+ bounded, pollable Sessions API transport and keeps macOS Claude release
290
+ qualification inside the maintained strict sandbox by using pip's
291
+ TLS-verifying certifi certificate path.
292
+ The v1.0.12 patch completes that Claude qualification fix: the maintained
293
+ provider qualification prompt no longer tells the agent to create its own
294
+ temporary directory, so it stays in the disposable workspace Code Mower
295
+ already created, and it states the existing contract that a result's total
296
+ `elapsed_seconds` is the sum of its step values.
288
297
  Package-only users can start from the public package rather than a source
289
298
  checkout.
290
299
 
@@ -317,7 +326,7 @@ Provider-contract baseline for the next release train:
317
326
 
318
327
  For release verification,
319
328
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
320
- the package-index procedure for `v1.0.10` / `code-mower==1.0.10`. The
329
+ the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
321
330
  GitHub release records the workflow and rehearsal evidence for the exact tag.
322
331
  After publication, [Release Qualification](docs/release-qualification.md)
323
332
  coordinates provider-specific install and operational checks without treating
@@ -472,6 +481,10 @@ or informational until your own calibration data proves it is useful: Gitar,
472
481
  Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
473
482
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
474
483
 
484
+ Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
485
+ `DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
486
+ in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
487
+
475
488
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
476
489
  surfaces and may use Gemini model infrastructure. Keep their auth, model
477
490
  provenance, calibration evidence, and release notes separate.
@@ -507,8 +520,8 @@ measurement work.
507
520
 
508
521
  ## Installation Status
509
522
 
510
- The current package-index release baseline is `v1.0.10`, with pinned package
511
- install spec `code-mower==1.0.10`. Release evidence is recorded on the GitHub
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
512
525
  release and in the first-user install rehearsal. The public repository is
513
526
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
514
527
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -587,6 +600,8 @@ first so local work exercises the same package entrypoint users install.
587
600
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
588
601
  - [v1.0.9 Release Notes](docs/v109-release-notes.md)
589
602
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
603
+ - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
604
+ - [v1.0.12 Release Notes](docs/v1012-release-notes.md)
590
605
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
591
606
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
592
607
  - [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.10/docs/try-in-10-minutes.md)
214
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/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
@@ -255,6 +255,15 @@ provider-neutral delivery contract with bounded no-change and owner-action
255
255
  outcomes, process-group cleanup so a finished provider is not reported as a
256
256
  timeout, simpler first-run defaults, host-led participant sessions, and a
257
257
  published 20-sample provider calibration scorecard.
258
+ The v1.0.11 patch moves canonical hosted Devin release campaigns onto the
259
+ bounded, pollable Sessions API transport and keeps macOS Claude release
260
+ qualification inside the maintained strict sandbox by using pip's
261
+ TLS-verifying certifi certificate path.
262
+ The v1.0.12 patch completes that Claude qualification fix: the maintained
263
+ provider qualification prompt no longer tells the agent to create its own
264
+ temporary directory, so it stays in the disposable workspace Code Mower
265
+ already created, and it states the existing contract that a result's total
266
+ `elapsed_seconds` is the sum of its step values.
258
267
  Package-only users can start from the public package rather than a source
259
268
  checkout.
260
269
 
@@ -287,7 +296,7 @@ Provider-contract baseline for the next release train:
287
296
 
288
297
  For release verification,
289
298
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
290
- the package-index procedure for `v1.0.10` / `code-mower==1.0.10`. The
299
+ the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
291
300
  GitHub release records the workflow and rehearsal evidence for the exact tag.
292
301
  After publication, [Release Qualification](docs/release-qualification.md)
293
302
  coordinates provider-specific install and operational checks without treating
@@ -442,6 +451,10 @@ or informational until your own calibration data proves it is useful: Gitar,
442
451
  Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
443
452
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
444
453
 
454
+ Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
455
+ `DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
456
+ in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
457
+
445
458
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
446
459
  surfaces and may use Gemini model infrastructure. Keep their auth, model
447
460
  provenance, calibration evidence, and release notes separate.
@@ -477,8 +490,8 @@ measurement work.
477
490
 
478
491
  ## Installation Status
479
492
 
480
- The current package-index release baseline is `v1.0.10`, with pinned package
481
- install spec `code-mower==1.0.10`. Release evidence is recorded on the GitHub
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
482
495
  release and in the first-user install rehearsal. The public repository is
483
496
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
484
497
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -557,6 +570,8 @@ first so local work exercises the same package entrypoint users install.
557
570
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
558
571
  - [v1.0.9 Release Notes](docs/v109-release-notes.md)
559
572
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
573
+ - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
574
+ - [v1.0.12 Release Notes](docs/v1012-release-notes.md)
560
575
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
561
576
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
562
577
  - [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.10"
7
+ version = "1.0.12"
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.10"
3
+ __version__ = "1.0.12"
@@ -57,6 +57,7 @@ import argparse
57
57
  import copy
58
58
  import json
59
59
  import os
60
+ import platform
60
61
  import shlex
61
62
  import shutil
62
63
  import subprocess
@@ -174,6 +175,58 @@ def _claude_sandbox_settings(package_source: str) -> dict[str, Any]:
174
175
  "network": {"allowedDomains": list(allowed_domains)},
175
176
  },
176
177
  }
178
+
179
+
180
+ #: Strips ambient pip configuration from the disposable qualification install:
181
+ #: no inherited index URLs, no user/site pip configuration file, and pip's own
182
+ #: ``--isolated`` mode for every other ambient setting.
183
+ PIP_AMBIENT_CONFIG_STRIP = "env -u PIP_INDEX_URL -u PIP_EXTRA_INDEX_URL PIP_CONFIG_FILE=/dev/null"
184
+ PIP_ISOLATED_BASE = f"{PIP_AMBIENT_CONFIG_STRIP} .venv/bin/python -m pip --isolated"
185
+ PIP_DEFAULT_BASE = ".venv/bin/python -m pip"
186
+ #: pip 24.2+ verifies certificates through the platform trust store. On macOS
187
+ #: that path calls Security.framework, which the maintained strict Claude OS
188
+ #: sandbox denies (``OSStatus -26276``) even with the package index allowlisted.
189
+ #: ``legacy-certs`` keeps TLS verification fully enabled: it only moves pip back
190
+ #: to its bundled certifi trust store, which needs no Security.framework call.
191
+ PIP_LEGACY_CERTS_FLAG = "--use-deprecated=legacy-certs"
192
+
193
+
194
+ def claude_macos_certificate_path_required(provider: str, *, platform_system: str = "") -> bool:
195
+ """True only for a Claude campaign run on macOS.
196
+
197
+ This is the exact scope of the upstream Claude Code macOS sandbox
198
+ certificate-validation defect. Linux Claude runs and every other provider
199
+ keep pip's default certificate path.
200
+ """
201
+ system = platform_system or platform.system()
202
+ return provider == "claude" and system.strip().lower() == "darwin"
203
+
204
+
205
+ def build_qualification_pip_command(
206
+ *,
207
+ provider: str,
208
+ package_source: str = DEFAULT_PACKAGE_SOURCE,
209
+ platform_system: str = "",
210
+ ) -> str:
211
+ """Return the pip command the qualification prompt tells the agent to run.
212
+
213
+ A macOS Claude run always gets the ambient-configuration strip as well as
214
+ :data:`PIP_LEGACY_CERTS_FLAG`, so the certificate path is chosen by this
215
+ adapter rather than by whatever pip configuration happens to be on the
216
+ host.
217
+ """
218
+ legacy_certs = claude_macos_certificate_path_required(
219
+ provider, platform_system=platform_system
220
+ )
221
+ if package_source == "testpypi" or legacy_certs:
222
+ command = PIP_ISOLATED_BASE
223
+ else:
224
+ command = PIP_DEFAULT_BASE
225
+ if legacy_certs:
226
+ command = f"{command} {PIP_LEGACY_CERTS_FLAG}"
227
+ return command
228
+
229
+
177
230
  ANTIGRAVITY_MODEL_ENV_NAMES = ("CODE_MOWER_ANTIGRAVITY_MODEL", "ANTIGRAVITY_MODEL")
178
231
  ANTIGRAVITY_AMBIENT_HOME_ENV = "ANTIGRAVITY_CLI_USE_AMBIENT_HOME"
179
232
  MUSE_MODEL_ENV_NAMES = ("CODE_MOWER_MUSE_MODEL", "MUSE_MODEL", "META_MUSE_MODEL")
@@ -385,6 +438,7 @@ def build_qualification_prompt(
385
438
  package_source: str = DEFAULT_PACKAGE_SOURCE,
386
439
  python_bin: str = "python3",
387
440
  target_runtime: str = "",
441
+ platform_system: str = "",
388
442
  ) -> str:
389
443
  """Build the shared release-qualification prompt for one provider run.
390
444
 
@@ -394,14 +448,19 @@ def build_qualification_prompt(
394
448
  directory it creates itself. ``package_source`` is the closed vocabulary
395
449
  (``pypi``/``testpypi``); when it is ``testpypi`` the prompt keeps candidate
396
450
  retrieval exclusive to TestPyPI and dependency resolution exclusive to
397
- production PyPI.
451
+ production PyPI. ``platform_system`` defaults to the running host and
452
+ exists so the macOS-only Claude certificate path is testable off macOS.
398
453
  """
399
454
  python_cmd = shlex.quote(python_bin or "python3")
455
+ legacy_certs = claude_macos_certificate_path_required(
456
+ provider, platform_system=platform_system
457
+ )
458
+ pip = build_qualification_pip_command(
459
+ provider=provider,
460
+ package_source=package_source,
461
+ platform_system=platform_system,
462
+ )
400
463
  if package_source == "testpypi":
401
- pip = (
402
- "env -u PIP_INDEX_URL -u PIP_EXTRA_INDEX_URL PIP_CONFIG_FILE=/dev/null "
403
- ".venv/bin/python -m pip --isolated"
404
- )
405
464
  steps = [
406
465
  "1. In the current disposable directory, run "
407
466
  f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
@@ -438,11 +497,11 @@ def build_qualification_prompt(
438
497
  "1. In the current disposable directory, run "
439
498
  f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
440
499
  "entry points for the remaining steps.\n"
441
- f"2. Install the starting version with `.venv/bin/python -m pip install"
500
+ f"2. Install the starting version with `{pip} install"
442
501
  " "
443
502
  f"{package_identity}=={starting_version}` to rehearse "
444
503
  f"an upgrade from exactly that version.\n"
445
- f'3. Upgrade with `.venv/bin/python -m pip install "{package_spec}"`.'
504
+ f'3. Upgrade with `{pip} install "{package_spec}"`.'
446
505
  )
447
506
  verification_step = 4
448
507
  else:
@@ -450,14 +509,15 @@ def build_qualification_prompt(
450
509
  "1. In the current disposable directory, run "
451
510
  f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
452
511
  "entry points for the remaining steps.\n"
453
- f"2. Install the exact release with `.venv/bin/python -m pip install"
512
+ f"2. Install the exact release with `{pip} install"
454
513
  f' "{package_spec}"`. No other version is acceptable.'
455
514
  )
456
515
  verification_step = 4
457
516
  lines = [
458
517
  f"You are the {provider} release-qualification agent for Code Mower.",
459
- "Qualify exactly one release in a disposable environment you create.",
460
- "Do all work inside a fresh temporary directory; do not read or modify",
518
+ "Qualify exactly one release in the current disposable workspace.",
519
+ "Code Mower already created this workspace; do not create or change into",
520
+ "another temporary directory. Do not read or modify",
461
521
  "any existing checkout, home directory, credential file, or environment",
462
522
  "variable holding a secret. Never print secrets, tokens, file paths,",
463
523
  "commands you ran, or raw logs in your final answer.",
@@ -472,6 +532,27 @@ def build_qualification_prompt(
472
532
  "run and any call to them ends the session without a result.",
473
533
  ]
474
534
  )
535
+ if legacy_certs:
536
+ # macOS-only Claude sandbox defect: pip's default trust store calls
537
+ # Security.framework, which this sandbox denies (OSStatus -26276).
538
+ lines.extend(
539
+ [
540
+ "Every pip command in the procedure below already carries "
541
+ f"`{PIP_LEGACY_CERTS_FLAG}`, because pip's default macOS trust",
542
+ "store is unreachable from this sandbox. Certificate verification",
543
+ "stays fully enabled; only the trust store changes. If this pip",
544
+ "build rejects that option as an invalid choice, rerun the identical",
545
+ "command without it and change nothing else. Never add",
546
+ "`--trusted-host`, never disable or skip TLS verification, and never",
547
+ "run any command outside the sandbox. If an install still fails",
548
+ "certificate verification, report the `package_install` step with",
549
+ "`failure_reason` `network`: a certificate-validation failure is",
550
+ "always `network`, never `sandbox_permission` and never",
551
+ "`package_index`. Use `package_index` only for an index response",
552
+ "that is not a certificate failure, such as a 404 or a missing",
553
+ "version.",
554
+ ]
555
+ )
475
556
  lines.extend(
476
557
  [
477
558
  "",
@@ -532,7 +613,8 @@ def build_qualification_prompt(
532
613
  "the step status strings: fail if any status is fail;",
533
614
  "pass_with_warnings if any status is warn or unavailable; otherwise",
534
615
  "pass. In particular, all-pass steps require outcome pass. No extra",
535
- "fields, no prose, no fences.",
616
+ "fields, no prose, no fences. Set total elapsed_seconds to the sum of",
617
+ "the step elapsed_seconds values (within one second for rounding).",
536
618
  ])
537
619
  return "\n".join(lines) + "\n"
538
620
 
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env python3
2
+ """Bounded Devin Sessions API v3 transport for release campaigns."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import copy
7
+ import hashlib
8
+ import json
9
+ import os
10
+ import re
11
+ import socket
12
+ import urllib.error
13
+ import urllib.request
14
+ from typing import Any, Callable, Mapping
15
+
16
+ from .campaign_adapters import (
17
+ ADOPTION_RESULT_JSON_SCHEMA,
18
+ DEFAULT_PACKAGE_SOURCE,
19
+ build_qualification_prompt,
20
+ )
21
+
22
+ API_BASE = "https://api.devin.ai"
23
+ DEVIN_API_KEY_ENV = "DEVIN_API_KEY"
24
+ DEVIN_ORG_ID_ENV = "DEVIN_ORG_ID"
25
+ DEVIN_REPOSITORIES_ENV = "CODE_MOWER_DEVIN_REPOSITORIES"
26
+ REQUEST_TIMEOUT_SECONDS = 30.0
27
+ MAX_RESPONSE_BYTES = 512 * 1024
28
+
29
+ _ORG_ID_RE = re.compile(r"^org-[A-Za-z0-9_-]+$")
30
+ # Session ids are opaque API references. Accept any bounded RFC 3986
31
+ # unreserved token instead of assuming Devin will retain one prefix forever.
32
+ _SESSION_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$")
33
+ _REPO_RE = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$")
34
+
35
+ SAFE_ERROR_CODES = frozenset(
36
+ {
37
+ "devin_api_rejected",
38
+ "devin_api_unavailable",
39
+ "devin_session_failed",
40
+ "devin_waiting_for_owner",
41
+ "hosted_result_rejected",
42
+ }
43
+ )
44
+
45
+ ApiRunner = Callable[[str, str, Mapping[str, Any] | None, Mapping[str, str]], Any]
46
+
47
+
48
+ class DevinApiError(Exception):
49
+ """API failure carrying only a closed, persistence-safe reason code."""
50
+
51
+ def __init__(self, code: str) -> None:
52
+ self.code = code if code in SAFE_ERROR_CODES else "devin_api_unavailable"
53
+ super().__init__(self.code)
54
+
55
+
56
+ def _validate_org_id(org_id: str) -> bool:
57
+ return bool(_ORG_ID_RE.fullmatch(org_id))
58
+
59
+
60
+ def _validate_session_id(session_id: str) -> bool:
61
+ return bool(_SESSION_ID_RE.fullmatch(session_id))
62
+
63
+
64
+ def repository_scope_acknowledged(
65
+ repo_slug: str,
66
+ *,
67
+ env: Mapping[str, str] | None = None,
68
+ ) -> bool:
69
+ """Require an exact local acknowledgement for the requested GitHub repo.
70
+
71
+ Devin v3 accepts an exact ``repos`` list on create but exposes no read-only
72
+ endpoint that proves GitHub connection scope before paid work starts. This
73
+ local acknowledgement closes that gap. The full configured inventory is
74
+ never returned, printed, persisted, or uploaded.
75
+ """
76
+ if not _REPO_RE.fullmatch(repo_slug):
77
+ return False
78
+ current_env = os.environ if env is None else env
79
+ configured = {
80
+ item.strip().casefold()
81
+ for item in str(current_env.get(DEVIN_REPOSITORIES_ENV) or "").split(",")
82
+ if item.strip()
83
+ }
84
+ return repo_slug.casefold() in configured
85
+
86
+
87
+ def credentials_from_env(
88
+ env: Mapping[str, str] | None = None,
89
+ ) -> tuple[str, str, str]:
90
+ """Return ``(api_key, org_id, missing_variable)`` without logging values."""
91
+ current_env = os.environ if env is None else env
92
+ api_key = str(current_env.get(DEVIN_API_KEY_ENV) or "").strip()
93
+ org_id = str(current_env.get(DEVIN_ORG_ID_ENV) or "").strip()
94
+ if not api_key:
95
+ return "", "", DEVIN_API_KEY_ENV
96
+ if not org_id:
97
+ return "", "", DEVIN_ORG_ID_ENV
98
+ if not _validate_org_id(org_id):
99
+ return "", "", DEVIN_ORG_ID_ENV
100
+ return api_key, org_id, ""
101
+
102
+
103
+ def make_api_request(
104
+ method: str,
105
+ path: str,
106
+ api_key: str,
107
+ body: Mapping[str, Any] | None = None,
108
+ *,
109
+ api_runner: ApiRunner | None = None,
110
+ request_timeout: float = REQUEST_TIMEOUT_SECONDS,
111
+ ) -> dict[str, Any]:
112
+ """Make one request and return a bounded JSON object.
113
+
114
+ The injected runner keeps tests entirely offline. Raw error bodies and
115
+ exception messages never cross this boundary.
116
+ """
117
+ url = f"{API_BASE}{path}"
118
+ headers = {"Authorization": f"Bearer {api_key}", "Accept": "application/json"}
119
+ if body is not None:
120
+ headers["Content-Type"] = "application/json"
121
+ try:
122
+ if api_runner is not None:
123
+ value = api_runner(method, url, body, headers)
124
+ else:
125
+ encoded = (
126
+ json.dumps(dict(body), separators=(",", ":")).encode("utf-8")
127
+ if body is not None
128
+ else None
129
+ )
130
+ request = urllib.request.Request(url, data=encoded, headers=headers, method=method)
131
+ with urllib.request.urlopen(request, timeout=request_timeout) as response:
132
+ raw = response.read(MAX_RESPONSE_BYTES + 1)
133
+ if len(raw) > MAX_RESPONSE_BYTES:
134
+ raise DevinApiError("devin_api_unavailable")
135
+ value = json.loads(raw.decode("utf-8"))
136
+ except DevinApiError:
137
+ raise
138
+ except urllib.error.HTTPError as exc:
139
+ code = "devin_api_rejected" if 400 <= exc.code < 500 else "devin_api_unavailable"
140
+ raise DevinApiError(code) from exc
141
+ except (urllib.error.URLError, socket.timeout, TimeoutError, OSError, ValueError) as exc:
142
+ raise DevinApiError("devin_api_unavailable") from exc
143
+ if not isinstance(value, dict):
144
+ raise DevinApiError("devin_api_unavailable")
145
+ return dict(value)
146
+
147
+
148
+ def build_devin_session_payload(
149
+ *,
150
+ campaign_id: str,
151
+ release_tag: str,
152
+ package_spec: str,
153
+ package_identity: str,
154
+ normalized_version: str,
155
+ qualification_context: str,
156
+ starting_version: str,
157
+ repo_slug: str,
158
+ package_source: str = DEFAULT_PACKAGE_SOURCE,
159
+ target_runtime: str = "",
160
+ ) -> dict[str, Any]:
161
+ """Build the exact-repo create body using Devin's v3 field names."""
162
+ if not _REPO_RE.fullmatch(repo_slug):
163
+ raise ValueError("repo_slug must be OWNER/REPO")
164
+ prompt = build_qualification_prompt(
165
+ provider="devin",
166
+ release_tag=release_tag,
167
+ package_spec=package_spec,
168
+ package_identity=package_identity,
169
+ normalized_version=normalized_version,
170
+ qualification_context=qualification_context,
171
+ starting_version=starting_version,
172
+ package_source=package_source,
173
+ python_bin="python3",
174
+ target_runtime=target_runtime,
175
+ )
176
+ reconciliation_tag = hashlib.sha256(
177
+ f"{campaign_id}:{release_tag}:{repo_slug}".encode("utf-8")
178
+ ).hexdigest()[:16]
179
+ return {
180
+ "prompt": prompt,
181
+ "repos": [repo_slug],
182
+ "structured_output_required": True,
183
+ "structured_output_schema": copy.deepcopy(ADOPTION_RESULT_JSON_SCHEMA),
184
+ "tags": ["code-mower", "release-qualification", f"cm-{reconciliation_tag}"],
185
+ "title": f"Code Mower {release_tag} qualification"[:128],
186
+ }
187
+
188
+
189
+ def create_devin_session(
190
+ org_id: str,
191
+ payload: Mapping[str, Any],
192
+ api_key: str,
193
+ *,
194
+ api_runner: ApiRunner | None = None,
195
+ ) -> tuple[str, str]:
196
+ """Create one paid session, returning a bounded reason on failure."""
197
+ if not _validate_org_id(org_id):
198
+ return "", "devin_api_rejected"
199
+ try:
200
+ data = make_api_request(
201
+ "POST",
202
+ f"/v3/organizations/{org_id}/sessions",
203
+ api_key,
204
+ payload,
205
+ api_runner=api_runner,
206
+ )
207
+ except DevinApiError as exc:
208
+ return "", exc.code
209
+ session_id = data.get("session_id")
210
+ if not isinstance(session_id, str) or not _validate_session_id(session_id):
211
+ return "", "devin_api_unavailable"
212
+ return session_id, ""
213
+
214
+
215
+ def poll_devin_session(
216
+ org_id: str,
217
+ session_id: str,
218
+ api_key: str,
219
+ *,
220
+ api_runner: ApiRunner | None = None,
221
+ ) -> tuple[str, dict[str, Any] | None, str]:
222
+ """Read one session snapshot.
223
+
224
+ Returns ``(state, structured_output, reason)`` where state is one of
225
+ ``running``, ``complete``, ``owner_action``, or ``failed``. Campaign watch
226
+ owns repeated polling and the one-hour deadline.
227
+ """
228
+ if not _validate_org_id(org_id) or not _validate_session_id(session_id):
229
+ return "failed", None, "devin_api_rejected"
230
+ try:
231
+ data = make_api_request(
232
+ "GET",
233
+ f"/v3/organizations/{org_id}/sessions/{session_id}",
234
+ api_key,
235
+ api_runner=api_runner,
236
+ )
237
+ except DevinApiError as exc:
238
+ return "failed", None, exc.code
239
+ status = str(data.get("status") or "")
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
+ if status in {"error", "suspended"} or detail in {
249
+ "error",
250
+ "usage_limit_exceeded",
251
+ "out_of_credits",
252
+ "out_of_quota",
253
+ "no_quota_allocation",
254
+ "payment_declined",
255
+ "org_usage_limit_exceeded",
256
+ "total_session_limit_exceeded",
257
+ }:
258
+ return "failed", None, "devin_session_failed"
259
+ return "running", None, ""
@@ -933,12 +933,12 @@ def check_adoption_campaign_readiness(
933
933
  elif lane.driver in {"hosted_bridge", "saas_event"}:
934
934
  has_credentials, missing_var = _check_credentials(lane, env=current_env)
935
935
  transport_ready, transport_var = _check_hosted_transport(
936
- lane, env=current_env
936
+ lane, env=current_env, repo_slug=repo_slug
937
937
  )
938
938
  # Closed dispatch profile: auth, installation, trigger,
939
939
  # trusted responder, and result return are reported
940
940
  # independently, so one verified dimension never masks another.
941
- dispatch_profile = hosted_dispatch_profile(lane, env=current_env)
941
+ dispatch_profile = hosted_dispatch_profile(lane, env=current_env, repo_slug=repo_slug)
942
942
  dispatch_blockers = hosted_dispatch_blockers(dispatch_profile)
943
943
  dispatch_summary = {
944
944
  name: bool(entry.get("ready")) for name, entry in dispatch_profile.items()
@@ -1034,8 +1034,12 @@ def check_adoption_campaign_readiness(
1034
1034
  message=f"{canonical} hosted campaign transport is not verified",
1035
1035
  detail=detail,
1036
1036
  remediation=(
1037
- f"Verify the {canonical} GitHub integration can answer campaign "
1038
- f"comments, then set {transport_var}=1."
1037
+ str(
1038
+ dispatch_profile.get("installation", {}).get(
1039
+ "remediation"
1040
+ )
1041
+ )
1042
+ or f"Verify {canonical} transport for {repo_slug}."
1039
1043
  ),
1040
1044
  )
1041
1045
  )
@@ -195,7 +195,29 @@ def classify_package_install_failure(*, exception: Exception, steps: list[dict[s
195
195
  "operation not permitted",
196
196
  )
197
197
 
198
+ # Certificate-validation failures: the transport could not establish trust.
199
+ # These are checked ahead of every other category, so a certificate failure
200
+ # is always `network`. It outranks the permission indicators because a
201
+ # platform trust store evaluated inside a strict OS sandbox (macOS
202
+ # Security.framework reports OSStatus -26276) fails with wording that also
203
+ # matches "operation not permitted"/EPERM, and it outranks the index
204
+ # indicators because an untrusted connection served nothing to classify.
205
+ # `package_index` stays the reason for a non-certificate index response.
206
+ certificate_indicators = (
207
+ "certificate verify failed",
208
+ "certificate_verify_failed",
209
+ "sslcertverificationerror",
210
+ "osstatus -26276",
211
+ "sectrustevaluate",
212
+ "unable to get local issuer certificate",
213
+ "self signed certificate",
214
+ "self-signed certificate",
215
+ )
216
+
198
217
  # Check in priority order: most specific first
218
+ if any(indicator in error_text for indicator in certificate_indicators):
219
+ return "network"
220
+
199
221
  if any(indicator in error_text for indicator in sandbox_permission_indicators):
200
222
  return "sandbox_permission"
201
223
 
@@ -276,6 +276,7 @@ PACKAGE_FILES = (
276
276
  ("tools/code_mower_prompts.py", "src/code_mower/prompts.py", "core"),
277
277
  ("src/code_mower/release_qualify.py", "src/code_mower/release_qualify.py", "core"),
278
278
  ("src/code_mower/release_campaigns.py", "src/code_mower/release_campaigns.py", "core"),
279
+ ("src/code_mower/devin_api.py", "src/code_mower/devin_api.py", "core"),
279
280
  ("src/code_mower/campaign_discovery.py", "src/code_mower/campaign_discovery.py", "core"),
280
281
  ("src/code_mower/campaign_adapters.py", "src/code_mower/campaign_adapters.py", "core"),
281
282
  ("src/code_mower/release_readiness.py", "src/code_mower/release_readiness.py", "core"),
@@ -226,11 +226,14 @@ REFERENCE_PROVIDERS: dict[str, ProviderLane] = {
226
226
  trigger_policy="manual",
227
227
  spend_policy="paid",
228
228
  provider_config={
229
- "bot_authors": ("devin-ai-integration", "devin-ai-integration[bot]"),
230
- "bot_authors_env": "DEVIN_BOT_AUTHORS",
231
- "trigger_comments": ("@devin run", "devin run"),
232
- "campaign_transport_ready_env": "CODE_MOWER_DEVIN_CAMPAIGN_TRANSPORT_READY",
229
+ "campaign_transport": "devin_api_v3",
230
+ "campaign_required_env_all": ("DEVIN_API_KEY", "DEVIN_ORG_ID"),
231
+ "campaign_repository_scope_env": "CODE_MOWER_DEVIN_REPOSITORIES",
233
232
  "campaign_response_timeout_seconds": 3600,
233
+ "status": (
234
+ "hosted Devin v3 Sessions API transport; "
235
+ "issue marker is optional audit evidence"
236
+ ),
234
237
  },
235
238
  ),
236
239
  "greptile": ProviderLane(