maintainability-agent 2.1.0__tar.gz → 2.2.0__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.
- {maintainability_agent-2.1.0/src/maintainability_agent.egg-info → maintainability_agent-2.2.0}/PKG-INFO +2 -2
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/README.md +1 -1
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/pyproject.toml +1 -1
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_agent.egg-info/SOURCES.txt +3 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/__init__.py +1 -1
- maintainability_agent-2.2.0/src/maintainability_audit/_gates.py +122 -0
- maintainability_agent-2.2.0/src/maintainability_audit/_ratchet.py +109 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/cli.py +14 -46
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/config.py +1 -1
- maintainability_agent-2.2.0/tests/test_dimension_ratchet.py +155 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_identity_resolution.py +5 -1
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_scope_conformance.py +6 -4
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/LICENSE +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/setup.cfg +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_assets/standard.md +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_catalog.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_derive.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_discovery.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_evidence_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_first_run.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_grant_ledger.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_history_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_html_report_sections.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_html_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_metric_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_pillars.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_practice.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_pressures.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_core.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_scan_history.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_scan_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_selection.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_semantic_policy.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_test_pairing.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_trends.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_work_order.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/evidence.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/idioms.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/metrics.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/prompts.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/report.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/scoring.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_added_lines.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_primary_estimate.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_scoring_path.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_spread_range.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_architecture.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_audit_components.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_backfill.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_band_concealment_p3.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_bands.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_cli.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_config_shape.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_consumer_migration.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_corroborate.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_dead_code.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_determinism.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_discovery.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_docs_links.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_economic_context.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_evidence_invariants.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_evidence_normalization.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_evidence_properties.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_format_ask.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_git_argv.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_history.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_history_window.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_html_executive.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_java_scored.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_population_floors.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_promises.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_recurrence.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_release_plan.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_release_plan_status.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_root_grants.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_runner.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_sarif.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_scan_history.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_scan_scope.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_scanning.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_scoring_calibration.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_skill_install.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_source_index.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_trends.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_unread_code.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_verified_grade.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_version_claim.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_work_order.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_written_record.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Dynamic: license-file
|
|
|
44
44
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
45
45
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
46
46
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
47
|
-
Version **2.
|
|
47
|
+
Version **2.2.0**.
|
|
48
48
|
|
|
49
49
|
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
|
|
50
50
|
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
6
6
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
7
7
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
8
|
-
Version **2.
|
|
8
|
+
Version **2.2.0**.
|
|
9
9
|
|
|
10
10
|
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
|
|
11
11
|
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maintainability-agent"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "Maintainability gate and AI remediation prompt generator for CI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# 3.11, not 3.10. `_discovery`, `_pillars` and `_runner` all import
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Dynamic: license-file
|
|
|
44
44
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
45
45
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
46
46
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
47
|
-
Version **2.
|
|
47
|
+
Version **2.2.0**.
|
|
48
48
|
|
|
49
49
|
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
|
|
50
50
|
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -33,6 +33,7 @@ src/maintainability_audit/_evidence_view.py
|
|
|
33
33
|
src/maintainability_audit/_finding_match.py
|
|
34
34
|
src/maintainability_audit/_first_run.py
|
|
35
35
|
src/maintainability_audit/_formula.py
|
|
36
|
+
src/maintainability_audit/_gates.py
|
|
36
37
|
src/maintainability_audit/_generic.py
|
|
37
38
|
src/maintainability_audit/_grant_ledger.py
|
|
38
39
|
src/maintainability_audit/_history_view.py
|
|
@@ -62,6 +63,7 @@ src/maintainability_audit/_ranges_csharp.py
|
|
|
62
63
|
src/maintainability_audit/_ranges_fortran.py
|
|
63
64
|
src/maintainability_audit/_ranges_java.py
|
|
64
65
|
src/maintainability_audit/_ranges_js.py
|
|
66
|
+
src/maintainability_audit/_ratchet.py
|
|
65
67
|
src/maintainability_audit/_recurrence.py
|
|
66
68
|
src/maintainability_audit/_runner.py
|
|
67
69
|
src/maintainability_audit/_safe_write.py
|
|
@@ -187,6 +189,7 @@ tests/test_declared_authorship.py
|
|
|
187
189
|
tests/test_declared_imports.py
|
|
188
190
|
tests/test_derivation_mix.py
|
|
189
191
|
tests/test_determinism.py
|
|
192
|
+
tests/test_dimension_ratchet.py
|
|
190
193
|
tests/test_direct_runner_availability_class.py
|
|
191
194
|
tests/test_discovery.py
|
|
192
195
|
tests/test_doc_claims.py
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""What happens after the audit and before the exit code.
|
|
2
|
+
|
|
3
|
+
Split from `cli.py` when it crossed this project's 500-line file gate —
|
|
4
|
+
the same reason `_mcp_setup`, `_adapters` and `test_architecture` were
|
|
5
|
+
split before it.
|
|
6
|
+
|
|
7
|
+
The split is not arbitrary. Everything here composes from the **finished
|
|
8
|
+
report**: whether the diff obeyed its work order, whether a dimension
|
|
9
|
+
slipped since the last comparable scan, and what those two facts mean for
|
|
10
|
+
the process exit code. None of it measures a tree and none of it may reach
|
|
11
|
+
scoring — a fact about an agent's behaviour, or about the difference
|
|
12
|
+
between two scans, is not evidence about the code's condition.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from .baseline import findings_not_in_baseline
|
|
22
|
+
from .git_tools import added_lines, changed_paths
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def attach_conformance(args: argparse.Namespace, report: dict) -> None:
|
|
26
|
+
"""Record how the diff relates to the work order, when asked.
|
|
27
|
+
|
|
28
|
+
Assembly, not scoring: the record is attached to the report and reaches
|
|
29
|
+
no dimension, because whether a diff was obedient is a fact about an
|
|
30
|
+
agent's behaviour and not evidence about the code's condition.
|
|
31
|
+
"""
|
|
32
|
+
if not args.conformance:
|
|
33
|
+
return
|
|
34
|
+
from ._conformance import scope_conformance
|
|
35
|
+
|
|
36
|
+
root = Path(report["root"])
|
|
37
|
+
changed = changed_paths(root, args.conformance)
|
|
38
|
+
added = added_lines(root, args.conformance)
|
|
39
|
+
report["scope_conformance"] = scope_conformance(
|
|
40
|
+
report, changed, args.conformance, added
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def attach_ratchet(report: dict, history_path: Path) -> None:
|
|
45
|
+
"""Record whether any category slipped since the last comparable scan."""
|
|
46
|
+
from ._ratchet import dimension_ratchet
|
|
47
|
+
from ._scan_history import read_history
|
|
48
|
+
|
|
49
|
+
if not history_path.exists():
|
|
50
|
+
return
|
|
51
|
+
report["dimension_ratchet"] = dimension_ratchet(read_history(history_path))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _attach_post_audit_records(
|
|
55
|
+
args: argparse.Namespace, report: dict, history_path: Path
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Records composed from the finished report, before it is rendered.
|
|
58
|
+
|
|
59
|
+
Both read the report rather than the tree, and neither reaches scoring:
|
|
60
|
+
whether a diff obeyed its work order, and whether a dimension slipped
|
|
61
|
+
since the last comparable scan, are facts about a change and its
|
|
62
|
+
history — not evidence about the code's condition.
|
|
63
|
+
"""
|
|
64
|
+
attach_conformance(args, report)
|
|
65
|
+
attach_ratchet(report, history_path)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _conformance_exit(args: argparse.Namespace, report: dict) -> int:
|
|
69
|
+
"""0 to continue; otherwise the exit code the conformance gate demands."""
|
|
70
|
+
if not args.fail_on_out_of_scope:
|
|
71
|
+
return 0
|
|
72
|
+
record = report.get("scope_conformance")
|
|
73
|
+
if record is None:
|
|
74
|
+
print("--fail-on-out-of-scope needs --conformance REVSPEC", file=sys.stderr)
|
|
75
|
+
return 2
|
|
76
|
+
# `clean`, not `conformant`: staying in scope while silencing the finding
|
|
77
|
+
# is the evasion the pairing exists to catch, and a gate that accepted it
|
|
78
|
+
# would be satisfied by the thing it guards against.
|
|
79
|
+
return 0 if record["clean"] else 1
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _regression_exit(args: argparse.Namespace, report: dict) -> int:
|
|
83
|
+
"""0 to continue; otherwise the exit code the ratchet demands."""
|
|
84
|
+
if not args.fail_on_regression:
|
|
85
|
+
return 0
|
|
86
|
+
ratchet = report.get("dimension_ratchet")
|
|
87
|
+
if ratchet is None:
|
|
88
|
+
print("--fail-on-regression needs a recorded history (--record-history)",
|
|
89
|
+
file=sys.stderr)
|
|
90
|
+
return 2
|
|
91
|
+
# A run that could not compare does not pass quietly: exiting 0 where the
|
|
92
|
+
# question was never asked is the "absence read as a pass" shape.
|
|
93
|
+
#
|
|
94
|
+
# The reason is not interpolated — it derives from recorded scan history,
|
|
95
|
+
# and code scanning is right that history fields have no business in a log
|
|
96
|
+
# line. It stays in the report, which a caller reads deliberately.
|
|
97
|
+
# Suppressing that alert was refused: this release ships the check that
|
|
98
|
+
# treats a suppression as a finding rather than a fix.
|
|
99
|
+
if not ratchet["comparable"]:
|
|
100
|
+
print("no comparable scan for --fail-on-regression; see "
|
|
101
|
+
"dimension_ratchet.reason in the report", file=sys.stderr)
|
|
102
|
+
return 2
|
|
103
|
+
return 1 if ratchet["regressed"] else 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def audit_exit_code(args: argparse.Namespace, report: dict) -> int:
|
|
107
|
+
if args.fail_on_new:
|
|
108
|
+
# Structured matching, never a label-set difference: a label
|
|
109
|
+
# changes under `git mv` and same-name reorder, and failing a
|
|
110
|
+
# build over either is a false report about the change.
|
|
111
|
+
root = Path(report["root"])
|
|
112
|
+
if findings_not_in_baseline(report, args.baseline, root):
|
|
113
|
+
return 1
|
|
114
|
+
if args.fail_on_gate and report["hard_gate_failures"]:
|
|
115
|
+
return 1
|
|
116
|
+
conformance = _conformance_exit(args, report)
|
|
117
|
+
if conformance:
|
|
118
|
+
return conformance
|
|
119
|
+
regression = _regression_exit(args, report)
|
|
120
|
+
if regression:
|
|
121
|
+
return regression
|
|
122
|
+
return 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Did any dimension get worse than the last comparable scan?
|
|
2
|
+
|
|
3
|
+
The third mechanism behind the attestation. `--fail-on-new` already catches
|
|
4
|
+
a finding that clears and returns, using structured identity so a rename is
|
|
5
|
+
not a new finding. What nothing caught is the slower failure: a change that
|
|
6
|
+
improves one dimension while quietly regressing another. Both scans are
|
|
7
|
+
green by every existing gate, the overall estimate can even rise, and the
|
|
8
|
+
thing that got worse is never named.
|
|
9
|
+
|
|
10
|
+
**The comparison is only honest inside one segment.** History is already
|
|
11
|
+
split wherever the instrument changed — a different calibration constant, a
|
|
12
|
+
different analyzer population — because two scans taken with different
|
|
13
|
+
instruments cannot be subtracted. `_scan_history.segments` owns that rule,
|
|
14
|
+
and this module refuses rather than reaching across a break. A ratchet that
|
|
15
|
+
compared a 1.x score to a 2.0 score would have reported every repository on
|
|
16
|
+
earth as catastrophically regressed on the day the corpus was extended, and
|
|
17
|
+
it would have been the ratchet that was wrong.
|
|
18
|
+
|
|
19
|
+
So there are three outcomes, not two: **held**, **regressed**, and **not
|
|
20
|
+
comparable**. The third is not a pass. It says the question could not be
|
|
21
|
+
asked, which is what a reader needs in order to know they are not being
|
|
22
|
+
reassured by silence.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
from ._scan_history import ScanRecord, segments
|
|
30
|
+
|
|
31
|
+
#: Scores are reported to one decimal, so a difference below this is the
|
|
32
|
+
#: rounding boundary rather than a movement. Named rather than inlined
|
|
33
|
+
#: because it is a judgment: too tight and every scan trips on noise, too
|
|
34
|
+
#: loose and a real slide hides under the threshold.
|
|
35
|
+
TOLERANCE = 0.05
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _series(record: ScanRecord, field: str) -> dict[str, float]:
|
|
39
|
+
values = getattr(record, field, None) or {}
|
|
40
|
+
return {
|
|
41
|
+
name: float(value) for name, value in values.items()
|
|
42
|
+
if isinstance(value, (int, float))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _regressions(
|
|
47
|
+
previous: ScanRecord, current: ScanRecord, field: str
|
|
48
|
+
) -> list[dict[str, Any]]:
|
|
49
|
+
"""Names that dropped, with the size of the drop."""
|
|
50
|
+
before, after = _series(previous, field), _series(current, field)
|
|
51
|
+
found = []
|
|
52
|
+
for name, was in sorted(before.items()):
|
|
53
|
+
# A name the current scan does not carry is not a regression: the
|
|
54
|
+
# aspect became unmeasurable, which the evidence model already
|
|
55
|
+
# reports as `Unknown` rather than as a zero. Scoring it as a drop
|
|
56
|
+
# to nothing would turn withheld evidence into a failure, which is
|
|
57
|
+
# the exact inversion P3 forbids.
|
|
58
|
+
if name not in after:
|
|
59
|
+
continue
|
|
60
|
+
now = after[name]
|
|
61
|
+
if was - now > TOLERANCE:
|
|
62
|
+
found.append({
|
|
63
|
+
"name": name, "was": round(was, 2),
|
|
64
|
+
"now": round(now, 2), "drop": round(was - now, 2),
|
|
65
|
+
})
|
|
66
|
+
return found
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def dimension_ratchet(records: list[ScanRecord]) -> dict[str, Any]:
|
|
70
|
+
"""Compare the newest scan with the previous comparable one.
|
|
71
|
+
|
|
72
|
+
`comparable` is the load-bearing field. False means the two scans sit
|
|
73
|
+
either side of an instrument change, or there is no earlier scan at
|
|
74
|
+
all — in both cases the question was not asked, and a caller must not
|
|
75
|
+
read that as "nothing regressed".
|
|
76
|
+
"""
|
|
77
|
+
if len(records) < 2:
|
|
78
|
+
return {
|
|
79
|
+
"comparable": False,
|
|
80
|
+
"reason": "no earlier scan to compare against",
|
|
81
|
+
"regressed": [],
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
latest = segments(records)[-1]
|
|
85
|
+
if len(latest.records) < 2:
|
|
86
|
+
return {
|
|
87
|
+
"comparable": False,
|
|
88
|
+
"reason": (
|
|
89
|
+
latest.break_reason
|
|
90
|
+
or "the previous scan was taken with a different instrument"
|
|
91
|
+
),
|
|
92
|
+
"regressed": [],
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
previous, current = latest.records[-2], latest.records[-1]
|
|
96
|
+
categories = _regressions(previous, current, "categories")
|
|
97
|
+
aspects = _regressions(previous, current, "aspects")
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
"comparable": True,
|
|
101
|
+
"against": getattr(previous, "commit", None),
|
|
102
|
+
"categories": categories,
|
|
103
|
+
"aspects": aspects,
|
|
104
|
+
# Categories only. An aspect can move while the category holding it
|
|
105
|
+
# holds, and failing on every aspect wobble makes the gate noise.
|
|
106
|
+
# Aspects are reported so a reader can see what moved underneath.
|
|
107
|
+
"regressed": categories,
|
|
108
|
+
"held": not categories,
|
|
109
|
+
}
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/cli.py
RENAMED
|
@@ -14,6 +14,10 @@ from ._first_run import (
|
|
|
14
14
|
maybe_prompt_first_run,
|
|
15
15
|
maybe_prompt_test_command,
|
|
16
16
|
)
|
|
17
|
+
from ._gates import (
|
|
18
|
+
_attach_post_audit_records,
|
|
19
|
+
audit_exit_code,
|
|
20
|
+
)
|
|
17
21
|
from ._mcp_audit import record_scan_and_attach
|
|
18
22
|
from ._safe_write import write_artifact
|
|
19
23
|
from ._scan_history import (
|
|
@@ -24,7 +28,6 @@ from ._user_config import mark_repo_seen
|
|
|
24
28
|
from ._work_order import SELECTABLE, combined_delta, select
|
|
25
29
|
from .baseline import (
|
|
26
30
|
finding_fingerprints,
|
|
27
|
-
findings_not_in_baseline,
|
|
28
31
|
load_baseline,
|
|
29
32
|
write_baseline,
|
|
30
33
|
)
|
|
@@ -36,7 +39,7 @@ from .config import (
|
|
|
36
39
|
load_config,
|
|
37
40
|
repository_path,
|
|
38
41
|
)
|
|
39
|
-
from .git_tools import
|
|
42
|
+
from .git_tools import changed_paths
|
|
40
43
|
from .instructions import (
|
|
41
44
|
INSTRUCTION_TARGETS,
|
|
42
45
|
UnknownTarget,
|
|
@@ -65,6 +68,14 @@ def _add_gate_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
65
68
|
"else'; without this the bound is an instruction nothing checks. "
|
|
66
69
|
"Reports only unless --fail-on-out-of-scope is passed.",
|
|
67
70
|
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--fail-on-regression", action="store_true",
|
|
73
|
+
help="Exit 1 when any scoring category is lower than the previous "
|
|
74
|
+
"comparable scan. Reads the recorded history, and refuses to "
|
|
75
|
+
"compare across an instrument change rather than reporting a "
|
|
76
|
+
"false regression: two scans taken under different calibration "
|
|
77
|
+
"cannot be subtracted.",
|
|
78
|
+
)
|
|
68
79
|
parser.add_argument(
|
|
69
80
|
"--fail-on-out-of-scope", action="store_true",
|
|
70
81
|
help="With --conformance, exit 1 when the diff touched files the work "
|
|
@@ -226,48 +237,6 @@ def write_outputs(args: argparse.Namespace, report: dict, rendered: str) -> None
|
|
|
226
237
|
json.dumps(report_to_sarif(report), indent=2) + "\n", json_artifact=True)
|
|
227
238
|
|
|
228
239
|
|
|
229
|
-
def attach_conformance(args: argparse.Namespace, report: dict) -> None:
|
|
230
|
-
"""Record how the diff relates to the work order, when asked.
|
|
231
|
-
|
|
232
|
-
Assembly, not scoring: the record is attached to the report and reaches
|
|
233
|
-
no dimension, because whether a diff was obedient is a fact about an
|
|
234
|
-
agent's behaviour and not evidence about the code's condition.
|
|
235
|
-
"""
|
|
236
|
-
if not args.conformance:
|
|
237
|
-
return
|
|
238
|
-
from ._conformance import scope_conformance
|
|
239
|
-
|
|
240
|
-
root = Path(report["root"])
|
|
241
|
-
changed = changed_paths(root, args.conformance)
|
|
242
|
-
added = added_lines(root, args.conformance)
|
|
243
|
-
report["scope_conformance"] = scope_conformance(
|
|
244
|
-
report, changed, args.conformance, added
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def audit_exit_code(args: argparse.Namespace, report: dict) -> int:
|
|
249
|
-
if args.fail_on_new:
|
|
250
|
-
# Structured matching, never a label-set difference: a label
|
|
251
|
-
# changes under `git mv` and same-name reorder, and failing a
|
|
252
|
-
# build over either is a false report about the change.
|
|
253
|
-
root = Path(report["root"])
|
|
254
|
-
if findings_not_in_baseline(report, args.baseline, root):
|
|
255
|
-
return 1
|
|
256
|
-
if args.fail_on_gate and report["hard_gate_failures"]:
|
|
257
|
-
return 1
|
|
258
|
-
if args.fail_on_out_of_scope:
|
|
259
|
-
record = report.get("scope_conformance")
|
|
260
|
-
if record is None:
|
|
261
|
-
print("--fail-on-out-of-scope needs --conformance REVSPEC", file=sys.stderr)
|
|
262
|
-
return 2
|
|
263
|
-
# `clean`, not `conformant`: staying in scope while silencing the
|
|
264
|
-
# finding is the evasion the pairing exists to catch, and a gate
|
|
265
|
-
# that accepted it would be satisfied by the thing it guards against.
|
|
266
|
-
if not record["clean"]:
|
|
267
|
-
return 1
|
|
268
|
-
return 0
|
|
269
|
-
|
|
270
|
-
|
|
271
240
|
def _analyzers_resolved(args: argparse.Namespace, config: dict) -> bool:
|
|
272
241
|
"""Whether the pool runs: flags beat config, config beats nothing.
|
|
273
242
|
|
|
@@ -325,7 +294,6 @@ def _install_skill_action(args: argparse.Namespace) -> int:
|
|
|
325
294
|
return 0
|
|
326
295
|
|
|
327
296
|
|
|
328
|
-
|
|
329
297
|
def _target_paths(pairs: list[str] | None) -> dict[str, str]:
|
|
330
298
|
"""`TARGET=PATH` arguments, as a mapping.
|
|
331
299
|
|
|
@@ -429,7 +397,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
429
397
|
record=bool(record), want_targets=bool(args.prompt_output))
|
|
430
398
|
# Before rendering, so the record is in the report every presentation
|
|
431
399
|
# and every consumer reads, rather than only in the exit code.
|
|
432
|
-
|
|
400
|
+
_attach_post_audit_records(args, report, history_path)
|
|
433
401
|
rendered = _render_presentation(args, report, history_path)
|
|
434
402
|
write_outputs(args, report, rendered)
|
|
435
403
|
mark_repo_seen(root) # completed audit: not a first run now, whatever the gate says (D13)
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/config.py
RENAMED
|
@@ -11,7 +11,7 @@ from ._config_defaults import DEFAULT_CONFIG, DEFAULT_IDIOM_GROUPS
|
|
|
11
11
|
# still the door every caller comes through.
|
|
12
12
|
__all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
|
|
13
13
|
|
|
14
|
-
VERSION = "2.
|
|
14
|
+
VERSION = "2.2.0"
|
|
15
15
|
|
|
16
16
|
PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
|
|
17
17
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""A change that improves one dimension while regressing another.
|
|
2
|
+
|
|
3
|
+
`--fail-on-new` catches a finding that clears and returns. Nothing caught
|
|
4
|
+
the slower failure: modularity up, testability quietly down, both scans
|
|
5
|
+
green by every existing gate, and the thing that got worse never named.
|
|
6
|
+
|
|
7
|
+
The judgment that matters here is not the subtraction. It is **when
|
|
8
|
+
subtracting is allowed at all**. Two scans taken with different
|
|
9
|
+
instruments — a different calibration constant, a different analyzer
|
|
10
|
+
population — cannot be compared, and `_scan_history.segments` already owns
|
|
11
|
+
that rule for the trend charts. A ratchet that ignored it would have
|
|
12
|
+
reported every repository on earth as catastrophically regressed on the day
|
|
13
|
+
2.0.0 extended the corpus and moved `CALIBRATION_C` from 5.8843 to 8.7161,
|
|
14
|
+
and the ratchet would have been the thing that was wrong.
|
|
15
|
+
|
|
16
|
+
So "not comparable" is a third outcome, and it is not a pass.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from maintainability_audit._ratchet import TOLERANCE, dimension_ratchet
|
|
22
|
+
from maintainability_audit._scan_history import ScanRecord
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _record(
|
|
26
|
+
commit: str,
|
|
27
|
+
categories: dict[str, float],
|
|
28
|
+
*,
|
|
29
|
+
calibration: float = 8.7161,
|
|
30
|
+
aspects: dict[str, float] | None = None,
|
|
31
|
+
) -> ScanRecord:
|
|
32
|
+
return ScanRecord(
|
|
33
|
+
recorded_at=f"2026-09-0{commit[-1]}T00:00:00Z",
|
|
34
|
+
commit=commit,
|
|
35
|
+
branch="main",
|
|
36
|
+
scope="repository",
|
|
37
|
+
rubric_version="2",
|
|
38
|
+
calibration=calibration,
|
|
39
|
+
thresholds_digest="same",
|
|
40
|
+
analyzers=("lizard", "jscpd"),
|
|
41
|
+
scored_languages=("python",),
|
|
42
|
+
estimate=4.0,
|
|
43
|
+
categories=categories,
|
|
44
|
+
aspects=aspects or {},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_a_dimension_that_slipped_is_named() -> None:
|
|
49
|
+
"""The failure the ratchet exists for: one up, one down, both green."""
|
|
50
|
+
records = [
|
|
51
|
+
_record("aaaaaa1", {"modularity": 4.0, "testability": 4.2}),
|
|
52
|
+
_record("aaaaaa2", {"modularity": 4.4, "testability": 3.6}),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
result = dimension_ratchet(records)
|
|
56
|
+
|
|
57
|
+
assert result["comparable"] is True
|
|
58
|
+
assert result["held"] is False
|
|
59
|
+
assert [item["name"] for item in result["regressed"]] == ["testability"]
|
|
60
|
+
assert result["regressed"][0]["drop"] == 0.6
|
|
61
|
+
assert result["regressed"][0]["was"] == 4.2
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_an_improvement_is_not_a_regression() -> None:
|
|
65
|
+
records = [
|
|
66
|
+
_record("aaaaaa1", {"modularity": 4.0}),
|
|
67
|
+
_record("aaaaaa2", {"modularity": 4.5}),
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
assert dimension_ratchet(records)["held"] is True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_movement_inside_the_rounding_boundary_is_not_a_slide() -> None:
|
|
74
|
+
"""Scores are reported to one decimal; noise below that is not news."""
|
|
75
|
+
records = [
|
|
76
|
+
_record("aaaaaa1", {"modularity": 4.00}),
|
|
77
|
+
_record("aaaaaa2", {"modularity": 4.00 - TOLERANCE / 2}),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
assert dimension_ratchet(records)["held"] is True
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_scans_across_an_instrument_change_are_not_comparable() -> None:
|
|
84
|
+
"""The case that would have made this ratchet a liability.
|
|
85
|
+
|
|
86
|
+
2.0.0 moved `CALIBRATION_C` 5.8843 -> 8.7161. Every score moved with it,
|
|
87
|
+
and subtracting across that boundary would report a catastrophic
|
|
88
|
+
regression everywhere while nothing about the code had changed.
|
|
89
|
+
"""
|
|
90
|
+
records = [
|
|
91
|
+
_record("aaaaaa1", {"modularity": 4.6}, calibration=5.8843),
|
|
92
|
+
_record("aaaaaa2", {"modularity": 3.1}, calibration=8.7161),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
result = dimension_ratchet(records)
|
|
96
|
+
|
|
97
|
+
assert result["comparable"] is False, (
|
|
98
|
+
"scores from two different calibrations were subtracted"
|
|
99
|
+
)
|
|
100
|
+
assert result["regressed"] == []
|
|
101
|
+
assert "instrument" in result["reason"] or "different" in result["reason"]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_not_comparable_is_not_a_pass() -> None:
|
|
105
|
+
"""A caller must be able to tell "nothing regressed" from "nobody asked".
|
|
106
|
+
|
|
107
|
+
Both have an empty `regressed` list, so the distinction has to live
|
|
108
|
+
somewhere a gate can read, and `held` must not be true where the
|
|
109
|
+
question was never asked.
|
|
110
|
+
"""
|
|
111
|
+
single = dimension_ratchet([_record("aaaaaa1", {"modularity": 4.0})])
|
|
112
|
+
|
|
113
|
+
assert single["comparable"] is False
|
|
114
|
+
assert single["regressed"] == []
|
|
115
|
+
assert single.get("held") is not True, (
|
|
116
|
+
"a scan with nothing to compare against reported that it held"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_an_aspect_that_became_unmeasurable_is_not_a_drop() -> None:
|
|
121
|
+
"""Withheld evidence must never read as a failure.
|
|
122
|
+
|
|
123
|
+
P3: withholding evidence cannot improve the grade — and the inversion
|
|
124
|
+
matters just as much. An aspect that stops being measurable is reported
|
|
125
|
+
as Unknown by the evidence model, not as a zero, so scoring its absence
|
|
126
|
+
as a fall to nothing would turn missing evidence into a regression.
|
|
127
|
+
"""
|
|
128
|
+
records = [
|
|
129
|
+
_record("aaaaaa1", {"modularity": 4.0}, aspects={"documentation": 4.5}),
|
|
130
|
+
_record("aaaaaa2", {"modularity": 4.0}, aspects={}),
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
result = dimension_ratchet(records)
|
|
134
|
+
|
|
135
|
+
assert result["aspects"] == []
|
|
136
|
+
assert result["held"] is True
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_aspects_are_reported_but_do_not_decide_the_verdict() -> None:
|
|
140
|
+
"""An aspect can wobble while its category holds.
|
|
141
|
+
|
|
142
|
+
Failing on every aspect movement makes the gate noise, and a noisy gate
|
|
143
|
+
gets switched off — but hiding what moved underneath makes the verdict
|
|
144
|
+
unactionable, so aspects are reported beside the decision.
|
|
145
|
+
"""
|
|
146
|
+
records = [
|
|
147
|
+
_record("aaaaaa1", {"modularity": 4.0}, aspects={"file_size": 4.4}),
|
|
148
|
+
_record("aaaaaa2", {"modularity": 4.0}, aspects={"file_size": 3.2}),
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
result = dimension_ratchet(records)
|
|
152
|
+
|
|
153
|
+
assert [item["name"] for item in result["aspects"]] == ["file_size"]
|
|
154
|
+
assert result["regressed"] == []
|
|
155
|
+
assert result["held"] is True
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/tests/test_identity_resolution.py
RENAMED
|
@@ -288,7 +288,11 @@ def test_fail_on_new_uses_structured_matching_not_a_label_set_difference() -> No
|
|
|
288
288
|
offenders.append(f"{path.name}:{node.lineno}")
|
|
289
289
|
assert not offenders, f"label-set finding comparison remains at {offenders}"
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
# `audit_exit_code` moved to `_gates` in 2.2.0, when `cli.py` crossed
|
|
292
|
+
# the 500-line file gate. The guard follows the function rather than the
|
|
293
|
+
# filename: what it pins is that the gate matches findings structurally,
|
|
294
|
+
# wherever that gate lives.
|
|
295
|
+
cli_tree = ast.parse((package / "_gates.py").read_text(encoding="utf-8"))
|
|
292
296
|
audit_exit = next(
|
|
293
297
|
node for node in cli_tree.body
|
|
294
298
|
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
@@ -220,10 +220,11 @@ def test_the_gate_reads_clean_not_conformant(tmp_path: Path) -> None:
|
|
|
220
220
|
`audit_exit_code`, because the decision this test is about lives in the
|
|
221
221
|
gate and not in the record.
|
|
222
222
|
"""
|
|
223
|
-
from maintainability_audit.
|
|
223
|
+
from maintainability_audit._gates import audit_exit_code
|
|
224
224
|
|
|
225
225
|
args = SimpleNamespace(
|
|
226
226
|
fail_on_new=False, fail_on_gate=False, fail_on_out_of_scope=True,
|
|
227
|
+
fail_on_regression=False,
|
|
227
228
|
baseline=None, conformance="main...HEAD",
|
|
228
229
|
)
|
|
229
230
|
silenced = {"hard_gate_failures": [], "scope_conformance": {
|
|
@@ -244,10 +245,11 @@ def test_asking_to_fail_without_asking_to_check_is_refused() -> None:
|
|
|
244
245
|
which is the "absence read as a pass" shape this project treats as a
|
|
245
246
|
defect class rather than an inconvenience.
|
|
246
247
|
"""
|
|
247
|
-
from maintainability_audit.
|
|
248
|
+
from maintainability_audit._gates import audit_exit_code
|
|
248
249
|
|
|
249
250
|
args = SimpleNamespace(
|
|
250
251
|
fail_on_new=False, fail_on_gate=False, fail_on_out_of_scope=True,
|
|
252
|
+
fail_on_regression=False,
|
|
251
253
|
baseline=None, conformance=None,
|
|
252
254
|
)
|
|
253
255
|
|
|
@@ -255,7 +257,7 @@ def test_asking_to_fail_without_asking_to_check_is_refused() -> None:
|
|
|
255
257
|
|
|
256
258
|
|
|
257
259
|
def test_attach_conformance_does_nothing_unless_asked() -> None:
|
|
258
|
-
from maintainability_audit.
|
|
260
|
+
from maintainability_audit._gates import attach_conformance
|
|
259
261
|
|
|
260
262
|
report = {"root": ".", "work_order": []}
|
|
261
263
|
attach_conformance(SimpleNamespace(conformance=None), report)
|
|
@@ -273,7 +275,7 @@ def test_attach_conformance_records_against_a_real_diff(tmp_path: Path) -> None:
|
|
|
273
275
|
"""
|
|
274
276
|
import subprocess
|
|
275
277
|
|
|
276
|
-
from maintainability_audit.
|
|
278
|
+
from maintainability_audit._gates import attach_conformance
|
|
277
279
|
|
|
278
280
|
def run(*args: str) -> None:
|
|
279
281
|
subprocess.run(args, cwd=tmp_path, check=True, capture_output=True, timeout=120) # noqa: S603
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/__main__.py
RENAMED
|
File without changes
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_adapters.py
RENAMED
|
File without changes
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_analysis.py
RENAMED
|
File without changes
|
{maintainability_agent-2.1.0 → maintainability_agent-2.2.0}/src/maintainability_audit/_aspects.py
RENAMED
|
File without changes
|