code-mower 1.0.8__tar.gz → 1.0.10__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.8 → code_mower-1.0.10}/PKG-INFO +48 -17
  2. {code_mower-1.0.8 → code_mower-1.0.10}/README.md +47 -16
  3. {code_mower-1.0.8 → code_mower-1.0.10}/pyproject.toml +1 -1
  4. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/__init__.py +1 -1
  5. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/board.py +83 -36
  6. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/builder_runs.py +4 -0
  7. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/campaign_adapters.py +231 -20
  8. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cli.py +19 -12
  9. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/__init__.py +2 -0
  10. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/adoption_runs.py +46 -20
  11. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/code_mower_telemetry.py +2 -0
  12. code_mower-1.0.10/src/code_mower/devin_cli_audit_pr.py +1483 -0
  13. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/campaign_auth.py +34 -7
  14. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_local_cli.py +99 -20
  15. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/init.py +76 -2
  16. code_mower-1.0.10/src/code_mower/lane_configs/devin_cli.py +36 -0
  17. code_mower-1.0.10/src/code_mower/lane_delivery.py +1375 -0
  18. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_status.py +1 -0
  19. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/migration_install.py +160 -20
  20. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/migration_rehearsal.py +7 -1
  21. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/next_steps.py +161 -44
  22. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package_manifest.py +12 -0
  23. code_mower-1.0.10/src/code_mower/participants.py +179 -0
  24. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_registry.py +52 -0
  25. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/release_campaigns.py +558 -70
  26. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/release_qualify.py +82 -4
  27. code_mower-1.0.10/src/code_mower/session.py +154 -0
  28. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/code-mower.example.yml +9 -4
  29. code_mower-1.0.10/src/code_mower/templates/lanes/devin.md +41 -0
  30. code_mower-1.0.10/src/code_mower/templates/lanes/run_mac_lane.sh +1232 -0
  31. code_mower-1.0.10/src/code_mower/templates/product-support/run_devin_cli_audit_pr.sh +63 -0
  32. {code_mower-1.0.8 → code_mower-1.0.10/src/code_mower}/templates/providers.yml +74 -5
  33. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  34. {code_mower-1.0.8 → code_mower-1.0.10/src/code_mower}/templates/workflows/local-cli-audit.yml.j2 +1 -0
  35. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/PKG-INFO +48 -17
  36. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/SOURCES.txt +16 -0
  37. code_mower-1.0.10/templates/lanes/devin.md +41 -0
  38. code_mower-1.0.10/templates/lanes/run_mac_lane.sh +1232 -0
  39. code_mower-1.0.10/templates/providers/devin_cli.yml +70 -0
  40. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/gitar.yml +1 -1
  41. {code_mower-1.0.8/src/code_mower → code_mower-1.0.10}/templates/providers.yml +74 -5
  42. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/builder-provenance.yml.j2 +1 -1
  43. {code_mower-1.0.8/src/code_mower → code_mower-1.0.10}/templates/workflows/local-cli-audit.yml.j2 +1 -0
  44. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_adoption_run_contract.py +44 -0
  45. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_board.py +173 -0
  46. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_builder_identity.py +4 -0
  47. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_campaign_adapters.py +652 -6
  48. code_mower-1.0.10/tests/test_devin_builder_lane.py +1538 -0
  49. code_mower-1.0.10/tests/test_devin_cli_audit_pr.py +974 -0
  50. code_mower-1.0.10/tests/test_devin_provider_contract.py +743 -0
  51. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_campaign_auth.py +6 -2
  52. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_init_build_loop.py +318 -15
  53. code_mower-1.0.10/tests/test_lane_delivery_contract.py +2175 -0
  54. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_migration_rehearsal.py +71 -16
  55. code_mower-1.0.10/tests/test_next_steps.py +147 -0
  56. code_mower-1.0.10/tests/test_package_install_failure_taxonomy.py +489 -0
  57. code_mower-1.0.10/tests/test_participant_sessions.py +210 -0
  58. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_fixture_contracts.py +3 -0
  59. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_release_campaigns.py +1372 -48
  60. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_release_hygiene.py +92 -78
  61. code_mower-1.0.8/src/code_mower/templates/lanes/run_mac_lane.sh +0 -532
  62. code_mower-1.0.8/templates/lanes/run_mac_lane.sh +0 -532
  63. {code_mower-1.0.8 → code_mower-1.0.10}/CODE_OF_CONDUCT.md +0 -0
  64. {code_mower-1.0.8 → code_mower-1.0.10}/LICENSE +0 -0
  65. {code_mower-1.0.8 → code_mower-1.0.10}/MANIFEST.in +0 -0
  66. {code_mower-1.0.8 → code_mower-1.0.10}/NOTICE +0 -0
  67. {code_mower-1.0.8 → code_mower-1.0.10}/SUPPORT.md +0 -0
  68. {code_mower-1.0.8 → code_mower-1.0.10}/requirements/requirements.txt +0 -0
  69. {code_mower-1.0.8 → code_mower-1.0.10}/setup.cfg +0 -0
  70. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/__init__.py +0 -0
  71. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/_base.py +0 -0
  72. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  73. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/gitar.py +0 -0
  74. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/greptile.py +0 -0
  75. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/adapters/qodo.py +0 -0
  76. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  77. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/antigravity_sdk_probe.py +0 -0
  78. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/audit_handoff_log.py +0 -0
  79. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/audit_labeler_lib.py +0 -0
  80. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/audit_limits.py +0 -0
  81. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/audit_progress.py +0 -0
  82. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/blind_review_artifacts.py +0 -0
  83. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/blind_review_coordinator.py +0 -0
  84. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/board_store.py +0 -0
  85. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/bootstrap.py +0 -0
  86. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/builder_experiment.py +0 -0
  87. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/__init__.py +0 -0
  88. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/arms.py +0 -0
  89. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/auto_discovery.py +0 -0
  90. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/commands.py +0 -0
  91. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/context_inputs.py +0 -0
  92. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/corpus.py +0 -0
  93. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/effect_report.py +0 -0
  94. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/evidence.py +0 -0
  95. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/evidence_report.py +0 -0
  96. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/identity.py +0 -0
  97. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/metrics.py +0 -0
  98. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/overlap.py +0 -0
  99. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/planning.py +0 -0
  100. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/policy.py +0 -0
  101. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/results.py +0 -0
  102. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/run_results.py +0 -0
  103. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/run_status.py +0 -0
  104. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/runner.py +0 -0
  105. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/truth.py +0 -0
  106. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/calibration/value_report.py +0 -0
  107. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/campaign_discovery.py +0 -0
  108. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/checks.py +0 -0
  109. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/claude_audit_pr.py +0 -0
  110. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/claude_cli_bounce.py +0 -0
  111. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/claude_cli_environment.py +0 -0
  112. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/clear_stale.py +0 -0
  113. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud.py +0 -0
  114. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/bundle.py +0 -0
  115. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/doctor.py +0 -0
  116. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/dogfood.py +0 -0
  117. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/endpoints.py +0 -0
  118. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/errors.py +0 -0
  119. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/events.py +0 -0
  120. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/export.py +0 -0
  121. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/git_metadata.py +0 -0
  122. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/manifest.py +0 -0
  123. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/operations.py +0 -0
  124. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/pr_outcomes.py +0 -0
  125. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/productivity.py +0 -0
  126. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/reports.py +0 -0
  127. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/setup.py +0 -0
  128. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/tokens.py +0 -0
  129. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/upload.py +0 -0
  130. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/cloud_client/work_types.py +0 -0
  131. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/code_mower_calibration.py +0 -0
  132. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/code_mower_context_packs.py +0 -0
  133. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/code_mower_merge.py +0 -0
  134. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  135. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/codex_audit_env_preflight.py +0 -0
  136. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/codex_audit_pr.py +0 -0
  137. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  138. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  139. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/config.py +0 -0
  140. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/controller.py +0 -0
  141. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/decisions.py +0 -0
  142. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor.py +0 -0
  143. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/__init__.py +0 -0
  144. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/adoption.py +0 -0
  145. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  146. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/cloud.py +0 -0
  147. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/common.py +0 -0
  148. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github.py +0 -0
  149. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions.py +0 -0
  150. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  151. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  152. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  153. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  154. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  155. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  156. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  157. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  158. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_api.py +0 -0
  159. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_branch.py +0 -0
  160. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_config.py +0 -0
  161. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_human_token.py +0 -0
  162. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_provider.py +0 -0
  163. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_repo.py +0 -0
  164. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/github_trusted_authors.py +0 -0
  165. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/groups.py +0 -0
  166. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/models.py +0 -0
  167. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/output.py +0 -0
  168. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/presets.py +0 -0
  169. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/privacy.py +0 -0
  170. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  171. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  172. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  173. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_env.py +0 -0
  174. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  175. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  176. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  177. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  178. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  179. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  180. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  181. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  182. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  183. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  184. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  185. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/providers.py +0 -0
  186. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/registry.py +0 -0
  187. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/runner.py +0 -0
  188. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/runtime.py +0 -0
  189. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  190. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
  191. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/doctor_checks/supervised_pilot.py +0 -0
  192. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/file_locks.py +0 -0
  193. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/gate_health.py +0 -0
  194. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  195. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/git_identity.py +0 -0
  196. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/grok_build_audit_pr.py +0 -0
  197. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  198. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/__init__.py +0 -0
  199. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/aider.py +0 -0
  200. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  201. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/claude.py +0 -0
  202. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/codex.py +0 -0
  203. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/devin.py +0 -0
  204. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  205. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/grok_build.py +0 -0
  206. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  207. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/local_llm.py +0 -0
  208. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/lane_configs/muse_cli.py +0 -0
  209. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/local_llm_audit_pr.py +0 -0
  210. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/local_llm_bakeoff.py +0 -0
  211. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/local_llm_calibration.py +0 -0
  212. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/local_llm_profiles.py +0 -0
  213. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/migration.py +0 -0
  214. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/migration_mirror.py +0 -0
  215. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/migration_readiness.py +0 -0
  216. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/muse_cli_audit_pr.py +0 -0
  217. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package.py +0 -0
  218. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package_content.py +0 -0
  219. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package_paths.py +0 -0
  220. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package_rendering.py +0 -0
  221. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/package_static.py +0 -0
  222. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/plan_context.py +0 -0
  223. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/productivity_report.py +0 -0
  224. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/prompts.py +0 -0
  225. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/__init__.py +0 -0
  226. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/comments.py +0 -0
  227. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/exit_codes.py +0 -0
  228. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/git.py +0 -0
  229. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/github_auth.py +0 -0
  230. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/github_pr.py +0 -0
  231. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  232. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/process.py +0 -0
  233. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/repo_paths.py +0 -0
  234. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/text_schema.py +0 -0
  235. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  236. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/provider_runners/workspace.py +0 -0
  237. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/providers/__init__.py +0 -0
  238. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/providers/local_cli.py +0 -0
  239. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/providers/provenance.py +0 -0
  240. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/release_readiness.py +0 -0
  241. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/reviewer_metrics.py +0 -0
  242. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/reviewer_spend.py +0 -0
  243. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/saas_reviewer_labeler.py +0 -0
  244. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/secrets.py +0 -0
  245. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/builder-experiment.example.json +0 -0
  246. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  247. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/calibration-corpus.json +0 -0
  248. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/context-packs.example.json +0 -0
  249. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  250. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  251. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  252. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  253. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  254. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  255. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  256. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  257. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  258. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lanes/README.md +0 -0
  259. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lanes/claude.md +0 -0
  260. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lanes/codex.md +0 -0
  261. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lanes/cursor.md +0 -0
  262. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/lanes/generic.md +0 -0
  263. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/code_mower +0 -0
  264. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  265. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  266. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  267. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  268. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  269. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/product-support/status_report.py +0 -0
  270. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  271. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  272. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  273. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  274. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  275. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  276. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  277. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  278. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  279. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  280. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  281. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  282. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  283. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  284. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  285. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  286. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  287. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/trailer_comment_labeler.py +0 -0
  288. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/versioning.py +0 -0
  289. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/work_orders.py +0 -0
  290. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower/workflow_actionlint.py +0 -0
  291. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/dependency_links.txt +0 -0
  292. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/entry_points.txt +0 -0
  293. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/requires.txt +0 -0
  294. {code_mower-1.0.8 → code_mower-1.0.10}/src/code_mower.egg-info/top_level.txt +0 -0
  295. {code_mower-1.0.8 → code_mower-1.0.10}/templates/builder-experiment.example.json +0 -0
  296. {code_mower-1.0.8 → code_mower-1.0.10}/templates/calibration-corpus.example.json +0 -0
  297. {code_mower-1.0.8 → code_mower-1.0.10}/templates/calibration-corpus.json +0 -0
  298. {code_mower-1.0.8 → code_mower-1.0.10}/templates/code-mower.yml.j2 +0 -0
  299. {code_mower-1.0.8 → code_mower-1.0.10}/templates/context-packs.example.json +0 -0
  300. {code_mower-1.0.8 → code_mower-1.0.10}/templates/cursor/BUGBOT.md +0 -0
  301. {code_mower-1.0.8 → code_mower-1.0.10}/templates/lanes/README.md +0 -0
  302. {code_mower-1.0.8 → code_mower-1.0.10}/templates/lanes/claude.md +0 -0
  303. {code_mower-1.0.8 → code_mower-1.0.10}/templates/lanes/codex.md +0 -0
  304. {code_mower-1.0.8 → code_mower-1.0.10}/templates/lanes/cursor.md +0 -0
  305. {code_mower-1.0.8 → code_mower-1.0.10}/templates/lanes/generic.md +0 -0
  306. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/acp_bridge.yml +0 -0
  307. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/aider.yml +0 -0
  308. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/antigravity_cli.yml +0 -0
  309. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/claude_audit.yml +0 -0
  310. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/claude_review.yml +0 -0
  311. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/coderabbit_cli.yml +0 -0
  312. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/codex.yml +0 -0
  313. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/cursor_bugbot.yml +0 -0
  314. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/cursor_cloud_agent.yml +0 -0
  315. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/devin.yml +0 -0
  316. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/gemini_cli.yml +0 -0
  317. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/greptile.yml +0 -0
  318. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/hermes_cli.yml +0 -0
  319. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/local_llm.yml +0 -0
  320. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/muse_cli.yml +0 -0
  321. {code_mower-1.0.8 → code_mower-1.0.10}/templates/providers/qodo.yml +0 -0
  322. {code_mower-1.0.8 → code_mower-1.0.10}/templates/reviewer-spend.example.json +0 -0
  323. {code_mower-1.0.8 → code_mower-1.0.10}/templates/reviewer-value-report.example.md +0 -0
  324. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  325. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  326. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  327. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  328. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  329. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  330. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  331. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  332. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  333. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  334. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  335. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  336. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  337. {code_mower-1.0.8 → code_mower-1.0.10}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  338. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_adoption_diagnostics.py +0 -0
  339. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_adoption_result_semantics.py +0 -0
  340. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_antigravity_sdk_probe.py +0 -0
  341. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_audit_comment_posture.py +0 -0
  342. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_audit_limits.py +0 -0
  343. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_builder_experiment.py +0 -0
  344. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_builder_runs.py +0 -0
  345. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_calibration_effect_report.py +0 -0
  346. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_calibration_truth.py +0 -0
  347. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_campaign_discovery.py +0 -0
  348. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_campaign_retry_evidence_711.py +0 -0
  349. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_checks.py +0 -0
  350. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_claude_audit_pr.py +0 -0
  351. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_claude_cli_bounce.py +0 -0
  352. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_clear_stale.py +0 -0
  353. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_cloud_client.py +0 -0
  354. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_cloud_git_metadata.py +0 -0
  355. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_cloud_manifest.py +0 -0
  356. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_cloud_reports.py +0 -0
  357. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  358. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_codex_audit_env_preflight.py +0 -0
  359. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_codex_audit_pr.py +0 -0
  360. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_controller.py +0 -0
  361. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_decision_audit_integration.py +0 -0
  362. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_decisions.py +0 -0
  363. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_actions_cost_summary.py +0 -0
  364. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_actions_failure_selection.py +0 -0
  365. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_boundaries.py +0 -0
  366. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_campaign_readiness.py +0 -0
  367. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_github_checks.py +0 -0
  368. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_output.py +0 -0
  369. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_privacy.py +0 -0
  370. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_provider_env_required.py +0 -0
  371. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_provider_env_tokens.py +0 -0
  372. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  373. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_provider_probe.py +0 -0
  374. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_provider_review_hygiene.py +0 -0
  375. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_registry.py +0 -0
  376. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_runtime.py +0 -0
  377. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_self_hosted_runner.py +0 -0
  378. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_doctor_supervised_pilot.py +0 -0
  379. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_file_locks.py +0 -0
  380. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_fork_pr_guard.py +0 -0
  381. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_gate_automerge.py +0 -0
  382. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_gate_health.py +0 -0
  383. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_hosted_dispatch_profile.py +0 -0
  384. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_init_actionlint.py +0 -0
  385. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_lane_status.py +0 -0
  386. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_local_llm_github_helpers.py +0 -0
  387. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_migration_setup_drift.py +0 -0
  388. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_plan_context.py +0 -0
  389. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_pr_outcome_contract.py +0 -0
  390. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_productivity_metrics_contract.py +0 -0
  391. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_productivity_report.py +0 -0
  392. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_prompts.py +0 -0
  393. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_local_cli.py +0 -0
  394. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_comments.py +0 -0
  395. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_git.py +0 -0
  396. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_github_pr.py +0 -0
  397. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_pr_worktree.py +0 -0
  398. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_process.py +0 -0
  399. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_repo_paths.py +0 -0
  400. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_text_schema.py +0 -0
  401. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_provider_runners_workspace.py +0 -0
  402. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_release_qualify.py +0 -0
  403. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_reviewer_metrics_core.py +0 -0
  404. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_reviewer_spend.py +0 -0
  405. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_supervised_pilot_contract.py +0 -0
  406. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_trailer_comment_labeler.py +0 -0
  407. {code_mower-1.0.8 → code_mower-1.0.10}/tests/test_work_orders.py +0 -0
  408. {code_mower-1.0.8 → code_mower-1.0.10}/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.8
3
+ Version: 1.0.10
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
@@ -40,8 +40,7 @@ gate.
40
40
 
41
41
  The short version:
42
42
 
43
- - create safe, manual-first reviewer lanes for Codex, Claude, Gitar, and other
44
- AI review tools;
43
+ - create safe, manual-first peer-review lanes for Codex and Claude;
45
44
  - run setup diagnostics before a lane can surprise you with spend, source
46
45
  exposure, or GitHub Actions churn;
47
46
  - turn issue text, external docs, and project doctrine into local work orders
@@ -73,6 +72,18 @@ Code Mower should feel like an engineering tool, not a demo harness:
73
72
 
74
73
  ## What It Looks Like
75
74
 
75
+ Start with Claude Code and Codex, or choose your participants during setup with
76
+ `code-mower init --interactive`. For example, `code-mower init --with
77
+ claude,codex,devin` previews that selection. The generated configuration remembers
78
+ your choices for later sessions.
79
+
80
+ Ask the agent you are using to start a Code Mower session; that agent is the
81
+ default orchestrator. `code-mower session start --repo OWNER/REPO --with
82
+ claude,codex,devin --host codex` prepares the operating brief when invoked from
83
+ Codex. The host agent drives the work using available execution paths.
84
+ See [Participants And Sessions](docs/sessions.md) for setup, host identity,
85
+ and product-specific capabilities.
86
+
76
87
  `code-mower doctor --adoption --repo OWNER/REPO` is the first useful command
77
88
  for a real repository. It checks your runtime, GitHub setup, provider CLIs,
78
89
  token posture, optional cloud setup, private-repo Actions cost traps, and
@@ -92,7 +103,7 @@ Example, shortened:
92
103
  ```text
93
104
  $ code-mower doctor --adoption --repo OWNER/REPO
94
105
  PASS config.validate config validates
95
- PASS profile.select selected profile: codex, claude_audit, gitar
106
+ PASS profile.select selected profile: codex, claude_audit
96
107
  PASS runtime.python Python 3.12 satisfies Code Mower requirements
97
108
  PASS runtime.github_auth GitHub CLI auth probe succeeded
98
109
  PASS runtime.local_cli codex codex found
@@ -205,6 +216,12 @@ Cold adopters should start with the reviewer gate, then add builders, then
205
216
  measure builder experiments; provider experiments come after that base loop is
206
217
  observable.
207
218
 
219
+ The initial reviewer and builder paths default to Claude + Codex. Other
220
+ participants require an explicit setup selection. `code-mower next-steps --repo
221
+ OWNER/REPO --pr NUMBER` shows setup, peer-audit requests, status, and local
222
+ evidence. Add `--advanced` for calibration, migration, package rehearsal, and
223
+ optional cloud guidance after the initial loop works.
224
+
208
225
  Install first from the [Install And Bootstrap](docs/install.md) matrix: pipx for
209
226
  laptops, uv tool installs for hosted agents or CI boxes, and an editable venv
210
227
  for Code Mower contributors. All paths require Python 3.12 or newer. For
@@ -224,7 +241,7 @@ agent report its actual host posture, exact installed version, doctor result,
224
241
  Board URL, and any owner-only click-list before it mutates the repo.
225
242
 
226
243
  The current package-index announcement entry point is the tagged
227
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.8/docs/try-in-10-minutes.md)
244
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.10/docs/try-in-10-minutes.md)
228
245
  guide. The v1.0 supervised-pilot release includes the native Board, the
229
246
  controller dry-run and policy contract, adoption and upgrade hardening from
230
247
  recent install rehearsals, package-index release checks, provider-diversity
@@ -259,6 +276,15 @@ artifact, campaigns survive checkout changes, TestPyPI qualification is
259
276
  closed, Cursor builder identity is distinct from Grok review, Antigravity uses
260
277
  explicit project isolation, and hosted Cursor and Devin profiles require
261
278
  verified dispatch and result transport.
279
+ The v1.0.9 patch makes Board refresh recovery deterministic, turns package
280
+ installation failures into bounded actionable diagnostics, and lets release
281
+ campaigns require established providers while retaining slower or experimental
282
+ providers as informational evidence.
283
+ The v1.0.10 patch makes local builder lanes deliverable and recoverable: a
284
+ provider-neutral delivery contract with bounded no-change and owner-action
285
+ outcomes, process-group cleanup so a finished provider is not reported as a
286
+ timeout, simpler first-run defaults, host-led participant sessions, and a
287
+ published 20-sample provider calibration scorecard.
262
288
  Package-only users can start from the public package rather than a source
263
289
  checkout.
264
290
 
@@ -291,7 +317,7 @@ Provider-contract baseline for the next release train:
291
317
 
292
318
  For release verification,
293
319
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
294
- the package-index procedure for `v1.0.8` / `code-mower==1.0.8`. The
320
+ the package-index procedure for `v1.0.10` / `code-mower==1.0.10`. The
295
321
  GitHub release records the workflow and rehearsal evidence for the exact tag.
296
322
  After publication, [Release Qualification](docs/release-qualification.md)
297
323
  coordinates provider-specific install and operational checks without treating
@@ -354,10 +380,11 @@ optional work order, single-writer branch, reviewer lanes, and fix rounds. Code
354
380
  Mower's templates now support that loop end to end; humans still own
355
381
  credentials, branch protection, calibration, and owner decisions.
356
382
 
357
- The reference adoption shape is Claude Code as orchestrator; Claude Code,
358
- Codex, and Cursor as builder lanes; Claude Code and Codex as reviewer lanes;
359
- and Gitar or Antigravity as informational reviewer signal until local
360
- calibration says otherwise.
383
+ The initial adoption shape uses Claude Code or Codex as orchestrator, builder,
384
+ and peer reviewer. The owning builder remains the only writer, and the other
385
+ provider supplies independent review. Other builders and reviewers are explicit
386
+ later additions; they follow the same lane policy with provider-specific
387
+ execution and authentication where needed.
361
388
 
362
389
  ## Why Not Just Run Codex Or Claude Yourself?
363
390
 
@@ -439,10 +466,10 @@ The first recommended lanes are local/manual:
439
466
  | --- | --- | --- |
440
467
  | Codex audit | structured local peer audit | merge-gating eligible after setup |
441
468
  | Claude audit | structured local peer audit | merge-gating eligible after setup |
442
- | Gitar | advisory third signal | informational until calibrated |
443
469
 
444
- Everything else starts manual or informational until your own calibration data
445
- proves it is useful: Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
470
+ Everything else is opt-in after the Claude + Codex loop works and stays manual
471
+ or informational until your own calibration data proves it is useful: Gitar,
472
+ Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
446
473
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
447
474
 
448
475
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
@@ -480,8 +507,8 @@ measurement work.
480
507
 
481
508
  ## Installation Status
482
509
 
483
- The current package-index release baseline is `v1.0.8`, with pinned package
484
- install spec `code-mower==1.0.8`. Release evidence is recorded on the GitHub
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
485
512
  release and in the first-user install rehearsal. The public repository is
486
513
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
487
514
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -516,8 +543,9 @@ first so local work exercises the same package entrypoint users install.
516
543
  conservative and team-controlled while automated retention jobs are roadmap
517
544
  work.
518
545
  - Advanced/provider/operator commands remain available behind
519
- `code-mower --help-all`. The default help path stays focused on `init`,
520
- `doctor`, calibration, value reports, and optional cloud export/upload.
546
+ `code-mower --help-all`. The default help path stays focused on setup,
547
+ `next-steps`, lane status, and local evidence; calibration and cloud commands
548
+ remain available through `--help-all`.
521
549
 
522
550
  ## Docs Map
523
551
 
@@ -537,6 +565,7 @@ first so local work exercises the same package entrypoint users install.
537
565
  - [Claude Lane Standing Instructions](docs/lanes/claude.md)
538
566
  - [Cursor Hosted Lane Standing Instructions](docs/lanes/cursor.md)
539
567
  - [Provider Matrix](docs/provider-matrix.md)
568
+ - [Provider Calibration Scorecard](docs/provider-calibration-scorecard.md)
540
569
  - [GitHub Setup](docs/github-setup.md)
541
570
  - [First Run Transcript](docs/first-run-transcript.md)
542
571
  - [First-User Demo Transcript](docs/first-user-demo-transcript.md)
@@ -556,6 +585,8 @@ first so local work exercises the same package entrypoint users install.
556
585
  - [v1.0.6 Release Notes](docs/v106-release-notes.md)
557
586
  - [v1.0.7 Release Notes](docs/v107-release-notes.md)
558
587
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
588
+ - [v1.0.9 Release Notes](docs/v109-release-notes.md)
589
+ - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
559
590
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
560
591
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
561
592
  - [Demo Calibration Example](examples/demo-calibration/README.md)
@@ -10,8 +10,7 @@ gate.
10
10
 
11
11
  The short version:
12
12
 
13
- - create safe, manual-first reviewer lanes for Codex, Claude, Gitar, and other
14
- AI review tools;
13
+ - create safe, manual-first peer-review lanes for Codex and Claude;
15
14
  - run setup diagnostics before a lane can surprise you with spend, source
16
15
  exposure, or GitHub Actions churn;
17
16
  - turn issue text, external docs, and project doctrine into local work orders
@@ -43,6 +42,18 @@ Code Mower should feel like an engineering tool, not a demo harness:
43
42
 
44
43
  ## What It Looks Like
45
44
 
45
+ Start with Claude Code and Codex, or choose your participants during setup with
46
+ `code-mower init --interactive`. For example, `code-mower init --with
47
+ claude,codex,devin` previews that selection. The generated configuration remembers
48
+ your choices for later sessions.
49
+
50
+ Ask the agent you are using to start a Code Mower session; that agent is the
51
+ default orchestrator. `code-mower session start --repo OWNER/REPO --with
52
+ claude,codex,devin --host codex` prepares the operating brief when invoked from
53
+ Codex. The host agent drives the work using available execution paths.
54
+ See [Participants And Sessions](docs/sessions.md) for setup, host identity,
55
+ and product-specific capabilities.
56
+
46
57
  `code-mower doctor --adoption --repo OWNER/REPO` is the first useful command
47
58
  for a real repository. It checks your runtime, GitHub setup, provider CLIs,
48
59
  token posture, optional cloud setup, private-repo Actions cost traps, and
@@ -62,7 +73,7 @@ Example, shortened:
62
73
  ```text
63
74
  $ code-mower doctor --adoption --repo OWNER/REPO
64
75
  PASS config.validate config validates
65
- PASS profile.select selected profile: codex, claude_audit, gitar
76
+ PASS profile.select selected profile: codex, claude_audit
66
77
  PASS runtime.python Python 3.12 satisfies Code Mower requirements
67
78
  PASS runtime.github_auth GitHub CLI auth probe succeeded
68
79
  PASS runtime.local_cli codex codex found
@@ -175,6 +186,12 @@ Cold adopters should start with the reviewer gate, then add builders, then
175
186
  measure builder experiments; provider experiments come after that base loop is
176
187
  observable.
177
188
 
189
+ The initial reviewer and builder paths default to Claude + Codex. Other
190
+ participants require an explicit setup selection. `code-mower next-steps --repo
191
+ OWNER/REPO --pr NUMBER` shows setup, peer-audit requests, status, and local
192
+ evidence. Add `--advanced` for calibration, migration, package rehearsal, and
193
+ optional cloud guidance after the initial loop works.
194
+
178
195
  Install first from the [Install And Bootstrap](docs/install.md) matrix: pipx for
179
196
  laptops, uv tool installs for hosted agents or CI boxes, and an editable venv
180
197
  for Code Mower contributors. All paths require Python 3.12 or newer. For
@@ -194,7 +211,7 @@ agent report its actual host posture, exact installed version, doctor result,
194
211
  Board URL, and any owner-only click-list before it mutates the repo.
195
212
 
196
213
  The current package-index announcement entry point is the tagged
197
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.8/docs/try-in-10-minutes.md)
214
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.10/docs/try-in-10-minutes.md)
198
215
  guide. The v1.0 supervised-pilot release includes the native Board, the
199
216
  controller dry-run and policy contract, adoption and upgrade hardening from
200
217
  recent install rehearsals, package-index release checks, provider-diversity
@@ -229,6 +246,15 @@ artifact, campaigns survive checkout changes, TestPyPI qualification is
229
246
  closed, Cursor builder identity is distinct from Grok review, Antigravity uses
230
247
  explicit project isolation, and hosted Cursor and Devin profiles require
231
248
  verified dispatch and result transport.
249
+ The v1.0.9 patch makes Board refresh recovery deterministic, turns package
250
+ installation failures into bounded actionable diagnostics, and lets release
251
+ campaigns require established providers while retaining slower or experimental
252
+ providers as informational evidence.
253
+ The v1.0.10 patch makes local builder lanes deliverable and recoverable: a
254
+ provider-neutral delivery contract with bounded no-change and owner-action
255
+ outcomes, process-group cleanup so a finished provider is not reported as a
256
+ timeout, simpler first-run defaults, host-led participant sessions, and a
257
+ published 20-sample provider calibration scorecard.
232
258
  Package-only users can start from the public package rather than a source
233
259
  checkout.
234
260
 
@@ -261,7 +287,7 @@ Provider-contract baseline for the next release train:
261
287
 
262
288
  For release verification,
263
289
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
264
- the package-index procedure for `v1.0.8` / `code-mower==1.0.8`. The
290
+ the package-index procedure for `v1.0.10` / `code-mower==1.0.10`. The
265
291
  GitHub release records the workflow and rehearsal evidence for the exact tag.
266
292
  After publication, [Release Qualification](docs/release-qualification.md)
267
293
  coordinates provider-specific install and operational checks without treating
@@ -324,10 +350,11 @@ optional work order, single-writer branch, reviewer lanes, and fix rounds. Code
324
350
  Mower's templates now support that loop end to end; humans still own
325
351
  credentials, branch protection, calibration, and owner decisions.
326
352
 
327
- The reference adoption shape is Claude Code as orchestrator; Claude Code,
328
- Codex, and Cursor as builder lanes; Claude Code and Codex as reviewer lanes;
329
- and Gitar or Antigravity as informational reviewer signal until local
330
- calibration says otherwise.
353
+ The initial adoption shape uses Claude Code or Codex as orchestrator, builder,
354
+ and peer reviewer. The owning builder remains the only writer, and the other
355
+ provider supplies independent review. Other builders and reviewers are explicit
356
+ later additions; they follow the same lane policy with provider-specific
357
+ execution and authentication where needed.
331
358
 
332
359
  ## Why Not Just Run Codex Or Claude Yourself?
333
360
 
@@ -409,10 +436,10 @@ The first recommended lanes are local/manual:
409
436
  | --- | --- | --- |
410
437
  | Codex audit | structured local peer audit | merge-gating eligible after setup |
411
438
  | Claude audit | structured local peer audit | merge-gating eligible after setup |
412
- | Gitar | advisory third signal | informational until calibrated |
413
439
 
414
- Everything else starts manual or informational until your own calibration data
415
- proves it is useful: Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
440
+ Everything else is opt-in after the Claude + Codex loop works and stays manual
441
+ or informational until your own calibration data proves it is useful: Gitar,
442
+ Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
416
443
  BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
417
444
 
418
445
  Gemini CLI and Antigravity are distinct lane ids even though both are Google
@@ -450,8 +477,8 @@ measurement work.
450
477
 
451
478
  ## Installation Status
452
479
 
453
- The current package-index release baseline is `v1.0.8`, with pinned package
454
- install spec `code-mower==1.0.8`. Release evidence is recorded on the GitHub
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
455
482
  release and in the first-user install rehearsal. The public repository is
456
483
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
457
484
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -486,8 +513,9 @@ first so local work exercises the same package entrypoint users install.
486
513
  conservative and team-controlled while automated retention jobs are roadmap
487
514
  work.
488
515
  - Advanced/provider/operator commands remain available behind
489
- `code-mower --help-all`. The default help path stays focused on `init`,
490
- `doctor`, calibration, value reports, and optional cloud export/upload.
516
+ `code-mower --help-all`. The default help path stays focused on setup,
517
+ `next-steps`, lane status, and local evidence; calibration and cloud commands
518
+ remain available through `--help-all`.
491
519
 
492
520
  ## Docs Map
493
521
 
@@ -507,6 +535,7 @@ first so local work exercises the same package entrypoint users install.
507
535
  - [Claude Lane Standing Instructions](docs/lanes/claude.md)
508
536
  - [Cursor Hosted Lane Standing Instructions](docs/lanes/cursor.md)
509
537
  - [Provider Matrix](docs/provider-matrix.md)
538
+ - [Provider Calibration Scorecard](docs/provider-calibration-scorecard.md)
510
539
  - [GitHub Setup](docs/github-setup.md)
511
540
  - [First Run Transcript](docs/first-run-transcript.md)
512
541
  - [First-User Demo Transcript](docs/first-user-demo-transcript.md)
@@ -526,6 +555,8 @@ first so local work exercises the same package entrypoint users install.
526
555
  - [v1.0.6 Release Notes](docs/v106-release-notes.md)
527
556
  - [v1.0.7 Release Notes](docs/v107-release-notes.md)
528
557
  - [v1.0.8 Release Notes](docs/v108-release-notes.md)
558
+ - [v1.0.9 Release Notes](docs/v109-release-notes.md)
559
+ - [v1.0.10 Release Notes](docs/v1010-release-notes.md)
529
560
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
530
561
  - [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
531
562
  - [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.8"
7
+ version = "1.0.10"
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.8"
3
+ __version__ = "1.0.10"
@@ -297,6 +297,8 @@ def _format_timestamp(value: datetime) -> str:
297
297
 
298
298
  STATUS_CACHE_RETRY_BASE_SECONDS = 5.0
299
299
  STATUS_CACHE_RETRY_MAX_SECONDS = 60.0
300
+ STATUS_CACHE_REFRESH_TIMEOUT_SECONDS = 120.0
301
+ STATUS_CACHE_TIMEOUT_SECONDS = STATUS_CACHE_REFRESH_TIMEOUT_SECONDS
300
302
 
301
303
 
302
304
  class StatusCache:
@@ -314,16 +316,20 @@ class StatusCache:
314
316
  consumers can identify *which* completed snapshot they are holding
315
317
  independently of whether that snapshot is still fresh.
316
318
 
317
- A failed refresh (or a failed refresh thread start) opens a bounded retry
318
- backoff window. Without it the cached snapshot stays stale while
319
- ``refresh_in_progress`` returns to false the instant the failure is
320
- recorded, so the very next request would start another expensive
321
- GitHub/local recomputation -- once per fast poll (~750ms) for as long as the
322
- failure persists. During the window ``get()`` still answers immediately from
323
- cold/stale metadata but starts nothing and reports ``refresh_in_progress``
324
- false, so the browser drops back to its normal interval. The window doubles
325
- per consecutive failure from ``retry_base_seconds`` up to
326
- ``retry_max_seconds`` and is cleared by the first success.
319
+ A failed refresh (including abnormal thread exits or non-``Exception``
320
+ terminations), a dead/abandoned refresh that exceeds the recovery timeout,
321
+ or a failed refresh thread start opens a bounded retry backoff window.
322
+ Without it the cached snapshot stays stale while ``refresh_in_progress``
323
+ returns to false the instant the failure is recorded, so the very next
324
+ request would start another expensive GitHub/local recomputation -- once
325
+ per fast poll (~750ms) for as long as the failure persists. During the
326
+ window ``get()`` still answers immediately from cold/stale metadata but
327
+ starts nothing and reports ``refresh_in_progress`` false, so the browser
328
+ drops back to its normal interval. The window doubles per consecutive
329
+ failure from ``retry_base_seconds`` up to ``retry_max_seconds`` and is
330
+ cleared by the first success. Ownership tokens ensure that late-exiting or
331
+ abandoned threads cannot overwrite newer generations or clear the
332
+ in-progress flag of a replacement refresh.
327
333
  """
328
334
 
329
335
  def __init__(
@@ -336,6 +342,8 @@ class StatusCache:
336
342
  start_thread: Any = None,
337
343
  retry_base_seconds: float = STATUS_CACHE_RETRY_BASE_SECONDS,
338
344
  retry_max_seconds: float = STATUS_CACHE_RETRY_MAX_SECONDS,
345
+ refresh_timeout_seconds: float = STATUS_CACHE_REFRESH_TIMEOUT_SECONDS,
346
+ timeout_seconds: float | None = None,
339
347
  ) -> None:
340
348
  self._compute = compute
341
349
  self._ttl_seconds = max(float(ttl_seconds), 0.0)
@@ -344,11 +352,16 @@ class StatusCache:
344
352
  self._start_thread = start_thread or self._default_start_thread
345
353
  self._retry_base_seconds = max(float(retry_base_seconds), 0.0)
346
354
  self._retry_max_seconds = max(float(retry_max_seconds), self._retry_base_seconds)
355
+ if timeout_seconds is not None:
356
+ refresh_timeout_seconds = timeout_seconds
357
+ self._refresh_timeout_seconds = max(float(refresh_timeout_seconds), 0.0)
347
358
  self._lock = Lock()
348
359
  self._snapshot: dict[str, Any] | None = None
349
360
  self._computed_at: datetime | None = None
350
361
  self._computed_monotonic: float | None = None
351
362
  self._refreshing = False
363
+ self._refresh_started_monotonic: float | None = None
364
+ self._refresh_owner = 0
352
365
  self._generation = 0
353
366
  self._last_error: str = ""
354
367
  self._last_error_at: datetime | None = None
@@ -403,6 +416,8 @@ class StatusCache:
403
416
  so nothing here can leak paths, output, or credentials.
404
417
  """
405
418
  self._refreshing = False
419
+ self._refresh_started_monotonic = None
420
+ self._refresh_owner += 1
406
421
  self._last_error = _cache_error_summary(exc)
407
422
  self._last_error_at = self._now()
408
423
  self._consecutive_failures += 1
@@ -418,6 +433,13 @@ class StatusCache:
418
433
  else None
419
434
  )
420
435
  is_stale = snapshot is None or age is None or age >= self._ttl_seconds
436
+ if (
437
+ self._refreshing
438
+ and self._refresh_started_monotonic is not None
439
+ and self._refresh_timeout_seconds > 0.0
440
+ and max(elapsed - self._refresh_started_monotonic, 0.0) >= self._refresh_timeout_seconds
441
+ ):
442
+ self._record_failure_locked(TimeoutError("status refresh timed out"))
421
443
  retry_in = (
422
444
  max(self._retry_after_monotonic - elapsed, 0.0)
423
445
  if self._retry_after_monotonic is not None
@@ -425,8 +447,12 @@ class StatusCache:
425
447
  )
426
448
  in_backoff = retry_in > 0.0
427
449
  should_start = is_stale and not self._refreshing and not in_backoff
450
+ owner: int | None = None
428
451
  if should_start:
429
452
  self._refreshing = True
453
+ self._refresh_owner += 1
454
+ owner = self._refresh_owner
455
+ self._refresh_started_monotonic = elapsed
430
456
  self._retry_after_monotonic = None
431
457
  metadata_snapshot = {
432
458
  "state": "cold" if snapshot is None else ("stale" if is_stale else "fresh"),
@@ -439,35 +465,54 @@ class StatusCache:
439
465
  "last_error": self._last_error,
440
466
  "last_error_at": _format_timestamp(self._last_error_at) if self._last_error_at else "",
441
467
  }
442
- if should_start:
468
+ if should_start and owner is not None:
469
+ def refresh_worker() -> None:
470
+ self._refresh(owner)
471
+
443
472
  try:
444
- self._start_thread(self._refresh)
445
- except Exception as exc: # noqa: BLE001 - a failed thread start must never crash the endpoint
473
+ self._start_thread(refresh_worker)
474
+ except (Exception, SystemExit) as exc: # noqa: BLE001 - a failed thread start must never crash the endpoint
446
475
  with self._lock:
447
- self._record_failure_locked(exc)
448
- metadata_snapshot["refresh_in_progress"] = False
449
- metadata_snapshot["retry_in_seconds"] = round(self._retry_delay_locked(), 3)
450
- metadata_snapshot["last_error"] = self._last_error
451
- metadata_snapshot["last_error_at"] = _format_timestamp(self._last_error_at)
476
+ if self._refresh_owner == owner:
477
+ self._record_failure_locked(exc)
478
+ metadata_snapshot["refresh_in_progress"] = False
479
+ metadata_snapshot["retry_in_seconds"] = round(self._retry_delay_locked(), 3)
480
+ metadata_snapshot["last_error"] = self._last_error
481
+ metadata_snapshot["last_error_at"] = _format_timestamp(self._last_error_at)
452
482
  return snapshot, metadata_snapshot
453
483
 
454
- def _refresh(self) -> None:
484
+ def _refresh(self, owner: int | None = None) -> None:
485
+ if owner is None:
486
+ with self._lock:
487
+ owner = self._refresh_owner
488
+ completed = False
455
489
  try:
456
490
  result = self._compute()
457
- except Exception as exc: # noqa: BLE001 - a background refresh must never crash the server
458
491
  with self._lock:
459
- self._record_failure_locked(exc)
492
+ if self._refresh_owner == owner:
493
+ self._snapshot = result
494
+ self._computed_at = self._now()
495
+ self._computed_monotonic = self._clock()
496
+ self._generation += 1
497
+ self._refreshing = False
498
+ self._refresh_started_monotonic = None
499
+ self._last_error = ""
500
+ self._last_error_at = None
501
+ self._consecutive_failures = 0
502
+ self._retry_after_monotonic = None
503
+ self._refresh_owner += 1
504
+ completed = True
505
+ except BaseException as exc: # noqa: BLE001 - a background refresh must never crash the server
506
+ with self._lock:
507
+ if self._refresh_owner == owner:
508
+ self._record_failure_locked(exc)
509
+ completed = True
460
510
  return
461
- with self._lock:
462
- self._snapshot = result
463
- self._computed_at = self._now()
464
- self._computed_monotonic = self._clock()
465
- self._generation += 1
466
- self._refreshing = False
467
- self._last_error = ""
468
- self._last_error_at = None
469
- self._consecutive_failures = 0
470
- self._retry_after_monotonic = None
511
+ finally:
512
+ if not completed:
513
+ with self._lock:
514
+ if self._refresh_owner == owner and self._refreshing:
515
+ self._record_failure_locked(RuntimeError("refresh thread exited abnormally"))
471
516
 
472
517
 
473
518
  def _pending_status_payload(config: BoardConfig) -> dict[str, Any]:
@@ -1370,7 +1415,7 @@ def render_board_html(config: BoardConfig) -> str:
1370
1415
  const campaigns = campaignsData.campaigns || [];
1371
1416
  const campaignRows = campaigns.flatMap(c => {{
1372
1417
  const header = `<div class="row"><div class="line"><b>Release ${{esc(c.release_tag)}}</b>${{pill(c.status)}}${{c.dry_run ? pill("dry-run") : pill("applied")}}${{pill(c.qualification_context)}}<span>${{seconds(c.elapsed_seconds)}}</span></div><div>next: <b>${{esc(c.next_action)}}</b></div></div>`;
1373
- const cardRows = (c.cards || []).map(card => `<div class="row" style="margin-left:16px"><div class="line"><b>${{esc(card.provider)}}</b><span class="${{stateClass(card.state)}}">${{esc(card.state)}}</span>${{pill(card.environment)}}${{card.transport_verified === false ? pill("transport unverified") : ""}}<span>${{seconds(card.elapsed_seconds)}}</span></div><div>next: <b>${{esc(card.next_action)}}</b></div>${{card.next_detail ? `<div class="muted">${{esc(card.next_detail)}}</div>` : ""}}${{card.response_deadline_at ? `<div class="muted" title="${{esc(card.response_deadline_at)}}">response deadline ${{localTime(card.response_deadline_at)}}</div>` : ""}}</div>`);
1418
+ const cardRows = (c.cards || []).map(card => `<div class="row" style="margin-left:16px"><div class="line"><b>${{esc(card.provider)}}</b>${{pill(card.posture || "required")}}<span class="${{stateClass(card.state)}}">${{esc(card.state)}}</span>${{pill(card.environment)}}${{card.transport_verified === false ? pill("transport unverified") : ""}}<span>${{seconds(card.elapsed_seconds)}}</span></div><div>next: <b>${{esc(card.next_action)}}</b></div>${{card.next_detail ? `<div class="muted">${{esc(card.next_detail)}}</div>` : ""}}${{card.response_deadline_at ? `<div class="muted" title="${{esc(card.response_deadline_at)}}">response deadline ${{localTime(card.response_deadline_at)}}</div>` : ""}}</div>`);
1374
1419
  return [header, ...cardRows];
1375
1420
  }}).join("");
1376
1421
  put("campaigns", campaignRows || empty(campaignsData.message || "No release campaigns."));
@@ -1815,14 +1860,16 @@ def make_handler(
1815
1860
  *,
1816
1861
  gh_json_runner: lane_status.GitHubJsonRunner = lane_status.run_gh_json,
1817
1862
  command_runner: lane_status.CommandRunner = lane_status.run_command,
1863
+ status_cache: StatusCache | None = None,
1818
1864
  ) -> type[BaseHTTPRequestHandler]:
1819
1865
  last_recorded_at: datetime | None = None
1820
1866
  last_recorded_generation = 0
1821
1867
  recording_lock = Lock()
1822
- status_cache = StatusCache(
1823
- lambda: status_payload(config, gh_json_runner=gh_json_runner, command_runner=command_runner),
1824
- ttl_seconds=config.refresh_seconds,
1825
- )
1868
+ if status_cache is None:
1869
+ status_cache = StatusCache(
1870
+ lambda: status_payload(config, gh_json_runner=gh_json_runner, command_runner=command_runner),
1871
+ ttl_seconds=config.refresh_seconds,
1872
+ )
1826
1873
 
1827
1874
  class BoardHandler(BaseHTTPRequestHandler):
1828
1875
  server_version = "CodeMowerBoard/0.1"
@@ -39,6 +39,8 @@ AUTHOR_INFERENCE_RULES = {
39
39
  "claude-bot": ("claude", "claude_code_action"),
40
40
  "cursor[bot]": ("cursor_cloud_agent", "cursor_cloud_agent"),
41
41
  "cursor": ("cursor_cloud_agent", "cursor_cloud_agent"),
42
+ "devin-ai-integration": ("devin", "devin"),
43
+ "devin-ai-integration[bot]": ("devin", "devin"),
42
44
  }
43
45
  BRANCH_PREFIX_INFERENCE_RULES = (
44
46
  ("cursor/", "cursor_cloud_agent", "cursor_cloud_agent"),
@@ -49,6 +51,8 @@ BRANCH_PREFIX_INFERENCE_RULES = (
49
51
  ("chatgpt-codex-", "codex", "chatgpt-codex-connector"),
50
52
  ("claude/", "claude", "claude_code_action"),
51
53
  ("claude-", "claude", "claude_code_action"),
54
+ ("devin/", "devin_cli", "devin_cli"),
55
+ ("devin-", "devin_cli", "devin_cli"),
52
56
  )
53
57
 
54
58