maintainability-agent 3.1.0__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.1.0/src/maintainability_agent.egg-info → maintainability_agent-3.2.0}/PKG-INFO +2 -2
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/README.md +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/pyproject.toml +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/SOURCES.txt +10 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/__init__.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_anchor.py +6 -3
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_derive.py +2 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_discovery.py +70 -26
- maintainability_agent-3.2.0/src/maintainability_audit/_evidence_reader.py +305 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_evidence_view.py +11 -4
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_grant_ledger.py +0 -8
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_history_view.py +85 -24
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_html_report_sections.py +78 -31
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_html_view.py +5 -3
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_in_loop_view.py +32 -15
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_metric_adapters.py +14 -127
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_pillars.py +77 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_practice.py +46 -24
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_pressures.py +61 -70
- maintainability_agent-3.1.0/src/maintainability_audit/prompts.py → maintainability_agent-3.2.0/src/maintainability_audit/_prompt_sections.py +40 -114
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_core.py +44 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_fortran.py +29 -11
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_php.py +2 -28
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_scan_history.py +36 -4
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_policy.py +18 -8
- maintainability_agent-3.2.0/src/maintainability_audit/_test_pairing.py +291 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_trends.py +1 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_verdict_adapters.py +50 -36
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order.py +39 -27
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/config.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/evidence.py +1 -227
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/idioms.py +22 -6
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/metrics.py +17 -9
- maintainability_agent-3.2.0/src/maintainability_audit/prompts.py +128 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/report.py +25 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/scoring.py +2 -5
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_primary_estimate.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_scoring_path.py +3 -3
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_spread_range.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_anchor_disclosure.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_band_concealment_p3.py +2 -1
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/tests/test_evidence_invariants.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_evidence_normalization.py +1 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_evidence_properties.py +1 -1
- {maintainability_agent-3.1.0 → 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.1.0 → 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.1.0 → maintainability_agent-3.2.0}/tests/test_release_plan_status.py +8 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_scan_scope.py +2 -6
- {maintainability_agent-3.1.0 → 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.1.0 → maintainability_agent-3.2.0}/tests/test_trends.py +14 -1
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_unanchored_set_matches_corpus.py +7 -2
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_verified_grade.py +1 -1
- maintainability_agent-3.1.0/src/maintainability_audit/_selection.py +0 -136
- maintainability_agent-3.1.0/src/maintainability_audit/_test_pairing.py +0 -149
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/LICENSE +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/setup.cfg +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_analyzer_sections.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_arguments.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_assets/standard.md +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_banner.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_criteria_scope.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_in_loop.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_operator_reads.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit_install.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_precommit_view.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_cobol.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_go.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_ruby.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ranges_swift.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_run_comparison.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_test_commands.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_adapters.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_added_lines.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_anchor_and_mode.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_architecture.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_attestation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_audit_components.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_backfill.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_bands.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_check_refuses_plus_only_fragments.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_cli.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_cobol_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_config_shape.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_corroborate.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_criteria_completion.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_dead_code.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declaration_criteria_scope.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_determinism.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_discovery.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_docs_links.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_economic_context.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_format_ask.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_git_argv.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_go_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_grammar_constructs.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_grammar_token_coverage.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_history.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_html_executive.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_in_loop_budgets.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_in_loop_check.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_java_scored.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_language_support_honesty.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_operator_named_paths.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_operator_named_reads.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_php_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_policy_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_precommit_staged.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_promises.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_python_complexity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_recurrence.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_release_plan.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_root_grants.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_ruby_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_run_comparison.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_runner.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_rust_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_sarif.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_scan_history.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_scanner_unsafe_direction.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_scanning.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_skill_install.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_sonar_resolve.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_source_index.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_suite_isolation.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_swift_declarations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_test_commands.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_tool_resolution.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_tree_chosen_spawn.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_tree_reads_use_the_primitive.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_unread_code.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_version_claim.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_work_order.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-3.1.0 → 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
@@ -212,8 +217,10 @@ tests/test_declaration_edge_cases.py
|
|
|
212
217
|
tests/test_declaration_grading.py
|
|
213
218
|
tests/test_declaration_ranges.py
|
|
214
219
|
tests/test_declaration_source.py
|
|
220
|
+
tests/test_declarative_parsers.py
|
|
215
221
|
tests/test_declared_authorship.py
|
|
216
222
|
tests/test_declared_imports.py
|
|
223
|
+
tests/test_delegated_security_pillar.py
|
|
217
224
|
tests/test_derivation_mix.py
|
|
218
225
|
tests/test_determinism.py
|
|
219
226
|
tests/test_dimension_ratchet.py
|
|
@@ -280,6 +287,7 @@ tests/test_network_disclosure.py
|
|
|
280
287
|
tests/test_one_setup_across_surfaces_class.py
|
|
281
288
|
tests/test_operator_named_paths.py
|
|
282
289
|
tests/test_operator_named_reads.py
|
|
290
|
+
tests/test_pairing_reads_imports.py
|
|
283
291
|
tests/test_pattern_budget.py
|
|
284
292
|
tests/test_phase6_claims.py
|
|
285
293
|
tests/test_php_declarations.py
|
|
@@ -303,6 +311,7 @@ tests/test_python_declarations.py
|
|
|
303
311
|
tests/test_read_boundary.py
|
|
304
312
|
tests/test_readme_claims.py
|
|
305
313
|
tests/test_recurrence.py
|
|
314
|
+
tests/test_release_needs_an_empty_ledger.py
|
|
306
315
|
tests/test_release_plan.py
|
|
307
316
|
tests/test_release_plan_status.py
|
|
308
317
|
tests/test_report_remedy_copy.py
|
|
@@ -334,6 +343,7 @@ tests/test_stage8_contract.py
|
|
|
334
343
|
tests/test_suite_isolation.py
|
|
335
344
|
tests/test_swift_declarations.py
|
|
336
345
|
tests/test_tdd_structure.py
|
|
346
|
+
tests/test_terminal_asks_the_same_questions.py
|
|
337
347
|
tests/test_test_commands.py
|
|
338
348
|
tests/test_test_execution_class.py
|
|
339
349
|
tests/test_three_presentations.py
|
{maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_anchor.py
RENAMED
|
@@ -63,8 +63,11 @@ def unanchored_sentence() -> str:
|
|
|
63
63
|
"""One sentence naming what the anchor omits, for the corpus note."""
|
|
64
64
|
if not UNANCHORED_LANGUAGES:
|
|
65
65
|
return ""
|
|
66
|
+
from ._grammar import agreement
|
|
67
|
+
|
|
68
|
+
say = agreement(len(UNANCHORED_LANGUAGES))
|
|
66
69
|
return (
|
|
67
|
-
f"{unanchored_names()}
|
|
68
|
-
"findings are as good as
|
|
69
|
-
"provisional."
|
|
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."
|
|
70
73
|
)
|
{maintainability_agent-3.1.0 → 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.1.0 → 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.
|
{maintainability_agent-3.1.0 → maintainability_agent-3.2.0}/src/maintainability_audit/_discovery.py
RENAMED
|
@@ -35,6 +35,7 @@ from __future__ import annotations
|
|
|
35
35
|
|
|
36
36
|
import json
|
|
37
37
|
import re
|
|
38
|
+
from collections.abc import Iterator
|
|
38
39
|
from dataclasses import dataclass, field
|
|
39
40
|
from enum import StrEnum
|
|
40
41
|
from pathlib import Path
|
|
@@ -228,25 +229,8 @@ def _generated_directories(root: Path, excludes: tuple[str, ...]) -> dict[str, s
|
|
|
228
229
|
relative = manifest.relative_to(root).as_posix()
|
|
229
230
|
if is_excluded(relative, list(excludes)):
|
|
230
231
|
continue
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
except PathNotAllowed:
|
|
234
|
-
# `PathNotAllowed` is a `ValueError`, so it would otherwise be
|
|
235
|
-
# swallowed by the clause below and the manifest would read as
|
|
236
|
-
# a malformed one rather than a refused one (D145). A FIFO
|
|
237
|
-
# named `package.json` is not bad JSON; it is a path this tool
|
|
238
|
-
# will not read, and saying so is the whole point of routing
|
|
239
|
-
# the read through the primitive.
|
|
240
|
-
raise
|
|
241
|
-
except (OSError, ValueError, AttributeError):
|
|
242
|
-
continue
|
|
243
|
-
if not isinstance(scripts, dict):
|
|
244
|
-
continue
|
|
245
|
-
for name, command in scripts.items():
|
|
246
|
-
for target in DELETES_DIRECTORY.findall(str(command)):
|
|
247
|
-
cleaned = target.strip("./")
|
|
248
|
-
if not cleaned or cleaned.startswith(".."):
|
|
249
|
-
continue
|
|
232
|
+
for name, command in _manifest_scripts(manifest).items():
|
|
233
|
+
for cleaned in _deleted_targets(str(command)):
|
|
250
234
|
directory = (manifest.parent / cleaned).relative_to(root).as_posix()
|
|
251
235
|
found.setdefault(
|
|
252
236
|
directory,
|
|
@@ -256,6 +240,40 @@ def _generated_directories(root: Path, excludes: tuple[str, ...]) -> dict[str, s
|
|
|
256
240
|
return found
|
|
257
241
|
|
|
258
242
|
|
|
243
|
+
def _manifest_scripts(manifest: Path) -> dict[str, Any]:
|
|
244
|
+
"""One `package.json`'s scripts block, or empty if it has none to read.
|
|
245
|
+
|
|
246
|
+
Empty covers unreadable, malformed and shaped-wrong alike, because
|
|
247
|
+
none of the three is a statement about generated directories. A
|
|
248
|
+
refusal is the exception: `PathNotAllowed` is re-raised.
|
|
249
|
+
"""
|
|
250
|
+
try:
|
|
251
|
+
scripts = json.loads(_text_of(manifest)).get("scripts", {})
|
|
252
|
+
except PathNotAllowed:
|
|
253
|
+
# `PathNotAllowed` is a `ValueError`, so it would otherwise be
|
|
254
|
+
# swallowed by the clause below and the manifest would read as
|
|
255
|
+
# a malformed one rather than a refused one (D145). A FIFO
|
|
256
|
+
# named `package.json` is not bad JSON; it is a path this tool
|
|
257
|
+
# will not read, and saying so is the whole point of routing
|
|
258
|
+
# the read through the primitive.
|
|
259
|
+
raise
|
|
260
|
+
except (OSError, ValueError, AttributeError):
|
|
261
|
+
return {}
|
|
262
|
+
return scripts if isinstance(scripts, dict) else {}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _deleted_targets(command: str) -> Iterator[str]:
|
|
266
|
+
"""The directory names one script command deletes, normalized.
|
|
267
|
+
|
|
268
|
+
A target that cleans to nothing, or that climbs out of the manifest's
|
|
269
|
+
own directory, is not a directory this repository generates.
|
|
270
|
+
"""
|
|
271
|
+
for target in DELETES_DIRECTORY.findall(command):
|
|
272
|
+
cleaned = target.strip("./")
|
|
273
|
+
if cleaned and not cleaned.startswith(".."):
|
|
274
|
+
yield cleaned
|
|
275
|
+
|
|
276
|
+
|
|
259
277
|
def _vendored_directories(root: Path) -> dict[str, str]:
|
|
260
278
|
"""Directories the repository says belong to someone else."""
|
|
261
279
|
found: dict[str, str] = {}
|
|
@@ -315,18 +333,44 @@ def _asset_snapshot_directories(root: Path, excludes: tuple[str, ...]) -> dict[s
|
|
|
315
333
|
}
|
|
316
334
|
|
|
317
335
|
|
|
336
|
+
def _sorted_by_kind(
|
|
337
|
+
files: list[Path],
|
|
338
|
+
) -> tuple[list[Path], list[Path], list[str]]:
|
|
339
|
+
"""Markup pages, source files, and the other suffixes present.
|
|
340
|
+
|
|
341
|
+
One pass, three answers. It was three comprehensions re-testing the
|
|
342
|
+
same two memberships, which read as cyclomatic 15 in sixteen lines —
|
|
343
|
+
the joint-highest in the package and one branch from failing the
|
|
344
|
+
gate — for a function whose actual job is "sort these into three
|
|
345
|
+
piles".
|
|
346
|
+
|
|
347
|
+
The two tests deliberately stay independent rather than becoming an
|
|
348
|
+
`elif` chain: `.html` is both a markup suffix and a known source
|
|
349
|
+
suffix, so it belongs in *both* piles, and an `elif` would quietly
|
|
350
|
+
drop it from `code` and change what the ratio below compares.
|
|
351
|
+
"""
|
|
352
|
+
markup: list[Path] = []
|
|
353
|
+
code: list[Path] = []
|
|
354
|
+
other: set[str] = set()
|
|
355
|
+
for found in files:
|
|
356
|
+
lowered = found.suffix.lower()
|
|
357
|
+
is_markup = lowered in _MARKUP_SUFFIXES
|
|
358
|
+
is_code = found.suffix in KNOWN_SOURCE_SUFFIXES
|
|
359
|
+
if is_markup:
|
|
360
|
+
markup.append(found)
|
|
361
|
+
if is_code:
|
|
362
|
+
code.append(found)
|
|
363
|
+
if found.suffix and not is_markup and not is_code:
|
|
364
|
+
other.add(lowered)
|
|
365
|
+
return markup, code, sorted(other)
|
|
366
|
+
|
|
367
|
+
|
|
318
368
|
def _asset_evidence(files: list[Path]) -> str | None:
|
|
319
369
|
"""Why a directory is a saved page asset, or None."""
|
|
320
370
|
versioned = sorted(f.name for f in files if _VERSIONED_SNAPSHOT.search(f.name))
|
|
321
371
|
if versioned:
|
|
322
372
|
return f"versioned page snapshot(s): {', '.join(versioned[:3])}"
|
|
323
|
-
markup
|
|
324
|
-
code = [f for f in files if f.suffix in KNOWN_SOURCE_SUFFIXES]
|
|
325
|
-
siblings = sorted({
|
|
326
|
-
f.suffix.lower() for f in files
|
|
327
|
-
if f.suffix and f.suffix.lower() not in _MARKUP_SUFFIXES
|
|
328
|
-
and f.suffix not in KNOWN_SOURCE_SUFFIXES
|
|
329
|
-
})
|
|
373
|
+
markup, code, siblings = _sorted_by_kind(files)
|
|
330
374
|
if len(markup) >= 2 and len(markup) > len(code) and siblings:
|
|
331
375
|
return (f"{len(markup)} HTML/CSS pages outnumbering source, beside "
|
|
332
376
|
f"non-source assets ({', '.join(siblings[:4])})")
|