code-mower 0.5.0b43__tar.gz → 0.5.0b44__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.
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/PKG-INFO +6 -6
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/README.md +5 -5
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/pyproject.toml +1 -1
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/__init__.py +1 -1
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/auto_discovery.py +3 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/claude_audit_pr.py +99 -23
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cli.py +1 -1
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/code_mower_telemetry.py +10 -2
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/codex_audit_pr.py +95 -9
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/__init__.py +10 -0
- code_mower-0.5.0b44/src/code_mower/provider_runners/verdict_artifacts.py +241 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/PKG-INFO +6 -6
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/SOURCES.txt +1 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_calibration_truth.py +48 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_claude_audit_pr.py +145 -1
- code_mower-0.5.0b44/tests/test_codex_audit_pr.py +166 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_release_hygiene.py +34 -34
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_reviewer_metrics_core.py +93 -0
- code_mower-0.5.0b43/src/code_mower/provider_runners/verdict_artifacts.py +0 -103
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/CODE_OF_CONDUCT.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/LICENSE +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/MANIFEST.in +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/NOTICE +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/SUPPORT.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/requirements/requirements.txt +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/setup.cfg +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/_base.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/cursor_bugbot.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/gitar.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/greptile.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/adapters/qodo.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/audit_handoff_log.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/audit_labeler_lib.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/audit_progress.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/blind_review_artifacts.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/blind_review_coordinator.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/bootstrap.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/builder_experiment.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/builder_runs.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/arms.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/commands.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/context_inputs.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/corpus.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/effect_report.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/evidence.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/evidence_report.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/identity.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/metrics.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/overlap.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/planning.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/policy.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/results.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/run_results.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/run_status.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/runner.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/truth.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/calibration/value_report.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/checks.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/claude_cli_environment.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/clear_stale.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/bundle.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/doctor.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/dogfood.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/endpoints.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/errors.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/events.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/export.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/git_metadata.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/manifest.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/operations.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/reports.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/setup.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/cloud_client/upload.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/code_mower_calibration.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/code_mower_context_packs.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/code_mower_merge.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/codex_audit_schema_smoke.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/codex_audit_verdict.schema.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/config.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/cloud.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/common.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_api.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_branch.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_config.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_provider.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/github_repo.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/groups.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/models.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/output.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/presets.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/privacy.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_env.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_probe.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/providers.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/registry.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/runner.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/runtime.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/gemini_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/grok_build_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/hermes_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/init.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/aider.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/claude.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/codex.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/devin.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/gemini_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/grok_build.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/hermes_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/lane_configs/local_llm.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/local_llm_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/local_llm_bakeoff.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/local_llm_calibration.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/local_llm_profiles.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/migration.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/migration_install.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/migration_mirror.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/migration_readiness.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/migration_rehearsal.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/next_steps.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package_content.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package_manifest.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package_paths.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package_rendering.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/package_static.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/plan_context.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/prompts.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_registry.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/comments.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/git.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/github_auth.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/github_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/pr_worktree.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/process.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/repo_paths.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/text_schema.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/provider_runners/workspace.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/providers/__init__.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/providers/local_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/providers/provenance.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/release_readiness.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/reviewer_metrics.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/reviewer_spend.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/saas_reviewer_labeler.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/secrets.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/code-mower.example.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/operability.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/code_mower +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/product-support/status_report.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/providers.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/versioning.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower/work_orders.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/dependency_links.txt +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/entry_points.txt +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/requires.txt +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/src/code_mower.egg-info/top_level.txt +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/code-mower.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/cursor/BUGBOT.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/acp_bridge.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/aider.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/antigravity_cli.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/claude_audit.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/claude_review.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/coderabbit_cli.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/codex.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/cursor_bugbot.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/devin.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/gemini_cli.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/gitar.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/greptile.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/hermes_cli.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/local_llm.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers/qodo.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/providers.yml +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/builder-provenance.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/code-mower-gate.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_audit_comment_posture.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_builder_identity.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_builder_runs.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_calibration_effect_report.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_checks.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_clear_stale.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_cloud_client.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_cloud_git_metadata.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_cloud_manifest.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_cloud_reports.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_boundaries.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_github_checks.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_output.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_privacy.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_provider_env_required.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_provider_env_tokens.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_provider_probe.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_doctor_registry.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_local_llm_github_helpers.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_plan_context.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_local_cli.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_comments.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_git.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_github_pr.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_pr_worktree.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_process.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_repo_paths.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_text_schema.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_provider_runners_workspace.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_reviewer_spend.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/tests/test_trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b43 → code_mower-0.5.0b44}/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.
|
|
3
|
+
Version: 0.5.0b44
|
|
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.
|
|
106
|
+
pipx install --python python3.12 code-mower==0.5.0b44
|
|
107
107
|
code-mower --version
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
`0.5.
|
|
110
|
+
`0.5.0b44` 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.
|
|
158
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b44`.
|
|
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.
|
|
313
|
+
The current public beta is `v0.5.0-beta.44` from
|
|
314
314
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
315
|
-
as `code-mower==0.5.
|
|
315
|
+
as `code-mower==0.5.0b44` 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.
|
|
91
|
+
pipx install --python python3.12 code-mower==0.5.0b44
|
|
92
92
|
code-mower --version
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
`0.5.
|
|
95
|
+
`0.5.0b44` 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.
|
|
143
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b44`.
|
|
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.
|
|
298
|
+
The current public beta is `v0.5.0-beta.44` from
|
|
299
299
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
300
|
-
as `code-mower==0.5.
|
|
300
|
+
as `code-mower==0.5.0b44` 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
|
|
|
@@ -12,6 +12,7 @@ from typing import Any, Mapping, Sequence
|
|
|
12
12
|
from .corpus import parse_int
|
|
13
13
|
from .identity import safe_slug
|
|
14
14
|
from .run_status import RUN_STATUS_BLOCKED, RUN_STATUS_PASS, RUN_STATUS_UNKNOWN
|
|
15
|
+
from ..provider_runners import is_fixture_verdict_comment
|
|
15
16
|
|
|
16
17
|
AUTO_DISCOVERY_SCHEMA = "code_mower.calibrationAutoDiscover.v1"
|
|
17
18
|
TRUTH_EXPECTATION_UNKNOWN = "unknown"
|
|
@@ -147,6 +148,8 @@ def _audit_runs_from_comments(comments: Sequence[Any]) -> list[dict[str, Any]]:
|
|
|
147
148
|
body = str(comment.get("body") or "")
|
|
148
149
|
if not body:
|
|
149
150
|
continue
|
|
151
|
+
if is_fixture_verdict_comment(body):
|
|
152
|
+
continue
|
|
150
153
|
for match in AUDIT_STATE_RE.finditer(body):
|
|
151
154
|
state = match.group("state")
|
|
152
155
|
reviewer = _provider_from_audit_state(match.group("provider"), state)
|
|
@@ -32,11 +32,13 @@ if __package__ in {None, "", "tools"}:
|
|
|
32
32
|
from tools.audit_progress import AuditProgress, run_subprocess_with_progress
|
|
33
33
|
from tools.claude_cli_environment import clean_claude_cli_env, env_flag
|
|
34
34
|
from tools.provider_runners import (
|
|
35
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
35
36
|
clip_text as _clip_text,
|
|
36
37
|
fetch_pull_request,
|
|
37
38
|
fetch_base_ref_sha as _shared_fetch_base_ref_sha,
|
|
38
39
|
fetch_pr_head_sha as _shared_fetch_pr_head_sha,
|
|
39
40
|
fetch_pr_head_sha_unless_local_matches as _shared_fetch_pr_head_sha_unless_local_matches,
|
|
41
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
40
42
|
limit_comment_body,
|
|
41
43
|
one_line as _one_line,
|
|
42
44
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -58,11 +60,13 @@ if __package__ in {None, "", "tools"}:
|
|
|
58
60
|
from audit_progress import AuditProgress, run_subprocess_with_progress # type: ignore
|
|
59
61
|
from claude_cli_environment import clean_claude_cli_env, env_flag # type: ignore
|
|
60
62
|
from provider_runners import ( # type: ignore
|
|
63
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
61
64
|
clip_text as _clip_text,
|
|
62
65
|
fetch_pull_request,
|
|
63
66
|
fetch_base_ref_sha as _shared_fetch_base_ref_sha,
|
|
64
67
|
fetch_pr_head_sha as _shared_fetch_pr_head_sha,
|
|
65
68
|
fetch_pr_head_sha_unless_local_matches as _shared_fetch_pr_head_sha_unless_local_matches,
|
|
69
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
66
70
|
limit_comment_body,
|
|
67
71
|
one_line as _one_line,
|
|
68
72
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -82,11 +86,13 @@ else: # pragma: no cover - exercised after package extraction.
|
|
|
82
86
|
from .claude_cli_environment import clean_claude_cli_env, env_flag
|
|
83
87
|
from .provider_runners import (
|
|
84
88
|
FetchedHeadMismatch,
|
|
89
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
85
90
|
clip_text as _clip_text,
|
|
86
91
|
fetch_base_ref_sha as _shared_fetch_base_ref_sha,
|
|
87
92
|
fetch_pull_request,
|
|
88
93
|
fetch_pr_head_sha as _shared_fetch_pr_head_sha,
|
|
89
94
|
fetch_pr_head_sha_unless_local_matches as _shared_fetch_pr_head_sha_unless_local_matches,
|
|
95
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
90
96
|
limit_comment_body,
|
|
91
97
|
one_line as _one_line,
|
|
92
98
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -445,6 +451,29 @@ def _apply_claude_verdict_guardrails(
|
|
|
445
451
|
return _unknown_structured_verdict(reason), reason
|
|
446
452
|
|
|
447
453
|
|
|
454
|
+
def _fixture_structured_quarantine_reason(parsed: ClaudeVerdict) -> Optional[str]:
|
|
455
|
+
if _is_fixture_structured_verdict(parsed.summary, list(parsed.findings)):
|
|
456
|
+
return "fixture-shaped structured verdict rejected by guardrail"
|
|
457
|
+
return None
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _quarantine_is_test_only(reason: Optional[str]) -> bool:
|
|
461
|
+
return reason == "PYTEST_CURRENT_TEST is set"
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _comment_with_runtime_quarantine_note(comment_body: str, reason: str) -> str:
|
|
465
|
+
note = (
|
|
466
|
+
"\nRuntime quarantine: local verdict artifact was quarantined because "
|
|
467
|
+
f"{reason}. Posting UNKNOWN so the lane requeues visibly.\n"
|
|
468
|
+
)
|
|
469
|
+
marker = f"\n\n{STALE_TRAILER}"
|
|
470
|
+
if marker in comment_body:
|
|
471
|
+
body = comment_body.replace(marker, note + "\n" + STALE_TRAILER, 1)
|
|
472
|
+
else:
|
|
473
|
+
body = comment_body.rstrip() + note + "\n" + STALE_TRAILER + "\n"
|
|
474
|
+
return limit_comment_body(body, STALE_TRAILER, provider_name="Claude")
|
|
475
|
+
|
|
476
|
+
|
|
448
477
|
def _write_claude_raw_output_sidecar(
|
|
449
478
|
artifact_path: Optional[Path],
|
|
450
479
|
attempts: List[Dict[str, Any]],
|
|
@@ -996,6 +1025,9 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
996
1025
|
parsed=parsed,
|
|
997
1026
|
)
|
|
998
1027
|
if not config.dry_run:
|
|
1028
|
+
quarantine_reason = _audit_runtime_quarantine_reason(
|
|
1029
|
+
comment_body=comment_body,
|
|
1030
|
+
)
|
|
999
1031
|
artifact_path = write_audit_verdict_artifact(
|
|
1000
1032
|
lane_id="claude-audit",
|
|
1001
1033
|
repo=repo,
|
|
@@ -1005,6 +1037,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1005
1037
|
verdict=result.verdict,
|
|
1006
1038
|
trailer=result.trailer,
|
|
1007
1039
|
comment_body=comment_body,
|
|
1040
|
+
quarantine_reason=quarantine_reason,
|
|
1008
1041
|
)
|
|
1009
1042
|
result.verdict_artifact_path = artifact_path
|
|
1010
1043
|
if artifact_path is not None:
|
|
@@ -1013,17 +1046,35 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1013
1046
|
file=sys.stderr,
|
|
1014
1047
|
flush=True,
|
|
1015
1048
|
)
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1049
|
+
if quarantine_reason:
|
|
1050
|
+
print(
|
|
1051
|
+
" runtime guard quarantined verdict artifact: "
|
|
1052
|
+
f"{quarantine_reason}",
|
|
1053
|
+
file=sys.stderr,
|
|
1054
|
+
flush=True,
|
|
1055
|
+
)
|
|
1056
|
+
if quarantine_reason and _quarantine_is_test_only(quarantine_reason):
|
|
1057
|
+
print(" skipped GitHub post for pytest-only quarantine", file=sys.stderr, flush=True)
|
|
1058
|
+
else:
|
|
1059
|
+
if quarantine_reason:
|
|
1060
|
+
result.verdict = "UNKNOWN"
|
|
1061
|
+
result.trailer = STALE_TRAILER
|
|
1062
|
+
comment_body = _comment_with_runtime_quarantine_note(
|
|
1063
|
+
comment_body,
|
|
1064
|
+
quarantine_reason,
|
|
1065
|
+
)
|
|
1066
|
+
result.comment_body = comment_body
|
|
1067
|
+
posted = post_pr_comment(repo, pr_number, comment_body, token=config.github_token)
|
|
1068
|
+
result.posted_comment_url = posted.get("html_url")
|
|
1069
|
+
_record_posted_comment_url(
|
|
1070
|
+
result.verdict_artifact_path,
|
|
1071
|
+
result.posted_comment_url,
|
|
1072
|
+
)
|
|
1073
|
+
print(
|
|
1074
|
+
f"posted {repo}#{pr_number} verdict=STALE "
|
|
1075
|
+
f"url={result.posted_comment_url}",
|
|
1076
|
+
file=sys.stderr,
|
|
1077
|
+
)
|
|
1027
1078
|
config.progress.emit(
|
|
1028
1079
|
"audit",
|
|
1029
1080
|
status="finish",
|
|
@@ -1082,6 +1133,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1082
1133
|
claude_stdout = ""
|
|
1083
1134
|
claude_stderr = ""
|
|
1084
1135
|
attempt_prompt = prompt
|
|
1136
|
+
final_fixture_reason: Optional[str] = None
|
|
1085
1137
|
t0 = time.time()
|
|
1086
1138
|
for attempt in range(1, MAX_CLAUDE_AUDIT_ATTEMPTS + 1):
|
|
1087
1139
|
parsed_candidate, attempt_stdout, attempt_stderr = run_claude_audit(
|
|
@@ -1094,6 +1146,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1094
1146
|
parsed_candidate,
|
|
1095
1147
|
diff_context.changed_files,
|
|
1096
1148
|
)
|
|
1149
|
+
final_fixture_reason = _fixture_structured_quarantine_reason(parsed_candidate)
|
|
1097
1150
|
raw_output_attempts.append(
|
|
1098
1151
|
{
|
|
1099
1152
|
"attempt": attempt,
|
|
@@ -1172,6 +1225,10 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1172
1225
|
)
|
|
1173
1226
|
|
|
1174
1227
|
if not config.dry_run:
|
|
1228
|
+
quarantine_reason = _audit_runtime_quarantine_reason(
|
|
1229
|
+
comment_body=comment_body,
|
|
1230
|
+
fixture_reason=final_fixture_reason if parsed.verdict == "UNKNOWN" else None,
|
|
1231
|
+
)
|
|
1175
1232
|
artifact_path = write_audit_verdict_artifact(
|
|
1176
1233
|
lane_id="claude-audit",
|
|
1177
1234
|
repo=repo,
|
|
@@ -1181,6 +1238,7 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1181
1238
|
verdict=result_verdict,
|
|
1182
1239
|
trailer=trailer,
|
|
1183
1240
|
comment_body=comment_body,
|
|
1241
|
+
quarantine_reason=quarantine_reason,
|
|
1184
1242
|
)
|
|
1185
1243
|
result.verdict_artifact_path = artifact_path
|
|
1186
1244
|
if artifact_path is not None:
|
|
@@ -1190,21 +1248,39 @@ def audit_pr(config: ClaudeAuditConfig, repo: str, pr_number: int) -> ClaudeAudi
|
|
|
1190
1248
|
flush=True,
|
|
1191
1249
|
)
|
|
1192
1250
|
_write_claude_raw_output_sidecar(artifact_path, raw_output_attempts)
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1251
|
+
if quarantine_reason:
|
|
1252
|
+
print(
|
|
1253
|
+
" runtime guard quarantined verdict artifact: "
|
|
1254
|
+
f"{quarantine_reason}",
|
|
1255
|
+
file=sys.stderr,
|
|
1256
|
+
flush=True,
|
|
1257
|
+
)
|
|
1258
|
+
if quarantine_reason and _quarantine_is_test_only(quarantine_reason):
|
|
1259
|
+
print(" skipped GitHub post for pytest-only quarantine", file=sys.stderr, flush=True)
|
|
1260
|
+
else:
|
|
1261
|
+
if quarantine_reason:
|
|
1262
|
+
result.verdict = "UNKNOWN"
|
|
1263
|
+
result.trailer = STALE_TRAILER
|
|
1264
|
+
comment_body = _comment_with_runtime_quarantine_note(
|
|
1265
|
+
comment_body,
|
|
1266
|
+
quarantine_reason,
|
|
1267
|
+
)
|
|
1268
|
+
result.comment_body = comment_body
|
|
1269
|
+
posted = post_pr_comment(repo, pr_number, comment_body, token=config.github_token)
|
|
1270
|
+
result.posted_comment_url = posted.get("html_url")
|
|
1271
|
+
_record_posted_comment_url(
|
|
1272
|
+
result.verdict_artifact_path,
|
|
1273
|
+
result.posted_comment_url,
|
|
1274
|
+
)
|
|
1275
|
+
print(
|
|
1276
|
+
f"posted {repo}#{pr_number} verdict={result_verdict} "
|
|
1277
|
+
f"url={result.posted_comment_url}",
|
|
1278
|
+
file=sys.stderr,
|
|
1279
|
+
)
|
|
1204
1280
|
config.progress.emit(
|
|
1205
1281
|
"audit",
|
|
1206
1282
|
status="finish",
|
|
1207
|
-
detail=f"{repo}#{pr_number} verdict={
|
|
1283
|
+
detail=f"{repo}#{pr_number} verdict={result.verdict}",
|
|
1208
1284
|
)
|
|
1209
1285
|
return result
|
|
1210
1286
|
|
|
@@ -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.
|
|
17
|
+
"`pipx install code-mower==0.5.0b44`, or run source checkouts with "
|
|
18
18
|
"`PYTHONPATH=src python -m code_mower.cli`."
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -18,12 +18,16 @@ if __package__ in {None, ""}:
|
|
|
18
18
|
sys.path.insert(0, str(module_dir.parent))
|
|
19
19
|
if module_dir.name == "code_mower": # pragma: no cover - extracted direct CLI.
|
|
20
20
|
from code_mower import audit_handoff_log
|
|
21
|
+
from code_mower.provider_runners import is_fixture_verdict_artifact
|
|
21
22
|
else:
|
|
22
23
|
from tools import audit_handoff_log
|
|
24
|
+
from tools.provider_runners import is_fixture_verdict_artifact
|
|
23
25
|
elif __package__ == "tools":
|
|
24
26
|
from tools import audit_handoff_log
|
|
27
|
+
from tools.provider_runners import is_fixture_verdict_artifact
|
|
25
28
|
else: # pragma: no cover - exercised after package extraction.
|
|
26
29
|
from . import audit_handoff_log
|
|
30
|
+
from .provider_runners import is_fixture_verdict_artifact
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
PASS_VERDICTS = {"completed", "done", "pass", "passed", "success", "succeeded"}
|
|
@@ -31,7 +35,6 @@ BLOCKED_VERDICTS = {"block", "blocked", "fail", "failed", "failure"}
|
|
|
31
35
|
VERDICT_ARTIFACT_SCHEMA = "code_mower.auditVerdictArtifact.v1"
|
|
32
36
|
BENCHMARK_EVENT_SCHEMA = "code_mower.benchmarkEvent.v1"
|
|
33
37
|
VERDICT_ARTIFACT_DIR_ENV = "CODE_MOWER_VERDICT_ARTIFACT_DIR"
|
|
34
|
-
DEFAULT_VERDICT_ARTIFACT_DIR = Path.home() / ".cache" / "code-mower-audits" / "verdicts"
|
|
35
38
|
SEVERITY_RE = re.compile(r"\b(P[0-3])=(\d+)\b")
|
|
36
39
|
AUDIT_TRAILER_RE = re.compile(
|
|
37
40
|
r"<!--\s*(?P<prefix>[A-Z0-9_]+_AUDIT_STATE)\s*:\s*(?P<label>[a-z0-9_.-]+)\s*-->",
|
|
@@ -43,7 +46,10 @@ def default_verdict_artifact_dir() -> Path:
|
|
|
43
46
|
configured = os.environ.get(VERDICT_ARTIFACT_DIR_ENV, "").strip()
|
|
44
47
|
if configured:
|
|
45
48
|
return Path(configured).expanduser()
|
|
46
|
-
|
|
49
|
+
cache_home = os.environ.get("XDG_CACHE_HOME", "").strip()
|
|
50
|
+
if cache_home:
|
|
51
|
+
return Path(cache_home).expanduser() / "code-mower-audits" / "verdicts"
|
|
52
|
+
return Path.home() / ".cache" / "code-mower-audits" / "verdicts"
|
|
47
53
|
|
|
48
54
|
|
|
49
55
|
def _normalize_repo_slug(value: str) -> str:
|
|
@@ -249,6 +255,8 @@ def export_reviewer_run_events_from_verdicts(
|
|
|
249
255
|
raise ValueError(f"{path}: verdict artifact must be a JSON object")
|
|
250
256
|
if payload.get("schema") != VERDICT_ARTIFACT_SCHEMA:
|
|
251
257
|
continue
|
|
258
|
+
if is_fixture_verdict_artifact(payload):
|
|
259
|
+
continue
|
|
252
260
|
artifact_repo = _normalize_repo_slug(
|
|
253
261
|
str(payload.get("repo") or _repo_slug_from_artifact_path(path))
|
|
254
262
|
)
|
|
@@ -89,11 +89,13 @@ if __package__ in {None, "", "tools"}:
|
|
|
89
89
|
from tools import reviewer_spend
|
|
90
90
|
from tools.audit_progress import AuditProgress, run_subprocess_with_progress
|
|
91
91
|
from tools.provider_runners import (
|
|
92
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
92
93
|
clip_text as _clip_text,
|
|
93
94
|
fetch_pull_request,
|
|
94
95
|
fetch_base_ref as _shared_fetch_base_ref,
|
|
95
96
|
fetch_pr_head as _shared_fetch_pr_head,
|
|
96
97
|
fetch_pr_head_unless_local_matches as _shared_fetch_pr_head_unless_local_matches,
|
|
98
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
97
99
|
limit_comment_body,
|
|
98
100
|
one_line as _one_line,
|
|
99
101
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -112,11 +114,13 @@ if __package__ in {None, "", "tools"}:
|
|
|
112
114
|
import reviewer_spend # type: ignore
|
|
113
115
|
from audit_progress import AuditProgress, run_subprocess_with_progress # type: ignore
|
|
114
116
|
from provider_runners import ( # type: ignore
|
|
117
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
115
118
|
clip_text as _clip_text,
|
|
116
119
|
fetch_pull_request,
|
|
117
120
|
fetch_base_ref as _shared_fetch_base_ref,
|
|
118
121
|
fetch_pr_head as _shared_fetch_pr_head,
|
|
119
122
|
fetch_pr_head_unless_local_matches as _shared_fetch_pr_head_unless_local_matches,
|
|
123
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
120
124
|
limit_comment_body,
|
|
121
125
|
one_line as _one_line,
|
|
122
126
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -135,12 +139,14 @@ else: # pragma: no cover - exercised after package extraction.
|
|
|
135
139
|
from . import reviewer_spend
|
|
136
140
|
from .audit_progress import AuditProgress, run_subprocess_with_progress
|
|
137
141
|
from .provider_runners import (
|
|
142
|
+
audit_runtime_quarantine_reason as _audit_runtime_quarantine_reason,
|
|
138
143
|
clip_text as _clip_text,
|
|
139
144
|
create_temp_worktree as _shared_create_temp_worktree,
|
|
140
145
|
fetch_base_ref as _shared_fetch_base_ref,
|
|
141
146
|
fetch_pull_request,
|
|
142
147
|
fetch_pr_head as _shared_fetch_pr_head,
|
|
143
148
|
fetch_pr_head_unless_local_matches as _shared_fetch_pr_head_unless_local_matches,
|
|
149
|
+
is_fixture_structured_verdict as _is_fixture_structured_verdict,
|
|
144
150
|
limit_comment_body,
|
|
145
151
|
one_line as _one_line,
|
|
146
152
|
parse_repo_paths as _parse_repo_paths,
|
|
@@ -240,6 +246,7 @@ class CodexVerdict:
|
|
|
240
246
|
# (e.g. verdict=pass but P2 findings are present). This is not
|
|
241
247
|
# rendered into the public PR comment; audit_pr() logs it to stderr.
|
|
242
248
|
mismatch_note: str = ""
|
|
249
|
+
quarantine_reason: str = ""
|
|
243
250
|
|
|
244
251
|
@property
|
|
245
252
|
def blocker_count(self) -> int:
|
|
@@ -258,6 +265,7 @@ class CodexVerdict:
|
|
|
258
265
|
"blocker_count": self.blocker_count,
|
|
259
266
|
"findings": self.findings,
|
|
260
267
|
"mismatch_note": self.mismatch_note,
|
|
268
|
+
"quarantine_reason": self.quarantine_reason,
|
|
261
269
|
}
|
|
262
270
|
|
|
263
271
|
|
|
@@ -313,6 +321,23 @@ BLOCKED_TRAILER = "<!-- CODEX_AUDIT_STATE: codex-audit-blocked -->"
|
|
|
313
321
|
AUDIT_RUN_TRAILER_PREFIX = "<!-- CODE_MOWER_AUDIT_RUN:"
|
|
314
322
|
|
|
315
323
|
|
|
324
|
+
def _quarantine_is_test_only(reason: Optional[str]) -> bool:
|
|
325
|
+
return reason == "PYTEST_CURRENT_TEST is set"
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _comment_with_runtime_quarantine_note(comment_body: str, reason: str) -> str:
|
|
329
|
+
note = (
|
|
330
|
+
"\nRuntime quarantine: local verdict artifact was quarantined because "
|
|
331
|
+
f"{reason}. Posting UNKNOWN so the lane requeues visibly.\n"
|
|
332
|
+
)
|
|
333
|
+
marker = f"\n\n{STALE_TRAILER}"
|
|
334
|
+
if marker in comment_body:
|
|
335
|
+
body = comment_body.replace(marker, note + "\n" + STALE_TRAILER, 1)
|
|
336
|
+
else:
|
|
337
|
+
body = comment_body.rstrip() + note + "\n" + STALE_TRAILER + "\n"
|
|
338
|
+
return limit_comment_body(body, STALE_TRAILER, provider_name="Codex")
|
|
339
|
+
|
|
340
|
+
|
|
316
341
|
# ----- Structured verdict validation -----
|
|
317
342
|
|
|
318
343
|
|
|
@@ -446,6 +471,20 @@ def parse_structured_codex_verdict(data: Any) -> CodexVerdict:
|
|
|
446
471
|
rendered_findings.append(raw_finding)
|
|
447
472
|
|
|
448
473
|
blocker_count = p_counts[0] + p_counts[1] + p_counts[2]
|
|
474
|
+
if _is_fixture_structured_verdict(summary, raw_findings):
|
|
475
|
+
return CodexVerdict(
|
|
476
|
+
verdict="UNKNOWN",
|
|
477
|
+
prose=(
|
|
478
|
+
"(structured Codex verdict is unusable: fixture-shaped structured "
|
|
479
|
+
"verdict; requeue and retry)"
|
|
480
|
+
),
|
|
481
|
+
p0_count=p_counts[0],
|
|
482
|
+
p1_count=p_counts[1],
|
|
483
|
+
p2_count=p_counts[2],
|
|
484
|
+
p3_count=p_counts[3],
|
|
485
|
+
findings=finding_lines,
|
|
486
|
+
quarantine_reason="fixture-shaped structured verdict",
|
|
487
|
+
)
|
|
449
488
|
if blocker_count > 0:
|
|
450
489
|
verdict = "BLOCKED"
|
|
451
490
|
mismatch_note = (
|
|
@@ -1367,6 +1406,9 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1367
1406
|
comment_body=comment_body, codex_stdout="", codex_stderr="",
|
|
1368
1407
|
)
|
|
1369
1408
|
if not config.dry_run:
|
|
1409
|
+
quarantine_reason = _audit_runtime_quarantine_reason(
|
|
1410
|
+
comment_body=comment_body,
|
|
1411
|
+
)
|
|
1370
1412
|
artifact_path = write_audit_verdict_artifact(
|
|
1371
1413
|
lane_id="codex-audit",
|
|
1372
1414
|
repo=repo,
|
|
@@ -1376,6 +1418,7 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1376
1418
|
verdict=result.verdict,
|
|
1377
1419
|
trailer=result.trailer,
|
|
1378
1420
|
comment_body=comment_body,
|
|
1421
|
+
quarantine_reason=quarantine_reason,
|
|
1379
1422
|
)
|
|
1380
1423
|
result.verdict_artifact_path = artifact_path
|
|
1381
1424
|
if artifact_path is not None:
|
|
@@ -1395,9 +1438,27 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1395
1438
|
# comment. See generated product-support wrapper
|
|
1396
1439
|
# finish_lock handling for the wrapper-side history and
|
|
1397
1440
|
# the general silent-success/silent-failure lesson.
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1441
|
+
if quarantine_reason:
|
|
1442
|
+
print(
|
|
1443
|
+
" runtime guard quarantined verdict artifact: "
|
|
1444
|
+
f"{quarantine_reason}",
|
|
1445
|
+
file=sys.stderr,
|
|
1446
|
+
flush=True,
|
|
1447
|
+
)
|
|
1448
|
+
if quarantine_reason and _quarantine_is_test_only(quarantine_reason):
|
|
1449
|
+
print(" skipped GitHub post for pytest-only quarantine", file=sys.stderr, flush=True)
|
|
1450
|
+
else:
|
|
1451
|
+
if quarantine_reason:
|
|
1452
|
+
result.verdict = "UNKNOWN"
|
|
1453
|
+
result.trailer = STALE_TRAILER
|
|
1454
|
+
comment_body = _comment_with_runtime_quarantine_note(
|
|
1455
|
+
comment_body,
|
|
1456
|
+
quarantine_reason,
|
|
1457
|
+
)
|
|
1458
|
+
result.comment_body = comment_body
|
|
1459
|
+
posted = post_pr_comment(repo, pr_number, comment_body,
|
|
1460
|
+
token=config.github_token)
|
|
1461
|
+
result.posted_comment_url = posted.get("html_url")
|
|
1401
1462
|
config.progress.emit(
|
|
1402
1463
|
"audit",
|
|
1403
1464
|
status="finish",
|
|
@@ -1547,6 +1608,12 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1547
1608
|
)
|
|
1548
1609
|
|
|
1549
1610
|
if not config.dry_run:
|
|
1611
|
+
quarantine_reason = _audit_runtime_quarantine_reason(
|
|
1612
|
+
comment_body=comment_body,
|
|
1613
|
+
fixture_reason=(
|
|
1614
|
+
parsed.quarantine_reason if parsed.verdict == "UNKNOWN" else None
|
|
1615
|
+
),
|
|
1616
|
+
)
|
|
1550
1617
|
artifact_path = write_audit_verdict_artifact(
|
|
1551
1618
|
lane_id="codex-audit",
|
|
1552
1619
|
repo=repo,
|
|
@@ -1556,6 +1623,7 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1556
1623
|
verdict=result_verdict,
|
|
1557
1624
|
trailer=trailer,
|
|
1558
1625
|
comment_body=comment_body,
|
|
1626
|
+
quarantine_reason=quarantine_reason,
|
|
1559
1627
|
)
|
|
1560
1628
|
result.verdict_artifact_path = artifact_path
|
|
1561
1629
|
if artifact_path is not None:
|
|
@@ -1568,16 +1636,34 @@ def audit_pr(config: AuditConfig, repo: str, pr_number: int) -> AuditResult:
|
|
|
1568
1636
|
# at the STALE-handler call site. tl;dr: post_pr_comment() raising
|
|
1569
1637
|
# is the only signal the wrapper's finish_lock has that posting
|
|
1570
1638
|
# failed. Do not catch the exception here.
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1639
|
+
if quarantine_reason:
|
|
1640
|
+
print(
|
|
1641
|
+
" runtime guard quarantined verdict artifact: "
|
|
1642
|
+
f"{quarantine_reason}",
|
|
1643
|
+
file=sys.stderr,
|
|
1644
|
+
flush=True,
|
|
1645
|
+
)
|
|
1646
|
+
if quarantine_reason and _quarantine_is_test_only(quarantine_reason):
|
|
1647
|
+
print(" skipped GitHub post for pytest-only quarantine", file=sys.stderr, flush=True)
|
|
1648
|
+
else:
|
|
1649
|
+
if quarantine_reason:
|
|
1650
|
+
result.verdict = "UNKNOWN"
|
|
1651
|
+
result.trailer = STALE_TRAILER
|
|
1652
|
+
comment_body = _comment_with_runtime_quarantine_note(
|
|
1653
|
+
comment_body,
|
|
1654
|
+
quarantine_reason,
|
|
1655
|
+
)
|
|
1656
|
+
result.comment_body = comment_body
|
|
1657
|
+
posted = post_pr_comment(repo, pr_number, comment_body,
|
|
1658
|
+
token=config.github_token)
|
|
1659
|
+
result.posted_comment_url = posted.get("html_url")
|
|
1660
|
+
print(f"posted {repo}#{pr_number} verdict={result_verdict} "
|
|
1661
|
+
f"url={result.posted_comment_url}", file=sys.stderr)
|
|
1576
1662
|
|
|
1577
1663
|
config.progress.emit(
|
|
1578
1664
|
"audit",
|
|
1579
1665
|
status="finish",
|
|
1580
|
-
detail=f"{repo}#{pr_number} verdict={
|
|
1666
|
+
detail=f"{repo}#{pr_number} verdict={result.verdict}",
|
|
1581
1667
|
)
|
|
1582
1668
|
return result
|
|
1583
1669
|
|
|
@@ -36,6 +36,11 @@ from .pr_worktree import (
|
|
|
36
36
|
from .repo_paths import parse_repo_paths
|
|
37
37
|
from .text_schema import clip_text, one_line, require_exact_keys
|
|
38
38
|
from .verdict_artifacts import (
|
|
39
|
+
audit_runtime_quarantine_reason,
|
|
40
|
+
fixture_verdict_comment_reason,
|
|
41
|
+
is_fixture_structured_verdict,
|
|
42
|
+
is_fixture_verdict_artifact,
|
|
43
|
+
is_fixture_verdict_comment,
|
|
39
44
|
load_audit_verdict_artifact,
|
|
40
45
|
repost_audit_verdict_artifact,
|
|
41
46
|
write_audit_verdict_artifact,
|
|
@@ -59,11 +64,16 @@ __all__ = [
|
|
|
59
64
|
"fetch_pr_head_sha_or_raise",
|
|
60
65
|
"fetch_pr_head_sha_unless_local_matches",
|
|
61
66
|
"fetch_pr_head_unless_local_matches",
|
|
67
|
+
"fixture_verdict_comment_reason",
|
|
68
|
+
"is_fixture_verdict_artifact",
|
|
69
|
+
"is_fixture_verdict_comment",
|
|
70
|
+
"is_fixture_structured_verdict",
|
|
62
71
|
"local_checkout_matches_head",
|
|
63
72
|
"load_audit_verdict_artifact",
|
|
64
73
|
"local_head_sha",
|
|
65
74
|
"limit_comment_body",
|
|
66
75
|
"MAX_GITHUB_COMMENT_CHARS",
|
|
76
|
+
"audit_runtime_quarantine_reason",
|
|
67
77
|
"clip_text",
|
|
68
78
|
"DEFAULT_HOME_ENV_KEYS",
|
|
69
79
|
"one_line",
|