code-mower 0.5.0b44__tar.gz → 0.5.0b45__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 (303) hide show
  1. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/PKG-INFO +6 -6
  2. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/README.md +5 -5
  3. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/pyproject.toml +1 -1
  4. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/__init__.py +1 -1
  5. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/claude_audit_pr.py +3 -0
  6. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cli.py +4 -1
  7. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/code_mower_telemetry.py +26 -7
  8. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/codex_audit_pr.py +3 -0
  9. code_mower-0.5.0b45/src/code_mower/gate_health.py +739 -0
  10. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/init.py +28 -6
  11. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/migration_mirror.py +1 -0
  12. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package_manifest.py +1 -0
  13. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/verdict_artifacts.py +6 -0
  14. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/code-mower.example.yml +3 -0
  15. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/base-audit.md +3 -0
  16. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  17. code_mower-0.5.0b45/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +55 -0
  18. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +24 -1
  19. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/PKG-INFO +6 -6
  20. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/SOURCES.txt +3 -0
  21. code_mower-0.5.0b45/templates/workflows/code-mower-gate-health.yml.j2 +55 -0
  22. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/self-hosted-local-audit.yml.j2 +24 -1
  23. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_claude_audit_pr.py +2 -0
  24. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_codex_audit_pr.py +2 -0
  25. code_mower-0.5.0b45/tests/test_gate_health.py +669 -0
  26. code_mower-0.5.0b45/tests/test_prompts.py +18 -0
  27. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_release_hygiene.py +120 -135
  28. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_reviewer_metrics_core.py +19 -13
  29. code_mower-0.5.0b44/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -321
  30. code_mower-0.5.0b44/templates/workflows/code-mower-gate-health.yml.j2 +0 -321
  31. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/CODE_OF_CONDUCT.md +0 -0
  32. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/LICENSE +0 -0
  33. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/MANIFEST.in +0 -0
  34. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/NOTICE +0 -0
  35. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/SUPPORT.md +0 -0
  36. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/requirements/requirements.txt +0 -0
  37. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/setup.cfg +0 -0
  38. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/__init__.py +0 -0
  39. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/_base.py +0 -0
  40. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  41. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/gitar.py +0 -0
  42. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/greptile.py +0 -0
  43. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/adapters/qodo.py +0 -0
  44. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  45. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/audit_handoff_log.py +0 -0
  46. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/audit_labeler_lib.py +0 -0
  47. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/audit_progress.py +0 -0
  48. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/blind_review_artifacts.py +0 -0
  49. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/blind_review_coordinator.py +0 -0
  50. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/bootstrap.py +0 -0
  51. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/builder_experiment.py +0 -0
  52. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/builder_runs.py +0 -0
  53. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/__init__.py +0 -0
  54. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/arms.py +0 -0
  55. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/auto_discovery.py +0 -0
  56. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/commands.py +0 -0
  57. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/context_inputs.py +0 -0
  58. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/corpus.py +0 -0
  59. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/effect_report.py +0 -0
  60. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/evidence.py +0 -0
  61. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/evidence_report.py +0 -0
  62. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/identity.py +0 -0
  63. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/metrics.py +0 -0
  64. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/overlap.py +0 -0
  65. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/planning.py +0 -0
  66. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/policy.py +0 -0
  67. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/results.py +0 -0
  68. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/run_results.py +0 -0
  69. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/run_status.py +0 -0
  70. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/runner.py +0 -0
  71. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/truth.py +0 -0
  72. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/calibration/value_report.py +0 -0
  73. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/checks.py +0 -0
  74. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/claude_cli_bounce.py +0 -0
  75. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/claude_cli_environment.py +0 -0
  76. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/clear_stale.py +0 -0
  77. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud.py +0 -0
  78. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/__init__.py +0 -0
  79. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/bundle.py +0 -0
  80. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/doctor.py +0 -0
  81. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/dogfood.py +0 -0
  82. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/endpoints.py +0 -0
  83. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/errors.py +0 -0
  84. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/events.py +0 -0
  85. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/export.py +0 -0
  86. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/git_metadata.py +0 -0
  87. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/manifest.py +0 -0
  88. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/operations.py +0 -0
  89. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/reports.py +0 -0
  90. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/setup.py +0 -0
  91. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/cloud_client/upload.py +0 -0
  92. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/code_mower_calibration.py +0 -0
  93. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/code_mower_context_packs.py +0 -0
  94. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/code_mower_merge.py +0 -0
  95. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  96. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/codex_audit_env_preflight.py +0 -0
  97. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  98. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  99. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/config.py +0 -0
  100. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor.py +0 -0
  101. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/__init__.py +0 -0
  102. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/cloud.py +0 -0
  103. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/common.py +0 -0
  104. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github.py +0 -0
  105. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions.py +0 -0
  106. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  107. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  108. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  109. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  110. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  111. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  112. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  113. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  114. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_api.py +0 -0
  115. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_branch.py +0 -0
  116. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_config.py +0 -0
  117. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_provider.py +0 -0
  118. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/github_repo.py +0 -0
  119. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/groups.py +0 -0
  120. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/models.py +0 -0
  121. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/output.py +0 -0
  122. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/presets.py +0 -0
  123. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/privacy.py +0 -0
  124. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  125. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  126. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  127. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_env.py +0 -0
  128. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  129. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  130. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  131. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  132. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  133. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  134. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  135. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  136. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  137. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  138. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  139. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/providers.py +0 -0
  140. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/registry.py +0 -0
  141. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/runner.py +0 -0
  142. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/runtime.py +0 -0
  143. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  144. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  145. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/grok_build_audit_pr.py +0 -0
  146. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  147. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/__init__.py +0 -0
  148. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/aider.py +0 -0
  149. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  150. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/claude.py +0 -0
  151. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/codex.py +0 -0
  152. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/devin.py +0 -0
  153. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  154. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/grok_build.py +0 -0
  155. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  156. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/lane_configs/local_llm.py +0 -0
  157. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/local_llm_audit_pr.py +0 -0
  158. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/local_llm_bakeoff.py +0 -0
  159. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/local_llm_calibration.py +0 -0
  160. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/local_llm_profiles.py +0 -0
  161. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/migration.py +0 -0
  162. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/migration_install.py +0 -0
  163. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/migration_readiness.py +0 -0
  164. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/migration_rehearsal.py +0 -0
  165. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/next_steps.py +0 -0
  166. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package.py +0 -0
  167. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package_content.py +0 -0
  168. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package_paths.py +0 -0
  169. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package_rendering.py +0 -0
  170. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/package_static.py +0 -0
  171. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/plan_context.py +0 -0
  172. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/prompts.py +0 -0
  173. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_registry.py +0 -0
  174. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/__init__.py +0 -0
  175. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/comments.py +0 -0
  176. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/git.py +0 -0
  177. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/github_auth.py +0 -0
  178. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/github_pr.py +0 -0
  179. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  180. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/process.py +0 -0
  181. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/repo_paths.py +0 -0
  182. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/text_schema.py +0 -0
  183. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/provider_runners/workspace.py +0 -0
  184. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/providers/__init__.py +0 -0
  185. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/providers/local_cli.py +0 -0
  186. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/providers/provenance.py +0 -0
  187. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/release_readiness.py +0 -0
  188. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/reviewer_metrics.py +0 -0
  189. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/reviewer_spend.py +0 -0
  190. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/saas_reviewer_labeler.py +0 -0
  191. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/secrets.py +0 -0
  192. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/builder-experiment.example.json +0 -0
  193. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  194. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/calibration-corpus.json +0 -0
  195. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/context-packs.example.json +0 -0
  196. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  197. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  198. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  199. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  200. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  201. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  202. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  203. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  204. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/code_mower +0 -0
  205. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  206. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  207. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  208. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  209. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  210. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/product-support/status_report.py +0 -0
  211. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/providers.yml +0 -0
  212. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  213. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  214. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  215. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  216. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  217. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  218. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  219. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  220. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  221. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  222. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  223. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  224. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/trailer_comment_labeler.py +0 -0
  225. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/versioning.py +0 -0
  226. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower/work_orders.py +0 -0
  227. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/dependency_links.txt +0 -0
  228. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/entry_points.txt +0 -0
  229. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/requires.txt +0 -0
  230. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/src/code_mower.egg-info/top_level.txt +0 -0
  231. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/builder-experiment.example.json +0 -0
  232. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/calibration-corpus.example.json +0 -0
  233. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/calibration-corpus.json +0 -0
  234. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/code-mower.yml.j2 +0 -0
  235. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/context-packs.example.json +0 -0
  236. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/cursor/BUGBOT.md +0 -0
  237. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/acp_bridge.yml +0 -0
  238. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/aider.yml +0 -0
  239. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/antigravity_cli.yml +0 -0
  240. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/claude_audit.yml +0 -0
  241. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/claude_review.yml +0 -0
  242. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/coderabbit_cli.yml +0 -0
  243. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/codex.yml +0 -0
  244. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/cursor_bugbot.yml +0 -0
  245. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/devin.yml +0 -0
  246. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/gemini_cli.yml +0 -0
  247. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/gitar.yml +0 -0
  248. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/greptile.yml +0 -0
  249. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/hermes_cli.yml +0 -0
  250. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/local_llm.yml +0 -0
  251. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers/qodo.yml +0 -0
  252. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/providers.yml +0 -0
  253. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/reviewer-spend.example.json +0 -0
  254. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/reviewer-value-report.example.md +0 -0
  255. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  256. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  257. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/builder-provenance.yml.j2 +0 -0
  258. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  259. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  260. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  261. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  262. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  263. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  264. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  265. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_audit_comment_posture.py +0 -0
  266. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_builder_identity.py +0 -0
  267. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_builder_runs.py +0 -0
  268. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_calibration_effect_report.py +0 -0
  269. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_calibration_truth.py +0 -0
  270. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_checks.py +0 -0
  271. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_claude_cli_bounce.py +0 -0
  272. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_clear_stale.py +0 -0
  273. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_cloud_client.py +0 -0
  274. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_cloud_git_metadata.py +0 -0
  275. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_cloud_manifest.py +0 -0
  276. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_cloud_reports.py +0 -0
  277. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  278. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_codex_audit_env_preflight.py +0 -0
  279. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_actions_cost_summary.py +0 -0
  280. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_actions_failure_selection.py +0 -0
  281. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_boundaries.py +0 -0
  282. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_github_checks.py +0 -0
  283. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_output.py +0 -0
  284. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_privacy.py +0 -0
  285. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_provider_env_required.py +0 -0
  286. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_provider_env_tokens.py +0 -0
  287. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_provider_probe.py +0 -0
  288. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_provider_review_hygiene.py +0 -0
  289. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_doctor_registry.py +0 -0
  290. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_local_llm_github_helpers.py +0 -0
  291. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_plan_context.py +0 -0
  292. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_local_cli.py +0 -0
  293. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_comments.py +0 -0
  294. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_git.py +0 -0
  295. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_github_pr.py +0 -0
  296. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_pr_worktree.py +0 -0
  297. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_process.py +0 -0
  298. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_repo_paths.py +0 -0
  299. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_text_schema.py +0 -0
  300. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_provider_runners_workspace.py +0 -0
  301. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_reviewer_spend.py +0 -0
  302. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_trailer_comment_labeler.py +0 -0
  303. {code_mower-0.5.0b44 → code_mower-0.5.0b45}/tests/test_work_orders.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.5.0b44
3
+ Version: 0.5.0b45
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -103,11 +103,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
103
103
 
104
104
  ```bash
105
105
  python3.12 --version
106
- pipx install --python python3.12 code-mower==0.5.0b44
106
+ pipx install --python python3.12 code-mower==0.5.0b45
107
107
  code-mower --version
108
108
  ```
109
109
 
110
- `0.5.0b44` is a beta release. Until Code Mower publishes a stable `1.0`
110
+ `0.5.0b45` is a beta release. Until Code Mower publishes a stable `1.0`
111
111
  line, use the explicit beta version above or allow prereleases with:
112
112
 
113
113
  ```bash
@@ -155,7 +155,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
155
155
 
156
156
  The current PyPI beta has been rehearsed end-to-end from a clean install:
157
157
  [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.0b44`.
158
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b45`.
159
159
 
160
160
  ## Optional: Plan Before Coding
161
161
 
@@ -310,9 +310,9 @@ builder provenance, start with
310
310
 
311
311
  ## Installation Status
312
312
 
313
- The current public beta is `v0.5.0-beta.44` from
313
+ The current public beta is `v0.5.0-beta.45` from
314
314
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
315
- as `code-mower==0.5.0b44` on [PyPI](https://pypi.org/project/code-mower/).
315
+ as `code-mower==0.5.0b45` on [PyPI](https://pypi.org/project/code-mower/).
316
316
  GitHub releases remain the auditable source for tags, build artifacts, and
317
317
  release notes.
318
318
 
@@ -88,11 +88,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
88
88
 
89
89
  ```bash
90
90
  python3.12 --version
91
- pipx install --python python3.12 code-mower==0.5.0b44
91
+ pipx install --python python3.12 code-mower==0.5.0b45
92
92
  code-mower --version
93
93
  ```
94
94
 
95
- `0.5.0b44` is a beta release. Until Code Mower publishes a stable `1.0`
95
+ `0.5.0b45` is a beta release. Until Code Mower publishes a stable `1.0`
96
96
  line, use the explicit beta version above or allow prereleases with:
97
97
 
98
98
  ```bash
@@ -140,7 +140,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
140
140
 
141
141
  The current PyPI beta has been rehearsed end-to-end from a clean install:
142
142
  [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.0b44`.
143
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b45`.
144
144
 
145
145
  ## Optional: Plan Before Coding
146
146
 
@@ -295,9 +295,9 @@ builder provenance, start with
295
295
 
296
296
  ## Installation Status
297
297
 
298
- The current public beta is `v0.5.0-beta.44` from
298
+ The current public beta is `v0.5.0-beta.45` from
299
299
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
300
- as `code-mower==0.5.0b44` on [PyPI](https://pypi.org/project/code-mower/).
300
+ as `code-mower==0.5.0b45` on [PyPI](https://pypi.org/project/code-mower/).
301
301
  GitHub releases remain the auditable source for tags, build artifacts, and
302
302
  release notes.
303
303
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.5.0b44"
7
+ version = "0.5.0b45"
8
8
  description = "Multi-reviewer AI code audit orchestration"
9
9
  requires-python = ">=3.11"
10
10
  readme = "README.md"
@@ -1,3 +1,3 @@
1
1
  """Code Mower package."""
2
2
 
3
- __version__ = "0.5.0b44"
3
+ __version__ = "0.5.0b45"
@@ -946,6 +946,7 @@ def format_comment(
946
946
 
947
947
 
948
948
  def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAuditResult:
949
+ audit_started = time.monotonic()
949
950
  local_repo = config.repo_paths.get(repo)
950
951
  if local_repo is None:
951
952
  raise ValueError(
@@ -1038,6 +1039,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
1038
1039
  trailer=result.trailer,
1039
1040
  comment_body=comment_body,
1040
1041
  quarantine_reason=quarantine_reason,
1042
+ duration_seconds=time.monotonic() - audit_started,
1041
1043
  )
1042
1044
  result.verdict_artifact_path = artifact_path
1043
1045
  if artifact_path is not None:
@@ -1239,6 +1241,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
1239
1241
  trailer=trailer,
1240
1242
  comment_body=comment_body,
1241
1243
  quarantine_reason=quarantine_reason,
1244
+ duration_seconds=time.monotonic() - audit_started,
1242
1245
  )
1243
1246
  result.verdict_artifact_path = artifact_path
1244
1247
  if artifact_path is not None:
@@ -14,7 +14,7 @@ from pathlib import Path
14
14
  if __package__ in {None, ""}:
15
15
  raise SystemExit(
16
16
  "code_mower.cli is a packaged entrypoint. Install Code Mower with "
17
- "`pipx install code-mower==0.5.0b44`, or run source checkouts with "
17
+ "`pipx install code-mower==0.5.0b45`, or run source checkouts with "
18
18
  "`PYTHONPATH=src python -m code_mower.cli`."
19
19
  )
20
20
 
@@ -40,6 +40,7 @@ from . import code_mower_telemetry
40
40
  from . import config as code_mower_config
41
41
  from . import doctor as code_mower_doctor
42
42
  from . import gemini_cli_audit_pr
43
+ from . import gate_health as code_mower_gate_health
43
44
  from . import grok_build_audit_pr
44
45
  from . import hermes_cli_audit_pr
45
46
  from . import init as code_mower_init
@@ -398,6 +399,7 @@ COMMAND_DESCRIPTIONS: dict[str, str] = {
398
399
  "codex-audit-schema-smoke": "Smoke-test Codex audit schema parsing.",
399
400
  "doctor": "Check runtime, GitHub, providers, privacy, and cloud setup.",
400
401
  "gemini-cli": "Run a Gemini CLI structured audit lane.",
402
+ "gate-health": "Alert when audit gate infrastructure stalls.",
401
403
  "grok-build": "Run a Grok Build informational audit lane.",
402
404
  "hermes-cli": "Run a Hermes CLI structured audit lane.",
403
405
  "init": "Render safe easy-mode setup output.",
@@ -529,6 +531,7 @@ COMMAND_HANDLERS: dict[str, CommandHandler] = {
529
531
  "codex-audit-schema-smoke": codex_audit_schema_smoke.main,
530
532
  "doctor": code_mower_doctor.main,
531
533
  "gemini-cli": gemini_cli_audit_pr.main,
534
+ "gate-health": code_mower_gate_health.main,
532
535
  "grok-build": grok_build_audit_pr.main,
533
536
  "hermes-cli": hermes_cli_audit_pr.main,
534
537
  "init": _init_main,
@@ -6,6 +6,7 @@ from __future__ import annotations
6
6
  import argparse
7
7
  import hashlib
8
8
  import json
9
+ import math
9
10
  import os
10
11
  import re
11
12
  import sys
@@ -121,6 +122,19 @@ def _artifact_severity_counts(payload: Mapping[str, Any]) -> tuple[dict[str, int
121
122
  return comment_counts, "unavailable"
122
123
 
123
124
 
125
+ def _artifact_duration_seconds(payload: Mapping[str, Any]) -> float | None:
126
+ raw = payload.get("duration_seconds")
127
+ if raw is None:
128
+ return None
129
+ try:
130
+ value = float(raw)
131
+ except (TypeError, ValueError):
132
+ return None
133
+ if not math.isfinite(value) or value < 0:
134
+ return None
135
+ return round(value, 3)
136
+
137
+
124
138
  def _normal_artifact_verdict(value: Any) -> str:
125
139
  verdict = str(value or "").strip().lower()
126
140
  if verdict in PASS_VERDICTS:
@@ -205,6 +219,17 @@ def reviewer_run_event_from_verdict_artifact(
205
219
  head = str(payload.get("head_sha_end") or payload.get("head_sha_start") or "")
206
220
  dimensions["head_sha"] = head
207
221
  dimensions["head_sha_short"] = head[:12]
222
+ metrics: dict[str, Any] = {
223
+ "finding_count": finding_count,
224
+ "p0_count": severities["p0"],
225
+ "p1_count": severities["p1"],
226
+ "p2_count": severities["p2"],
227
+ "p3_count": severities["p3"],
228
+ }
229
+ duration_seconds = _artifact_duration_seconds(payload)
230
+ if duration_seconds is not None:
231
+ metrics["duration_seconds_total"] = duration_seconds
232
+ dimensions["duration_source"] = "verdict_artifact"
208
233
  return {
209
234
  "schema": BENCHMARK_EVENT_SCHEMA,
210
235
  "event_type": "reviewer_run",
@@ -215,13 +240,7 @@ def reviewer_run_event_from_verdict_artifact(
215
240
  "provider": _lane_provider(lane_id),
216
241
  "lens": "base",
217
242
  "status": status,
218
- "metrics": {
219
- "finding_count": finding_count,
220
- "p0_count": severities["p0"],
221
- "p1_count": severities["p1"],
222
- "p2_count": severities["p2"],
223
- "p3_count": severities["p3"],
224
- },
243
+ "metrics": metrics,
225
244
  "dimensions": dimensions,
226
245
  }
227
246
 
@@ -1294,6 +1294,7 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
1294
1294
  """End-to-end audit of one PR. Creates a temporary worktree at the PR
1295
1295
  head, runs Codex review, structures its verdict, formats + posts a
1296
1296
  comment."""
1297
+ audit_started = time.monotonic()
1297
1298
  local_repo = config.repo_paths.get(repo)
1298
1299
  if local_repo is None:
1299
1300
  raise ValueError(
@@ -1419,6 +1420,7 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
1419
1420
  trailer=result.trailer,
1420
1421
  comment_body=comment_body,
1421
1422
  quarantine_reason=quarantine_reason,
1423
+ duration_seconds=time.monotonic() - audit_started,
1422
1424
  )
1423
1425
  result.verdict_artifact_path = artifact_path
1424
1426
  if artifact_path is not None:
@@ -1624,6 +1626,7 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
1624
1626
  trailer=trailer,
1625
1627
  comment_body=comment_body,
1626
1628
  quarantine_reason=quarantine_reason,
1629
+ duration_seconds=time.monotonic() - audit_started,
1627
1630
  )
1628
1631
  result.verdict_artifact_path = artifact_path
1629
1632
  if artifact_path is not None: