maintainability-agent 3.0.2__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {maintainability_agent-3.0.2/src/maintainability_agent.egg-info → maintainability_agent-3.2.0}/PKG-INFO +2 -2
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/README.md +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/pyproject.toml +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/SOURCES.txt +15 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/__init__.py +1 -1
- maintainability_agent-3.2.0/src/maintainability_audit/_anchor.py +73 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_assets/standard.md +39 -18
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_banner.py +23 -3
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_catalog.py +22 -2
- maintainability_agent-3.2.0/src/maintainability_audit/_delegated_pillar.py +181 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_derive.py +2 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_discovery.py +85 -19
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_environment.py +54 -2
- maintainability_agent-3.2.0/src/maintainability_audit/_evidence_reader.py +305 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_evidence_view.py +11 -4
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_first_run.py +57 -16
- maintainability_agent-3.2.0/src/maintainability_audit/_grammar.py +93 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_grant_ledger.py +0 -8
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_history_view.py +85 -24
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_html_report_sections.py +78 -31
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_html_view.py +5 -3
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_in_loop.py +47 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_in_loop_view.py +32 -15
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_metric_adapters.py +14 -127
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_pillars.py +77 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_practice.py +71 -25
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_pressures.py +61 -70
- maintainability_agent-3.0.2/src/maintainability_audit/prompts.py → maintainability_agent-3.2.0/src/maintainability_audit/_prompt_sections.py +40 -114
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_core.py +44 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_fortran.py +29 -11
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_php.py +2 -28
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_rust.py +2 -31
- maintainability_agent-3.2.0/src/maintainability_audit/_ratio_adapters.py +153 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_scan_history.py +36 -4
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_scan_view.py +46 -18
- maintainability_agent-3.2.0/src/maintainability_audit/_selection.py +177 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_policy.py +18 -8
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_ts.py +14 -4
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_setup_persist.py +47 -3
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_test_commands.py +23 -2
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_test_execution.py +23 -2
- maintainability_agent-3.2.0/src/maintainability_audit/_test_pairing.py +291 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_trends.py +1 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_verdict_adapters.py +50 -36
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order.py +39 -27
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/config.py +53 -2
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/evidence.py +1 -227
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/idioms.py +22 -6
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/metrics.py +38 -10
- maintainability_agent-3.2.0/src/maintainability_audit/prompts.py +128 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/report.py +25 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/scoring.py +2 -5
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_primary_estimate.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_scoring_path.py +3 -3
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_spread_range.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_anchor_disclosure.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_band_concealment_p3.py +2 -1
- maintainability_agent-3.2.0/tests/test_check_refuses_plus_only_fragments.py +38 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_consumer_migration.py +2 -1
- maintainability_agent-3.2.0/tests/test_declarative_parsers.py +220 -0
- maintainability_agent-3.2.0/tests/test_delegated_security_pillar.py +242 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_evidence_invariants.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_evidence_normalization.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_evidence_properties.py +1 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_history_window.py +10 -25
- maintainability_agent-3.2.0/tests/test_pairing_reads_imports.py +213 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_population_floors.py +1 -1
- maintainability_agent-3.2.0/tests/test_release_needs_an_empty_ledger.py +150 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_release_plan_status.py +8 -1
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scan_scope.py +2 -6
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scoring_calibration.py +2 -5
- maintainability_agent-3.2.0/tests/test_terminal_asks_the_same_questions.py +98 -0
- maintainability_agent-3.2.0/tests/test_tree_cannot_opt_the_host_in.py +111 -0
- maintainability_agent-3.2.0/tests/test_tree_reads_use_the_primitive.py +167 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_trends.py +14 -1
- maintainability_agent-3.2.0/tests/test_unanchored_set_matches_corpus.py +129 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_verified_grade.py +1 -1
- maintainability_agent-3.2.0/tests/test_work_order_binds_to_this_interpreter.py +72 -0
- maintainability_agent-3.0.2/src/maintainability_audit/_anchor.py +0 -49
- maintainability_agent-3.0.2/src/maintainability_audit/_selection.py +0 -136
- maintainability_agent-3.0.2/src/maintainability_audit/_test_pairing.py +0 -149
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/LICENSE +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/setup.cfg +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_analyzer_sections.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_arguments.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_criteria_scope.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_operator_reads.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit_install.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit_view.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_cobol.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_go.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_ruby.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_swift.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_run_comparison.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_adapters.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_added_lines.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_anchor_and_mode.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_architecture.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_attestation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_audit_components.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_backfill.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_bands.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_cli.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_cobol_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_config_shape.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_corroborate.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_criteria_completion.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_dead_code.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declaration_criteria_scope.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_determinism.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_discovery.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_docs_links.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_economic_context.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_format_ask.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_git_argv.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_go_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_grammar_constructs.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_grammar_token_coverage.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_history.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_html_executive.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_in_loop_budgets.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_in_loop_check.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_java_scored.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_language_support_honesty.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_operator_named_paths.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_operator_named_reads.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_php_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_policy_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_precommit_staged.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_promises.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_python_complexity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_recurrence.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_release_plan.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_root_grants.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_ruby_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_run_comparison.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_runner.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_rust_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_sarif.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scan_history.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scanner_unsafe_direction.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scanning.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_skill_install.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_sonar_resolve.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_source_index.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_suite_isolation.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_swift_declarations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_test_commands.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_tool_resolution.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_tree_chosen_spawn.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_unread_code.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_version_claim.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_work_order.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/tests/test_written_record.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -45,7 +45,7 @@ Dynamic: license-file
|
|
|
45
45
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
46
46
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
47
47
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
48
|
-
Version **3.0
|
|
48
|
+
Version **3.2.0**.
|
|
49
49
|
|
|
50
50
|
**Planned, not shipped:** the audit tool will become `maintainability-audit`;
|
|
51
51
|
a new `maintainability-agent` companion will run it and automate human-selected
|
|
@@ -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.0
|
|
8
|
+
Version **3.2.0**.
|
|
9
9
|
|
|
10
10
|
**Planned, not shipped:** the audit tool will become `maintainability-audit`;
|
|
11
11
|
a new `maintainability-agent` companion will run it and automate human-selected
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maintainability-agent"
|
|
7
|
-
version = "3.0
|
|
7
|
+
version = "3.2.0"
|
|
8
8
|
description = "Maintainability gate and AI remediation prompt generator for CI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# 3.11, not 3.10. `_discovery`, `_pillars` and `_runner` all import
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -45,7 +45,7 @@ Dynamic: license-file
|
|
|
45
45
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
46
46
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
47
47
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
48
|
-
Version **3.0
|
|
48
|
+
Version **3.2.0**.
|
|
49
49
|
|
|
50
50
|
**Planned, not shipped:** the audit tool will become `maintainability-audit`;
|
|
51
51
|
a new `maintainability-agent` companion will run it and automate human-selected
|
|
@@ -29,18 +29,21 @@ src/maintainability_audit/_conformance.py
|
|
|
29
29
|
src/maintainability_audit/_corroborate.py
|
|
30
30
|
src/maintainability_audit/_coverage_notes.py
|
|
31
31
|
src/maintainability_audit/_criteria_scope.py
|
|
32
|
+
src/maintainability_audit/_delegated_pillar.py
|
|
32
33
|
src/maintainability_audit/_derive.py
|
|
33
34
|
src/maintainability_audit/_discovery.py
|
|
34
35
|
src/maintainability_audit/_documents.py
|
|
35
36
|
src/maintainability_audit/_economics.py
|
|
36
37
|
src/maintainability_audit/_economics_view.py
|
|
37
38
|
src/maintainability_audit/_environment.py
|
|
39
|
+
src/maintainability_audit/_evidence_reader.py
|
|
38
40
|
src/maintainability_audit/_evidence_view.py
|
|
39
41
|
src/maintainability_audit/_finding_match.py
|
|
40
42
|
src/maintainability_audit/_first_run.py
|
|
41
43
|
src/maintainability_audit/_formula.py
|
|
42
44
|
src/maintainability_audit/_gates.py
|
|
43
45
|
src/maintainability_audit/_generic.py
|
|
46
|
+
src/maintainability_audit/_grammar.py
|
|
44
47
|
src/maintainability_audit/_grant_ledger.py
|
|
45
48
|
src/maintainability_audit/_history_view.py
|
|
46
49
|
src/maintainability_audit/_hostile_prompt.py
|
|
@@ -68,6 +71,7 @@ src/maintainability_audit/_precommit.py
|
|
|
68
71
|
src/maintainability_audit/_precommit_install.py
|
|
69
72
|
src/maintainability_audit/_precommit_view.py
|
|
70
73
|
src/maintainability_audit/_pressures.py
|
|
74
|
+
src/maintainability_audit/_prompt_sections.py
|
|
71
75
|
src/maintainability_audit/_ranges_c.py
|
|
72
76
|
src/maintainability_audit/_ranges_cobol.py
|
|
73
77
|
src/maintainability_audit/_ranges_core.py
|
|
@@ -82,6 +86,7 @@ src/maintainability_audit/_ranges_ruby.py
|
|
|
82
86
|
src/maintainability_audit/_ranges_rust.py
|
|
83
87
|
src/maintainability_audit/_ranges_swift.py
|
|
84
88
|
src/maintainability_audit/_ratchet.py
|
|
89
|
+
src/maintainability_audit/_ratio_adapters.py
|
|
85
90
|
src/maintainability_audit/_recurrence.py
|
|
86
91
|
src/maintainability_audit/_run_comparison.py
|
|
87
92
|
src/maintainability_audit/_runner.py
|
|
@@ -183,6 +188,7 @@ tests/test_calibration_tooling.py
|
|
|
183
188
|
tests/test_catalog_selection.py
|
|
184
189
|
tests/test_catalog_tier_promise.py
|
|
185
190
|
tests/test_chat_primary_docs.py
|
|
191
|
+
tests/test_check_refuses_plus_only_fragments.py
|
|
186
192
|
tests/test_checkstyle_adapter.py
|
|
187
193
|
tests/test_checkstyle_catalog.py
|
|
188
194
|
tests/test_ci_history_recipe.py
|
|
@@ -211,8 +217,10 @@ tests/test_declaration_edge_cases.py
|
|
|
211
217
|
tests/test_declaration_grading.py
|
|
212
218
|
tests/test_declaration_ranges.py
|
|
213
219
|
tests/test_declaration_source.py
|
|
220
|
+
tests/test_declarative_parsers.py
|
|
214
221
|
tests/test_declared_authorship.py
|
|
215
222
|
tests/test_declared_imports.py
|
|
223
|
+
tests/test_delegated_security_pillar.py
|
|
216
224
|
tests/test_derivation_mix.py
|
|
217
225
|
tests/test_determinism.py
|
|
218
226
|
tests/test_dimension_ratchet.py
|
|
@@ -279,6 +287,7 @@ tests/test_network_disclosure.py
|
|
|
279
287
|
tests/test_one_setup_across_surfaces_class.py
|
|
280
288
|
tests/test_operator_named_paths.py
|
|
281
289
|
tests/test_operator_named_reads.py
|
|
290
|
+
tests/test_pairing_reads_imports.py
|
|
282
291
|
tests/test_pattern_budget.py
|
|
283
292
|
tests/test_phase6_claims.py
|
|
284
293
|
tests/test_php_declarations.py
|
|
@@ -302,6 +311,7 @@ tests/test_python_declarations.py
|
|
|
302
311
|
tests/test_read_boundary.py
|
|
303
312
|
tests/test_readme_claims.py
|
|
304
313
|
tests/test_recurrence.py
|
|
314
|
+
tests/test_release_needs_an_empty_ledger.py
|
|
305
315
|
tests/test_release_plan.py
|
|
306
316
|
tests/test_release_plan_status.py
|
|
307
317
|
tests/test_report_remedy_copy.py
|
|
@@ -333,14 +343,18 @@ tests/test_stage8_contract.py
|
|
|
333
343
|
tests/test_suite_isolation.py
|
|
334
344
|
tests/test_swift_declarations.py
|
|
335
345
|
tests/test_tdd_structure.py
|
|
346
|
+
tests/test_terminal_asks_the_same_questions.py
|
|
336
347
|
tests/test_test_commands.py
|
|
337
348
|
tests/test_test_execution_class.py
|
|
338
349
|
tests/test_three_presentations.py
|
|
339
350
|
tests/test_tool_resolution.py
|
|
351
|
+
tests/test_tree_cannot_opt_the_host_in.py
|
|
340
352
|
tests/test_tree_chosen_spawn.py
|
|
353
|
+
tests/test_tree_reads_use_the_primitive.py
|
|
341
354
|
tests/test_trends.py
|
|
342
355
|
tests/test_type_fields_not_functions_class.py
|
|
343
356
|
tests/test_uat_falsifiers.py
|
|
357
|
+
tests/test_unanchored_set_matches_corpus.py
|
|
344
358
|
tests/test_unread_code.py
|
|
345
359
|
tests/test_user_config_tier.py
|
|
346
360
|
tests/test_verification_audit_closures.py
|
|
@@ -348,6 +362,7 @@ tests/test_verified_grade.py
|
|
|
348
362
|
tests/test_version_claim.py
|
|
349
363
|
tests/test_wheel_contents.py
|
|
350
364
|
tests/test_work_order.py
|
|
365
|
+
tests/test_work_order_binds_to_this_interpreter.py
|
|
351
366
|
tests/test_work_order_items.py
|
|
352
367
|
tests/test_work_order_selection.py
|
|
353
368
|
tests/test_workflow_supply_chain.py
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""What the reference corpus does not hold, and how to say it.
|
|
2
|
+
|
|
3
|
+
Rubric data, like `_calibration`: a fact about the anchor rather than a
|
|
4
|
+
computation over a repository. It lives beside the constant it qualifies
|
|
5
|
+
because the two go stale together — a recalibration that adds Swift and
|
|
6
|
+
COBOL to the corpus empties this in the same commit that moves
|
|
7
|
+
`CALIBRATION_C`.
|
|
8
|
+
|
|
9
|
+
**Unanchored is policy, not an oversight.** Under the corpus policy
|
|
10
|
+
decided with 2.4.1, a language ships parsed and the corpus is re-measured
|
|
11
|
+
once after the remaining scanners land: adding a scanner moves
|
|
12
|
+
`scanner_fingerprint` and invalidates every stored measurement, so paying
|
|
13
|
+
per language means paying in full, repeatedly, for an anchor that is
|
|
14
|
+
obsolete again at the next one.
|
|
15
|
+
|
|
16
|
+
What is *not* policy is silence about it where the grade is read. The
|
|
17
|
+
report carried `score.reference` and the note said the corpus spanned
|
|
18
|
+
"every language this scanner parses" — which was true when it was written
|
|
19
|
+
and false from 2.4.0 onward, for three releases. A Grok audit on
|
|
20
|
+
2026-09-04 named it as the second instance of a shape this project had
|
|
21
|
+
already shipped once: a limit disclosed only in JSON is disclosed nowhere
|
|
22
|
+
that matters.
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
#: Parsed by a scanner, absent from the reference corpus.
|
|
27
|
+
#:
|
|
28
|
+
#: Stated rather than derived, and the reason still holds:
|
|
29
|
+
#: `tools/calibration/corpus.json` is a repository file that does not ship
|
|
30
|
+
#: in the wheel, so a runtime read would be unavailable exactly where a
|
|
31
|
+
#: user reads a grade. What a stated list buys in availability it owes in
|
|
32
|
+
#: upkeep, and it did not pay.
|
|
33
|
+
#:
|
|
34
|
+
#: **D143.** This read `("Swift", "COBOL", "Go", "Rust", "PHP", "Ruby")`
|
|
35
|
+
#: after 3.0.0 anchored five of those six. The corpus grew from 112
|
|
36
|
+
#: repositories to 180 and from eight measured languages to thirteen, and
|
|
37
|
+
#: this line did not move — so every skin told a Swift, Go, Rust, PHP or
|
|
38
|
+
#: Ruby reader their grade was provisional against a corpus that had
|
|
39
|
+
#: measured their language for two releases. A caveat that names an
|
|
40
|
+
#: anchored language is not a caution, it is a false statement about the
|
|
41
|
+
#: evidence, and it undersells the thing the recalibration was for.
|
|
42
|
+
#:
|
|
43
|
+
#: COBOL stays, and stays alone. It is parsed and deliberately never
|
|
44
|
+
#: anchored: GitHub holds one COBOL repository above 500 stars and what is
|
|
45
|
+
#: there is curriculum, Java parsers and JavaScript wrappers rather than
|
|
46
|
+
#: COBOL codebases, so the corpus policy excludes it permanently rather
|
|
47
|
+
#: than temporarily. Emptying this tuple would delete a disclosure that is
|
|
48
|
+
#: still true.
|
|
49
|
+
#:
|
|
50
|
+
#: `tests/test_unanchored_set_matches_corpus.py` recomputes
|
|
51
|
+
#: `parsed - corpus` from `DECLARATION_SUFFIXES` and `corpus.json` and
|
|
52
|
+
#: fails if this stops matching — including when a language is *added* to
|
|
53
|
+
#: the corpus, which is the direction that went unnoticed.
|
|
54
|
+
UNANCHORED_LANGUAGES: tuple[str, ...] = ("COBOL",)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def unanchored_names() -> str:
|
|
58
|
+
"""The languages, joined for a sentence. Empty when there are none."""
|
|
59
|
+
return " and ".join(UNANCHORED_LANGUAGES)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def unanchored_sentence() -> str:
|
|
63
|
+
"""One sentence naming what the anchor omits, for the corpus note."""
|
|
64
|
+
if not UNANCHORED_LANGUAGES:
|
|
65
|
+
return ""
|
|
66
|
+
from ._grammar import agreement
|
|
67
|
+
|
|
68
|
+
say = agreement(len(UNANCHORED_LANGUAGES))
|
|
69
|
+
return (
|
|
70
|
+
f"{unanchored_names()} {say.verb} parsed but absent from it, so "
|
|
71
|
+
f"{say.possessive} findings are as good as {say.possessive} "
|
|
72
|
+
f"parser while {say.possessive} grade is provisional."
|
|
73
|
+
)
|
|
@@ -118,10 +118,20 @@ The corpus median lands at **4.0 (B)**: a well-run real codebase earns a B, and
|
|
|
118
118
|
|
|
119
119
|
### The reference corpus
|
|
120
120
|
|
|
121
|
-
Calibration is reproducible, not a snapshot someone took once. The corpus is defined in [`tools/calibration/corpus.json`](../tools/calibration/corpus.json) —
|
|
121
|
+
Calibration is reproducible, not a snapshot someone took once. The corpus is defined in [`tools/calibration/corpus.json`](../tools/calibration/corpus.json) — **180 mature open-source repositories pinned to exact commits**, spanning 24 to 18,789 source files and 2,749,575 declarations across thirteen languages: Python, TypeScript, JavaScript, Java, C, C++, C#, Fortran, Swift, Go, Rust, PHP and Ruby.
|
|
122
|
+
|
|
123
|
+
The forty repositories 1.x calibrated on are all still in it, at the commits they were measured at then:
|
|
122
124
|
|
|
123
125
|
> angular · ansible · ant-design · anime · axios · Chart.js · code-server · django · echarts · excalidraw · express · fastapi · flask · freeCodeCamp · github-readme-stats · hackingtool · hoppscotch · jquery · keras · localstack · lodash · manim · material-ui · mermaid · models · n8n · nest · playwright · reveal.js · scrapy · strapi · svelte · tabby · tailwindcss · transformers · uBlock · vite · webpack · youtube-dl · yt-dlp
|
|
124
126
|
|
|
127
|
+
**This paragraph opened "40 mature open-source repositories … across
|
|
128
|
+
Python, TypeScript and JavaScript" for two releases after 3.0.0 measured
|
|
129
|
+
180 across thirteen (D143).** The corrected numbers were four paragraphs
|
|
130
|
+
below it the whole time, so a reader met both and had nothing to tell
|
|
131
|
+
them which was current. Same defect as the unanchored caveat below and
|
|
132
|
+
found in the same pass: a count written into prose, with nothing that
|
|
133
|
+
fails when the thing it counts moves.
|
|
134
|
+
|
|
125
135
|
**What the anchor does not cover.** For five releases this section named a
|
|
126
136
|
real defect: the corpus was 40 repositories of Python, TypeScript and
|
|
127
137
|
JavaScript while the scanner parsed eight languages, so Java, C, C++, C#
|
|
@@ -131,23 +141,34 @@ median and fortran-lang/stdlib at **1.10x** — the first a true statement
|
|
|
131
141
|
about LAPACK relative to mature OSS *web* code, and not a statement about
|
|
132
142
|
typical Fortran, because no typical Fortran was in the comparison set.
|
|
133
143
|
|
|
134
|
-
**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
pinned to the commits they were measured at, so
|
|
138
|
-
is the languages added and nothing else.
|
|
139
|
-
|
|
140
|
-
**
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
144
|
+
**3.0.0 extended the corpus.** It is now **180 repositories spanning
|
|
145
|
+
thirteen languages**: Python, TypeScript, JavaScript, Java, C, C++, C#,
|
|
146
|
+
Fortran, Swift, Go, Rust, PHP and Ruby. The 112 rows measured for 2.0.0
|
|
147
|
+
are unchanged and still pinned to the commits they were measured at, so
|
|
148
|
+
what moved the constants is the languages added and nothing else.
|
|
149
|
+
|
|
150
|
+
**One parsed language is not in it: COBOL.** It is **unanchored** — a
|
|
151
|
+
scanner reads it, and the medians its rates are compared against were
|
|
152
|
+
measured on other languages. The cost is disclosed rather than absorbed:
|
|
153
|
+
findings in COBOL are as good as their parser, a COBOL grade is
|
|
154
|
+
provisional, and every surface that prints a grade says so.
|
|
155
|
+
|
|
156
|
+
COBOL is unanchored **permanently**, not pending a re-measure. Against
|
|
157
|
+
the corpus criteria GitHub holds one COBOL repository above 500 stars,
|
|
158
|
+
and what is public is curriculum, Java parsers and JavaScript wrappers
|
|
159
|
+
rather than COBOL codebases; the language's real corpus is on private
|
|
160
|
+
mainframes. Anchoring it on what exists would build a reference out of
|
|
161
|
+
teaching material — an anchor that *looks* like one, which is worse than
|
|
162
|
+
the disclosed absence.
|
|
163
|
+
|
|
164
|
+
Two corrections are recorded here rather than quietly applied, because
|
|
165
|
+
both were live for multiple releases. This sentence read "every language
|
|
166
|
+
this scanner parses" for three releases after that stopped being true.
|
|
167
|
+
It then named **six** unanchored languages for two releases after 3.0.0
|
|
168
|
+
anchored five of them (D143) — Swift, Go, Rust, PHP and Ruby readers were
|
|
169
|
+
told their grade was provisional against a corpus that had measured their
|
|
170
|
+
language. A caveat naming an anchored language is not a caution; it is a
|
|
171
|
+
false statement about the evidence.
|
|
151
172
|
|
|
152
173
|
Three limits remain, and they are narrower than the one they replace:
|
|
153
174
|
|
{maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_banner.py
RENAMED
|
@@ -17,9 +17,12 @@ one-way.
|
|
|
17
17
|
"""
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import os
|
|
20
21
|
import re
|
|
21
22
|
from pathlib import Path
|
|
22
23
|
|
|
24
|
+
from ._operator_reads import open_regular_file
|
|
25
|
+
|
|
23
26
|
# Whatever a language uses to open a comment, plus decoration a generator
|
|
24
27
|
# may pad the line with: `#`, `//`, `*`, `/*`, `!`, `--`, `<!--`, `;`, and
|
|
25
28
|
# the emoji rules some tools draw. `@` is spared, or `# @generated` would
|
|
@@ -40,12 +43,29 @@ BANNER_LINES = 20
|
|
|
40
43
|
def banner_says_generated(
|
|
41
44
|
path: Path, banners: tuple[str, ...]
|
|
42
45
|
) -> str | None:
|
|
43
|
-
"""The banner text, if the head of this file carries one.
|
|
46
|
+
"""The banner text, if the head of this file carries one.
|
|
47
|
+
|
|
48
|
+
The head only, so this stays cheap on a large tree — but read
|
|
49
|
+
*through* a checked handle rather than by name, so a FIFO refuses
|
|
50
|
+
instead of stopping the audit dead (D145). `path.open()` on one waits
|
|
51
|
+
for a writer that never comes, and the previous `except OSError`
|
|
52
|
+
could not have caught that: there is no error to catch, only a
|
|
53
|
+
process that never returns.
|
|
54
|
+
"""
|
|
44
55
|
try:
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
handle = open_regular_file(
|
|
57
|
+
path,
|
|
58
|
+
"Banner detection reads the head of a discovered file; a "
|
|
59
|
+
"device, socket or FIFO would block the audit rather than "
|
|
60
|
+
"declare itself generated.",
|
|
61
|
+
)
|
|
47
62
|
except OSError:
|
|
48
63
|
return None
|
|
64
|
+
try:
|
|
65
|
+
with os.fdopen(handle, "r", encoding="utf-8", errors="replace", closefd=False) as opened:
|
|
66
|
+
head = "".join(next(opened, "") for _ in range(BANNER_LINES)).lower()
|
|
67
|
+
finally:
|
|
68
|
+
os.close(handle)
|
|
49
69
|
previous: str | None = None
|
|
50
70
|
for raw in head.splitlines():
|
|
51
71
|
stripped = COMMENT_LEAD.sub("", raw).strip()
|
{maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_catalog.py
RENAMED
|
@@ -190,7 +190,23 @@ def decide(tool: dict[str, Any], settings: dict[str, Any]) -> Selection:
|
|
|
190
190
|
3. the depth, licence and concern tiers.
|
|
191
191
|
"""
|
|
192
192
|
slug = tool["slug"]
|
|
193
|
+
return (
|
|
194
|
+
_denial(tool, settings)
|
|
195
|
+
or (Selection(slug, True, "explicitly allowed by name")
|
|
196
|
+
if slug in settings["allow_tools"] else None)
|
|
197
|
+
or _tier_decision(tool, settings)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _denial(tool: dict[str, Any], settings: dict[str, Any]) -> Selection | None:
|
|
202
|
+
"""Step 1: every deny, which beats even an explicit allow.
|
|
193
203
|
|
|
204
|
+
`None` means nothing here refused the tool, not that it was admitted —
|
|
205
|
+
the caller has two more steps. Separate from the tiers because these
|
|
206
|
+
are the operator's own prohibitions and the tiers are policy: a deny
|
|
207
|
+
that could be overridden by an allow would not be a deny.
|
|
208
|
+
"""
|
|
209
|
+
slug = tool["slug"]
|
|
194
210
|
if slug in settings["deny_tools"]:
|
|
195
211
|
return Selection(slug, False, "denied by name")
|
|
196
212
|
if tool["license_class"] in settings["deny_license_classes"]:
|
|
@@ -198,10 +214,14 @@ def decide(tool: dict[str, Any], settings: dict[str, Any]) -> Selection:
|
|
|
198
214
|
denied_concerns = set(tool["upstream_tags"]) & set(settings["deny_concerns"])
|
|
199
215
|
if denied_concerns:
|
|
200
216
|
return Selection(slug, False, f"concern {','.join(sorted(denied_concerns))} denied")
|
|
217
|
+
return None
|
|
201
218
|
|
|
202
|
-
if slug in settings["allow_tools"]:
|
|
203
|
-
return Selection(slug, True, "explicitly allowed by name")
|
|
204
219
|
|
|
220
|
+
def _tier_decision(tool: dict[str, Any], settings: dict[str, Any]) -> Selection:
|
|
221
|
+
"""Step 3: the depth, licence and concern tiers, for a tool no deny
|
|
222
|
+
caught and no allow admitted. The only step that can end in `True`
|
|
223
|
+
on the tool's own merits."""
|
|
224
|
+
slug = tool["slug"]
|
|
205
225
|
if tool["deprecated"]:
|
|
206
226
|
return Selection(slug, False, "deprecated upstream")
|
|
207
227
|
if not tool["languages"]:
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Reading a delegated pillar's own report of itself.
|
|
2
|
+
|
|
3
|
+
[ADR 007](adr-007-pillars-and-practice.md) makes the five pillars of the
|
|
4
|
+
source framework the top-level taxonomy and declares **Security
|
|
5
|
+
delegated to `secure-code-agent`**, reported as `NotApplicable` so that
|
|
6
|
+
silence is never read as safety. That entry was always a placeholder for
|
|
7
|
+
an artifact that did not exist yet: the other tool measures the pillar,
|
|
8
|
+
so the other tool has to be the one that reports it.
|
|
9
|
+
|
|
10
|
+
`secure-code-agent` 0.5.0 ships the emitter — `--security-pillar <path>`
|
|
11
|
+
writes `security-pillar.json`, schema `secure-code-agent/security-pillar`
|
|
12
|
+
— and it was built against *this* vocabulary rather than its own. The
|
|
13
|
+
scope words, the two-axis split and the posture matrix with its
|
|
14
|
+
thresholds all come from `_pillars.py`, because two tools saying "level
|
|
15
|
+
3" or "healthy" about one repository have to mean the same thing by it
|
|
16
|
+
or the joined view is worse than either alone.
|
|
17
|
+
|
|
18
|
+
This module reads the document and checks it is the one expected. The
|
|
19
|
+
*shaping* of the pillar entry lives in `_pillars` beside the entries it
|
|
20
|
+
sits among — scoring may not import a scanner, and reading a path the
|
|
21
|
+
audited tree chooses is what makes this one. Neither half computes a
|
|
22
|
+
number: a delegated pillar's numbers belong to the tool that measured
|
|
23
|
+
them, and a consumer that recomputed anything would be a second opinion
|
|
24
|
+
nobody asked for.
|
|
25
|
+
|
|
26
|
+
**Absence is the normal case and stays the documented one.** No file
|
|
27
|
+
means the pillar reports exactly what it reported before — delegated,
|
|
28
|
+
`NotApplicable`, naming the other tool. That path is not a failure and
|
|
29
|
+
does not warn: most repositories run one tool.
|
|
30
|
+
|
|
31
|
+
**A file that cannot be trusted is refused rather than partly believed.**
|
|
32
|
+
Wrong schema, unreadable JSON, a shape that is not an object — each
|
|
33
|
+
returns `None`, and the pillar falls back to the honest placeholder. The
|
|
34
|
+
alternative is a security posture assembled from a document this tool
|
|
35
|
+
does not actually understand, which is worse than no posture at all.
|
|
36
|
+
|
|
37
|
+
A trailing note on where this sits: it reads a path from the audited
|
|
38
|
+
tree, so it is a scanner rather than part of the rubric.
|
|
39
|
+
`test_scoring_never_imports_scanners_or_assembly` holds that boundary,
|
|
40
|
+
and `report` is what joins the two.
|
|
41
|
+
"""
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
import json
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
from typing import Any
|
|
47
|
+
|
|
48
|
+
from ._operator_reads import PathNotAllowed, read_source_file
|
|
49
|
+
|
|
50
|
+
#: Written beside the other artifacts a repository keeps about itself.
|
|
51
|
+
#: The path is a convention rather than a search: a document this tool
|
|
52
|
+
#: trusts for a whole pillar should be somewhere a reader can find, not
|
|
53
|
+
#: wherever a glob happened to match.
|
|
54
|
+
DEFAULT_PILLAR_PATH = ".maintainability/security-pillar.json"
|
|
55
|
+
|
|
56
|
+
#: The contract this module understands. A document announcing anything
|
|
57
|
+
#: else is refused rather than read hopefully — the schema string is the
|
|
58
|
+
#: producer's promise about the shape, and guessing past it is how a
|
|
59
|
+
#: consumer starts reporting fields that mean something different.
|
|
60
|
+
SCHEMA = "secure-code-agent/security-pillar"
|
|
61
|
+
SCHEMA_VERSION = 1
|
|
62
|
+
|
|
63
|
+
#: What the pillar block takes from the document. Named rather than
|
|
64
|
+
#: copied wholesale so a field added upstream cannot silently appear in
|
|
65
|
+
#: this tool's report carrying meaning nobody here has checked.
|
|
66
|
+
CARRIED = (
|
|
67
|
+
"practice",
|
|
68
|
+
"condition",
|
|
69
|
+
"condition_letter",
|
|
70
|
+
"posture",
|
|
71
|
+
"verified_grade",
|
|
72
|
+
"evidence_status",
|
|
73
|
+
"evidence_reasons",
|
|
74
|
+
"coverage",
|
|
75
|
+
"findings_by_severity",
|
|
76
|
+
"reported_not_scored",
|
|
77
|
+
"loc_scanned",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def read_delegated(root: Path, relative: str = DEFAULT_PILLAR_PATH) -> dict[str, Any] | None:
|
|
82
|
+
"""The delegated pillar's own report, or `None` when there is none.
|
|
83
|
+
|
|
84
|
+
`None` for every reason a reader might not get a usable document:
|
|
85
|
+
the file is absent, it is not a regular file, it does not parse, it
|
|
86
|
+
is not an object, or it announces a schema this tool does not know.
|
|
87
|
+
All five collapse to one answer because the caller does the same
|
|
88
|
+
thing with each — keep the placeholder that names the other tool.
|
|
89
|
+
|
|
90
|
+
Read through the regular-file primitive like every other path the
|
|
91
|
+
audited tree chooses (D145): a FIFO here would hang the audit rather
|
|
92
|
+
than fail it.
|
|
93
|
+
"""
|
|
94
|
+
path = Path(root) / relative
|
|
95
|
+
if not path.exists():
|
|
96
|
+
return None
|
|
97
|
+
try:
|
|
98
|
+
payload = json.loads("\n".join(read_source_file(path)))
|
|
99
|
+
except (OSError, ValueError) as error:
|
|
100
|
+
if isinstance(error, PathNotAllowed):
|
|
101
|
+
raise
|
|
102
|
+
return None
|
|
103
|
+
if not isinstance(payload, dict):
|
|
104
|
+
return None
|
|
105
|
+
if payload.get("schema") != SCHEMA:
|
|
106
|
+
return None
|
|
107
|
+
if payload.get("schema_version") != SCHEMA_VERSION:
|
|
108
|
+
return None
|
|
109
|
+
return payload if _is_well_formed(payload) else None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
#: Fields whose *shape* the consumer depends on. A header check alone
|
|
113
|
+
#: accepts any object announcing the right schema, and the pillar then
|
|
114
|
+
#: reads these as if the producer had promised them.
|
|
115
|
+
_SHAPES: tuple[tuple[str, type | tuple[type, ...]], ...] = (
|
|
116
|
+
("producer", dict),
|
|
117
|
+
("practice", dict),
|
|
118
|
+
("condition", (int, float, type(None))),
|
|
119
|
+
("posture", (str, type(None))),
|
|
120
|
+
("evidence_status", (str, type(None))),
|
|
121
|
+
("coverage", (dict, type(None))),
|
|
122
|
+
("findings_by_severity", (dict, type(None))),
|
|
123
|
+
("reported_not_scored", (dict, type(None))),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
#: The postures this tool knows how to render. A document naming one it
|
|
127
|
+
#: does not is refused rather than printed through: the word is the
|
|
128
|
+
#: reader's whole summary of the pillar.
|
|
129
|
+
_POSTURES = frozenset({"healthy", "managed debt", "unmanaged debt", "unverified"})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _is_well_formed(payload: dict[str, Any]) -> bool:
|
|
133
|
+
"""Whether the document's fields are the shapes the pillar reads.
|
|
134
|
+
|
|
135
|
+
The header said what the document *claims to be*; this asks whether
|
|
136
|
+
it is. Checking only `schema` accepted
|
|
137
|
+
`{"producer": "not-an-object", ...}`, which the pillar then indexed
|
|
138
|
+
as a mapping and crashed on — a well-formed announcement with a
|
|
139
|
+
malformed body, which is the shape a header check cannot see.
|
|
140
|
+
|
|
141
|
+
Also refused: a `posture` this tool cannot render, and a `posture`
|
|
142
|
+
the document's own two axes do not support. The second is the one
|
|
143
|
+
worth stating. `healthy` requires practice at or above
|
|
144
|
+
`HIGH_PRACTICE` and a condition at or above `GOOD_CONDITION`; a
|
|
145
|
+
document claiming `healthy` at practice 1 is either a different
|
|
146
|
+
matrix or a mistake, and either way this tool must not print it.
|
|
147
|
+
Both tools are supposed to mean the same thing by the word — the
|
|
148
|
+
consumer is where that is checkable.
|
|
149
|
+
"""
|
|
150
|
+
for name, kinds in _SHAPES:
|
|
151
|
+
if name in payload and not isinstance(payload[name], kinds):
|
|
152
|
+
return False
|
|
153
|
+
practice = payload.get("practice")
|
|
154
|
+
if isinstance(practice, dict) and not isinstance(practice.get("level"), int):
|
|
155
|
+
return False
|
|
156
|
+
posture = payload.get("posture")
|
|
157
|
+
if posture is not None and posture not in _POSTURES:
|
|
158
|
+
return False
|
|
159
|
+
return _posture_agrees(payload)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _posture_agrees(payload: dict[str, Any]) -> bool:
|
|
163
|
+
"""Whether the stated posture follows from the two axes given.
|
|
164
|
+
|
|
165
|
+
Recomputed rather than trusted. The matrix and its thresholds are
|
|
166
|
+
`_pillars.py`'s, copied into the producer by value, and a copied
|
|
167
|
+
constant is a constant that can drift — so the one place the two
|
|
168
|
+
can be compared is here, against a document carrying both inputs
|
|
169
|
+
and the answer.
|
|
170
|
+
"""
|
|
171
|
+
from ._pillars import posture as compute
|
|
172
|
+
|
|
173
|
+
stated = payload.get("posture")
|
|
174
|
+
practice = payload.get("practice")
|
|
175
|
+
if stated is None or not isinstance(practice, dict):
|
|
176
|
+
return True
|
|
177
|
+
level = practice.get("level")
|
|
178
|
+
condition = payload.get("condition")
|
|
179
|
+
if not isinstance(level, int):
|
|
180
|
+
return False
|
|
181
|
+
return compute(level, condition) == stated
|
{maintainability_agent-3.0.2 → maintainability_agent-3.2.0}/src/maintainability_audit/_derive.py
RENAMED
|
@@ -17,9 +17,10 @@ from statistics import median
|
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
19
|
from ._aspects import evidence_aspect_scores, is_untested
|
|
20
|
+
from ._evidence_reader import normalize_report_evidence
|
|
20
21
|
from ._formula import CALIBRATED_ASPECTS, curve, overall_from_aspects
|
|
21
22
|
from ._pressures import production_pressures
|
|
22
|
-
from .evidence import REPORT_SCHEMA_VERSION, SCHEMA_VERSION_KEY
|
|
23
|
+
from .evidence import REPORT_SCHEMA_VERSION, SCHEMA_VERSION_KEY
|
|
23
24
|
|
|
24
25
|
# The stored column holding the analyzers' production reading. Named
|
|
25
26
|
# once because both the refusal and the mix key on it.
|