maintainability-agent 3.6.0__tar.gz → 3.6.2__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-3.6.0/src/maintainability_agent.egg-info → maintainability_agent-3.6.2}/PKG-INFO +2 -2
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/README.md +1 -1
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/pyproject.toml +1 -1
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/SOURCES.txt +4 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/__init__.py +1 -1
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/standard.md +14 -2
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics.py +11 -2
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_view.py +21 -4
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_view.py +3 -3
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop.py +11 -4
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit.py +10 -6
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_prompt_sections.py +83 -16
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order.py +84 -16
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_view.py +35 -3
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_weights.py +29 -10
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/config.py +1 -1
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/prompts.py +31 -15
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/renderers.py +17 -11
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/report.py +20 -4
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/scoring.py +9 -5
- maintainability_agent-3.6.2/tests/test_anchor_caveat_and_counts_follow_the_run.py +164 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_grading.py +11 -2
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_demo_tree.py +8 -1
- maintainability_agent-3.6.2/tests/test_every_surface_says_what_the_run_found.py +239 -0
- maintainability_agent-3.6.2/tests/test_exposure_never_outranks_band.py +66 -0
- maintainability_agent-3.6.2/tests/test_work_items_state_their_own_finding.py +313 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/LICENSE +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/setup.cfg +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_analyzer_sections.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_anchor.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_arguments.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_banner.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_catalog.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_criteria_scope.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_delegated_pillar.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_derive.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_discovery.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_reader.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_first_run.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_grammar.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_grant_ledger.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_history_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_report_sections.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_metric_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_operator_reads.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_pillars.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_practice.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_install.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_pressures.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cobol.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_core.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_fortran.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_go.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_php.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_ruby.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_rust.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_swift.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratio_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_run_comparison.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_history.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_selection.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_policy.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_commands.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_pairing.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_trends.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_verdict_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/evidence.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/idioms.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/metrics.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_added_lines.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_primary_estimate.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_scoring_path.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_spread_range.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anchor_and_mode.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anchor_disclosure.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_architecture.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_attestation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_audit_components.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_backfill.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_concealment_p3.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_bands.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_chat_leads_with_the_work_order.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_check_refuses_plus_only_fragments.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_child_sandbox.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cli.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cobol_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_config_shape.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_consumer_migration.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_corroborate.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_criteria_completion.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_dead_code.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_criteria_scope.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declarative_parsers.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_delegated_security_pillar.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_determinism.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_discovery.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_docs_links.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_economic_context.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_invariants.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_normalization.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_properties.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_example_config_opens_claimed_languages.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_format_ask.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_argv.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_go_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grammar_constructs.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grammar_token_coverage.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_window.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_html_executive.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_in_loop_budgets.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_in_loop_check.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_scored.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_language_support_honesty.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_format_contract.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_operator_named_paths.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_operator_named_reads.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pairing_reads_imports.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_php_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_policy_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_population_floors.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_precommit_staged.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_promises.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_python_complexity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_recurrence.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_needs_an_empty_ledger.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_plan.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_plan_status.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_root_grants.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ruby_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_run_comparison.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_runner.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_rust_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_sarif.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scan_history.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scan_scope.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scanner_unsafe_direction.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scanning.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scoring_calibration.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_skill_install.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_sonar_resolve.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_source_index.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_stdout_outputs.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_suite_isolation.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_swift_declarations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_terminal_asks_the_same_questions.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_test_commands.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tool_resolution.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_chosen_spawn.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_reads_use_the_primitive.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_trends.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_unanchored_set_matches_corpus.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_unread_code.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_verified_grade.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_version_claim.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_written_record.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 3.6.
|
|
3
|
+
Version: 3.6.2
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -46,7 +46,7 @@ Dynamic: license-file
|
|
|
46
46
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
47
47
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
48
48
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
49
|
-
Version **3.6.
|
|
49
|
+
Version **3.6.2**.
|
|
50
50
|
|
|
51
51
|
**Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
|
|
52
52
|
COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
|
|
@@ -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 **3.6.
|
|
8
|
+
Version **3.6.2**.
|
|
9
9
|
|
|
10
10
|
**Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
|
|
11
11
|
COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maintainability-agent"
|
|
7
|
-
version = "3.6.
|
|
7
|
+
version = "3.6.2"
|
|
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: 3.6.
|
|
3
|
+
Version: 3.6.2
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -46,7 +46,7 @@ Dynamic: license-file
|
|
|
46
46
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
47
47
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
48
48
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
49
|
-
Version **3.6.
|
|
49
|
+
Version **3.6.2**.
|
|
50
50
|
|
|
51
51
|
**Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
|
|
52
52
|
COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
|
|
@@ -163,6 +163,7 @@ tests/test_analyzer_scoring_path.py
|
|
|
163
163
|
tests/test_analyzer_spread_range.py
|
|
164
164
|
tests/test_analyzer_xml_bounds.py
|
|
165
165
|
tests/test_anchor_and_mode.py
|
|
166
|
+
tests/test_anchor_caveat_and_counts_follow_the_run.py
|
|
166
167
|
tests/test_anchor_disclosure.py
|
|
167
168
|
tests/test_annotations_match_behaviour.py
|
|
168
169
|
tests/test_anticipated_refusals.py
|
|
@@ -235,11 +236,13 @@ tests/test_economic_context.py
|
|
|
235
236
|
tests/test_empty_output_not_clean.py
|
|
236
237
|
tests/test_empty_output_not_clean_adapters.py
|
|
237
238
|
tests/test_environment_work_order.py
|
|
239
|
+
tests/test_every_surface_says_what_the_run_found.py
|
|
238
240
|
tests/test_evidence_invariants.py
|
|
239
241
|
tests/test_evidence_normalization.py
|
|
240
242
|
tests/test_evidence_properties.py
|
|
241
243
|
tests/test_example_config_opens_claimed_languages.py
|
|
242
244
|
tests/test_exclusion_dialects.py
|
|
245
|
+
tests/test_exposure_never_outranks_band.py
|
|
243
246
|
tests/test_falsifier_standard.py
|
|
244
247
|
tests/test_file_list_cap_class.py
|
|
245
248
|
tests/test_finding_identity.py
|
|
@@ -368,6 +371,7 @@ tests/test_verification_audit_closures.py
|
|
|
368
371
|
tests/test_verified_grade.py
|
|
369
372
|
tests/test_version_claim.py
|
|
370
373
|
tests/test_wheel_contents.py
|
|
374
|
+
tests/test_work_items_state_their_own_finding.py
|
|
371
375
|
tests/test_work_order.py
|
|
372
376
|
tests/test_work_order_binds_to_this_interpreter.py
|
|
373
377
|
tests/test_work_order_items.py
|
|
@@ -351,7 +351,7 @@ place it in one of four bands:
|
|
|
351
351
|
|
|
352
352
|
| Finding class | Risk | Effort | Band | Why |
|
|
353
353
|
|---|---:|---:|---|---|
|
|
354
|
-
| `risk-pattern` | 5 | 1 | **quick-win** | a
|
|
354
|
+
| `risk-pattern` | 5 | 1 | **quick-win** | a risk pattern is a rule the active configuration enforces, and each hit is a single located line |
|
|
355
355
|
| `oversized-declaration` | 4 | 2 | **quick-win** | a long, branching function is where defects concentrate and where every future change has to be understood first; extracting one is bounded, local work |
|
|
356
356
|
| `unpaired-hotspot` | 4 | 2 | **quick-win** | an oversized production unit with no paired test is where changes land unguarded; adding a characterization test is bounded, local work |
|
|
357
357
|
| `duplicate-block` | 4 | 4 | **major-project** | duplicated logic means a fix applied in one place and missed in the others; deduplicating across a codebase is a design change, not a tidy-up |
|
|
@@ -360,6 +360,15 @@ place it in one of four bands:
|
|
|
360
360
|
| `dead-code` | 2 | 1 | **fill-in** | unreachable code costs reading time and misleads a search, but deleting it is the cheapest change there is |
|
|
361
361
|
| `competing-libraries` | 2 | 4 | **reconsider** | two libraries doing one job is a decision nobody made; converging on one is a migration across every call site |
|
|
362
362
|
|
|
363
|
+
**A band is a judgment about the class, not a size for the item.** The
|
|
364
|
+
effort above is declared once per finding class, so a 2876-line class and a
|
|
365
|
+
90-line function share `oversized-declaration`'s band. The *Why* column is
|
|
366
|
+
that class-level judgment and is published here; a work item does not repeat
|
|
367
|
+
its effort claim. Each item instead states its own reading — its kind, and
|
|
368
|
+
each figure against the limit it is graded on (`currently 2876 lines against
|
|
369
|
+
the 300-line class limit`) — so a reader, or an agent sizing the work, has
|
|
370
|
+
the fact rather than the class's estimate of it (D164).
|
|
371
|
+
|
|
363
372
|
**Why Major Projects are withheld from the agent prompt.** An agent told to
|
|
364
373
|
deduplicate a pattern across forty files produces exactly the sprawling,
|
|
365
374
|
unreviewable diff a bounded prompt exists to prevent. The work is real and
|
|
@@ -369,7 +378,10 @@ appears in the report; scoping it is a human's job first.
|
|
|
369
378
|
what clearing that single finding moves the published score — honestly zero
|
|
370
379
|
more often than not, because the overall is the mean of the *rounded*
|
|
371
380
|
categories and is therefore a step function. `class_delta` is what clearing
|
|
372
|
-
every finding of that class is worth, and it is what the ordering uses
|
|
381
|
+
every finding of that class is worth, and it is what the band ordering uses
|
|
382
|
+
within a band. When an economic context is configured, ADR 004's exposure
|
|
383
|
+
sort takes its place *inside* each band — never across bands, so a Fill-In
|
|
384
|
+
never leads a Quick Win (D170) — and the work order's heading says so (D169).
|
|
373
385
|
Neither is estimated: both come from re-running `score_report` over a summary
|
|
374
386
|
with those findings removed. Per-item deltas do not sum to the whole.
|
|
375
387
|
|
{maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics.py
RENAMED
|
@@ -133,18 +133,27 @@ def _exposure(item: dict[str, Any], churn: dict[str, int],
|
|
|
133
133
|
|
|
134
134
|
|
|
135
135
|
def reorder_by_exposure(report: dict[str, Any]) -> None:
|
|
136
|
-
"""Most-exposed first, in place, keeping every item intact.
|
|
136
|
+
"""Most-exposed first within each band, in place, keeping every item intact.
|
|
137
137
|
|
|
138
138
|
Applied only when an economic context exists: exposure is the
|
|
139
139
|
ordering that context asks for, and without one the risk-by-effort
|
|
140
140
|
order stands untouched. The sort moves whole items, so severity,
|
|
141
141
|
risk, effort, band and class delta stay on each one — the standard
|
|
142
142
|
evidence is reordered, never erased.
|
|
143
|
+
|
|
144
|
+
**Band stays the primary key (D170).** This sorted on exposure alone,
|
|
145
|
+
so a Fill-In on a file that changes often led a Quick Win on a stable
|
|
146
|
+
one — the nit-loop ADR 007 §3 rule 5 forbids. ADR 004 asks for the work
|
|
147
|
+
order to be reordered by exposure; it never asked for exposure to
|
|
148
|
+
outrank band, so ordering within a band satisfies both as written.
|
|
143
149
|
"""
|
|
150
|
+
from ._work_order import BAND_ORDER
|
|
151
|
+
|
|
144
152
|
churn = _churn_by_path(report)
|
|
145
153
|
returns = _returns_by_fingerprint(report)
|
|
146
154
|
items = report.get("work_order") or []
|
|
147
|
-
items.sort(key=lambda item: (
|
|
155
|
+
items.sort(key=lambda item: (BAND_ORDER.get(item.get("band") or "", len(BAND_ORDER)),
|
|
156
|
+
-_exposure(item, churn, returns),
|
|
148
157
|
item.get("title") or ""))
|
|
149
158
|
|
|
150
159
|
|
|
@@ -26,6 +26,7 @@ compatibility semantics.
|
|
|
26
26
|
"""
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
|
+
from collections.abc import Iterable
|
|
29
30
|
from typing import Any
|
|
30
31
|
|
|
31
32
|
# A foundation, not the scoring layer: grammar is neither scoring nor
|
|
@@ -346,17 +347,33 @@ def test_suite_lines(block: dict[str, Any] | None) -> list[str]:
|
|
|
346
347
|
return lines
|
|
347
348
|
|
|
348
349
|
|
|
349
|
-
def unanchored_languages(
|
|
350
|
+
def unanchored_languages(
|
|
351
|
+
score: dict[str, Any], present: Iterable[str] | None = None
|
|
352
|
+
) -> tuple[str, ...]:
|
|
350
353
|
"""Parsed languages the reference corpus does not hold, from the report.
|
|
351
354
|
|
|
352
355
|
Read off `score.reference` rather than imported from `_anchor`, so a
|
|
353
356
|
report rendered from stored JSON discloses what *that* run's anchor
|
|
354
357
|
omitted rather than what today's build omits.
|
|
358
|
+
|
|
359
|
+
``present`` is the run's own language census, `summary.languages`
|
|
360
|
+
(D167). The anchor's gap is a fact about the corpus, but the caveat
|
|
361
|
+
is a claim about *this* grade: "a grade reported for code in COBOL is
|
|
362
|
+
provisional" printed on a Java tree tells the reader something false
|
|
363
|
+
about what they are looking at. ``None`` means the census is unknown —
|
|
364
|
+
a report stored before it existed — and keeps the whole list, because
|
|
365
|
+
a limit that cannot be ruled out is still disclosed.
|
|
355
366
|
"""
|
|
356
|
-
|
|
367
|
+
names = tuple((score.get("reference") or {}).get("unanchored_languages") or ())
|
|
368
|
+
if present is None:
|
|
369
|
+
return names
|
|
370
|
+
here = set(present)
|
|
371
|
+
return tuple(name for name in names if name in here)
|
|
357
372
|
|
|
358
373
|
|
|
359
|
-
def unanchored_caveat(
|
|
374
|
+
def unanchored_caveat(
|
|
375
|
+
score: dict[str, Any], present: Iterable[str] | None = None
|
|
376
|
+
) -> list[str]:
|
|
360
377
|
"""The anchor's gap, in one sentence, for any skin that prints a grade.
|
|
361
378
|
|
|
362
379
|
Lives here because all three skins were about to carry their own copy
|
|
@@ -365,7 +382,7 @@ def unanchored_caveat(score: dict[str, Any]) -> list[str]:
|
|
|
365
382
|
disclosed only there is disclosed nowhere that matters, which is the
|
|
366
383
|
shape this project already shipped once as F1.
|
|
367
384
|
"""
|
|
368
|
-
names = unanchored_languages(score)
|
|
385
|
+
names = unanchored_languages(score, present)
|
|
369
386
|
if not names:
|
|
370
387
|
return []
|
|
371
388
|
say = agreement(len(names))
|
{maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_view.py
RENAMED
|
@@ -90,9 +90,9 @@ def render_html(report: dict[str, Any], records: list[Any]) -> str:
|
|
|
90
90
|
return "\n".join(parts)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def _unanchored_html(score: dict[str, Any]) -> list[str]:
|
|
93
|
+
def _unanchored_html(score: dict[str, Any], present: Any = None) -> list[str]:
|
|
94
94
|
"""The anchor's gap, beside the letter rather than only in the JSON."""
|
|
95
|
-
names = view.unanchored_languages(score)
|
|
95
|
+
names = view.unanchored_languages(score, present)
|
|
96
96
|
if not names:
|
|
97
97
|
return []
|
|
98
98
|
say = agreement(len(names))
|
|
@@ -122,7 +122,7 @@ def _executive_strip(report: dict[str, Any], score: dict[str, Any],
|
|
|
122
122
|
f"Source: {escape(view.estimate_source(score))}</div>",
|
|
123
123
|
f"<div>{escape(view.status_sentence(score, report.get('analyzer_coverage') is not None))}</div>",
|
|
124
124
|
f"<div>{gate}</div>",
|
|
125
|
-
*_unanchored_html(score),
|
|
125
|
+
*_unanchored_html(score, (report.get("summary") or {}).get("languages")),
|
|
126
126
|
f"<div>{escape(_direction_sentence(records))}</div>",
|
|
127
127
|
"<table><tr><th>Severity</th><th>Findings</th></tr>",
|
|
128
128
|
*count_rows,
|
{maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop.py
RENAMED
|
@@ -37,6 +37,7 @@ import re
|
|
|
37
37
|
from pathlib import Path
|
|
38
38
|
from typing import Any
|
|
39
39
|
|
|
40
|
+
from ._work_order import _declaration_reading
|
|
40
41
|
from .declarations import DECLARATION_SUFFIXES, detect_functions
|
|
41
42
|
from .metrics import file_status
|
|
42
43
|
|
|
@@ -237,11 +238,17 @@ def _declaration_findings(
|
|
|
237
238
|
# number. Never negative: it names a budget that failed.
|
|
238
239
|
"breached": breaches[0]["budget"],
|
|
239
240
|
"over_by": breaches[0]["over_by"],
|
|
241
|
+
# The work order's own wording, called rather than copied: the
|
|
242
|
+
# copy printed a class's complexity against a function limit
|
|
243
|
+
# after the work order stopped doing so (D164).
|
|
240
244
|
"target": (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
"reduce below the configured limits ("
|
|
246
|
+
+ _declaration_reading(
|
|
247
|
+
{"lines": metric.lines, "complexity": metric.complexity,
|
|
248
|
+
"kind": metric.kind, "cognitive": metric.cognitive},
|
|
249
|
+
thresholds,
|
|
250
|
+
)
|
|
251
|
+
+ ")"
|
|
245
252
|
),
|
|
246
253
|
})
|
|
247
254
|
return findings
|
{maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit.py
RENAMED
|
@@ -171,6 +171,11 @@ def staged_report(root: Path, config: dict[str, Any]) -> dict[str, Any]:
|
|
|
171
171
|
return {
|
|
172
172
|
"root": str(root),
|
|
173
173
|
"scanned": scannable,
|
|
174
|
+
# The limits these hotspots were graded against, so the work-order
|
|
175
|
+
# builder can name them. Without this the hook worded a class
|
|
176
|
+
# "graded on length alone" while the audit said "against the
|
|
177
|
+
# 300-line class limit" (D171).
|
|
178
|
+
"thresholds": thresholds,
|
|
174
179
|
"largest_files": largest,
|
|
175
180
|
"function_hotspots": hotspots,
|
|
176
181
|
"risk_findings": risk,
|
|
@@ -204,13 +209,12 @@ def _risk_items(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
204
209
|
"title": f"{entry['pattern']} added in {entry['path']}",
|
|
205
210
|
"path": entry["path"], "line": entry["line"],
|
|
206
211
|
"target": (
|
|
207
|
-
f"
|
|
208
|
-
"pattern
|
|
209
|
-
"told about"
|
|
212
|
+
f"act on or justify this {entry['pattern']} match; it is a "
|
|
213
|
+
"risk pattern the active configuration enforces"
|
|
210
214
|
),
|
|
211
215
|
"rationale": (
|
|
212
|
-
"the
|
|
213
|
-
"change is adding a line that matches it"
|
|
216
|
+
"the active configuration declares this pattern risky, and "
|
|
217
|
+
"this change is adding a line that matches it"
|
|
214
218
|
),
|
|
215
219
|
# Above a threshold breach and below an added suppression. A
|
|
216
220
|
# risk pattern is what the repository asked to see; switching
|
|
@@ -289,7 +293,7 @@ def staged_findings(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
289
293
|
from ._work_order import _items_from_files, _items_from_hotspots, band_of
|
|
290
294
|
|
|
291
295
|
items: list[dict[str, Any]] = []
|
|
292
|
-
for entry in _items_from_hotspots(report) + _items_from_files(report):
|
|
296
|
+
for entry in _items_from_hotspots(report, report.get("thresholds")) + _items_from_files(report):
|
|
293
297
|
weight = entry.pop("weight")
|
|
294
298
|
rationale = entry.pop("rationale", None) or weight.rationale
|
|
295
299
|
items.append({**entry, "rationale": rationale,
|
|
@@ -89,7 +89,17 @@ def prompt_analyzer_caveat(report: dict[str, Any]) -> list[str]:
|
|
|
89
89
|
"""
|
|
90
90
|
if not (report.get("analyzer_measurements") or report.get("analyzer_findings")):
|
|
91
91
|
return []
|
|
92
|
-
|
|
92
|
+
score = report.get("score") or {}
|
|
93
|
+
if not view.is_scored(score):
|
|
94
|
+
# No estimate was issued, so none can have a source (D172). The
|
|
95
|
+
# analyzer output is still evidence about the code, and says so.
|
|
96
|
+
return [
|
|
97
|
+
"**No maintainability estimate was issued for this run**, so none is "
|
|
98
|
+
"attributed to the analyzers. Their output is reported here as "
|
|
99
|
+
"evidence about the code, never as a change to a score.",
|
|
100
|
+
"",
|
|
101
|
+
]
|
|
102
|
+
scored = score.get("analyzer_scored_dimensions") or []
|
|
93
103
|
if scored:
|
|
94
104
|
return [
|
|
95
105
|
"**The maintainability estimate above uses the analyzer readings** for "
|
|
@@ -149,6 +159,50 @@ def _withheld_paragraph(report: dict[str, Any]) -> list[str]:
|
|
|
149
159
|
]
|
|
150
160
|
|
|
151
161
|
|
|
162
|
+
def _prompt_work_items(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
163
|
+
"""The items this prompt hands to an agent, after withholding."""
|
|
164
|
+
# Withhold anything the history shows was fixed and came back
|
|
165
|
+
# twice. Naming it as a design candidate while asking an agent to
|
|
166
|
+
# patch it a third time would change nothing.
|
|
167
|
+
escalated = {
|
|
168
|
+
item["fingerprint"] for item in report.get("design_review_candidates") or []
|
|
169
|
+
}
|
|
170
|
+
return prompt_items(report.get("work_order") or [], escalated=escalated)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def prompt_has_work(report: dict[str, Any]) -> bool:
|
|
174
|
+
"""Whether this prompt hands an agent anything to change (D173).
|
|
175
|
+
|
|
176
|
+
A report with no `work_order` key at all — stored before the field
|
|
177
|
+
existed, or assembled by hand — cannot say there is nothing to do, so
|
|
178
|
+
it keeps the prompt it always had rather than reading as "Nothing to
|
|
179
|
+
do" over findings it does carry.
|
|
180
|
+
"""
|
|
181
|
+
return "work_order" not in report or bool(_prompt_work_items(report))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _no_prompt_work(report: dict[str, Any]) -> list[str]:
|
|
185
|
+
"""What the prompt says in place of a task when there is none (D173).
|
|
186
|
+
|
|
187
|
+
Two cases, because they are different facts. An empty work order is the
|
|
188
|
+
chat report's "Nothing to do", in the same words. A work order whose
|
|
189
|
+
every item was withheld — a Major Project, or a finding escalated for
|
|
190
|
+
design review — has work in it, none of it an agent's to patch.
|
|
191
|
+
"""
|
|
192
|
+
if not report.get("work_order"):
|
|
193
|
+
from ._work_order_view import NOTHING_TO_DO
|
|
194
|
+
|
|
195
|
+
return [NOTHING_TO_DO, "", "Do not change code on the strength of this audit.", ""]
|
|
196
|
+
return [
|
|
197
|
+
"**Nothing in scope for this prompt.** Every work-order item needs a "
|
|
198
|
+
"design decision or keeps coming back, so none is handed to an agent. "
|
|
199
|
+
"They are in the report. Do not change code on the strength of this "
|
|
200
|
+
"prompt.",
|
|
201
|
+
"",
|
|
202
|
+
*_withheld_paragraph(report),
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
|
|
152
206
|
def prompt_work_order(report: dict[str, Any]) -> list[str]:
|
|
153
207
|
"""The ordered work, leading the prompt, Major Projects withheld.
|
|
154
208
|
|
|
@@ -161,18 +215,16 @@ def prompt_work_order(report: dict[str, Any]) -> list[str]:
|
|
|
161
215
|
told to deduplicate a pattern across forty files produces exactly the
|
|
162
216
|
sprawling, unreviewable diff a bounded prompt exists to prevent.
|
|
163
217
|
"""
|
|
164
|
-
|
|
165
|
-
# twice. Naming it as a design candidate while asking an agent to
|
|
166
|
-
# patch it a third time would change nothing.
|
|
167
|
-
escalated = {
|
|
168
|
-
item["fingerprint"] for item in report.get("design_review_candidates") or []
|
|
169
|
-
}
|
|
170
|
-
items = prompt_items(report.get("work_order") or [], escalated=escalated)
|
|
218
|
+
items = _prompt_work_items(report)
|
|
171
219
|
if not items:
|
|
172
|
-
return []
|
|
220
|
+
return _no_prompt_work(report) if "work_order" in report else []
|
|
173
221
|
lines = [
|
|
174
|
-
|
|
175
|
-
|
|
222
|
+
# What the order is, not what it is worth (D169): `prompt_items`
|
|
223
|
+
# promotes risk-5 classes and keeps one item per class, so this
|
|
224
|
+
# list and the report's table can lead with different items.
|
|
225
|
+
"Work in this order: severe findings (risk 5) first, then the work "
|
|
226
|
+
"order's own order, one item per kind of finding. Stop when the "
|
|
227
|
+
"change stops being reviewable.",
|
|
176
228
|
"",
|
|
177
229
|
]
|
|
178
230
|
for index, item in enumerate(items, start=1):
|
|
@@ -217,7 +269,22 @@ DIMENSION_GUIDANCE = {
|
|
|
217
269
|
}
|
|
218
270
|
|
|
219
271
|
|
|
220
|
-
def
|
|
272
|
+
def corpus_span(score: dict[str, Any]) -> str:
|
|
273
|
+
"""How much of what this scanner parses the corpus holds, counted (D168).
|
|
274
|
+
|
|
275
|
+
Read off `score.reference`, the two lists the corpus note is built
|
|
276
|
+
from. The prompt typed "eight of the ten parsed languages" while the
|
|
277
|
+
note on the same report said thirteen of fourteen: a count written
|
|
278
|
+
as prose goes stale the first time a language is added, and nothing
|
|
279
|
+
fails when it does.
|
|
280
|
+
"""
|
|
281
|
+
reference = score.get("reference") or {}
|
|
282
|
+
held = len(reference.get("corpus_languages") or ())
|
|
283
|
+
parsed = held + len(reference.get("unanchored_languages") or ())
|
|
284
|
+
return f"{held} of the {parsed} parsed languages"
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def prompt_pressure_section(score: dict[str, Any], present: Any = None) -> list[str]:
|
|
221
288
|
"""Tell the agent *what kind* of trouble this repo is in, and how much.
|
|
222
289
|
|
|
223
290
|
A letter grade is not actionable. These figures are multiples of what
|
|
@@ -247,7 +314,7 @@ def prompt_pressure_section(score: dict[str, Any]) -> list[str]:
|
|
|
247
314
|
if not view.is_scored(score):
|
|
248
315
|
# The grade blockers still render below: those say *why* no
|
|
249
316
|
# number was issued, which is exactly what this reader needs.
|
|
250
|
-
return [*view.unanchored_caveat(score), *_grade_blocker_lines(score)]
|
|
317
|
+
return [*view.unanchored_caveat(score, present), *_grade_blocker_lines(score)]
|
|
251
318
|
dimensions = score.get("dimensions") or {}
|
|
252
319
|
elevated = sorted(
|
|
253
320
|
# `is not None` first: an unmeasured dimension is legitimate --
|
|
@@ -259,13 +326,13 @@ def prompt_pressure_section(score: dict[str, Any]) -> list[str]:
|
|
|
259
326
|
key=lambda item: -item[1],
|
|
260
327
|
)
|
|
261
328
|
# Unanchored languages are provisional here too, elevated or not.
|
|
262
|
-
lines: list[str] = view.unanchored_caveat(score)
|
|
329
|
+
lines: list[str] = view.unanchored_caveat(score, present)
|
|
263
330
|
if elevated:
|
|
264
331
|
lines.extend(
|
|
265
332
|
[
|
|
266
333
|
"Where this repo is worse than typical real-world code",
|
|
267
|
-
"(1.0x = the median of a mature open-source corpus of
|
|
268
|
-
"
|
|
334
|
+
f"(1.0x = the median of a mature open-source corpus of "
|
|
335
|
+
f"{corpus_span(score)}; elevated dimensions only):",
|
|
269
336
|
"",
|
|
270
337
|
]
|
|
271
338
|
)
|
{maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order.py
RENAMED
|
@@ -17,7 +17,7 @@ from ._identity import (
|
|
|
17
17
|
finding_fingerprints,
|
|
18
18
|
risk_identities,
|
|
19
19
|
)
|
|
20
|
-
from ._work_order_weights import CLASS_RISK_EFFORT, ClassWeight
|
|
20
|
+
from ._work_order_weights import AUDIT_VERIFICATION, CLASS_RISK_EFFORT, ClassWeight
|
|
21
21
|
from .scoring import score_report
|
|
22
22
|
|
|
23
23
|
|
|
@@ -36,6 +36,11 @@ class Band(StrEnum):
|
|
|
36
36
|
HIGH_RISK = 3
|
|
37
37
|
HIGH_EFFORT = 3
|
|
38
38
|
|
|
39
|
+
#: ADR 007 §3's order of the four cells, taken from `Band`'s declaration
|
|
40
|
+
#: order. Both sorts read it — the band sort here and `reorder_by_exposure`
|
|
41
|
+
#: — so no ordering can place a Fill-In above a Quick Win (D170).
|
|
42
|
+
BAND_ORDER = {band.value: rank for rank, band in enumerate(Band)}
|
|
43
|
+
|
|
39
44
|
|
|
40
45
|
def band_of(risk: int, effort: int) -> Band:
|
|
41
46
|
"""Which of the four cells a finding falls in."""
|
|
@@ -76,7 +81,59 @@ def _delta_for(report: dict[str, Any], counter: str, amount: int) -> float:
|
|
|
76
81
|
return round(max(0.0, (after or before) - before), 3)
|
|
77
82
|
|
|
78
83
|
|
|
79
|
-
def
|
|
84
|
+
def _declaration_reading(hotspot: dict[str, Any], thresholds: dict[str, int] | None) -> str:
|
|
85
|
+
"""What this declaration measures, each figure against the limit it is graded on (D164).
|
|
86
|
+
|
|
87
|
+
A class is graded on length alone (`declarations.class_status`), so it
|
|
88
|
+
is given its length and the class budget and nothing else: its
|
|
89
|
+
complexity is the sum of its methods' branches, already counted
|
|
90
|
+
against those methods, and printing it beside a function limit
|
|
91
|
+
described a 2876-line class as a function with complexity 25. A
|
|
92
|
+
function is graded on lines, complexity and cognitive cost, so each
|
|
93
|
+
appears with its own limit. Without thresholds — a caller holding only
|
|
94
|
+
the report — the figures are stated bare rather than against a
|
|
95
|
+
default the repository may not use.
|
|
96
|
+
"""
|
|
97
|
+
lines = hotspot["lines"]
|
|
98
|
+
if hotspot.get("kind") == "class":
|
|
99
|
+
if thresholds is None:
|
|
100
|
+
return f"currently {lines} lines; a class is graded on length alone"
|
|
101
|
+
limit = thresholds.get("max_class_lines", thresholds["max_function_lines"])
|
|
102
|
+
return f"currently {lines} lines against the {limit}-line class limit"
|
|
103
|
+
if thresholds is None:
|
|
104
|
+
return f"currently {lines} lines, complexity {hotspot['complexity']}"
|
|
105
|
+
parts = [
|
|
106
|
+
f"{lines} lines against {thresholds['max_function_lines']}",
|
|
107
|
+
f"complexity {hotspot['complexity']} against {thresholds['max_complexity']}",
|
|
108
|
+
]
|
|
109
|
+
max_cognitive = thresholds.get("max_cognitive_complexity")
|
|
110
|
+
if max_cognitive is not None and hotspot.get("cognitive") is not None:
|
|
111
|
+
parts.append(f"cognitive {hotspot['cognitive']} against {max_cognitive}")
|
|
112
|
+
return "currently " + ", ".join(parts)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _declaration_rationale(hotspot: dict[str, Any]) -> str:
|
|
116
|
+
"""Why this declaration matters, without sizing the change it needs (D164).
|
|
117
|
+
|
|
118
|
+
The class weight's rationale ends "extracting one is bounded, local
|
|
119
|
+
work" — a judgment about the class of finding, published in the
|
|
120
|
+
standard beside its declared effort. Printed on one item it became a
|
|
121
|
+
claim about that item, and it was false for a 2876-line class. The
|
|
122
|
+
band stays declared per class; the item states what it is and its own
|
|
123
|
+
reading states how far past the limit it sits.
|
|
124
|
+
"""
|
|
125
|
+
if hotspot.get("kind") == "class":
|
|
126
|
+
return ("an oversized class hides its own structure, and every change "
|
|
127
|
+
"to it is read against all of it")
|
|
128
|
+
if float(hotspot["complexity"]) <= 10:
|
|
129
|
+
return "a long function is where every future change has to be understood first"
|
|
130
|
+
return ("a long, branching function is where defects concentrate and where "
|
|
131
|
+
"every future change has to be understood first")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _items_from_hotspots(
|
|
135
|
+
report: dict[str, Any], thresholds: dict[str, int] | None = None
|
|
136
|
+
) -> list[dict[str, Any]]:
|
|
80
137
|
"""Declarations past a threshold, worst first."""
|
|
81
138
|
weight = CLASS_RISK_EFFORT["oversized-declaration"]
|
|
82
139
|
# Computed once over the whole population, because an ordinal is a
|
|
@@ -100,18 +157,13 @@ def _items_from_hotspots(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
100
157
|
"line": hotspot["start_line"],
|
|
101
158
|
"target": (
|
|
102
159
|
f"reduce below the configured limits "
|
|
103
|
-
f"(
|
|
160
|
+
f"({_declaration_reading(hotspot, thresholds)})"
|
|
104
161
|
),
|
|
105
162
|
"severity": float(hotspot["lines"]) + 4.0 * float(hotspot["complexity"]),
|
|
106
163
|
"fingerprint": identities[
|
|
107
164
|
(hotspot["path"], hotspot["name"], hotspot["start_line"])
|
|
108
165
|
],
|
|
109
|
-
"rationale": (
|
|
110
|
-
"a long function is where every future change has to be "
|
|
111
|
-
"understood first; extracting one is bounded, local work"
|
|
112
|
-
if float(hotspot["complexity"]) <= 10
|
|
113
|
-
else None
|
|
114
|
-
),
|
|
166
|
+
"rationale": _declaration_rationale(hotspot),
|
|
115
167
|
"weight": weight,
|
|
116
168
|
})
|
|
117
169
|
return items
|
|
@@ -130,6 +182,11 @@ def _items_from_unpaired(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
130
182
|
"path": path,
|
|
131
183
|
"line": finding.get("line"),
|
|
132
184
|
"target": f"add a paired test for `{name}`",
|
|
185
|
+
# Not the class rationale: "adding a characterization test is
|
|
186
|
+
# bounded, local work" sizes the item, and a 1907-line class
|
|
187
|
+
# with no test is not bounded work (D164).
|
|
188
|
+
"rationale": ("an oversized production unit with no paired test is "
|
|
189
|
+
"where changes land unguarded"),
|
|
133
190
|
"severity": float(finding.get("lines") or 1),
|
|
134
191
|
"weight": weight,
|
|
135
192
|
})
|
|
@@ -234,11 +291,22 @@ def _items_from_counted(report: dict[str, Any]) -> list[dict[str, Any]]:
|
|
|
234
291
|
}
|
|
235
292
|
if name == "risk-pattern":
|
|
236
293
|
item["fingerprint"] = risks[(path, finding["name"], finding["line"])]
|
|
294
|
+
# "remove the configured risk pattern" read, for a TODO, as
|
|
295
|
+
# "delete the comment" — which clears the finding and the
|
|
296
|
+
# score while the debt it records stays (D165).
|
|
297
|
+
item["target"] = (
|
|
298
|
+
f"act on what the `{finding['name']}` rule matched here, or "
|
|
299
|
+
"say why it stays; deleting the matched text alone hides "
|
|
300
|
+
"the finding without resolving it"
|
|
301
|
+
)
|
|
237
302
|
items.append(item)
|
|
238
303
|
return items
|
|
239
304
|
|
|
240
305
|
|
|
241
|
-
def work_order(
|
|
306
|
+
def work_order(
|
|
307
|
+
report: dict[str, Any], include_reconsider: bool = False,
|
|
308
|
+
thresholds: dict[str, int] | None = None,
|
|
309
|
+
) -> list[dict[str, Any]]:
|
|
242
310
|
"""Every actionable finding, ordered by risk against effort.
|
|
243
311
|
|
|
244
312
|
Quick Wins first, then Major Projects, then Fill-Ins; Reconsider is
|
|
@@ -247,7 +315,7 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
|
|
|
247
315
|
value rather than by how many of something there are.
|
|
248
316
|
"""
|
|
249
317
|
raw = (
|
|
250
|
-
_items_from_hotspots(report)
|
|
318
|
+
_items_from_hotspots(report, thresholds)
|
|
251
319
|
+ _items_from_files(report)
|
|
252
320
|
+ _items_from_counted(report)
|
|
253
321
|
+ _items_from_idioms(report)
|
|
@@ -268,7 +336,6 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
|
|
|
268
336
|
counts[entry["finding_class"]] = counts.get(entry["finding_class"], 0) + 1
|
|
269
337
|
per_class: dict[str, float] = {}
|
|
270
338
|
class_delta: dict[str, float] = {}
|
|
271
|
-
ordering = {Band.QUICK_WIN: 0, Band.MAJOR_PROJECT: 1, Band.FILL_IN: 2, Band.RECONSIDER: 3}
|
|
272
339
|
items: list[dict[str, Any]] = []
|
|
273
340
|
for entry in raw:
|
|
274
341
|
weight: ClassWeight = entry.pop("weight")
|
|
@@ -298,7 +365,7 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
|
|
|
298
365
|
|
|
299
366
|
items.extend(_items_from_semantic(report))
|
|
300
367
|
items.sort(key=lambda item: (
|
|
301
|
-
|
|
368
|
+
BAND_ORDER[item["band"]], -item["class_delta"],
|
|
302
369
|
# Within a class every delta is identical, so severity is what
|
|
303
370
|
# actually orders the work a reader will do first.
|
|
304
371
|
-item["severity"], item["path"]))
|
|
@@ -358,7 +425,7 @@ def _semantic_item(
|
|
|
358
425
|
"delta": 0.0,
|
|
359
426
|
"class_delta": 0.0,
|
|
360
427
|
"class_count": class_count,
|
|
361
|
-
"verification":
|
|
428
|
+
"verification": AUDIT_VERIFICATION,
|
|
362
429
|
}
|
|
363
430
|
|
|
364
431
|
|
|
@@ -416,8 +483,9 @@ def prompt_items(items: list[dict[str, Any]], limit: int = 12,
|
|
|
416
483
|
escalated: set[str] | None = None) -> list[dict[str, Any]]:
|
|
417
484
|
"""Agent subset: no major projects, no escalated returns; Severe leads.
|
|
418
485
|
|
|
419
|
-
|
|
420
|
-
|
|
486
|
+
The economic reorder orders items by exposure within each band (D170),
|
|
487
|
+
so a risk-5 item can still sit below hotter Quick Wins of other classes.
|
|
488
|
+
The table can stay exposure-ordered; the paste of 12 cannot drop Severe.
|
|
421
489
|
"""
|
|
422
490
|
blocked = escalated or set()
|
|
423
491
|
eligible = [
|