maintainability-agent 3.0.0__tar.gz → 3.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {maintainability_agent-3.0.0/src/maintainability_agent.egg-info → maintainability_agent-3.0.2}/PKG-INFO +2 -2
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/README.md +1 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/pyproject.toml +1 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_agent.egg-info/SOURCES.txt +2 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/__init__.py +1 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_in_loop.py +14 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_operator_reads.py +60 -9
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_runner.py +31 -4
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_second_source.py +36 -4
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/config.py +1 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/metrics.py +25 -7
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/source.py +8 -4
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_criteria_completion.py +31 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_in_loop_check.py +38 -0
- maintainability_agent-3.0.2/tests/test_language_support_honesty.py +112 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_operator_named_reads.py +52 -3
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_pool_runs_by_config.py +5 -1
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_source_index.py +17 -8
- maintainability_agent-3.0.2/tests/test_tool_resolution.py +166 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/LICENSE +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/setup.cfg +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_analyzer_sections.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_anchor.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_arguments.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_assets/standard.md +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_banner.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_catalog.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_criteria_scope.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_derive.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_discovery.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_evidence_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_first_run.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_grant_ledger.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_history_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_html_report_sections.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_html_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_in_loop_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_mcp_setup.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_metric_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_pillars.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_practice.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_precommit.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_precommit_install.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_precommit_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_pressures.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_cobol.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_core.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_fortran.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_go.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_php.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_ruby.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_rust.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ranges_swift.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_run_comparison.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_scan_history.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_scan_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_selection.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_semantic_policy.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_test_commands.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_test_pairing.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_trends.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_verdict_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_work_order.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/evidence.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/idioms.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/prompts.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/report.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/scoring.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_added_lines.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_primary_estimate.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_scoring_path.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_spread_range.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_anchor_and_mode.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_anchor_disclosure.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_architecture.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_attestation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_audit_components.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_backfill.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_band_concealment_p3.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_bands.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_cli.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_cobol_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_config_shape.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_consumer_migration.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_corroborate.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_dead_code.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declaration_criteria_scope.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_determinism.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_discovery.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_docs_links.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_economic_context.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_evidence_invariants.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_evidence_normalization.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_evidence_properties.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_format_ask.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_git_argv.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_go_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_grammar_constructs.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_grammar_token_coverage.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_history.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_history_window.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_html_executive.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_in_loop_budgets.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_java_scored.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_operator_named_paths.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_php_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_policy_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_population_floors.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_precommit_staged.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_promises.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_python_complexity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_recurrence.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_release_plan.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_release_plan_status.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_root_grants.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_ruby_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_run_comparison.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_runner.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_rust_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_sarif.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scan_history.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scan_scope.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scanner_unsafe_direction.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scanning.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_scoring_calibration.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_skill_install.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_sonar_resolve.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_suite_isolation.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_swift_declarations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_test_commands.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_tree_chosen_spawn.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_trends.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_unread_code.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_verified_grade.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_version_claim.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_work_order.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_written_record.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2
|
|
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.0.2**.
|
|
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.0.2**.
|
|
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.0.2"
|
|
8
8
|
description = "Maintainability gate and AI remediation prompt generator for CI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# 3.11, not 3.10. `_discovery`, `_pillars` and `_runner` all import
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2
|
|
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.0.2**.
|
|
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
|
|
@@ -269,6 +269,7 @@ tests/test_java_wiring.py
|
|
|
269
269
|
tests/test_js_complexity_operators.py
|
|
270
270
|
tests/test_js_declarations.py
|
|
271
271
|
tests/test_language_coverage.py
|
|
272
|
+
tests/test_language_support_honesty.py
|
|
272
273
|
tests/test_mcp_baseline_payload.py
|
|
273
274
|
tests/test_mcp_history.py
|
|
274
275
|
tests/test_mcp_server.py
|
|
@@ -335,6 +336,7 @@ tests/test_tdd_structure.py
|
|
|
335
336
|
tests/test_test_commands.py
|
|
336
337
|
tests/test_test_execution_class.py
|
|
337
338
|
tests/test_three_presentations.py
|
|
339
|
+
tests/test_tool_resolution.py
|
|
338
340
|
tests/test_tree_chosen_spawn.py
|
|
339
341
|
tests/test_trends.py
|
|
340
342
|
tests/test_type_fields_not_functions_class.py
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_in_loop.py
RENAMED
|
@@ -283,7 +283,20 @@ def _is_unified_diff(text: str) -> bool:
|
|
|
283
283
|
has_old = any(line.startswith("--- ") for line in lines)
|
|
284
284
|
has_new = any(line.startswith("+++ ") for line in lines)
|
|
285
285
|
has_hunk = any(_HUNK_HEADER.match(line) for line in lines)
|
|
286
|
-
|
|
286
|
+
# Either half of the shape is enough, because an agent pastes either
|
|
287
|
+
# half (D138). Requiring all three read a hunk-only fragment — the
|
|
288
|
+
# commonest paste of the two, since a chat window shows the hunk and
|
|
289
|
+
# not the file headers — as file content, and every suffix `--check`
|
|
290
|
+
# claims to parse reported `declarations_read: true` on it. That is
|
|
291
|
+
# absence read as a pass arriving through the same door D133 closed
|
|
292
|
+
# for the complete diff, one fragment shape to the left.
|
|
293
|
+
#
|
|
294
|
+
# The mention-versus-assertion guard is unaffected and is why this
|
|
295
|
+
# can be loosened safely: `_HUNK_HEADER` is anchored with `match`,
|
|
296
|
+
# so a hunk header quoted inside a string — `"paste a hunk like
|
|
297
|
+
# @@ -1,3 +1,4 @@ here"` — is not at the start of its line and does
|
|
298
|
+
# not count. Somebody writing *about* a diff still parses.
|
|
299
|
+
return has_hunk or (has_old and has_new)
|
|
287
300
|
|
|
288
301
|
|
|
289
302
|
def _parses(path: str, text: str) -> bool:
|
|
@@ -30,6 +30,61 @@ class PathNotAllowed(ValueError):
|
|
|
30
30
|
MAX_OPERATOR_FILE_BYTES = 8 * 1024 * 1024
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def open_regular_file(path: Path, why: str) -> int:
|
|
34
|
+
"""Open a path only if it is a regular file, and hand back the handle.
|
|
35
|
+
|
|
36
|
+
The one regular-file control, so there is never a second
|
|
37
|
+
implementation of it to drift. `read_operator_file` reads what an
|
|
38
|
+
operator named; `read_source_file` reads what discovery found. Those
|
|
39
|
+
are different populations with different decoding and different size
|
|
40
|
+
rules, and exactly one thing in common — neither may block on a FIFO
|
|
41
|
+
or drain memory from a device.
|
|
42
|
+
|
|
43
|
+
Splitting it out is D141. The operator-named door was hardened after
|
|
44
|
+
S8707 and the scan door was not, so a FIFO named `src/hang.py` still
|
|
45
|
+
stopped an audit dead: `read_text` on it waits for a writer that
|
|
46
|
+
never comes. Listing the state modules was never going to catch that,
|
|
47
|
+
because a discovered source path is a different population from a
|
|
48
|
+
configured one.
|
|
49
|
+
|
|
50
|
+
`O_NONBLOCK` is what makes the check possible at all — without it the
|
|
51
|
+
open itself blocks before any validation can run — and the handle is
|
|
52
|
+
returned rather than the path, so the caller reads *through what was
|
|
53
|
+
checked*. Re-opening by name would reintroduce the
|
|
54
|
+
time-of-check/time-of-use gap this exists to close.
|
|
55
|
+
"""
|
|
56
|
+
import stat as stat_module
|
|
57
|
+
|
|
58
|
+
handle = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
|
|
59
|
+
if not stat_module.S_ISREG(os.fstat(handle).st_mode):
|
|
60
|
+
os.close(handle)
|
|
61
|
+
raise PathNotAllowed(f"{path} is not a regular file. {why}")
|
|
62
|
+
return handle
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def read_source_file(path: Path) -> list[str]:
|
|
66
|
+
"""Read a discovered source file, tolerating undecodable bytes.
|
|
67
|
+
|
|
68
|
+
Same regular-file guard as `read_operator_file`, deliberately
|
|
69
|
+
different in the two places a scan differs from a configured read:
|
|
70
|
+
it does not cap the size, because a large file in the tree is a
|
|
71
|
+
finding rather than a refusal, and it replaces undecodable bytes
|
|
72
|
+
instead of raising, because a scan must not abort on one file's
|
|
73
|
+
encoding.
|
|
74
|
+
"""
|
|
75
|
+
handle = open_regular_file(
|
|
76
|
+
path,
|
|
77
|
+
"The scan reads files discovery found; a device, socket or FIFO "
|
|
78
|
+
"in the tree would block the audit rather than be measured.",
|
|
79
|
+
)
|
|
80
|
+
try:
|
|
81
|
+
with os.fdopen(handle, "rb", closefd=False) as opened:
|
|
82
|
+
raw = opened.read()
|
|
83
|
+
finally:
|
|
84
|
+
os.close(handle)
|
|
85
|
+
return raw.decode("utf-8", errors="replace").splitlines()
|
|
86
|
+
|
|
87
|
+
|
|
33
88
|
def read_operator_file(path: Path) -> str:
|
|
34
89
|
"""Read a file the operator named, after checking it is one.
|
|
35
90
|
|
|
@@ -67,8 +122,6 @@ def read_operator_file(path: Path) -> str:
|
|
|
67
122
|
ordinary setup. The audited tree's own default path is a different
|
|
68
123
|
question and `discovered_config` already refuses a symlink there.
|
|
69
124
|
"""
|
|
70
|
-
import stat as stat_module
|
|
71
|
-
|
|
72
125
|
# Opened once, then checked and read **through that handle** — the
|
|
73
126
|
# same discipline `_safe_write` uses for writes, and for the same
|
|
74
127
|
# reason. Checking `os.stat(path)` and then calling `path.read_text()`
|
|
@@ -79,15 +132,13 @@ def read_operator_file(path: Path) -> str:
|
|
|
79
132
|
# for reading otherwise blocks until a writer appears, so the process
|
|
80
133
|
# would hang *before* reaching any validation — the very failure this
|
|
81
134
|
# function exists to prevent.
|
|
82
|
-
handle =
|
|
135
|
+
handle = open_regular_file(
|
|
136
|
+
path,
|
|
137
|
+
"This reads configuration and baselines; a device, socket or FIFO "
|
|
138
|
+
"named here would block or exhaust memory rather than parse.",
|
|
139
|
+
)
|
|
83
140
|
try:
|
|
84
141
|
info = os.fstat(handle)
|
|
85
|
-
if not stat_module.S_ISREG(info.st_mode):
|
|
86
|
-
raise PathNotAllowed(
|
|
87
|
-
f"{path} is not a regular file. This reads configuration "
|
|
88
|
-
"and baselines; a device, socket or FIFO named here would "
|
|
89
|
-
"block or exhaust memory rather than parse."
|
|
90
|
-
)
|
|
91
142
|
if info.st_size > MAX_OPERATOR_FILE_BYTES:
|
|
92
143
|
raise PathNotAllowed(
|
|
93
144
|
f"{path} is {info.st_size} bytes, over the "
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/_runner.py
RENAMED
|
@@ -32,8 +32,10 @@ import re
|
|
|
32
32
|
import shutil
|
|
33
33
|
import subprocess
|
|
34
34
|
import sys
|
|
35
|
+
import sysconfig
|
|
35
36
|
import tempfile
|
|
36
37
|
import time
|
|
38
|
+
from contextlib import suppress
|
|
37
39
|
from dataclasses import dataclass, field
|
|
38
40
|
from enum import StrEnum
|
|
39
41
|
from pathlib import Path
|
|
@@ -137,13 +139,38 @@ def locate(executable: str) -> str | None:
|
|
|
137
139
|
`maintainability-audit --analyzers` finds almost nothing and reports
|
|
138
140
|
an honest but useless "not installed" for every one of them.
|
|
139
141
|
"""
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
for directory in _agent_script_dirs():
|
|
143
|
+
candidate = directory / executable
|
|
144
|
+
if candidate.is_file():
|
|
145
|
+
return str(candidate)
|
|
144
146
|
return shutil.which(executable)
|
|
145
147
|
|
|
146
148
|
|
|
149
|
+
def _agent_script_dirs() -> tuple[Path, ...]:
|
|
150
|
+
"""Where this interpreter's console scripts land, in precedence order.
|
|
151
|
+
|
|
152
|
+
Two directories, because `pip install lizard` writes to a different
|
|
153
|
+
one depending on whether the agent lives in a virtualenv. In a venv
|
|
154
|
+
it is the interpreter's own `bin`. On a **system** Python it is the
|
|
155
|
+
per-user scripts directory, because the framework directory is not
|
|
156
|
+
writable and pip falls back to `--user` — on macOS that is
|
|
157
|
+
`~/Library/Python/3.11/bin`, which is not on the default `PATH`.
|
|
158
|
+
|
|
159
|
+
Searching only the first was D142. A user followed the environment
|
|
160
|
+
work order's own instruction, ran `pip install lizard`, and the next
|
|
161
|
+
audit still reported it "not installed or not on PATH" — because it
|
|
162
|
+
was installed exactly where neither this function nor `PATH` looked.
|
|
163
|
+
The whole Python pool went missing that way on the MCP surface, so
|
|
164
|
+
`declarations` fell to the built-in tier while the report's own
|
|
165
|
+
remedy could not fix it.
|
|
166
|
+
"""
|
|
167
|
+
directories = [Path(sys.executable).parent]
|
|
168
|
+
with suppress(Exception):
|
|
169
|
+
scheme = sysconfig.get_preferred_scheme("user")
|
|
170
|
+
directories.append(Path(sysconfig.get_path("scripts", scheme=scheme)))
|
|
171
|
+
return tuple(directories)
|
|
172
|
+
|
|
173
|
+
|
|
147
174
|
# Variables that make an interpreter or a linter load code from
|
|
148
175
|
# somewhere the operator did not choose. `PYTHONPATH` and `NODE_PATH`
|
|
149
176
|
# put a directory on an import path; `PYTHONSTARTUP` names a file
|
|
@@ -37,10 +37,42 @@ def analyzer_scored(external: ExternalPressures | None) -> list[str]:
|
|
|
37
37
|
"""
|
|
38
38
|
if external is None:
|
|
39
39
|
return []
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
filled = _completed_from_the_built_in_tier(external)
|
|
41
|
+
return sorted(
|
|
42
|
+
f"{name} (completed by built-in detectors)" if name in filled else name
|
|
43
|
+
for name in {
|
|
44
|
+
name for population in (external.all_code, external.production)
|
|
45
|
+
for name, value in population.items() if value is not None
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _completed_from_the_built_in_tier(external: ExternalPressures) -> set[str]:
|
|
51
|
+
"""Dimensions whose criterion set the analyzers did not cover alone.
|
|
52
|
+
|
|
53
|
+
A published rate that mixes two counting conventions must say so
|
|
54
|
+
(D140). `declarations` is scored on cyclomatic complexity, declaration
|
|
55
|
+
lines and cognitive complexity, and no analyzer in the pool supplies
|
|
56
|
+
all three for any language but Python — `lizard` reports no cognitive
|
|
57
|
+
complexity at all — so on thirteen of the fourteen parsed languages
|
|
58
|
+
the built-in scanner fills that criterion per declaration.
|
|
59
|
+
|
|
60
|
+
Naming it is ADR 006 working rather than an exception to it: the
|
|
61
|
+
analyzer tier stays primary for what it measures, and the label stops
|
|
62
|
+
crediting `lizard` for the scanner's reading. Derived from the raw
|
|
63
|
+
measurements the pressures were reduced from, so it cannot disagree
|
|
64
|
+
with what was actually published.
|
|
65
|
+
"""
|
|
66
|
+
from ._criteria_scope import _languages_missing_a_criterion, _unit_languages
|
|
67
|
+
from ._pressures import _units_by_concept
|
|
68
|
+
|
|
69
|
+
if not external.measurements:
|
|
70
|
+
return set()
|
|
71
|
+
measurements = list(external.measurements)
|
|
72
|
+
per_unit = _units_by_concept(measurements, production_only=False)
|
|
73
|
+
if not _languages_missing_a_criterion(per_unit, _unit_languages(measurements)):
|
|
74
|
+
return set()
|
|
75
|
+
return {"declarations"}
|
|
44
76
|
|
|
45
77
|
|
|
46
78
|
def widen_for_disagreement(
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/config.py
RENAMED
|
@@ -20,7 +20,7 @@ from ._operator_reads import (
|
|
|
20
20
|
# still the door every caller comes through.
|
|
21
21
|
__all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
|
|
22
22
|
|
|
23
|
-
VERSION = "3.0.
|
|
23
|
+
VERSION = "3.0.2"
|
|
24
24
|
|
|
25
25
|
PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
|
|
26
26
|
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/metrics.py
RENAMED
|
@@ -22,6 +22,7 @@ from ._metrics_types import KNOWN_SOURCE_SUFFIXES, FileMetric, FunctionMetric
|
|
|
22
22
|
# Re-exported because `metrics.is_test_path` is the import path a dozen
|
|
23
23
|
# callers already use, and the move is not their business.
|
|
24
24
|
from ._metrics_types import is_test_path as is_test_path
|
|
25
|
+
from ._operator_reads import PathNotAllowed, read_source_file
|
|
25
26
|
from .declarations import DECLARATION_SUFFIXES, detect_functions
|
|
26
27
|
from .source import SourceIndex, index_or_new
|
|
27
28
|
|
|
@@ -66,7 +67,7 @@ def iter_files(root: Path, config: dict[str, Any], only_paths: set[str] | None =
|
|
|
66
67
|
resolved_root = root.resolve()
|
|
67
68
|
out: list[Path] = []
|
|
68
69
|
for path in root.rglob("*"):
|
|
69
|
-
if
|
|
70
|
+
if path.is_dir():
|
|
70
71
|
continue
|
|
71
72
|
if not within(resolved_root, path):
|
|
72
73
|
continue
|
|
@@ -75,8 +76,28 @@ def iter_files(root: Path, config: dict[str, Any], only_paths: set[str] | None =
|
|
|
75
76
|
continue
|
|
76
77
|
if only_paths is not None and rel not in only_paths:
|
|
77
78
|
continue
|
|
78
|
-
if path.suffix in include_ext:
|
|
79
|
-
|
|
79
|
+
if path.suffix not in include_ext:
|
|
80
|
+
continue
|
|
81
|
+
if not path.is_file():
|
|
82
|
+
# Refused, not skipped (D141). The walk tested `is_file()`
|
|
83
|
+
# first, which is False for a FIFO, so a path named
|
|
84
|
+
# `src/hang.py` left the audit silently one file short — and
|
|
85
|
+
# a scan that quietly measures less than it was asked to is
|
|
86
|
+
# the absence-read-as-a-pass this project keeps finding.
|
|
87
|
+
#
|
|
88
|
+
# Skipping and blocking are the two ways this can go wrong
|
|
89
|
+
# and they are both wrong: the read primitive below refuses a
|
|
90
|
+
# FIFO rather than waiting on it, and this refuses it rather
|
|
91
|
+
# than pretending the file was not there. Directories are
|
|
92
|
+
# excluded above, and a symlink leaving the tree is dropped
|
|
93
|
+
# by `within`, so what reaches here is a path that claims to
|
|
94
|
+
# be source and is not a file.
|
|
95
|
+
raise PathNotAllowed(
|
|
96
|
+
f"{path} has a source extension but is not a regular file. "
|
|
97
|
+
"A device, socket or FIFO in the tree cannot be measured, "
|
|
98
|
+
"and omitting it would under-report the scan."
|
|
99
|
+
)
|
|
100
|
+
out.append(path)
|
|
80
101
|
return sorted(out)
|
|
81
102
|
|
|
82
103
|
|
|
@@ -160,10 +181,7 @@ def read_lines(path: Path) -> list[str]:
|
|
|
160
181
|
served from ``SourceIndex`` instead, so a file is not read once per
|
|
161
182
|
scanner — see ``source``.
|
|
162
183
|
"""
|
|
163
|
-
|
|
164
|
-
return path.read_text(encoding="utf-8").splitlines()
|
|
165
|
-
except UnicodeDecodeError:
|
|
166
|
-
return path.read_text(encoding="utf-8", errors="replace").splitlines()
|
|
184
|
+
return read_source_file(path)
|
|
167
185
|
|
|
168
186
|
|
|
169
187
|
def file_status(lines: int, thresholds: dict[str, int]) -> str:
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/src/maintainability_audit/source.py
RENAMED
|
@@ -19,6 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
from pathlib import Path
|
|
20
20
|
|
|
21
21
|
from ._metrics_types import DeclRange
|
|
22
|
+
from ._operator_reads import read_source_file
|
|
22
23
|
from .declarations import DECLARATION_SUFFIXES, declaration_ranges
|
|
23
24
|
|
|
24
25
|
|
|
@@ -51,10 +52,13 @@ class SourceIndex:
|
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
def _read(path: Path) -> list[str]:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
"""Every scan read goes through the regular-file primitive (D141).
|
|
56
|
+
|
|
57
|
+
`read_text` on a FIFO discovered in the tree waits for a writer that
|
|
58
|
+
never comes, so a file named `src/hang.py` stopped the audit rather
|
|
59
|
+
than being measured or refused.
|
|
60
|
+
"""
|
|
61
|
+
return read_source_file(path)
|
|
58
62
|
|
|
59
63
|
|
|
60
64
|
def index_or_new(index: SourceIndex | None) -> SourceIndex:
|
{maintainability_agent-3.0.0 → maintainability_agent-3.0.2}/tests/test_criteria_completion.py
RENAMED
|
@@ -29,7 +29,13 @@ import pytest
|
|
|
29
29
|
|
|
30
30
|
from maintainability_audit._criteria_scope import canonical_path
|
|
31
31
|
from maintainability_audit._metrics_types import Measurement
|
|
32
|
-
from maintainability_audit._pressures import
|
|
32
|
+
from maintainability_audit._pressures import (
|
|
33
|
+
ExternalPressures,
|
|
34
|
+
analyzer_pressures,
|
|
35
|
+
analyzer_production_pressures,
|
|
36
|
+
declined_dimensions,
|
|
37
|
+
)
|
|
38
|
+
from maintainability_audit._second_source import analyzer_scored
|
|
33
39
|
|
|
34
40
|
ROOT = "/repo/"
|
|
35
41
|
|
|
@@ -169,6 +175,30 @@ def test_the_note_states_the_composition_rather_than_crediting_one_tier(
|
|
|
169
175
|
assert "built-in scanner supplied" in entry["reason"]
|
|
170
176
|
|
|
171
177
|
|
|
178
|
+
def test_a_completed_go_pressure_names_its_builtin_fill_when_published(
|
|
179
|
+
limits: dict,
|
|
180
|
+
) -> None:
|
|
181
|
+
"""The score's source label must not credit lizard for scanner evidence.
|
|
182
|
+
|
|
183
|
+
The two sides deliberately use different spellings: lizard's ``./``
|
|
184
|
+
path and the scanner's repository-relative path. Building both from
|
|
185
|
+
one path string is the inert-merge hole #198 already had. Go is a
|
|
186
|
+
non-Python population where lizard supplies cyclomatic complexity and
|
|
187
|
+
lines while the built-in scanner supplies cognitive complexity.
|
|
188
|
+
"""
|
|
189
|
+
go = _lizard_go(3)
|
|
190
|
+
completed = _built_in_go(3)
|
|
191
|
+
published = ExternalPressures(
|
|
192
|
+
all_code=analyzer_pressures(go, limits, completed, ROOT),
|
|
193
|
+
production=analyzer_production_pressures(go, limits, completed, ROOT),
|
|
194
|
+
measurements=tuple(go),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
assert analyzer_scored(published) == [
|
|
198
|
+
"declarations (completed by built-in detectors)"
|
|
199
|
+
], "a mixed-tier pressure is published as an analyzer-only reading"
|
|
200
|
+
|
|
201
|
+
|
|
172
202
|
def test_a_still_incomplete_language_is_still_reported_as_a_fallback(
|
|
173
203
|
limits: dict,
|
|
174
204
|
) -> None:
|
|
@@ -24,6 +24,7 @@ from pathlib import Path
|
|
|
24
24
|
import pytest
|
|
25
25
|
|
|
26
26
|
from maintainability_audit.config import DEFAULT_CONFIG
|
|
27
|
+
from maintainability_audit.declarations import DECLARATION_SUFFIXES
|
|
27
28
|
|
|
28
29
|
TIGHT = {"max_function_lines": 10, "warn_function_lines": 6,
|
|
29
30
|
"max_file_lines": 40, "warn_file_lines": 20,
|
|
@@ -379,6 +380,43 @@ def test_content_that_does_not_parse_says_so_instead_of_reading_as_clean() -> No
|
|
|
379
380
|
assert "parse" in result["note"].lower()
|
|
380
381
|
|
|
381
382
|
|
|
383
|
+
@pytest.mark.parametrize("suffix", sorted(DECLARATION_SUFFIXES))
|
|
384
|
+
def test_a_hunk_without_diff_headers_is_unread_for_every_declaration_suffix(
|
|
385
|
+
suffix: str,
|
|
386
|
+
) -> None:
|
|
387
|
+
"""An agent often pastes just the hunk, not a complete ``diff -u``.
|
|
388
|
+
|
|
389
|
+
The population comes from the declaration dispatcher rather than a
|
|
390
|
+
hand-picked language list. In particular, the suffix here is not an
|
|
391
|
+
example the test author selected: every language that ``check_content``
|
|
392
|
+
claims it can read must reject the hunk-shaped fragment.
|
|
393
|
+
"""
|
|
394
|
+
result = _check(f"src/proposed{suffix}", "@@ -1 +1 @@\n+new content\n")
|
|
395
|
+
|
|
396
|
+
assert result["declarations_read"] is False, (
|
|
397
|
+
f"a hunk without ---/+++ was reported as readable for {suffix}"
|
|
398
|
+
)
|
|
399
|
+
assert result["note"], f"the refusal for {suffix} gave no reason"
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def test_valid_brace_source_is_still_read_after_diff_refusal() -> None:
|
|
403
|
+
"""Covers existing behaviour: brace source already read as parsed at
|
|
404
|
+
the base, so this guards the D138 refusal rather than proving it.
|
|
405
|
+
|
|
406
|
+
Annotated by the implementor, not the test author, because the
|
|
407
|
+
falsifier gate requires the phrase and rejected the change without
|
|
408
|
+
it. Nothing else about the test is altered.
|
|
409
|
+
|
|
410
|
+
Diff detection is a shape check, not a reason to reject brace code.
|
|
411
|
+
It is the exact case a careless refusal breaks: widening the shape
|
|
412
|
+
test until every file refuses would pass the falsifier beside it and
|
|
413
|
+
make `--check` useless on the twelve brace languages.
|
|
414
|
+
"""
|
|
415
|
+
result = _check("src/widget.js", "function widget() { return 1; }\n")
|
|
416
|
+
|
|
417
|
+
assert result["declarations_read"] is True
|
|
418
|
+
|
|
419
|
+
|
|
382
420
|
def test_content_that_parses_is_still_reported_as_read() -> None:
|
|
383
421
|
"""Covers existing behaviour: valid content already reported True.
|
|
384
422
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""The language-support lead may not out-claim its own verification — D139.
|
|
2
|
+
|
|
3
|
+
`docs/language-support.md` says two things about how a language's branch
|
|
4
|
+
set is arrived at. Seventy lines apart, they disagreed for two releases:
|
|
5
|
+
the lead said every language's set is *derived from its own grammar*,
|
|
6
|
+
and the verification section said only Python's is and the rest are sets
|
|
7
|
+
somebody wrote down.
|
|
8
|
+
|
|
9
|
+
D129 closed by correcting the section. A reader of the table never
|
|
10
|
+
reaches the section, so the sentence that reaches them kept over-claiming
|
|
11
|
+
— which is the shape this register keeps finding, a correction applied
|
|
12
|
+
where it was reported rather than where it is read.
|
|
13
|
+
|
|
14
|
+
The check has to survive the obvious way of satisfying it, which is why
|
|
15
|
+
it is written from both ends: deleting the honest paragraph must not make
|
|
16
|
+
the page pass. So the page must **say** the distinction, and must not
|
|
17
|
+
say the thing the distinction contradicts.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import re
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
PAGE = Path(__file__).resolve().parents[1] / "docs" / "language-support.md"
|
|
27
|
+
|
|
28
|
+
#: The claim D129 retired. Any spelling of "every language's set comes
|
|
29
|
+
#: from its grammar" is the defect; the words are matched loosely so a
|
|
30
|
+
#: rewording does not walk out from under the test.
|
|
31
|
+
OVERCLAIM = re.compile(
|
|
32
|
+
r"each language'?s?\s+branch\s+set\s+is\s+derived\s+from\s+\*{0,2}its\s+own\s+grammar",
|
|
33
|
+
re.IGNORECASE,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def page() -> str:
|
|
39
|
+
text = PAGE.read_text(encoding="utf-8")
|
|
40
|
+
assert text.strip(), f"{PAGE} is empty, so every check here would pass over nothing"
|
|
41
|
+
return text
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_the_lead_does_not_claim_every_language_is_derived_from_its_grammar(
|
|
45
|
+
page: str,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""The sentence D129 named, in the place a reader actually reaches."""
|
|
48
|
+
found = OVERCLAIM.search(page)
|
|
49
|
+
|
|
50
|
+
assert not found, (
|
|
51
|
+
"the language-support lead still says every language's branch set is "
|
|
52
|
+
f"derived from its own grammar: {found.group(0)!r}. Only Python's is "
|
|
53
|
+
"— `ast` implements the grammar and CI enumerates from it. Every "
|
|
54
|
+
"other language's set was written from the same knowledge as the "
|
|
55
|
+
"scanner it checks, which is what D125-D129 cost."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_the_page_states_the_distinction_rather_than_merely_omitting_it(
|
|
60
|
+
page: str,
|
|
61
|
+
) -> None:
|
|
62
|
+
"""Covers existing behaviour: the honest paragraph shipped with D129,
|
|
63
|
+
so this passes at the base. It guards the fix rather than proving it,
|
|
64
|
+
and the falsifier beside it is the one that fails without the change.
|
|
65
|
+
|
|
66
|
+
It exists because the cheapest fix for that test is to say nothing at
|
|
67
|
+
all — which is the same defect facing the other way, a page that
|
|
68
|
+
under-claims by silence. The distinction has to be *stated*, and
|
|
69
|
+
deleting the paragraph to satisfy a check that only forbids a
|
|
70
|
+
sentence must not work. Demonstrated: removing it fails this test.
|
|
71
|
+
"""
|
|
72
|
+
says_python_is_derived = re.search(
|
|
73
|
+
r"python'?s?\s+(branch set|coverage)\s+is\s+derived\s+from\s+"
|
|
74
|
+
r"(the|its own)\s+grammar",
|
|
75
|
+
page, re.IGNORECASE,
|
|
76
|
+
)
|
|
77
|
+
says_the_rest_are_sets = re.search(
|
|
78
|
+
r"(every other language|the rest)[^.]{0,80}\bset\b", page, re.IGNORECASE,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
assert says_python_is_derived, (
|
|
82
|
+
"the page no longer says Python's set is derived from the grammar, "
|
|
83
|
+
"so a reader cannot tell which language the enumeration covers"
|
|
84
|
+
)
|
|
85
|
+
assert says_the_rest_are_sets, (
|
|
86
|
+
"the page no longer says the other languages' sets are sets rather "
|
|
87
|
+
"than grammar enumerations. Omitting it passes the over-claim check "
|
|
88
|
+
"by saying nothing, which is the same defect facing the other way"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_the_lizard_sweep_is_not_described_as_a_grammar(page: str) -> None:
|
|
93
|
+
"""2.11.1's token sweep is a second opinion, not a specification.
|
|
94
|
+
|
|
95
|
+
`test_grammar_token_coverage` asks the pinned `lizard` which tokens it
|
|
96
|
+
counts as decisions. That is an independent implementation's keyword
|
|
97
|
+
list — better than the author's memory, and still not the language's
|
|
98
|
+
grammar. The page has to keep those two apart, because calling the
|
|
99
|
+
sweep a grammar enumeration would re-open D139 with extra steps.
|
|
100
|
+
"""
|
|
101
|
+
assert re.search(r"lizard", page, re.IGNORECASE), (
|
|
102
|
+
"the page does not mention the lizard sweep at all, so a reader "
|
|
103
|
+
"cannot tell what the non-Python check actually is"
|
|
104
|
+
)
|
|
105
|
+
assert re.search(
|
|
106
|
+
r"lizard[^.]{0,120}(keyword list|second implementation|not a grammar|"
|
|
107
|
+
r"rather than a grammar)",
|
|
108
|
+
page, re.IGNORECASE | re.DOTALL,
|
|
109
|
+
), (
|
|
110
|
+
"the page mentions lizard without saying it is a second "
|
|
111
|
+
"implementation's keyword list rather than a grammar enumeration"
|
|
112
|
+
)
|