code-mower 1.0.10__tar.gz → 1.0.11__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.11}/PKG-INFO +14 -5
  2. {code_mower-1.0.10 → code_mower-1.0.11}/README.md +13 -4
  3. {code_mower-1.0.10 → code_mower-1.0.11}/pyproject.toml +1 -1
  4. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/__init__.py +1 -1
  5. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/campaign_adapters.py +88 -8
  6. code_mower-1.0.11/src/code_mower/devin_api.py +259 -0
  7. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/adoption.py +8 -4
  8. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/migration_install.py +22 -0
  9. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package_manifest.py +1 -0
  10. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_registry.py +7 -4
  11. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/release_campaigns.py +682 -31
  12. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/release_qualify.py +27 -2
  13. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/providers.yml +8 -1
  14. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  15. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/PKG-INFO +14 -5
  16. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/SOURCES.txt +2 -0
  17. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/devin.yml +8 -1
  18. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers.yml +8 -1
  19. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/builder-provenance.yml.j2 +1 -1
  20. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_campaign_adapters.py +165 -0
  21. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_campaign_retry_evidence_711.py +5 -4
  22. code_mower-1.0.11/tests/test_devin_api.py +556 -0
  23. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_devin_provider_contract.py +13 -4
  24. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_campaign_readiness.py +16 -10
  25. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_hosted_dispatch_profile.py +52 -30
  26. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_package_install_failure_taxonomy.py +58 -0
  27. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_release_campaigns.py +142 -86
  28. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_release_hygiene.py +47 -46
  29. {code_mower-1.0.10 → code_mower-1.0.11}/CODE_OF_CONDUCT.md +0 -0
  30. {code_mower-1.0.10 → code_mower-1.0.11}/LICENSE +0 -0
  31. {code_mower-1.0.10 → code_mower-1.0.11}/MANIFEST.in +0 -0
  32. {code_mower-1.0.10 → code_mower-1.0.11}/NOTICE +0 -0
  33. {code_mower-1.0.10 → code_mower-1.0.11}/SUPPORT.md +0 -0
  34. {code_mower-1.0.10 → code_mower-1.0.11}/requirements/requirements.txt +0 -0
  35. {code_mower-1.0.10 → code_mower-1.0.11}/setup.cfg +0 -0
  36. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/__init__.py +0 -0
  37. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/_base.py +0 -0
  38. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  39. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/gitar.py +0 -0
  40. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/greptile.py +0 -0
  41. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/adapters/qodo.py +0 -0
  42. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  43. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/antigravity_sdk_probe.py +0 -0
  44. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/audit_handoff_log.py +0 -0
  45. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/audit_labeler_lib.py +0 -0
  46. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/audit_limits.py +0 -0
  47. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/audit_progress.py +0 -0
  48. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/blind_review_artifacts.py +0 -0
  49. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/blind_review_coordinator.py +0 -0
  50. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/board.py +0 -0
  51. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/board_store.py +0 -0
  52. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/bootstrap.py +0 -0
  53. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/builder_experiment.py +0 -0
  54. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/builder_runs.py +0 -0
  55. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/__init__.py +0 -0
  56. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/arms.py +0 -0
  57. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/auto_discovery.py +0 -0
  58. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/commands.py +0 -0
  59. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/context_inputs.py +0 -0
  60. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/corpus.py +0 -0
  61. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/effect_report.py +0 -0
  62. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/evidence.py +0 -0
  63. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/evidence_report.py +0 -0
  64. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/identity.py +0 -0
  65. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/metrics.py +0 -0
  66. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/overlap.py +0 -0
  67. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/planning.py +0 -0
  68. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/policy.py +0 -0
  69. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/results.py +0 -0
  70. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/run_results.py +0 -0
  71. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/run_status.py +0 -0
  72. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/runner.py +0 -0
  73. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/truth.py +0 -0
  74. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/calibration/value_report.py +0 -0
  75. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/campaign_discovery.py +0 -0
  76. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/checks.py +0 -0
  77. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/claude_audit_pr.py +0 -0
  78. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/claude_cli_bounce.py +0 -0
  79. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/claude_cli_environment.py +0 -0
  80. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/clear_stale.py +0 -0
  81. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cli.py +0 -0
  82. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud.py +0 -0
  83. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/__init__.py +0 -0
  84. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/adoption_runs.py +0 -0
  85. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/bundle.py +0 -0
  86. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/doctor.py +0 -0
  87. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/dogfood.py +0 -0
  88. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/endpoints.py +0 -0
  89. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/errors.py +0 -0
  90. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/events.py +0 -0
  91. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/export.py +0 -0
  92. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/git_metadata.py +0 -0
  93. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/manifest.py +0 -0
  94. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/operations.py +0 -0
  95. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/pr_outcomes.py +0 -0
  96. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/productivity.py +0 -0
  97. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/reports.py +0 -0
  98. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/setup.py +0 -0
  99. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/tokens.py +0 -0
  100. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/upload.py +0 -0
  101. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/cloud_client/work_types.py +0 -0
  102. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/code_mower_calibration.py +0 -0
  103. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/code_mower_context_packs.py +0 -0
  104. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/code_mower_merge.py +0 -0
  105. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/code_mower_telemetry.py +0 -0
  106. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  107. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/codex_audit_env_preflight.py +0 -0
  108. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/codex_audit_pr.py +0 -0
  109. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  110. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  111. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/config.py +0 -0
  112. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/controller.py +0 -0
  113. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/decisions.py +0 -0
  114. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/devin_cli_audit_pr.py +0 -0
  115. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor.py +0 -0
  116. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/__init__.py +0 -0
  117. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  118. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/campaign_auth.py +0 -0
  119. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/cloud.py +0 -0
  120. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/common.py +0 -0
  121. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github.py +0 -0
  122. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions.py +0 -0
  123. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  124. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  125. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  126. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  127. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  128. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  129. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  130. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  131. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_api.py +0 -0
  132. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_branch.py +0 -0
  133. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_config.py +0 -0
  134. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_human_token.py +0 -0
  135. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_provider.py +0 -0
  136. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_repo.py +0 -0
  137. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/github_trusted_authors.py +0 -0
  138. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/groups.py +0 -0
  139. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/models.py +0 -0
  140. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/output.py +0 -0
  141. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/presets.py +0 -0
  142. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/privacy.py +0 -0
  143. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  144. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  145. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  146. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_env.py +0 -0
  147. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  148. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  149. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  150. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  151. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  152. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  153. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  154. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  155. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  156. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  157. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  158. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  159. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/providers.py +0 -0
  160. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/registry.py +0 -0
  161. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/runner.py +0 -0
  162. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/runtime.py +0 -0
  163. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  164. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
  165. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/doctor_checks/supervised_pilot.py +0 -0
  166. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/file_locks.py +0 -0
  167. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/gate_health.py +0 -0
  168. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  169. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/git_identity.py +0 -0
  170. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/grok_build_audit_pr.py +0 -0
  171. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  172. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/init.py +0 -0
  173. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/__init__.py +0 -0
  174. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/aider.py +0 -0
  175. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  176. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/claude.py +0 -0
  177. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/codex.py +0 -0
  178. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/devin.py +0 -0
  179. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/devin_cli.py +0 -0
  180. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  181. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/grok_build.py +0 -0
  182. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  183. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/local_llm.py +0 -0
  184. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_configs/muse_cli.py +0 -0
  185. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_delivery.py +0 -0
  186. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/lane_status.py +0 -0
  187. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/local_llm_audit_pr.py +0 -0
  188. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/local_llm_bakeoff.py +0 -0
  189. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/local_llm_calibration.py +0 -0
  190. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/local_llm_profiles.py +0 -0
  191. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/migration.py +0 -0
  192. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/migration_mirror.py +0 -0
  193. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/migration_readiness.py +0 -0
  194. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/migration_rehearsal.py +0 -0
  195. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/muse_cli_audit_pr.py +0 -0
  196. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/next_steps.py +0 -0
  197. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package.py +0 -0
  198. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package_content.py +0 -0
  199. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package_paths.py +0 -0
  200. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package_rendering.py +0 -0
  201. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/package_static.py +0 -0
  202. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/participants.py +0 -0
  203. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/plan_context.py +0 -0
  204. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/productivity_report.py +0 -0
  205. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/prompts.py +0 -0
  206. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/__init__.py +0 -0
  207. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/comments.py +0 -0
  208. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/exit_codes.py +0 -0
  209. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/git.py +0 -0
  210. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/github_auth.py +0 -0
  211. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/github_pr.py +0 -0
  212. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  213. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/process.py +0 -0
  214. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/repo_paths.py +0 -0
  215. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/text_schema.py +0 -0
  216. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  217. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/provider_runners/workspace.py +0 -0
  218. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/providers/__init__.py +0 -0
  219. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/providers/local_cli.py +0 -0
  220. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/providers/provenance.py +0 -0
  221. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/release_readiness.py +0 -0
  222. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/reviewer_metrics.py +0 -0
  223. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/reviewer_spend.py +0 -0
  224. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/saas_reviewer_labeler.py +0 -0
  225. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/secrets.py +0 -0
  226. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/session.py +0 -0
  227. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/builder-experiment.example.json +0 -0
  228. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  229. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/calibration-corpus.json +0 -0
  230. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/code-mower.example.yml +0 -0
  231. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/context-packs.example.json +0 -0
  232. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  233. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  234. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  235. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  236. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  237. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  238. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  239. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  240. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  241. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/README.md +0 -0
  242. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/claude.md +0 -0
  243. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/codex.md +0 -0
  244. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/cursor.md +0 -0
  245. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/devin.md +0 -0
  246. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/generic.md +0 -0
  247. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
  248. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/code_mower +0 -0
  249. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  250. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  251. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  252. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  253. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/run_devin_cli_audit_pr.sh +0 -0
  254. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  255. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/product-support/status_report.py +0 -0
  256. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  257. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  258. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  259. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  260. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  261. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  262. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  263. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  264. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  265. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  266. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  267. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  268. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  269. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  270. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  271. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  272. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  273. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  274. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/trailer_comment_labeler.py +0 -0
  275. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/versioning.py +0 -0
  276. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/work_orders.py +0 -0
  277. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower/workflow_actionlint.py +0 -0
  278. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/dependency_links.txt +0 -0
  279. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/entry_points.txt +0 -0
  280. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/requires.txt +0 -0
  281. {code_mower-1.0.10 → code_mower-1.0.11}/src/code_mower.egg-info/top_level.txt +0 -0
  282. {code_mower-1.0.10 → code_mower-1.0.11}/templates/builder-experiment.example.json +0 -0
  283. {code_mower-1.0.10 → code_mower-1.0.11}/templates/calibration-corpus.example.json +0 -0
  284. {code_mower-1.0.10 → code_mower-1.0.11}/templates/calibration-corpus.json +0 -0
  285. {code_mower-1.0.10 → code_mower-1.0.11}/templates/code-mower.yml.j2 +0 -0
  286. {code_mower-1.0.10 → code_mower-1.0.11}/templates/context-packs.example.json +0 -0
  287. {code_mower-1.0.10 → code_mower-1.0.11}/templates/cursor/BUGBOT.md +0 -0
  288. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/README.md +0 -0
  289. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/claude.md +0 -0
  290. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/codex.md +0 -0
  291. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/cursor.md +0 -0
  292. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/devin.md +0 -0
  293. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/generic.md +0 -0
  294. {code_mower-1.0.10 → code_mower-1.0.11}/templates/lanes/run_mac_lane.sh +0 -0
  295. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/acp_bridge.yml +0 -0
  296. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/aider.yml +0 -0
  297. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/antigravity_cli.yml +0 -0
  298. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/claude_audit.yml +0 -0
  299. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/claude_review.yml +0 -0
  300. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/coderabbit_cli.yml +0 -0
  301. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/codex.yml +0 -0
  302. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/cursor_bugbot.yml +0 -0
  303. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/cursor_cloud_agent.yml +0 -0
  304. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/devin_cli.yml +0 -0
  305. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/gemini_cli.yml +0 -0
  306. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/gitar.yml +0 -0
  307. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/greptile.yml +0 -0
  308. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/hermes_cli.yml +0 -0
  309. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/local_llm.yml +0 -0
  310. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/muse_cli.yml +0 -0
  311. {code_mower-1.0.10 → code_mower-1.0.11}/templates/providers/qodo.yml +0 -0
  312. {code_mower-1.0.10 → code_mower-1.0.11}/templates/reviewer-spend.example.json +0 -0
  313. {code_mower-1.0.10 → code_mower-1.0.11}/templates/reviewer-value-report.example.md +0 -0
  314. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  315. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  316. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  317. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  318. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  319. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  320. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  321. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  322. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  323. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  324. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  325. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  326. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  327. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  328. {code_mower-1.0.10 → code_mower-1.0.11}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  329. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_adoption_diagnostics.py +0 -0
  330. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_adoption_result_semantics.py +0 -0
  331. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_adoption_run_contract.py +0 -0
  332. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_antigravity_sdk_probe.py +0 -0
  333. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_audit_comment_posture.py +0 -0
  334. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_audit_limits.py +0 -0
  335. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_board.py +0 -0
  336. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_builder_experiment.py +0 -0
  337. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_builder_identity.py +0 -0
  338. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_builder_runs.py +0 -0
  339. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_calibration_effect_report.py +0 -0
  340. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_calibration_truth.py +0 -0
  341. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_campaign_discovery.py +0 -0
  342. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_checks.py +0 -0
  343. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_claude_audit_pr.py +0 -0
  344. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_claude_cli_bounce.py +0 -0
  345. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_clear_stale.py +0 -0
  346. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_cloud_client.py +0 -0
  347. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_cloud_git_metadata.py +0 -0
  348. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_cloud_manifest.py +0 -0
  349. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_cloud_reports.py +0 -0
  350. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  351. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_codex_audit_env_preflight.py +0 -0
  352. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_codex_audit_pr.py +0 -0
  353. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_controller.py +0 -0
  354. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_decision_audit_integration.py +0 -0
  355. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_decisions.py +0 -0
  356. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_devin_builder_lane.py +0 -0
  357. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_devin_cli_audit_pr.py +0 -0
  358. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_actions_cost_summary.py +0 -0
  359. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_actions_failure_selection.py +0 -0
  360. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_boundaries.py +0 -0
  361. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_campaign_auth.py +0 -0
  362. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_github_checks.py +0 -0
  363. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_output.py +0 -0
  364. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_privacy.py +0 -0
  365. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_provider_env_required.py +0 -0
  366. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_provider_env_tokens.py +0 -0
  367. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  368. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_provider_probe.py +0 -0
  369. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_provider_review_hygiene.py +0 -0
  370. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_registry.py +0 -0
  371. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_runtime.py +0 -0
  372. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_self_hosted_runner.py +0 -0
  373. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_doctor_supervised_pilot.py +0 -0
  374. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_file_locks.py +0 -0
  375. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_fork_pr_guard.py +0 -0
  376. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_gate_automerge.py +0 -0
  377. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_gate_health.py +0 -0
  378. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_init_actionlint.py +0 -0
  379. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_init_build_loop.py +0 -0
  380. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_lane_delivery_contract.py +0 -0
  381. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_lane_status.py +0 -0
  382. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_local_llm_github_helpers.py +0 -0
  383. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_migration_rehearsal.py +0 -0
  384. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_migration_setup_drift.py +0 -0
  385. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_next_steps.py +0 -0
  386. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_participant_sessions.py +0 -0
  387. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_plan_context.py +0 -0
  388. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_pr_outcome_contract.py +0 -0
  389. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_productivity_metrics_contract.py +0 -0
  390. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_productivity_report.py +0 -0
  391. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_prompts.py +0 -0
  392. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_fixture_contracts.py +0 -0
  393. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_local_cli.py +0 -0
  394. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_comments.py +0 -0
  395. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_git.py +0 -0
  396. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_github_pr.py +0 -0
  397. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_pr_worktree.py +0 -0
  398. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_process.py +0 -0
  399. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_repo_paths.py +0 -0
  400. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_text_schema.py +0 -0
  401. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_provider_runners_workspace.py +0 -0
  402. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_release_qualify.py +0 -0
  403. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_reviewer_metrics_core.py +0 -0
  404. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_reviewer_spend.py +0 -0
  405. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_supervised_pilot_contract.py +0 -0
  406. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_trailer_comment_labeler.py +0 -0
  407. {code_mower-1.0.10 → code_mower-1.0.11}/tests/test_work_orders.py +0 -0
  408. {code_mower-1.0.10 → code_mower-1.0.11}/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.11
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.11/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,10 @@ 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.
288
292
  Package-only users can start from the public package rather than a source
289
293
  checkout.
290
294
 
@@ -317,7 +321,7 @@ Provider-contract baseline for the next release train:
317
321
 
318
322
  For release verification,
319
323
  [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
324
+ the package-index procedure for `v1.0.11` / `code-mower==1.0.11`. The
321
325
  GitHub release records the workflow and rehearsal evidence for the exact tag.
322
326
  After publication, [Release Qualification](docs/release-qualification.md)
323
327
  coordinates provider-specific install and operational checks without treating
@@ -472,6 +476,10 @@ or informational until your own calibration data proves it is useful: Gitar,
472
476
  Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
473
477
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
474
478
 
479
+ Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
480
+ `DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
481
+ in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
482
+
475
483
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
476
484
  surfaces and may use Gemini model infrastructure. Keep their auth, model
477
485
  provenance, calibration evidence, and release notes separate.
@@ -507,8 +515,8 @@ measurement work.
507
515
 
508
516
  ## Installation Status
509
517
 
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
518
+ The current package-index release baseline is `v1.0.11`, with pinned package
519
+ install spec `code-mower==1.0.11`. Release evidence is recorded on the GitHub
512
520
  release and in the first-user install rehearsal. The public repository is
513
521
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
514
522
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -587,6 +595,7 @@ first so local work exercises the same package entrypoint users install.
587
595
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
588
596
  - [v1.0.9 Release Notes](docs/v109-release-notes.md)
589
597
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
598
+ - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
590
599
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
591
600
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
592
601
  - [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.11/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,10 @@ 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.
258
262
  Package-only users can start from the public package rather than a source
259
263
  checkout.
260
264
 
@@ -287,7 +291,7 @@ Provider-contract baseline for the next release train:
287
291
 
288
292
  For release verification,
289
293
  [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
294
+ the package-index procedure for `v1.0.11` / `code-mower==1.0.11`. The
291
295
  GitHub release records the workflow and rehearsal evidence for the exact tag.
292
296
  After publication, [Release Qualification](docs/release-qualification.md)
293
297
  coordinates provider-specific install and operational checks without treating
@@ -442,6 +446,10 @@ or informational until your own calibration data proves it is useful: Gitar,
442
446
  Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
443
447
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
444
448
 
449
+ Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
450
+ `DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
451
+ in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
452
+
445
453
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
446
454
  surfaces and may use Gemini model infrastructure. Keep their auth, model
447
455
  provenance, calibration evidence, and release notes separate.
@@ -477,8 +485,8 @@ measurement work.
477
485
 
478
486
  ## Installation Status
479
487
 
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
488
+ The current package-index release baseline is `v1.0.11`, with pinned package
489
+ install spec `code-mower==1.0.11`. Release evidence is recorded on the GitHub
482
490
  release and in the first-user install rehearsal. The public repository is
483
491
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
484
492
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -557,6 +565,7 @@ first so local work exercises the same package entrypoint users install.
557
565
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
558
566
  - [v1.0.9 Release Notes](docs/v109-release-notes.md)
559
567
  - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
568
+ - [v1.0.11 Release Notes](docs/v1011-release-notes.md)
560
569
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
561
570
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
562
571
  - [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.11"
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.11"
@@ -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,7 +509,7 @@ 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
@@ -472,6 +531,27 @@ def build_qualification_prompt(
472
531
  "run and any call to them ends the session without a result.",
473
532
  ]
474
533
  )
534
+ if legacy_certs:
535
+ # macOS-only Claude sandbox defect: pip's default trust store calls
536
+ # Security.framework, which this sandbox denies (OSStatus -26276).
537
+ lines.extend(
538
+ [
539
+ "Every pip command in the procedure below already carries "
540
+ f"`{PIP_LEGACY_CERTS_FLAG}`, because pip's default macOS trust",
541
+ "store is unreachable from this sandbox. Certificate verification",
542
+ "stays fully enabled; only the trust store changes. If this pip",
543
+ "build rejects that option as an invalid choice, rerun the identical",
544
+ "command without it and change nothing else. Never add",
545
+ "`--trusted-host`, never disable or skip TLS verification, and never",
546
+ "run any command outside the sandbox. If an install still fails",
547
+ "certificate verification, report the `package_install` step with",
548
+ "`failure_reason` `network`: a certificate-validation failure is",
549
+ "always `network`, never `sandbox_permission` and never",
550
+ "`package_index`. Use `package_index` only for an index response",
551
+ "that is not a certificate failure, such as a 404 or a missing",
552
+ "version.",
553
+ ]
554
+ )
475
555
  lines.extend(
476
556
  [
477
557
  "",
@@ -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(