maintainability-agent 2.3.0__tar.gz → 2.4.1__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.3.0/src/maintainability_agent.egg-info → maintainability_agent-2.4.1}/PKG-INFO +49 -10
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/README.md +48 -9
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/pyproject.toml +1 -1
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1/src/maintainability_agent.egg-info}/PKG-INFO +49 -10
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/SOURCES.txt +3 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/__init__.py +1 -1
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_cognitive.py +21 -4
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_config_defaults.py +1 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_metrics_types.py +14 -0
- maintainability_agent-2.4.1/src/maintainability_audit/_ranges_swift.py +215 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/config.py +1 -1
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/declarations.py +15 -2
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_claimed_languages.py +18 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_mcp_server.py +8 -6
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_population_floors.py +30 -0
- maintainability_agent-2.4.1/tests/test_suite_isolation.py +139 -0
- maintainability_agent-2.4.1/tests/test_swift_declarations.py +264 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/LICENSE +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/setup.cfg +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_assets/standard.md +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_catalog.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_derive.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_discovery.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_evidence_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_first_run.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_grant_ledger.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_history_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_html_report_sections.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_html_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_metric_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_pillars.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_practice.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_pressures.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_core.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_fortran.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_scan_history.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_scan_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_selection.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_policy.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_test_pairing.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_trends.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_verdict_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/evidence.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/idioms.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/metrics.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/prompts.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/report.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/scoring.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_added_lines.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_primary_estimate.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_scoring_path.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_spread_range.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_architecture.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_attestation.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_audit_components.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_backfill.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_band_concealment_p3.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_bands.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_cli.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_config_shape.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_consumer_migration.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_corroborate.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_dead_code.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_determinism.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_discovery.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_docs_links.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_economic_context.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_evidence_invariants.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_evidence_normalization.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_evidence_properties.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_format_ask.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_git_argv.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_history.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_history_window.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_html_executive.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_java_scored.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_promises.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_recurrence.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_release_plan.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_release_plan_status.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_root_grants.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_runner.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_sarif.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_scan_history.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_scan_scope.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_scanning.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_scoring_calibration.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_skill_install.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_source_index.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_trends.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_unread_code.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_verified_grade.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_version_claim.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_work_order.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/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.4.1
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,10 +44,10 @@ 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.4.1**.
|
|
48
48
|
|
|
49
|
-
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form
|
|
50
|
-
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
49
|
+
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
50
|
+
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
51
51
|
measured with that language's own reading of what a branch is.
|
|
52
52
|
[What that means per language](#language-support).
|
|
53
53
|
|
|
@@ -124,9 +124,12 @@ the independent check on their own work, so a platform that generates code and
|
|
|
124
124
|
grades it is producing a self-assessment — a property of the arrangement, not a
|
|
125
125
|
criticism of any one of them. This writes nothing and runs no model, which is
|
|
126
126
|
what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
Since 2.1.0 the work order is also **checked**: `--conformance` compares the
|
|
128
|
+
returned diff against the paths the report named, `--fail-on-regression`
|
|
129
|
+
ratchets the dimension scores, and `--attestation-output` composes them into one
|
|
130
|
+
record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
|
|
131
|
+
The limit, stated in the same breath: those checks read the diff's **shape**,
|
|
132
|
+
never its correctness — whether the change works is not a claim this tool makes.
|
|
130
133
|
|
|
131
134
|
One pre-registered experiment has tested the bounded prompt.
|
|
132
135
|
Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
|
|
@@ -217,6 +220,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
|
|
|
217
220
|
diff; on a change too small to support a rate, the estimate and grade are
|
|
218
221
|
withheld and the scope is named as the reason.
|
|
219
222
|
|
|
223
|
+
### Checking that the agent did the work
|
|
224
|
+
|
|
225
|
+
The work order tells an agent to fix exactly these findings and refactor nothing
|
|
226
|
+
else. These flags check that the diff that came back obeyed it — read the
|
|
227
|
+
diff's _shape_, not its correctness:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
maintainability-agent \
|
|
231
|
+
--config maintainability-agent.json \
|
|
232
|
+
--conformance main...HEAD \
|
|
233
|
+
--fail-on-out-of-scope \
|
|
234
|
+
--fail-on-regression \
|
|
235
|
+
--attestation-output maintainability-attestation.md
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
- **`--conformance <revspec>`** compares the diff against the paths the report
|
|
239
|
+
named, and answers two questions separately: did it **stay in scope**, and did
|
|
240
|
+
it **silence nothing**. They stay separate because a change can obey the work
|
|
241
|
+
order and still add a `# noqa` to a finding inside it. A test added for a fix
|
|
242
|
+
stays in scope even though the work order never named the test file.
|
|
243
|
+
- **`--fail-on-out-of-scope`** turns that into a CI failure.
|
|
244
|
+
- **`--fail-on-regression`** ratchets the _dimension_ scores against scan
|
|
245
|
+
history, catching a change that improves one dimension while silently
|
|
246
|
+
regressing another. It has three outcomes, not two — held, regressed, and
|
|
247
|
+
**not comparable**, because two scans taken under different calibration cannot
|
|
248
|
+
be differenced.
|
|
249
|
+
- **`--attestation-output`** writes the three into one per-change record: what
|
|
250
|
+
was measured, what the agent was told to change, whether it stayed inside the
|
|
251
|
+
work order, and what moved. It is reproducible and **not signed** — nothing
|
|
252
|
+
here holds a key, and the document says so in its own text. A check nobody ran
|
|
253
|
+
renders as _not asked_, never as passed.
|
|
254
|
+
|
|
255
|
+
The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
|
|
256
|
+
has the history of why this was the hole under the product's central claim.
|
|
257
|
+
|
|
220
258
|
## What it analyzes
|
|
221
259
|
|
|
222
260
|
The deterministic scanner reads code from your repo (no LLM calls) and produces
|
|
@@ -252,9 +290,9 @@ SonarQube, Qlty) rather than replacing them — their SARIF folds in via
|
|
|
252
290
|
and on an unrecognized language it will quietly under-report rather than fail.**
|
|
253
291
|
Coverage comes from two layers.
|
|
254
292
|
|
|
255
|
-
|
|
256
|
-
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6),
|
|
257
|
-
and HTML. Each has a scanner written for it and a documented list of what it
|
|
293
|
+
Nine languages are parsed as of **2.4.0**: Python (1.0), Java (1.0), C (1.1),
|
|
294
|
+
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6), Swift (2.4), the
|
|
295
|
+
JS/TS family, and HTML. Each has a scanner written for it and a documented list of what it
|
|
258
296
|
misses — a language is claimed here only when both exist.
|
|
259
297
|
|
|
260
298
|
**Built-in scanner (always on, no dependencies)** — reads function/class
|
|
@@ -268,6 +306,7 @@ these:
|
|
|
268
306
|
| C (`.c`, `.h`) | dedicated brace-bounded scanner — functions, `struct`/`enum`/`union` | Bounded; prototypes and macros are not declarations |
|
|
269
307
|
| C++ (`.cpp`, `.hpp`, `.cc`, `.cxx`, `.hh`) | dedicated brace-bounded scanner — functions, class members, namespaces, templates | Bounded; bodyless declarations are not definitions |
|
|
270
308
|
| C# (`.cs`) | dedicated brace-bounded scanner — methods, constructors, `class`/`interface`/`struct`/`record`/`enum` | Bounded; properties are not declarations |
|
|
309
|
+
| Swift (`.swift`) | dedicated brace-bounded scanner — functions, initialisers, subscripts, `class`/`struct`/`enum`/`protocol`/`actor` | Bounded; extension members carry their type, protocol requirements and computed properties are not declarations |
|
|
271
310
|
| Fortran, free-form (`.f90`, `.f95`, `.f03`, `.f08`, `.F90`, `.F95`, `.F03`, `.F08`, `.pf`) | dedicated **keyword**-bounded scanner — modules, subroutines, functions, derived types | Bounded by `end`; measured with Fortran's own branch and nesting reading |
|
|
272
311
|
| Fortran, fixed-form (`.f`, `.for`, `.ftn`, `.F`, `.FOR`, `.FTN`) | the same scanner over card-column source; continuations joined, labelled `DO` loops understood | Bounded by `end` or by the loop's label |
|
|
273
312
|
| JS / TS / JSX / TSX (`.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx`) | brace/paren depth over a masked copy | Bounded by the declaration's own braces |
|
|
@@ -5,10 +5,10 @@
|
|
|
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.4.1**.
|
|
9
9
|
|
|
10
|
-
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form
|
|
11
|
-
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
10
|
+
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
11
|
+
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
12
12
|
measured with that language's own reading of what a branch is.
|
|
13
13
|
[What that means per language](#language-support).
|
|
14
14
|
|
|
@@ -85,9 +85,12 @@ the independent check on their own work, so a platform that generates code and
|
|
|
85
85
|
grades it is producing a self-assessment — a property of the arrangement, not a
|
|
86
86
|
criticism of any one of them. This writes nothing and runs no model, which is
|
|
87
87
|
what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
Since 2.1.0 the work order is also **checked**: `--conformance` compares the
|
|
89
|
+
returned diff against the paths the report named, `--fail-on-regression`
|
|
90
|
+
ratchets the dimension scores, and `--attestation-output` composes them into one
|
|
91
|
+
record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
|
|
92
|
+
The limit, stated in the same breath: those checks read the diff's **shape**,
|
|
93
|
+
never its correctness — whether the change works is not a claim this tool makes.
|
|
91
94
|
|
|
92
95
|
One pre-registered experiment has tested the bounded prompt.
|
|
93
96
|
Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
|
|
@@ -178,6 +181,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
|
|
|
178
181
|
diff; on a change too small to support a rate, the estimate and grade are
|
|
179
182
|
withheld and the scope is named as the reason.
|
|
180
183
|
|
|
184
|
+
### Checking that the agent did the work
|
|
185
|
+
|
|
186
|
+
The work order tells an agent to fix exactly these findings and refactor nothing
|
|
187
|
+
else. These flags check that the diff that came back obeyed it — read the
|
|
188
|
+
diff's _shape_, not its correctness:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
maintainability-agent \
|
|
192
|
+
--config maintainability-agent.json \
|
|
193
|
+
--conformance main...HEAD \
|
|
194
|
+
--fail-on-out-of-scope \
|
|
195
|
+
--fail-on-regression \
|
|
196
|
+
--attestation-output maintainability-attestation.md
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- **`--conformance <revspec>`** compares the diff against the paths the report
|
|
200
|
+
named, and answers two questions separately: did it **stay in scope**, and did
|
|
201
|
+
it **silence nothing**. They stay separate because a change can obey the work
|
|
202
|
+
order and still add a `# noqa` to a finding inside it. A test added for a fix
|
|
203
|
+
stays in scope even though the work order never named the test file.
|
|
204
|
+
- **`--fail-on-out-of-scope`** turns that into a CI failure.
|
|
205
|
+
- **`--fail-on-regression`** ratchets the _dimension_ scores against scan
|
|
206
|
+
history, catching a change that improves one dimension while silently
|
|
207
|
+
regressing another. It has three outcomes, not two — held, regressed, and
|
|
208
|
+
**not comparable**, because two scans taken under different calibration cannot
|
|
209
|
+
be differenced.
|
|
210
|
+
- **`--attestation-output`** writes the three into one per-change record: what
|
|
211
|
+
was measured, what the agent was told to change, whether it stayed inside the
|
|
212
|
+
work order, and what moved. It is reproducible and **not signed** — nothing
|
|
213
|
+
here holds a key, and the document says so in its own text. A check nobody ran
|
|
214
|
+
renders as _not asked_, never as passed.
|
|
215
|
+
|
|
216
|
+
The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
|
|
217
|
+
has the history of why this was the hole under the product's central claim.
|
|
218
|
+
|
|
181
219
|
## What it analyzes
|
|
182
220
|
|
|
183
221
|
The deterministic scanner reads code from your repo (no LLM calls) and produces
|
|
@@ -213,9 +251,9 @@ SonarQube, Qlty) rather than replacing them — their SARIF folds in via
|
|
|
213
251
|
and on an unrecognized language it will quietly under-report rather than fail.**
|
|
214
252
|
Coverage comes from two layers.
|
|
215
253
|
|
|
216
|
-
|
|
217
|
-
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6),
|
|
218
|
-
and HTML. Each has a scanner written for it and a documented list of what it
|
|
254
|
+
Nine languages are parsed as of **2.4.0**: Python (1.0), Java (1.0), C (1.1),
|
|
255
|
+
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6), Swift (2.4), the
|
|
256
|
+
JS/TS family, and HTML. Each has a scanner written for it and a documented list of what it
|
|
219
257
|
misses — a language is claimed here only when both exist.
|
|
220
258
|
|
|
221
259
|
**Built-in scanner (always on, no dependencies)** — reads function/class
|
|
@@ -229,6 +267,7 @@ these:
|
|
|
229
267
|
| C (`.c`, `.h`) | dedicated brace-bounded scanner — functions, `struct`/`enum`/`union` | Bounded; prototypes and macros are not declarations |
|
|
230
268
|
| C++ (`.cpp`, `.hpp`, `.cc`, `.cxx`, `.hh`) | dedicated brace-bounded scanner — functions, class members, namespaces, templates | Bounded; bodyless declarations are not definitions |
|
|
231
269
|
| C# (`.cs`) | dedicated brace-bounded scanner — methods, constructors, `class`/`interface`/`struct`/`record`/`enum` | Bounded; properties are not declarations |
|
|
270
|
+
| Swift (`.swift`) | dedicated brace-bounded scanner — functions, initialisers, subscripts, `class`/`struct`/`enum`/`protocol`/`actor` | Bounded; extension members carry their type, protocol requirements and computed properties are not declarations |
|
|
232
271
|
| Fortran, free-form (`.f90`, `.f95`, `.f03`, `.f08`, `.F90`, `.F95`, `.F03`, `.F08`, `.pf`) | dedicated **keyword**-bounded scanner — modules, subroutines, functions, derived types | Bounded by `end`; measured with Fortran's own branch and nesting reading |
|
|
233
272
|
| Fortran, fixed-form (`.f`, `.for`, `.ftn`, `.F`, `.FOR`, `.FTN`) | the same scanner over card-column source; continuations joined, labelled `DO` loops understood | Bounded by `end` or by the loop's label |
|
|
234
273
|
| JS / TS / JSX / TSX (`.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx`) | brace/paren depth over a masked copy | Bounded by the declaration's own braces |
|
|
@@ -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.4.1"
|
|
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.4.1
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,10 +44,10 @@ 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.4.1**.
|
|
48
48
|
|
|
49
|
-
**Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form
|
|
50
|
-
fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
49
|
+
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
50
|
+
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
51
51
|
measured with that language's own reading of what a branch is.
|
|
52
52
|
[What that means per language](#language-support).
|
|
53
53
|
|
|
@@ -124,9 +124,12 @@ the independent check on their own work, so a platform that generates code and
|
|
|
124
124
|
grades it is producing a self-assessment — a property of the arrangement, not a
|
|
125
125
|
criticism of any one of them. This writes nothing and runs no model, which is
|
|
126
126
|
what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
Since 2.1.0 the work order is also **checked**: `--conformance` compares the
|
|
128
|
+
returned diff against the paths the report named, `--fail-on-regression`
|
|
129
|
+
ratchets the dimension scores, and `--attestation-output` composes them into one
|
|
130
|
+
record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
|
|
131
|
+
The limit, stated in the same breath: those checks read the diff's **shape**,
|
|
132
|
+
never its correctness — whether the change works is not a claim this tool makes.
|
|
130
133
|
|
|
131
134
|
One pre-registered experiment has tested the bounded prompt.
|
|
132
135
|
Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
|
|
@@ -217,6 +220,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
|
|
|
217
220
|
diff; on a change too small to support a rate, the estimate and grade are
|
|
218
221
|
withheld and the scope is named as the reason.
|
|
219
222
|
|
|
223
|
+
### Checking that the agent did the work
|
|
224
|
+
|
|
225
|
+
The work order tells an agent to fix exactly these findings and refactor nothing
|
|
226
|
+
else. These flags check that the diff that came back obeyed it — read the
|
|
227
|
+
diff's _shape_, not its correctness:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
maintainability-agent \
|
|
231
|
+
--config maintainability-agent.json \
|
|
232
|
+
--conformance main...HEAD \
|
|
233
|
+
--fail-on-out-of-scope \
|
|
234
|
+
--fail-on-regression \
|
|
235
|
+
--attestation-output maintainability-attestation.md
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
- **`--conformance <revspec>`** compares the diff against the paths the report
|
|
239
|
+
named, and answers two questions separately: did it **stay in scope**, and did
|
|
240
|
+
it **silence nothing**. They stay separate because a change can obey the work
|
|
241
|
+
order and still add a `# noqa` to a finding inside it. A test added for a fix
|
|
242
|
+
stays in scope even though the work order never named the test file.
|
|
243
|
+
- **`--fail-on-out-of-scope`** turns that into a CI failure.
|
|
244
|
+
- **`--fail-on-regression`** ratchets the _dimension_ scores against scan
|
|
245
|
+
history, catching a change that improves one dimension while silently
|
|
246
|
+
regressing another. It has three outcomes, not two — held, regressed, and
|
|
247
|
+
**not comparable**, because two scans taken under different calibration cannot
|
|
248
|
+
be differenced.
|
|
249
|
+
- **`--attestation-output`** writes the three into one per-change record: what
|
|
250
|
+
was measured, what the agent was told to change, whether it stayed inside the
|
|
251
|
+
work order, and what moved. It is reproducible and **not signed** — nothing
|
|
252
|
+
here holds a key, and the document says so in its own text. A check nobody ran
|
|
253
|
+
renders as _not asked_, never as passed.
|
|
254
|
+
|
|
255
|
+
The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
|
|
256
|
+
has the history of why this was the hole under the product's central claim.
|
|
257
|
+
|
|
220
258
|
## What it analyzes
|
|
221
259
|
|
|
222
260
|
The deterministic scanner reads code from your repo (no LLM calls) and produces
|
|
@@ -252,9 +290,9 @@ SonarQube, Qlty) rather than replacing them — their SARIF folds in via
|
|
|
252
290
|
and on an unrecognized language it will quietly under-report rather than fail.**
|
|
253
291
|
Coverage comes from two layers.
|
|
254
292
|
|
|
255
|
-
|
|
256
|
-
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6),
|
|
257
|
-
and HTML. Each has a scanner written for it and a documented list of what it
|
|
293
|
+
Nine languages are parsed as of **2.4.0**: Python (1.0), Java (1.0), C (1.1),
|
|
294
|
+
C++ (1.2), C# (1.3), Fortran (free-form 1.4, fixed-form 1.6), Swift (2.4), the
|
|
295
|
+
JS/TS family, and HTML. Each has a scanner written for it and a documented list of what it
|
|
258
296
|
misses — a language is claimed here only when both exist.
|
|
259
297
|
|
|
260
298
|
**Built-in scanner (always on, no dependencies)** — reads function/class
|
|
@@ -268,6 +306,7 @@ these:
|
|
|
268
306
|
| C (`.c`, `.h`) | dedicated brace-bounded scanner — functions, `struct`/`enum`/`union` | Bounded; prototypes and macros are not declarations |
|
|
269
307
|
| C++ (`.cpp`, `.hpp`, `.cc`, `.cxx`, `.hh`) | dedicated brace-bounded scanner — functions, class members, namespaces, templates | Bounded; bodyless declarations are not definitions |
|
|
270
308
|
| C# (`.cs`) | dedicated brace-bounded scanner — methods, constructors, `class`/`interface`/`struct`/`record`/`enum` | Bounded; properties are not declarations |
|
|
309
|
+
| Swift (`.swift`) | dedicated brace-bounded scanner — functions, initialisers, subscripts, `class`/`struct`/`enum`/`protocol`/`actor` | Bounded; extension members carry their type, protocol requirements and computed properties are not declarations |
|
|
271
310
|
| Fortran, free-form (`.f90`, `.f95`, `.f03`, `.f08`, `.F90`, `.F95`, `.F03`, `.F08`, `.pf`) | dedicated **keyword**-bounded scanner — modules, subroutines, functions, derived types | Bounded by `end`; measured with Fortran's own branch and nesting reading |
|
|
272
311
|
| Fortran, fixed-form (`.f`, `.for`, `.ftn`, `.F`, `.FOR`, `.FTN`) | the same scanner over card-column source; continuations joined, labelled `DO` loops understood | Bounded by `end` or by the loop's label |
|
|
273
312
|
| JS / TS / JSX / TSX (`.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx`) | brace/paren depth over a masked copy | Bounded by the declaration's own braces |
|
|
@@ -64,6 +64,7 @@ src/maintainability_audit/_ranges_csharp.py
|
|
|
64
64
|
src/maintainability_audit/_ranges_fortran.py
|
|
65
65
|
src/maintainability_audit/_ranges_java.py
|
|
66
66
|
src/maintainability_audit/_ranges_js.py
|
|
67
|
+
src/maintainability_audit/_ranges_swift.py
|
|
67
68
|
src/maintainability_audit/_ratchet.py
|
|
68
69
|
src/maintainability_audit/_recurrence.py
|
|
69
70
|
src/maintainability_audit/_runner.py
|
|
@@ -289,6 +290,8 @@ tests/test_source_index.py
|
|
|
289
290
|
tests/test_spotbugs_adapter.py
|
|
290
291
|
tests/test_spotbugs_catalog.py
|
|
291
292
|
tests/test_stage8_contract.py
|
|
293
|
+
tests/test_suite_isolation.py
|
|
294
|
+
tests/test_swift_declarations.py
|
|
292
295
|
tests/test_tdd_structure.py
|
|
293
296
|
tests/test_test_execution_class.py
|
|
294
297
|
tests/test_three_presentations.py
|
{maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_cognitive.py
RENAMED
|
@@ -45,6 +45,14 @@ _NESTING_NODES = (ast.If, ast.For, ast.AsyncFor, ast.While, ast.ExceptHandler, a
|
|
|
45
45
|
_NESTING_ONLY = (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)
|
|
46
46
|
|
|
47
47
|
_CONTROL_RE = re.compile(r"\b(if|for|while|catch|switch|case|elif|except)\b")
|
|
48
|
+
#: Swift adds `guard` — an early exit that is its primary branching idiom —
|
|
49
|
+
#: and `repeat`, its do-while. Without them a function built from guards
|
|
50
|
+
#: reads as having no branches at all, which is the Fortran `do` defect in
|
|
51
|
+
#: another language: six nested loops once scored complexity 1 because the
|
|
52
|
+
#: pattern did not know the keyword.
|
|
53
|
+
_SWIFT_CONTROL_RE = re.compile(
|
|
54
|
+
r"\b(if|for|while|catch|switch|case|guard|repeat)\b"
|
|
55
|
+
)
|
|
48
56
|
_ELSE_RE = re.compile(r"\belse\b")
|
|
49
57
|
_BOOLEAN_RE = re.compile(r"&&|\|\|")
|
|
50
58
|
|
|
@@ -167,7 +175,7 @@ def fortran_cognitive(lines: list[str]) -> int:
|
|
|
167
175
|
return score
|
|
168
176
|
|
|
169
177
|
|
|
170
|
-
def brace_cognitive(lines: list[str]) -> int:
|
|
178
|
+
def brace_cognitive(lines: list[str], control: re.Pattern[str] | None = None) -> int:
|
|
171
179
|
"""Approximate cognitive complexity for a C-family declaration body.
|
|
172
180
|
|
|
173
181
|
Nesting is read from brace depth relative to the declaration's own
|
|
@@ -191,16 +199,25 @@ def brace_cognitive(lines: list[str]) -> int:
|
|
|
191
199
|
if base is None and opens:
|
|
192
200
|
base = depth
|
|
193
201
|
nesting = max(0, depth - (base if base is not None else 0))
|
|
194
|
-
score += _score_brace_line(line, nesting)
|
|
202
|
+
score += _score_brace_line(line, nesting, control or _CONTROL_RE)
|
|
195
203
|
depth = max(0, depth + opens - closes)
|
|
196
204
|
return score
|
|
197
205
|
|
|
198
206
|
|
|
199
|
-
def _score_brace_line(line: str, nesting: int) -> int:
|
|
207
|
+
def _score_brace_line(line: str, nesting: int, control: re.Pattern[str]) -> int:
|
|
200
208
|
score = 0
|
|
201
|
-
for _ in
|
|
209
|
+
for _ in control.finditer(line):
|
|
202
210
|
score += 1 + nesting
|
|
203
211
|
if _ELSE_RE.search(line):
|
|
204
212
|
score += 1
|
|
205
213
|
score += len(_BOOLEAN_RE.findall(line))
|
|
206
214
|
return score
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def swift_cognitive(lines: list[str]) -> int:
|
|
218
|
+
"""`brace_cognitive` reading Swift's control keywords.
|
|
219
|
+
|
|
220
|
+
Swift is braced, so nesting is read the same way; only the vocabulary
|
|
221
|
+
differs, and `guard` is the difference that matters.
|
|
222
|
+
"""
|
|
223
|
+
return brace_cognitive(lines, _SWIFT_CONTROL_RE)
|
|
@@ -53,6 +53,20 @@ COMPLEXITY_RE = re.compile(
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
#: Swift's `guard` is an early exit and its primary branching idiom, and
|
|
57
|
+
#: `repeat` is its do-while. Neither is in the C-family pattern, so a
|
|
58
|
+
#: guard-heavy function would read as branchless — the same defect Fortran
|
|
59
|
+
#: had with `do`.
|
|
60
|
+
SWIFT_COMPLEXITY_RE = re.compile(
|
|
61
|
+
r"\b(if|for|while|case|catch|guard|repeat)\b|&&|\|\||\?\?|\?(?![.?])"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def swift_branch_points(line: str) -> int:
|
|
66
|
+
"""Decision points on one line of Swift."""
|
|
67
|
+
return len(SWIFT_COMPLEXITY_RE.findall(line))
|
|
68
|
+
|
|
69
|
+
|
|
56
70
|
def branch_points(line: str) -> int:
|
|
57
71
|
"""Decision points on one line, for the C family and Python."""
|
|
58
72
|
return len(COMPLEXITY_RE.findall(line))
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Declaration ranges for Swift.
|
|
2
|
+
|
|
3
|
+
Braced, so it reuses `scan_bounded` with C, C++, C# and Java. What is
|
|
4
|
+
different is worth stating, because two of the differences are the whole
|
|
5
|
+
job and one of them is a trap this project has already fallen into once.
|
|
6
|
+
|
|
7
|
+
**Every declaration is keyword-led.** `func`, `init`, `subscript`, `class`,
|
|
8
|
+
`struct`, `enum`, `protocol`, `actor`, `extension`. That makes recognition
|
|
9
|
+
*easier* than C++, where a bare `name(` is equally a call, a macro and a
|
|
10
|
+
constructor, and where a wrong guess let a macro swallow the next
|
|
11
|
+
declaration's braces. Nothing here has to guess.
|
|
12
|
+
|
|
13
|
+
**An `extension` adds members to a type declared elsewhere**, often in
|
|
14
|
+
another file. `extension Widget { func draw() }` must report `Widget.draw`
|
|
15
|
+
rather than a second bare `draw` indistinguishable from every other type's,
|
|
16
|
+
which is the same rule C++ applies to an out-of-line `void geo::Widget::draw()`.
|
|
17
|
+
The extension itself is walked into and not graded: it is a container, and
|
|
18
|
+
grading it would count its members twice.
|
|
19
|
+
|
|
20
|
+
**Computed properties are not declarations**, and this is the C# properties
|
|
21
|
+
problem in Swift spelling. `var area: Double { w * h }` has braces and would
|
|
22
|
+
bound perfectly cleanly; an ordinary Swift type has many, each a line or
|
|
23
|
+
two, none anybody's maintenance burden. Counting them would dilute the
|
|
24
|
+
population every declaration rate divides by. They are excluded by
|
|
25
|
+
construction rather than by a rule: every pattern here requires either a
|
|
26
|
+
parameter list or a type keyword, and a property has neither.
|
|
27
|
+
|
|
28
|
+
**A protocol requirement has no body** — `func draw()` with nothing after
|
|
29
|
+
it — so it mints nothing, exactly as a C prototype and a pure virtual do.
|
|
30
|
+
A protocol of forty requirements is not forty declarations.
|
|
31
|
+
|
|
32
|
+
One claim was corrected while writing this. The roadmap said Swift's string
|
|
33
|
+
interpolation "puts braces inside literals, so masking has to run before
|
|
34
|
+
depth counting". It does not: Swift interpolates with `\\(expr)` —
|
|
35
|
+
parentheses, not braces — and string contents are masked before any
|
|
36
|
+
counting regardless. The real reason masking matters here is the ordinary
|
|
37
|
+
one every language shares: a brace inside a string literal, `"{}"`, would
|
|
38
|
+
desync depth.
|
|
39
|
+
"""
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import re
|
|
43
|
+
|
|
44
|
+
from ._metrics_types import DeclRange
|
|
45
|
+
from ._ranges_core import _mask_generics, scan_bounded
|
|
46
|
+
|
|
47
|
+
# Stripped once per line so the patterns stay small: these lead a
|
|
48
|
+
# declaration and say nothing about what it is.
|
|
49
|
+
_SW_MODIFIER_RE = re.compile(
|
|
50
|
+
r"^\s*(?:(?:public|private|internal|fileprivate|open|static|final"
|
|
51
|
+
r"|override|mutating|nonmutating|convenience|required|lazy|weak|unowned"
|
|
52
|
+
r"|indirect|dynamic|optional|async|throws|rethrows|infix|prefix|postfix"
|
|
53
|
+
r"|package)\s+)*"
|
|
54
|
+
)
|
|
55
|
+
# `class` is both a declaration keyword and a modifier: `class Widget` is a
|
|
56
|
+
# type, `class func make()` is a type-level method. Stripping it with the
|
|
57
|
+
# other modifiers cost every `final class Store` its keyword — the type
|
|
58
|
+
# vanished and only its members were reported. So it is removed only where
|
|
59
|
+
# a declaration keyword follows it, and left alone otherwise.
|
|
60
|
+
_SW_CLASS_MODIFIER_RE = re.compile(r"^class\s+(?=(?:func|var|let|subscript)\b)")
|
|
61
|
+
# `@objc`, `@available(iOS 13, *)`, `@MainActor` — an attribute leads a
|
|
62
|
+
# declaration and is not one. Stripped, so what follows is still read.
|
|
63
|
+
_SW_ATTRIBUTE_RE = re.compile(r"^\s*(?:@[A-Za-z_]\w*(?:\([^)]*\))?\s*)+")
|
|
64
|
+
# `extension Widget`, `extension Widget: Drawable`, `extension Array where …`
|
|
65
|
+
_SW_EXTENSION_RE = re.compile(r"^extension\s+([A-Za-z_][\w.]*)")
|
|
66
|
+
# The container keywords. `protocol` is here so its body is walked into —
|
|
67
|
+
# its requirements are then skipped for having no body, which is what makes
|
|
68
|
+
# a forty-requirement protocol mint nothing.
|
|
69
|
+
_SW_TYPE_RE = re.compile(
|
|
70
|
+
r"^(?:class|struct|enum|protocol|actor)\s+([A-Za-z_]\w*)"
|
|
71
|
+
)
|
|
72
|
+
# `func name(`, and the three declarations that carry no `func` keyword.
|
|
73
|
+
_SW_FUNC_RE = re.compile(r"^func\s+([A-Za-z_]\w*|[^\s(]+)\s*(?:<[^>]*>)?\s*\(")
|
|
74
|
+
_SW_INIT_RE = re.compile(r"^(init\??|deinit|subscript)\b")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _swift_declaration(text: str) -> tuple[str, str | None] | None:
|
|
78
|
+
"""``(name, kind)`` for a Swift declaration on one masked line.
|
|
79
|
+
|
|
80
|
+
``kind`` is ``None`` for an `extension`: walk in, grade nothing.
|
|
81
|
+
"""
|
|
82
|
+
line = _SW_ATTRIBUTE_RE.sub("", _mask_generics(text), count=1)
|
|
83
|
+
body = line[_SW_MODIFIER_RE.match(line).end():]
|
|
84
|
+
body = _SW_CLASS_MODIFIER_RE.sub("", body, count=1)
|
|
85
|
+
body = body[_SW_MODIFIER_RE.match(body).end():]
|
|
86
|
+
|
|
87
|
+
extension = _SW_EXTENSION_RE.match(body)
|
|
88
|
+
if extension is not None:
|
|
89
|
+
# The extended type's name, carried so its members can be reported
|
|
90
|
+
# as `Widget.draw` rather than as a second bare `draw`.
|
|
91
|
+
return extension.group(1), None
|
|
92
|
+
|
|
93
|
+
type_match = _SW_TYPE_RE.match(body)
|
|
94
|
+
if type_match is not None:
|
|
95
|
+
return type_match.group(1), "class"
|
|
96
|
+
|
|
97
|
+
func = _SW_FUNC_RE.match(body)
|
|
98
|
+
if func is not None:
|
|
99
|
+
return (func.group(1), "function") if _opens_a_body(body) else None
|
|
100
|
+
|
|
101
|
+
special = _SW_INIT_RE.match(body)
|
|
102
|
+
if special is not None:
|
|
103
|
+
return (special.group(1).rstrip("?"), "function") if _opens_a_body(body) else None
|
|
104
|
+
|
|
105
|
+
# Anything else — `var`, `let`, a computed property, a `case` — is not
|
|
106
|
+
# a declaration this tool measures. Falling through rather than listing
|
|
107
|
+
# exclusions keeps the rule "a declaration is keyword-led and named".
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _opens_a_body(body: str) -> bool:
|
|
112
|
+
"""Whether this line starts a body, or is a requirement with none.
|
|
113
|
+
|
|
114
|
+
Swift has no statement terminator, so the shared `skip_bare` check
|
|
115
|
+
cannot work here: it looks for a signature that closes without opening
|
|
116
|
+
a brace, and in C or C# that is a `;`. A Swift protocol requirement
|
|
117
|
+
simply ends at the newline, so the end-finder walks on and adopts the
|
|
118
|
+
*next* declaration's brace — which is how `func describe() -> String`
|
|
119
|
+
inside a protocol came back measured as two lines of body.
|
|
120
|
+
|
|
121
|
+
The rule that replaces it: a signature whose parentheses balance on
|
|
122
|
+
this line and which then shows no `{` has no body. A wrapped signature
|
|
123
|
+
leaves its parentheses unbalanced, so it is still read as a
|
|
124
|
+
declaration and its body is found normally:
|
|
125
|
+
|
|
126
|
+
func draw( <- unbalanced here, kept
|
|
127
|
+
into: Canvas
|
|
128
|
+
) throws {
|
|
129
|
+
|
|
130
|
+
A body written Allman — `func f()` with `{` alone on the next line —
|
|
131
|
+
is missed and mints nothing. That is legal Swift and vanishingly rare
|
|
132
|
+
in it, and missing one declaration is the cheaper error than counting
|
|
133
|
+
every protocol requirement in the tree.
|
|
134
|
+
"""
|
|
135
|
+
if "{" in body:
|
|
136
|
+
return True
|
|
137
|
+
return body.count("(") != body.count(")")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def swift_declaration_ranges(lines: list[str]) -> tuple[list[DeclRange], list[str]]:
|
|
141
|
+
"""Functions, initialisers and types, each bounded by its own body.
|
|
142
|
+
|
|
143
|
+
Types and extensions are descended into, because that is where members
|
|
144
|
+
live; a function body is stepped over, so nothing inside one is read as
|
|
145
|
+
a declaration.
|
|
146
|
+
|
|
147
|
+
Bodyless declarations mint nothing, as in C, C++ and C#: a protocol
|
|
148
|
+
requirement is a signature with nothing to measure, and grading it
|
|
149
|
+
would put one-line members into the population every rate divides by.
|
|
150
|
+
|
|
151
|
+
Everything it misses, it misses in the safe direction:
|
|
152
|
+
|
|
153
|
+
- **Computed properties** (`var area: Double { w * h }`) are not
|
|
154
|
+
declarations, the same call C# makes for the same reason.
|
|
155
|
+
- **A closure assigned to a property** is a body without a declaration
|
|
156
|
+
keyword and is not counted.
|
|
157
|
+
- **Declarations produced by a macro** (`@freestanding`, `#`-macros)
|
|
158
|
+
are not in the source and are not seen, as in C and C++.
|
|
159
|
+
- **Conditional compilation is not evaluated**, so a declaration in a
|
|
160
|
+
disabled `#if` arm still counts.
|
|
161
|
+
"""
|
|
162
|
+
ranges, masked = scan_bounded(
|
|
163
|
+
lines, _swift_declaration, descend=("class",), skip_preprocessor=True
|
|
164
|
+
)
|
|
165
|
+
return _qualify_extension_members(ranges, masked), masked
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _extension_spans(masked: list[str]) -> list[tuple[int, int, str]]:
|
|
169
|
+
"""Every `extension X { … }` as (start, end, extended type)."""
|
|
170
|
+
def only_extensions(text: str) -> tuple[str, str | None] | None:
|
|
171
|
+
found = _swift_declaration(text)
|
|
172
|
+
if found is None:
|
|
173
|
+
return None
|
|
174
|
+
name, kind = found
|
|
175
|
+
return (name, "class") if kind is None else None
|
|
176
|
+
|
|
177
|
+
spans, _ = scan_bounded(
|
|
178
|
+
masked, only_extensions, descend=(), skip_preprocessor=True
|
|
179
|
+
)
|
|
180
|
+
return [(item.start, item.end, item.name) for item in spans]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _qualify_extension_members(
|
|
184
|
+
ranges: list[DeclRange], masked: list[str]
|
|
185
|
+
) -> list[DeclRange]:
|
|
186
|
+
"""Report an extension's members under the type they extend.
|
|
187
|
+
|
|
188
|
+
`extension Widget { func draw() }` becomes `Widget.draw`. Without it
|
|
189
|
+
the report carries a bare `draw` indistinguishable from every other
|
|
190
|
+
type's `draw`, and a reader given "shorten `draw`" cannot find which
|
|
191
|
+
one — the same reason C++ keeps the qualification on an out-of-line
|
|
192
|
+
`void geo::Widget::draw()`, except that in Swift the source does not
|
|
193
|
+
write it and the scanner has to carry it.
|
|
194
|
+
|
|
195
|
+
A member already qualified is left alone, and a nested type inside an
|
|
196
|
+
extension keeps its own name: the prefix answers "which type does this
|
|
197
|
+
belong to", which a named type already answers for itself.
|
|
198
|
+
"""
|
|
199
|
+
spans = _extension_spans(masked)
|
|
200
|
+
if not spans:
|
|
201
|
+
return ranges
|
|
202
|
+
qualified = []
|
|
203
|
+
for item in ranges:
|
|
204
|
+
owner = next(
|
|
205
|
+
(name for start, end, name in spans
|
|
206
|
+
if start < item.start <= end and item.kind == "function"),
|
|
207
|
+
None,
|
|
208
|
+
)
|
|
209
|
+
if owner is None or "." in item.name:
|
|
210
|
+
qualified.append(item)
|
|
211
|
+
continue
|
|
212
|
+
qualified.append(
|
|
213
|
+
DeclRange(item.start, item.end, f"{owner}.{item.name}", item.kind)
|
|
214
|
+
)
|
|
215
|
+
return qualified
|
{maintainability_agent-2.3.0 → maintainability_agent-2.4.1}/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.4.1"
|
|
15
15
|
|
|
16
16
|
PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
|
|
17
17
|
|