code-mower 0.5.0b51__tar.gz → 0.5.0b52__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 (341) hide show
  1. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/MANIFEST.in +2 -0
  2. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/PKG-INFO +49 -46
  3. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/README.md +48 -45
  4. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/pyproject.toml +2 -1
  5. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/__init__.py +1 -1
  6. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/audit_labeler_lib.py +222 -17
  7. code_mower-0.5.0b52/src/code_mower/audit_limits.py +141 -0
  8. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/claude_audit_pr.py +386 -86
  9. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cli.py +4 -1
  10. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/codex_audit_pr.py +640 -76
  11. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/config.py +270 -3
  12. code_mower-0.5.0b52/src/code_mower/decisions.py +717 -0
  13. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor.py +12 -0
  14. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/__init__.py +18 -0
  15. code_mower-0.5.0b52/src/code_mower/doctor_checks/audit_limits.py +186 -0
  16. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github.py +10 -0
  17. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_branch.py +17 -5
  18. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_human_token.py +10 -7
  19. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_repo.py +2 -2
  20. code_mower-0.5.0b52/src/code_mower/doctor_checks/provider_local_audit_setup.py +162 -0
  21. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/providers.py +8 -0
  22. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/registry.py +13 -2
  23. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/runner.py +27 -1
  24. code_mower-0.5.0b52/src/code_mower/doctor_checks/self_hosted_runner.py +964 -0
  25. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/init.py +1063 -57
  26. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/claude.py +1 -0
  27. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/codex.py +1 -0
  28. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/migration_mirror.py +1 -0
  29. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package.py +5 -0
  30. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package_content.py +24 -1
  31. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package_manifest.py +31 -0
  32. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/__init__.py +9 -1
  33. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/github_pr.py +31 -1
  34. code_mower-0.5.0b52/src/code_mower/provider_runners/repo_paths.py +87 -0
  35. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/code-mower.example.yml +20 -0
  36. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/base-audit.md +10 -0
  37. code_mower-0.5.0b52/src/code_mower/templates/lanes/README.md +39 -0
  38. code_mower-0.5.0b52/src/code_mower/templates/lanes/claude.md +22 -0
  39. code_mower-0.5.0b52/src/code_mower/templates/lanes/codex.md +22 -0
  40. code_mower-0.5.0b52/src/code_mower/templates/lanes/generic.md +20 -0
  41. code_mower-0.5.0b52/src/code_mower/templates/lanes/grok.md +22 -0
  42. code_mower-0.5.0b52/src/code_mower/templates/lanes/run_mac_lane.sh +529 -0
  43. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  44. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +81 -27
  45. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +3 -5
  46. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/code-mower-gate-health.yml.j2 +6 -7
  47. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +44 -17
  48. code_mower-0.5.0b52/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +549 -0
  49. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +1 -1
  50. code_mower-0.5.0b52/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +125 -0
  51. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +5 -5
  52. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/saas-reviewer-labeler.yml.j2 +1 -2
  53. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/self-hosted-local-audit.yml.j2 +6 -0
  54. {code_mower-0.5.0b51 → code_mower-0.5.0b52/src/code_mower}/templates/workflows/trailer-comment-labeler.yml.j2 +2 -2
  55. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/weekly-status.yml.j2 +9 -9
  56. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/trailer_comment_labeler.py +40 -3
  57. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/versioning.py +20 -0
  58. code_mower-0.5.0b52/src/code_mower/workflow_actionlint.py +231 -0
  59. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/PKG-INFO +49 -46
  60. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/SOURCES.txt +29 -0
  61. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/code-mower.yml.j2 +6 -0
  62. code_mower-0.5.0b52/templates/lanes/README.md +39 -0
  63. code_mower-0.5.0b52/templates/lanes/claude.md +22 -0
  64. code_mower-0.5.0b52/templates/lanes/codex.md +22 -0
  65. code_mower-0.5.0b52/templates/lanes/generic.md +20 -0
  66. code_mower-0.5.0b52/templates/lanes/grok.md +22 -0
  67. code_mower-0.5.0b52/templates/lanes/run_mac_lane.sh +529 -0
  68. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/builder-provenance.yml.j2 +1 -1
  69. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +81 -27
  70. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +3 -5
  71. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/code-mower-gate-health.yml.j2 +6 -7
  72. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/code-mower-gate.yml.j2 +44 -17
  73. code_mower-0.5.0b52/templates/workflows/dispatch-lanes.yml.j2 +549 -0
  74. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/hosted-bridge.yml.j2 +1 -1
  75. code_mower-0.5.0b52/templates/workflows/lane-mac-runner.yml.j2 +125 -0
  76. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/saas-reviewer-labeler.yml.j2 +1 -2
  77. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/self-hosted-local-audit.yml.j2 +6 -0
  78. {code_mower-0.5.0b51/src/code_mower → code_mower-0.5.0b52}/templates/workflows/trailer-comment-labeler.yml.j2 +2 -2
  79. code_mower-0.5.0b52/tests/test_audit_limits.py +71 -0
  80. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_builder_identity.py +22 -0
  81. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_claude_audit_pr.py +339 -0
  82. code_mower-0.5.0b52/tests/test_codex_audit_pr.py +715 -0
  83. code_mower-0.5.0b52/tests/test_decision_audit_integration.py +218 -0
  84. code_mower-0.5.0b52/tests/test_decisions.py +478 -0
  85. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_github_checks.py +95 -4
  86. code_mower-0.5.0b52/tests/test_doctor_provider_local_audit_setup.py +90 -0
  87. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_registry.py +35 -0
  88. code_mower-0.5.0b52/tests/test_doctor_self_hosted_runner.py +302 -0
  89. code_mower-0.5.0b52/tests/test_init_actionlint.py +134 -0
  90. code_mower-0.5.0b52/tests/test_init_build_loop.py +1713 -0
  91. code_mower-0.5.0b52/tests/test_plan_context.py +448 -0
  92. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_prompts.py +3 -0
  93. code_mower-0.5.0b52/tests/test_provider_runners_github_pr.py +166 -0
  94. code_mower-0.5.0b52/tests/test_provider_runners_repo_paths.py +59 -0
  95. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_release_hygiene.py +1066 -83
  96. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_trailer_comment_labeler.py +133 -1
  97. code_mower-0.5.0b51/src/code_mower/provider_runners/repo_paths.py +0 -23
  98. code_mower-0.5.0b51/tests/test_codex_audit_pr.py +0 -243
  99. code_mower-0.5.0b51/tests/test_plan_context.py +0 -241
  100. code_mower-0.5.0b51/tests/test_provider_runners_github_pr.py +0 -65
  101. code_mower-0.5.0b51/tests/test_provider_runners_repo_paths.py +0 -26
  102. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/CODE_OF_CONDUCT.md +0 -0
  103. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/LICENSE +0 -0
  104. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/NOTICE +0 -0
  105. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/SUPPORT.md +0 -0
  106. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/requirements/requirements.txt +0 -0
  107. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/setup.cfg +0 -0
  108. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/__init__.py +0 -0
  109. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/_base.py +0 -0
  110. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  111. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/gitar.py +0 -0
  112. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/greptile.py +0 -0
  113. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/adapters/qodo.py +0 -0
  114. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  115. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/audit_handoff_log.py +0 -0
  116. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/audit_progress.py +0 -0
  117. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/blind_review_artifacts.py +0 -0
  118. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/blind_review_coordinator.py +0 -0
  119. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/bootstrap.py +0 -0
  120. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/builder_experiment.py +0 -0
  121. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/builder_runs.py +0 -0
  122. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/__init__.py +0 -0
  123. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/arms.py +0 -0
  124. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/auto_discovery.py +0 -0
  125. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/commands.py +0 -0
  126. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/context_inputs.py +0 -0
  127. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/corpus.py +0 -0
  128. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/effect_report.py +0 -0
  129. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/evidence.py +0 -0
  130. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/evidence_report.py +0 -0
  131. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/identity.py +0 -0
  132. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/metrics.py +0 -0
  133. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/overlap.py +0 -0
  134. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/planning.py +0 -0
  135. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/policy.py +0 -0
  136. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/results.py +0 -0
  137. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/run_results.py +0 -0
  138. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/run_status.py +0 -0
  139. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/runner.py +0 -0
  140. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/truth.py +0 -0
  141. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/calibration/value_report.py +0 -0
  142. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/checks.py +0 -0
  143. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/claude_cli_bounce.py +0 -0
  144. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/claude_cli_environment.py +0 -0
  145. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/clear_stale.py +0 -0
  146. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud.py +0 -0
  147. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/__init__.py +0 -0
  148. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/bundle.py +0 -0
  149. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/doctor.py +0 -0
  150. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/dogfood.py +0 -0
  151. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/endpoints.py +0 -0
  152. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/errors.py +0 -0
  153. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/events.py +0 -0
  154. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/export.py +0 -0
  155. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/git_metadata.py +0 -0
  156. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/manifest.py +0 -0
  157. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/operations.py +0 -0
  158. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/reports.py +0 -0
  159. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/setup.py +0 -0
  160. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/cloud_client/upload.py +0 -0
  161. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/code_mower_calibration.py +0 -0
  162. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/code_mower_context_packs.py +0 -0
  163. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/code_mower_merge.py +0 -0
  164. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/code_mower_telemetry.py +0 -0
  165. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  166. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/codex_audit_env_preflight.py +0 -0
  167. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  168. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  169. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/cloud.py +0 -0
  170. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/common.py +0 -0
  171. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions.py +0 -0
  172. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  173. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  174. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  175. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  176. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  177. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  178. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  179. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  180. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_api.py +0 -0
  181. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_config.py +0 -0
  182. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/github_provider.py +0 -0
  183. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/groups.py +0 -0
  184. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/models.py +0 -0
  185. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/output.py +0 -0
  186. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/presets.py +0 -0
  187. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/privacy.py +0 -0
  188. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  189. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  190. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  191. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_env.py +0 -0
  192. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  193. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  194. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  195. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  196. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  197. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  198. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  199. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  200. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  201. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  202. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  203. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/runtime.py +0 -0
  204. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  205. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/gate_health.py +0 -0
  206. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  207. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/grok_build_audit_pr.py +0 -0
  208. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  209. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/__init__.py +0 -0
  210. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/aider.py +0 -0
  211. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  212. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/devin.py +0 -0
  213. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  214. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/grok_build.py +0 -0
  215. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  216. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/lane_configs/local_llm.py +0 -0
  217. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/local_llm_audit_pr.py +0 -0
  218. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/local_llm_bakeoff.py +0 -0
  219. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/local_llm_calibration.py +0 -0
  220. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/local_llm_profiles.py +0 -0
  221. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/migration.py +0 -0
  222. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/migration_install.py +0 -0
  223. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/migration_readiness.py +0 -0
  224. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/migration_rehearsal.py +0 -0
  225. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/next_steps.py +0 -0
  226. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package_paths.py +0 -0
  227. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package_rendering.py +0 -0
  228. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/package_static.py +0 -0
  229. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/plan_context.py +0 -0
  230. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/prompts.py +0 -0
  231. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_registry.py +0 -0
  232. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/comments.py +0 -0
  233. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/git.py +0 -0
  234. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/github_auth.py +0 -0
  235. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  236. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/process.py +0 -0
  237. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/text_schema.py +0 -0
  238. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  239. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/provider_runners/workspace.py +0 -0
  240. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/providers/__init__.py +0 -0
  241. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/providers/local_cli.py +0 -0
  242. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/providers/provenance.py +0 -0
  243. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/release_readiness.py +0 -0
  244. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/reviewer_metrics.py +0 -0
  245. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/reviewer_spend.py +0 -0
  246. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/saas_reviewer_labeler.py +0 -0
  247. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/secrets.py +0 -0
  248. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/builder-experiment.example.json +0 -0
  249. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  250. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/calibration-corpus.json +0 -0
  251. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/context-packs.example.json +0 -0
  252. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  253. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  254. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  255. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  256. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  257. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  258. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  259. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  260. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/code_mower +0 -0
  261. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  262. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  263. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  264. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  265. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  266. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/product-support/status_report.py +0 -0
  267. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/providers.yml +0 -0
  268. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  269. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  270. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  271. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  272. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  273. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  274. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower/work_orders.py +0 -0
  275. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/dependency_links.txt +0 -0
  276. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/entry_points.txt +0 -0
  277. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/requires.txt +0 -0
  278. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/src/code_mower.egg-info/top_level.txt +0 -0
  279. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/builder-experiment.example.json +0 -0
  280. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/calibration-corpus.example.json +0 -0
  281. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/calibration-corpus.json +0 -0
  282. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/context-packs.example.json +0 -0
  283. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/cursor/BUGBOT.md +0 -0
  284. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/acp_bridge.yml +0 -0
  285. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/aider.yml +0 -0
  286. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/antigravity_cli.yml +0 -0
  287. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/claude_audit.yml +0 -0
  288. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/claude_review.yml +0 -0
  289. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/coderabbit_cli.yml +0 -0
  290. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/codex.yml +0 -0
  291. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/cursor_bugbot.yml +0 -0
  292. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/devin.yml +0 -0
  293. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/gemini_cli.yml +0 -0
  294. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/gitar.yml +0 -0
  295. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/greptile.yml +0 -0
  296. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/hermes_cli.yml +0 -0
  297. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/local_llm.yml +0 -0
  298. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers/qodo.yml +0 -0
  299. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/providers.yml +0 -0
  300. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/reviewer-spend.example.json +0 -0
  301. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/reviewer-value-report.example.md +0 -0
  302. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  303. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  304. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  305. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  306. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  307. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_audit_comment_posture.py +0 -0
  308. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_builder_runs.py +0 -0
  309. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_calibration_effect_report.py +0 -0
  310. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_calibration_truth.py +0 -0
  311. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_checks.py +0 -0
  312. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_claude_cli_bounce.py +0 -0
  313. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_clear_stale.py +0 -0
  314. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_cloud_client.py +0 -0
  315. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_cloud_git_metadata.py +0 -0
  316. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_cloud_manifest.py +0 -0
  317. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_cloud_reports.py +0 -0
  318. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  319. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_codex_audit_env_preflight.py +0 -0
  320. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_actions_cost_summary.py +0 -0
  321. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_actions_failure_selection.py +0 -0
  322. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_boundaries.py +0 -0
  323. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_output.py +0 -0
  324. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_privacy.py +0 -0
  325. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_provider_env_required.py +0 -0
  326. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_provider_env_tokens.py +0 -0
  327. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_provider_probe.py +0 -0
  328. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_provider_review_hygiene.py +0 -0
  329. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_doctor_runtime.py +0 -0
  330. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_gate_health.py +0 -0
  331. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_local_llm_github_helpers.py +0 -0
  332. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_local_cli.py +0 -0
  333. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_comments.py +0 -0
  334. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_git.py +0 -0
  335. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_pr_worktree.py +0 -0
  336. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_process.py +0 -0
  337. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_text_schema.py +0 -0
  338. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_provider_runners_workspace.py +0 -0
  339. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_reviewer_metrics_core.py +0 -0
  340. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_reviewer_spend.py +0 -0
  341. {code_mower-0.5.0b51 → code_mower-0.5.0b52}/tests/test_work_orders.py +0 -0
@@ -1,9 +1,11 @@
1
1
  recursive-include src/code_mower/templates *.yml *.yaml *.json
2
2
  recursive-include src/code_mower/templates *.md
3
3
  recursive-include src/code_mower/templates *.j2
4
+ recursive-include src/code_mower/templates/lanes *
4
5
  recursive-include src/code_mower/templates/product-support *
5
6
  include src/code_mower/*.json
6
7
  recursive-include templates *.j2 *.json *.md *.yml *.yaml
8
+ recursive-include templates/lanes *
7
9
  include requirements/*.txt
8
10
  include LICENSE
9
11
  include NOTICE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.5.0b51
3
+ Version: 0.5.0b52
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -19,6 +19,9 @@ Code Mower helps teams set up AI peer-programmer and reviewer lanes on real
19
19
  GitHub pull requests, then measure which builders and reviewers are useful on
20
20
  their actual codebase.
21
21
 
22
+ Code Mower is beta, bring-your-own-agent-loop software for teams willing to
23
+ calibrate reviewers. It is not a drop-in autonomous merge gate.
24
+
22
25
  The short version:
23
26
 
24
27
  - create safe, manual-first reviewer lanes for Codex, Claude, Gitar, and other
@@ -97,46 +100,26 @@ known-blocked control, and three reviewer lanes. It shows the decision Code
97
100
  Mower is built to support: which AI reviewers are useful, noisy, expensive,
98
101
  fast, or eligible for stronger merge policy on your actual codebase.
99
102
 
100
- ## Try It First
101
-
102
- Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
103
-
104
- ```bash
105
- python3.12 --version
106
- pipx install --python python3.12 code-mower==0.5.0b51
107
- code-mower --version
108
- ```
109
-
110
- `0.5.0b51` is a beta release. Until Code Mower publishes a stable `1.0`
111
- line, use the explicit beta version above or allow prereleases with:
103
+ ## Start Here
112
104
 
113
- ```bash
114
- pipx install --python python3.12 --pip-args="--pre" code-mower
115
- ```
105
+ Choose one path. Each path has one guide and gets to one visible outcome.
116
106
 
117
- From the repository you want to pilot:
118
-
119
- ```bash
120
- code-mower init --easy
121
- code-mower doctor --preflight
122
- code-mower checks detect --json
123
- ```
107
+ | Path | Use When | Route | Guide |
108
+ | --- | --- | --- | --- |
109
+ | A. Reviewer gate in 10 minutes | You want one audited PR before recurring workflows or builder dispatch. | Install, run `init --easy`, run `doctor --preflight`, open a small setup PR, run Codex and Claude audits, then merge manually when the audit evidence is clean. | [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md) |
110
+ | B. Build loop in 30 minutes | You want builders plus an orchestrator pattern after the reviewer gate works. | Complete path A, then add the automation token, require `code-mower/gate` from Any source, enable repository auto-merge, prove the self-hosted Mac lane runner with `doctor --runner`, run `init --builders`, and dispatch the first issue. | [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md) |
124
111
 
125
- In Git worktrees, `checks detect` also offers `code-mower.pr-size`, a local
126
- PR-size lint that defaults to 300 changed lines and flags large batches of
127
- near-identical files.
112
+ The beta.52 announcement entry point remains the tagged
113
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.5.0-beta.52/docs/try-in-10-minutes.md)
114
+ guide.
128
115
 
129
- When those look sane, write the generated setup to a reviewable folder and
130
- produce the starter local report:
116
+ ## What Calibration Does And Does Not Prove
131
117
 
132
- ```bash
133
- code-mower init --easy --apply --output-dir .code-mower.generated
134
- code-mower calibration value-report .code-mower.generated/calibration-corpus.json \
135
- --output .code-mower/reviewer-value-report.md
136
- ```
118
+ The generated starter corpus proves that the commands run and the report path
119
+ works. It does not prove that a reviewer should gate merges. Promote reviewer
120
+ lanes only after repository-specific known-clean and known-blocked evidence
121
+ meets the [lane promotion policy](docs/lane-promotion-policy.md).
137
122
 
138
- The generated setup also includes the configurable owner escalation and weekly
139
- status digest templates. The generated starter corpus proves the command path.
140
123
  To bootstrap a draft from your repository history:
141
124
 
142
125
  ```bash
@@ -155,7 +138,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
155
138
 
156
139
  The current PyPI beta has been rehearsed end-to-end from a clean install:
157
140
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
158
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b51`.
141
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b52`.
159
142
 
160
143
  ## Optional: Plan Before Coding
161
144
 
@@ -205,6 +188,15 @@ That lets CodeMower.com show `issue -> plan -> work order -> builder run -> PR
205
188
  transcripts, prompts, or issue body text. See
206
189
  [docs/builders-grok-cursor.md](docs/builders-grok-cursor.md).
207
190
 
191
+ ## Roles
192
+
193
+ Code Mower records builder provenance for Claude Code, Codex, Cursor-style
194
+ hosted builders, and similar authoring lanes, then runs reviewer lanes against
195
+ the resulting pull requests. The orchestrator is a workflow convention: issue,
196
+ optional work order, single-writer branch, reviewer lanes, and fix rounds. Code
197
+ Mower's templates now support that loop end to end; humans still own
198
+ credentials, branch protection, calibration, and owner decisions.
199
+
208
200
  ## Why Not Just Run Codex Or Claude Yourself?
209
201
 
210
202
  You should, at first. Code Mower is not a replacement for a good local agent or
@@ -301,18 +293,18 @@ engineer can:
301
293
  7. optionally upload sanitized metadata to CodeMower.com and see useful team
302
294
  dashboard signal.
303
295
 
304
- Future builder/orchestrator experiments extend the same loop from "who reviews
305
- best?" to "which AI builder plus reviewer loop ships best on this product?" See
296
+ Build-loop templates extend the same loop from "who reviews best?" to "which AI
297
+ builder plus reviewer loop ships best on this product?" Start with
298
+ [docs/build-loop-in-30-minutes.md](docs/build-loop-in-30-minutes.md), then use
306
299
  [docs/builder-experiments.md](docs/builder-experiments.md) and
307
- [docs/authoring-intelligence.md](docs/authoring-intelligence.md). For hosted
308
- builder provenance, start with
309
- [docs/builders-grok-cursor.md](docs/builders-grok-cursor.md).
300
+ [docs/authoring-intelligence.md](docs/authoring-intelligence.md) for deeper
301
+ measurement work.
310
302
 
311
303
  ## Installation Status
312
304
 
313
- The current public beta is `v0.5.0-beta.51` from
305
+ The current public beta is `v0.5.0-beta.52` from
314
306
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
315
- as `code-mower==0.5.0b51` on [PyPI](https://pypi.org/project/code-mower/).
307
+ as `code-mower==0.5.0b52` on [PyPI](https://pypi.org/project/code-mower/).
316
308
  GitHub releases remain the auditable source for tags, build artifacts, and
317
309
  release notes.
318
310
 
@@ -349,7 +341,19 @@ The wrapper resolves Python 3.12+ and refuses stale or old system Python shims.
349
341
  ## Docs Map
350
342
 
351
343
  - [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md)
352
- - [Quickstart](docs/quickstart.md)
344
+ - [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md)
345
+ - [Quickstart Reference](docs/quickstart.md)
346
+ - [Planning And Work Orders](docs/planning-work-orders.md)
347
+ - [Builder Providers: Grok And Cursor](docs/builders-grok-cursor.md)
348
+ - [Build Loop Operations](docs/build-loop.md)
349
+ - [Self-Hosted Mac Runner](docs/self-hosted-mac-runner.md)
350
+ - [Local Audit Runner](docs/local-audit-runner.md)
351
+ - [Lane Standing Instructions](docs/lanes/README.md)
352
+ - [Codex Lane Standing Instructions](docs/lanes/codex.md)
353
+ - [Claude Lane Standing Instructions](docs/lanes/claude.md)
354
+ - [Cursor Hosted Lane Standing Instructions](docs/lanes/grok.md)
355
+ - [Provider Matrix](docs/provider-matrix.md)
356
+ - [GitHub Setup](docs/github-setup.md)
353
357
  - [First Run Transcript](docs/first-run-transcript.md)
354
358
  - [First-User Demo Transcript](docs/first-user-demo-transcript.md)
355
359
  - [First-User Install Rehearsal](docs/first-user-install-rehearsal.md)
@@ -358,8 +362,7 @@ The wrapper resolves Python 3.12+ and refuses stale or old system Python shims.
358
362
  - [PyPI Release Runbook](docs/pypi-release.md)
359
363
  - [Sample Doctor Output](docs/sample-doctor-output.md)
360
364
  - [Architecture](docs/architecture.md)
361
- - [Provider Matrix](docs/provider-matrix.md)
362
- - [GitHub Setup](docs/github-setup.md)
365
+ - [Lane Promotion Policy](docs/lane-promotion-policy.md)
363
366
  - [Cloud Sharing](docs/cloud-sharing.md)
364
367
  - [Cloud Data Contract](docs/cloud-data-contract.md)
365
368
  - [Privacy And Threat Model](docs/privacy-threat-model.md)
@@ -4,6 +4,9 @@ Code Mower helps teams set up AI peer-programmer and reviewer lanes on real
4
4
  GitHub pull requests, then measure which builders and reviewers are useful on
5
5
  their actual codebase.
6
6
 
7
+ Code Mower is beta, bring-your-own-agent-loop software for teams willing to
8
+ calibrate reviewers. It is not a drop-in autonomous merge gate.
9
+
7
10
  The short version:
8
11
 
9
12
  - create safe, manual-first reviewer lanes for Codex, Claude, Gitar, and other
@@ -82,46 +85,26 @@ known-blocked control, and three reviewer lanes. It shows the decision Code
82
85
  Mower is built to support: which AI reviewers are useful, noisy, expensive,
83
86
  fast, or eligible for stronger merge policy on your actual codebase.
84
87
 
85
- ## Try It First
86
-
87
- Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
88
-
89
- ```bash
90
- python3.12 --version
91
- pipx install --python python3.12 code-mower==0.5.0b51
92
- code-mower --version
93
- ```
94
-
95
- `0.5.0b51` is a beta release. Until Code Mower publishes a stable `1.0`
96
- line, use the explicit beta version above or allow prereleases with:
88
+ ## Start Here
97
89
 
98
- ```bash
99
- pipx install --python python3.12 --pip-args="--pre" code-mower
100
- ```
90
+ Choose one path. Each path has one guide and gets to one visible outcome.
101
91
 
102
- From the repository you want to pilot:
103
-
104
- ```bash
105
- code-mower init --easy
106
- code-mower doctor --preflight
107
- code-mower checks detect --json
108
- ```
92
+ | Path | Use When | Route | Guide |
93
+ | --- | --- | --- | --- |
94
+ | A. Reviewer gate in 10 minutes | You want one audited PR before recurring workflows or builder dispatch. | Install, run `init --easy`, run `doctor --preflight`, open a small setup PR, run Codex and Claude audits, then merge manually when the audit evidence is clean. | [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md) |
95
+ | B. Build loop in 30 minutes | You want builders plus an orchestrator pattern after the reviewer gate works. | Complete path A, then add the automation token, require `code-mower/gate` from Any source, enable repository auto-merge, prove the self-hosted Mac lane runner with `doctor --runner`, run `init --builders`, and dispatch the first issue. | [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md) |
109
96
 
110
- In Git worktrees, `checks detect` also offers `code-mower.pr-size`, a local
111
- PR-size lint that defaults to 300 changed lines and flags large batches of
112
- near-identical files.
97
+ The beta.52 announcement entry point remains the tagged
98
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.5.0-beta.52/docs/try-in-10-minutes.md)
99
+ guide.
113
100
 
114
- When those look sane, write the generated setup to a reviewable folder and
115
- produce the starter local report:
101
+ ## What Calibration Does And Does Not Prove
116
102
 
117
- ```bash
118
- code-mower init --easy --apply --output-dir .code-mower.generated
119
- code-mower calibration value-report .code-mower.generated/calibration-corpus.json \
120
- --output .code-mower/reviewer-value-report.md
121
- ```
103
+ The generated starter corpus proves that the commands run and the report path
104
+ works. It does not prove that a reviewer should gate merges. Promote reviewer
105
+ lanes only after repository-specific known-clean and known-blocked evidence
106
+ meets the [lane promotion policy](docs/lane-promotion-policy.md).
122
107
 
123
- The generated setup also includes the configurable owner escalation and weekly
124
- status digest templates. The generated starter corpus proves the command path.
125
108
  To bootstrap a draft from your repository history:
126
109
 
127
110
  ```bash
@@ -140,7 +123,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
140
123
 
141
124
  The current PyPI beta has been rehearsed end-to-end from a clean install:
142
125
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
143
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b51`.
126
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b52`.
144
127
 
145
128
  ## Optional: Plan Before Coding
146
129
 
@@ -190,6 +173,15 @@ That lets CodeMower.com show `issue -> plan -> work order -> builder run -> PR
190
173
  transcripts, prompts, or issue body text. See
191
174
  [docs/builders-grok-cursor.md](docs/builders-grok-cursor.md).
192
175
 
176
+ ## Roles
177
+
178
+ Code Mower records builder provenance for Claude Code, Codex, Cursor-style
179
+ hosted builders, and similar authoring lanes, then runs reviewer lanes against
180
+ the resulting pull requests. The orchestrator is a workflow convention: issue,
181
+ optional work order, single-writer branch, reviewer lanes, and fix rounds. Code
182
+ Mower's templates now support that loop end to end; humans still own
183
+ credentials, branch protection, calibration, and owner decisions.
184
+
193
185
  ## Why Not Just Run Codex Or Claude Yourself?
194
186
 
195
187
  You should, at first. Code Mower is not a replacement for a good local agent or
@@ -286,18 +278,18 @@ engineer can:
286
278
  7. optionally upload sanitized metadata to CodeMower.com and see useful team
287
279
  dashboard signal.
288
280
 
289
- Future builder/orchestrator experiments extend the same loop from "who reviews
290
- best?" to "which AI builder plus reviewer loop ships best on this product?" See
281
+ Build-loop templates extend the same loop from "who reviews best?" to "which AI
282
+ builder plus reviewer loop ships best on this product?" Start with
283
+ [docs/build-loop-in-30-minutes.md](docs/build-loop-in-30-minutes.md), then use
291
284
  [docs/builder-experiments.md](docs/builder-experiments.md) and
292
- [docs/authoring-intelligence.md](docs/authoring-intelligence.md). For hosted
293
- builder provenance, start with
294
- [docs/builders-grok-cursor.md](docs/builders-grok-cursor.md).
285
+ [docs/authoring-intelligence.md](docs/authoring-intelligence.md) for deeper
286
+ measurement work.
295
287
 
296
288
  ## Installation Status
297
289
 
298
- The current public beta is `v0.5.0-beta.51` from
290
+ The current public beta is `v0.5.0-beta.52` from
299
291
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
300
- as `code-mower==0.5.0b51` on [PyPI](https://pypi.org/project/code-mower/).
292
+ as `code-mower==0.5.0b52` on [PyPI](https://pypi.org/project/code-mower/).
301
293
  GitHub releases remain the auditable source for tags, build artifacts, and
302
294
  release notes.
303
295
 
@@ -334,7 +326,19 @@ The wrapper resolves Python 3.12+ and refuses stale or old system Python shims.
334
326
  ## Docs Map
335
327
 
336
328
  - [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md)
337
- - [Quickstart](docs/quickstart.md)
329
+ - [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md)
330
+ - [Quickstart Reference](docs/quickstart.md)
331
+ - [Planning And Work Orders](docs/planning-work-orders.md)
332
+ - [Builder Providers: Grok And Cursor](docs/builders-grok-cursor.md)
333
+ - [Build Loop Operations](docs/build-loop.md)
334
+ - [Self-Hosted Mac Runner](docs/self-hosted-mac-runner.md)
335
+ - [Local Audit Runner](docs/local-audit-runner.md)
336
+ - [Lane Standing Instructions](docs/lanes/README.md)
337
+ - [Codex Lane Standing Instructions](docs/lanes/codex.md)
338
+ - [Claude Lane Standing Instructions](docs/lanes/claude.md)
339
+ - [Cursor Hosted Lane Standing Instructions](docs/lanes/grok.md)
340
+ - [Provider Matrix](docs/provider-matrix.md)
341
+ - [GitHub Setup](docs/github-setup.md)
338
342
  - [First Run Transcript](docs/first-run-transcript.md)
339
343
  - [First-User Demo Transcript](docs/first-user-demo-transcript.md)
340
344
  - [First-User Install Rehearsal](docs/first-user-install-rehearsal.md)
@@ -343,8 +347,7 @@ The wrapper resolves Python 3.12+ and refuses stale or old system Python shims.
343
347
  - [PyPI Release Runbook](docs/pypi-release.md)
344
348
  - [Sample Doctor Output](docs/sample-doctor-output.md)
345
349
  - [Architecture](docs/architecture.md)
346
- - [Provider Matrix](docs/provider-matrix.md)
347
- - [GitHub Setup](docs/github-setup.md)
350
+ - [Lane Promotion Policy](docs/lane-promotion-policy.md)
348
351
  - [Cloud Sharing](docs/cloud-sharing.md)
349
352
  - [Cloud Data Contract](docs/cloud-data-contract.md)
350
353
  - [Privacy And Threat Model](docs/privacy-threat-model.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.5.0b51"
7
+ version = "0.5.0b52"
8
8
  description = "Multi-reviewer AI code audit orchestration"
9
9
  requires-python = ">=3.11"
10
10
  readme = "README.md"
@@ -31,6 +31,7 @@ code_mower = [
31
31
  "templates/**/*.yml",
32
32
  "templates/**/*.yaml",
33
33
  "templates/**/*.j2",
34
+ "templates/lanes/*",
34
35
  "templates/product-support/*",
35
36
  ]
36
37
 
@@ -1,3 +1,3 @@
1
1
  """Code Mower package."""
2
2
 
3
- __version__ = "0.5.0b51"
3
+ __version__ = "0.5.0b52"
@@ -22,6 +22,14 @@ from typing import Any, Callable, Dict, Mapping, Optional, Pattern, Sequence
22
22
  from urllib.parse import quote
23
23
  import re
24
24
 
25
+ if __package__:
26
+ try:
27
+ from . import decisions as code_mower_decisions
28
+ except ImportError: # pragma: no cover - copied tools fallback
29
+ import decisions as code_mower_decisions # type: ignore
30
+ else: # pragma: no cover - direct helper execution
31
+ import decisions as code_mower_decisions # type: ignore
32
+
25
33
  MIN_ABBREVIATED_SHA_LENGTH = 7
26
34
  AUTHOR_EXCLUSION_ENV = "CODE_MOWER_AUTHOR_EXCLUSION_JSON"
27
35
  ACTIONS_RUN_MARKER_RE = re.compile(
@@ -58,6 +66,35 @@ class ActionsRunMarker:
58
66
  body_sha256: str
59
67
 
60
68
 
69
+ @dataclass(frozen=True)
70
+ class AuditVerdict:
71
+ verdict: str
72
+ updated_at: str
73
+ created_at: str
74
+ comment_id: int
75
+ comment_index: int
76
+ run_id: str
77
+
78
+ def sort_key(self) -> tuple[str, str, int, int]:
79
+ return (self.updated_at, self.created_at, self.comment_id, self.comment_index)
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class AuditRunInFlight:
84
+ run_id: str
85
+ job_name: str
86
+ queued_since: str
87
+ run_status: str
88
+ job_status: str
89
+ job_conclusion: str
90
+
91
+ def description(self) -> str:
92
+ run_id = self.run_id or "unknown"
93
+ job_name = self.job_name or "unknown"
94
+ queued_since = self.queued_since or "unknown"
95
+ return f"run {run_id} job {job_name!r} queued since {queued_since}"
96
+
97
+
61
98
  @dataclass(frozen=True)
62
99
  class LaneConfig:
63
100
  name: str
@@ -71,6 +108,7 @@ class LaneConfig:
71
108
  pass_patterns: tuple[Pattern[str], ...]
72
109
  blocked_patterns: tuple[Pattern[str], ...]
73
110
  label_state_fallbacks: bool = False
111
+ decision_coverage: bool = False
74
112
  token_env_vars: tuple[str, ...] = ("GITHUB_TOKEN",)
75
113
 
76
114
  @functools.lru_cache(maxsize=1)
@@ -364,7 +402,12 @@ def audit_comment_head_sha(body: str) -> str:
364
402
  return match.group(1) if match else ""
365
403
 
366
404
 
367
- def terminal_audit_trailer_verdict(lane: Mapping[str, Any], body: str) -> str:
405
+ def terminal_audit_trailer_verdict(
406
+ lane: Mapping[str, Any],
407
+ body: str,
408
+ *,
409
+ decisions: Sequence[code_mower_decisions.DecisionRecord] = (),
410
+ ) -> str:
368
411
  candidates: list[tuple[int, str]] = []
369
412
  for label_key, verdict in (("done", "done"), ("blocked", "blocked")):
370
413
  label = str(lane.get(label_key) or "")
@@ -375,7 +418,18 @@ def terminal_audit_trailer_verdict(lane: Mapping[str, Any], body: str) -> str:
375
418
  candidates.append((index, verdict))
376
419
  if not candidates:
377
420
  return ""
378
- return max(candidates, key=lambda item: item[0])[1]
421
+ verdict = max(candidates, key=lambda item: item[0])[1]
422
+ if (
423
+ verdict == "blocked"
424
+ and lane.get("decision_coverage") is True
425
+ and code_mower_decisions.audit_blockers_are_decision_covered(
426
+ body,
427
+ decisions,
428
+ lane=str(lane.get("author_lane") or lane.get("id") or ""),
429
+ )
430
+ ):
431
+ return "done"
432
+ return verdict
379
433
 
380
434
 
381
435
  def current_audit_trailer_verdict(
@@ -383,10 +437,11 @@ def current_audit_trailer_verdict(
383
437
  body: str,
384
438
  *,
385
439
  head_sha: str,
440
+ decisions: Sequence[code_mower_decisions.DecisionRecord] = (),
386
441
  ) -> str:
387
442
  if "Head SHA: `" + head_sha + "`" not in body:
388
443
  return ""
389
- return terminal_audit_trailer_verdict(lane, body)
444
+ return terminal_audit_trailer_verdict(lane, body, decisions=decisions)
390
445
 
391
446
 
392
447
  def latest_current_audit_verdict(
@@ -398,14 +453,45 @@ def latest_current_audit_verdict(
398
453
  [Mapping[str, Any], str, str, object, str | None],
399
454
  bool,
400
455
  ],
456
+ decision_authorities: Sequence[str] = (),
401
457
  ) -> str:
402
- verdicts: list[tuple[tuple[str, str, int, int], str]] = []
458
+ verdict = latest_current_audit_verdict_detail(
459
+ lane,
460
+ comments,
461
+ head_sha=head_sha,
462
+ trusted_comment_author=trusted_comment_author,
463
+ decision_authorities=decision_authorities,
464
+ )
465
+ return verdict.verdict if verdict else ""
466
+
467
+
468
+ def latest_current_audit_verdict_detail(
469
+ lane: Mapping[str, Any],
470
+ comments: Sequence[Mapping[str, Any]],
471
+ *,
472
+ head_sha: str,
473
+ trusted_comment_author: Callable[
474
+ [Mapping[str, Any], str, str, object, str | None],
475
+ bool,
476
+ ],
477
+ decision_authorities: Sequence[str] = (),
478
+ ) -> AuditVerdict | None:
479
+ verdicts: list[AuditVerdict] = []
480
+ decisions = code_mower_decisions.collect_decision_records_from_comments(
481
+ comments,
482
+ authorities=decision_authorities,
483
+ )
403
484
  for index, comment in enumerate(comments):
404
485
  author = str(((comment.get("user") or {}).get("login")) or "")
405
486
  body = str(comment.get("body") or "")
406
487
  if not trusted_comment_author(lane, author, body, comment.get("id"), None):
407
488
  continue
408
- verdict = current_audit_trailer_verdict(lane, body, head_sha=head_sha)
489
+ verdict = current_audit_trailer_verdict(
490
+ lane,
491
+ body,
492
+ head_sha=head_sha,
493
+ decisions=decisions,
494
+ )
409
495
  if verdict:
410
496
  try:
411
497
  comment_id = int(comment.get("id") or 0)
@@ -419,10 +505,46 @@ def latest_current_audit_verdict(
419
505
  or ""
420
506
  )
421
507
  created = str(comment.get("created_at") or comment.get("createdAt") or "")
422
- verdicts.append(((updated, created, comment_id, index), verdict))
508
+ verdicts.append(
509
+ AuditVerdict(
510
+ verdict=verdict,
511
+ updated_at=updated,
512
+ created_at=created,
513
+ comment_id=comment_id,
514
+ comment_index=index,
515
+ run_id=parse_audit_run_id(body),
516
+ )
517
+ )
423
518
  if verdicts:
424
- return max(verdicts, key=lambda item: item[0])[1]
425
- return ""
519
+ return max(verdicts, key=lambda item: item.sort_key())
520
+ return None
521
+
522
+
523
+ def audit_verdict_newer_than_in_flight(
524
+ verdict: AuditVerdict | None,
525
+ detail: AuditRunInFlight,
526
+ ) -> bool:
527
+ if (
528
+ verdict is None
529
+ or verdict.verdict != "done"
530
+ or not verdict.updated_at
531
+ or not detail.queued_since
532
+ ):
533
+ return False
534
+ try:
535
+ verdict_run_id = int(verdict.run_id)
536
+ detail_run_id = int(detail.run_id)
537
+ except (TypeError, ValueError):
538
+ verdict_run_id = None
539
+ detail_run_id = None
540
+ if verdict_run_id is not None and detail_run_id is not None:
541
+ if verdict_run_id != detail_run_id:
542
+ return verdict_run_id > detail_run_id
543
+ if verdict.updated_at > detail.queued_since:
544
+ return True
545
+ if verdict.updated_at != detail.queued_since:
546
+ return False
547
+ return False
426
548
 
427
549
 
428
550
  def attested_non_current_audit_heads(
@@ -502,23 +624,69 @@ def audit_job_matches_lane(job: Mapping[str, Any], lane: Mapping[str, Any]) -> b
502
624
  return any(token in name for token in _audit_lane_match_tokens(lane))
503
625
 
504
626
 
505
- def audit_run_in_flight_for_lane(
627
+ def _audit_mapping_timestamp(item: Mapping[str, Any], keys: Sequence[str]) -> str:
628
+ for key in keys:
629
+ value = str(item.get(key) or "")
630
+ if value:
631
+ return value
632
+ return ""
633
+
634
+
635
+ def audit_run_queued_since(
636
+ run: Mapping[str, Any],
637
+ job: Mapping[str, Any] | None = None,
638
+ ) -> str:
639
+ if job is not None:
640
+ job_time = _audit_mapping_timestamp(
641
+ job,
642
+ (
643
+ "queued_at",
644
+ "queuedAt",
645
+ "started_at",
646
+ "startedAt",
647
+ "created_at",
648
+ "createdAt",
649
+ "completed_at",
650
+ "completedAt",
651
+ ),
652
+ )
653
+ if job_time:
654
+ return job_time
655
+ return _audit_mapping_timestamp(
656
+ run,
657
+ (
658
+ "created_at",
659
+ "createdAt",
660
+ "queued_at",
661
+ "queuedAt",
662
+ "run_started_at",
663
+ "runStartedAt",
664
+ "started_at",
665
+ "startedAt",
666
+ "updated_at",
667
+ "updatedAt",
668
+ ),
669
+ )
670
+
671
+
672
+ def audit_run_in_flight_detail_for_lane(
506
673
  entry: Mapping[str, Any],
507
674
  lane: Mapping[str, Any],
508
675
  *,
509
676
  head_sha: str,
510
677
  pr_number: int | str,
511
- ) -> bool:
678
+ ) -> AuditRunInFlight | None:
512
679
  run = entry.get("run") if isinstance(entry.get("run"), Mapping) else entry
513
680
  if not isinstance(run, Mapping):
514
- return False
515
- if str(run.get("status") or "") not in AUDIT_RUN_NON_TERMINAL_STATUSES:
516
- return False
681
+ return None
682
+ run_status = str(run.get("status") or "")
683
+ if run_status not in AUDIT_RUN_NON_TERMINAL_STATUSES:
684
+ return None
517
685
  workflows = parse_csv_set(str(lane.get("github_actions_workflows") or ""))
518
686
  if not workflow_path_matches(audit_run_workflow_path(run), workflows):
519
- return False
687
+ return None
520
688
  if not audit_run_matches_pr_head(run, head_sha=head_sha, pr_number=pr_number):
521
- return False
689
+ return None
522
690
  jobs = entry.get("jobs") if isinstance(entry.get("jobs"), list) else []
523
691
  non_terminal_jobs = [
524
692
  job
@@ -530,8 +698,45 @@ def audit_run_in_flight_for_lane(
530
698
  )
531
699
  ]
532
700
  if non_terminal_jobs:
533
- return any(audit_job_matches_lane(job, lane) for job in non_terminal_jobs)
534
- return bool(entry.get("jobs_fetch_failed") or not jobs)
701
+ for job in non_terminal_jobs:
702
+ if audit_job_matches_lane(job, lane):
703
+ return AuditRunInFlight(
704
+ run_id=str(run.get("id") or ""),
705
+ job_name=str(job.get("name") or ""),
706
+ queued_since=audit_run_queued_since(run, job),
707
+ run_status=run_status,
708
+ job_status=str(job.get("status") or ""),
709
+ job_conclusion=str(job.get("conclusion") or ""),
710
+ )
711
+ return None
712
+ if entry.get("jobs_fetch_failed") or not jobs:
713
+ return AuditRunInFlight(
714
+ run_id=str(run.get("id") or ""),
715
+ job_name="jobs unavailable",
716
+ queued_since=audit_run_queued_since(run),
717
+ run_status=run_status,
718
+ job_status="unknown",
719
+ job_conclusion="",
720
+ )
721
+ return None
722
+
723
+
724
+ def audit_run_in_flight_for_lane(
725
+ entry: Mapping[str, Any],
726
+ lane: Mapping[str, Any],
727
+ *,
728
+ head_sha: str,
729
+ pr_number: int | str,
730
+ ) -> bool:
731
+ return (
732
+ audit_run_in_flight_detail_for_lane(
733
+ entry,
734
+ lane,
735
+ head_sha=head_sha,
736
+ pr_number=pr_number,
737
+ )
738
+ is not None
739
+ )
535
740
 
536
741
 
537
742
  def _pr_item_matches_head(