maintainability-agent 4.2.0__tar.gz → 4.3.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.
Files changed (471) hide show
  1. {maintainability_agent-4.2.0/src/maintainability_agent.egg-info → maintainability_agent-4.3.0}/PKG-INFO +3 -3
  2. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/README.md +2 -2
  3. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0/src/maintainability_agent.egg-info}/PKG-INFO +3 -3
  4. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_agent.egg-info/SOURCES.txt +4 -0
  5. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/__init__.py +1 -1
  6. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_adapters.py +46 -1
  7. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_analysis.py +19 -0
  8. maintainability_agent-4.3.0/src/maintainability_audit/_changed_code_policy.py +98 -0
  9. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_gates.py +2 -1
  10. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_html_view.py +25 -4
  11. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_audit.py +3 -1
  12. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_metric_adapters.py +6 -4
  13. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ratio_adapters.py +4 -1
  14. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/config.py +2 -0
  15. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/renderers.py +25 -4
  16. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/report.py +31 -8
  17. maintainability_agent-4.3.0/tests/test_analyzers_against_the_real_tools.py +42 -0
  18. maintainability_agent-4.3.0/tests/test_analyzers_report_what_actually_failed.py +108 -0
  19. maintainability_agent-4.3.0/tests/test_changed_code_policy.py +137 -0
  20. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/LICENSE +0 -0
  21. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/pyproject.toml +0 -0
  22. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/setup.cfg +0 -0
  23. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  24. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  25. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
  26. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  27. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/__main__.py +0 -0
  28. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_analyzer_sections.py +0 -0
  29. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_anchor.py +0 -0
  30. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_arguments.py +0 -0
  31. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_aspects.py +0 -0
  32. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  33. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_assets/standard.md +0 -0
  34. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_attestation.py +0 -0
  35. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_backfill.py +0 -0
  36. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_bands.py +0 -0
  37. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_banner.py +0 -0
  38. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_built_ins.py +0 -0
  39. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_calibration.py +0 -0
  40. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_catalog.py +0 -0
  41. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_charts.py +0 -0
  42. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_cognitive.py +0 -0
  43. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_config_defaults.py +0 -0
  44. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_conformance.py +0 -0
  45. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_corroborate.py +0 -0
  46. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_coverage_notes.py +0 -0
  47. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_criteria_scope.py +0 -0
  48. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_delegated_pillar.py +0 -0
  49. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_derive.py +0 -0
  50. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_discovery.py +0 -0
  51. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_documents.py +0 -0
  52. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_economics.py +0 -0
  53. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_economics_view.py +0 -0
  54. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_environment.py +0 -0
  55. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_evidence_reader.py +0 -0
  56. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_evidence_view.py +0 -0
  57. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_finding_match.py +0 -0
  58. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_first_run.py +0 -0
  59. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_formula.py +0 -0
  60. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_generic.py +0 -0
  61. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_grammar.py +0 -0
  62. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_grant_ledger.py +0 -0
  63. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_handoff.py +0 -0
  64. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_history_view.py +0 -0
  65. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
  66. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_hotspots.py +0 -0
  67. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_html_report_sections.py +0 -0
  68. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_identity.py +0 -0
  69. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_in_loop.py +0 -0
  70. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_in_loop_view.py +0 -0
  71. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
  72. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_markdown_sections.py +0 -0
  73. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_masking.py +0 -0
  74. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_gate.py +0 -0
  75. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_grants.py +0 -0
  76. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
  77. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_resources.py +0 -0
  78. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_mcp_setup.py +0 -0
  79. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_metrics_types.py +0 -0
  80. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_operator_reads.py +0 -0
  81. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_oracle.py +0 -0
  82. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_pillars.py +0 -0
  83. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_practice.py +0 -0
  84. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_precommit.py +0 -0
  85. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_precommit_install.py +0 -0
  86. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_precommit_view.py +0 -0
  87. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_pressures.py +0 -0
  88. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_prompt_sections.py +0 -0
  89. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_c.py +0 -0
  90. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_cobol.py +0 -0
  91. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_core.py +0 -0
  92. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
  93. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
  94. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
  95. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_go.py +0 -0
  96. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_java.py +0 -0
  97. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_js.py +0 -0
  98. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_kotlin.py +0 -0
  99. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_php.py +0 -0
  100. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_ruby.py +0 -0
  101. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_rust.py +0 -0
  102. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_shell.py +0 -0
  103. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ranges_swift.py +0 -0
  104. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_ratchet.py +0 -0
  105. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_recurrence.py +0 -0
  106. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_run_comparison.py +0 -0
  107. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_runner.py +0 -0
  108. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_running_version.py +0 -0
  109. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_safe_write.py +0 -0
  110. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_scan_history.py +0 -0
  111. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_scan_view.py +0 -0
  112. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_second_source.py +0 -0
  113. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_security_delegate.py +0 -0
  114. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_security_work_order.py +0 -0
  115. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_selection.py +0 -0
  116. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_semantic.py +0 -0
  117. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_semantic_policy.py +0 -0
  118. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_semantic_ts.py +0 -0
  119. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_semantic_view.py +0 -0
  120. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_setup_errors.py +0 -0
  121. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_setup_persist.py +0 -0
  122. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  123. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  124. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  125. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  126. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  127. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  128. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_skill_install.py +0 -0
  129. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_stored_grants.py +0 -0
  130. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_tdd_view.py +0 -0
  131. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_test_commands.py +0 -0
  132. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_test_execution.py +0 -0
  133. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_test_pairing.py +0 -0
  134. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_tokens.py +0 -0
  135. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_tool_adapters.py +0 -0
  136. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_trends.py +0 -0
  137. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_user_config.py +0 -0
  138. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
  139. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_verification.py +0 -0
  140. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_work_order.py +0 -0
  141. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_work_order_view.py +0 -0
  142. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_work_order_weights.py +0 -0
  143. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/_xml.py +0 -0
  144. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/baseline.py +0 -0
  145. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/cli.py +0 -0
  146. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/deadcode.py +0 -0
  147. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/declarations.py +0 -0
  148. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/duplication.py +0 -0
  149. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/evidence.py +0 -0
  150. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/git_tools.py +0 -0
  151. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/history.py +0 -0
  152. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/idioms.py +0 -0
  153. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/instructions.py +0 -0
  154. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/mcp_server.py +0 -0
  155. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/metrics.py +0 -0
  156. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/prompts.py +0 -0
  157. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/sarif.py +0 -0
  158. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/scoring.py +0 -0
  159. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/similarity.py +0 -0
  160. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/src/maintainability_audit/source.py +0 -0
  161. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_clone_names_every_copy.py +0 -0
  162. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_dangling_source_link_is_named_not_fatal.py +0 -0
  163. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_format_override_is_disclosed.py +0 -0
  164. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_matching_format_stays_silent.py +0 -0
  165. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_published_question_offers_what_it_accepts.py +0 -0
  166. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_rendered_docs_site_is_not_scored_as_source.py +0 -0
  167. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_a_setup_question_keeps_its_contract.py +0 -0
  168. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_acquisition_trust.py +0 -0
  169. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_adapter_docs.py +0 -0
  170. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_adapter_recordings.py +0 -0
  171. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_adapters.py +0 -0
  172. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_added_lines.py +0 -0
  173. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_an_absent_work_order_renders_nothing.py +0 -0
  174. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_an_unmeasured_pillar_reports_no_number.py +0 -0
  175. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analysis_coverage.py +0 -0
  176. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analysis_execution.py +0 -0
  177. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_bridge.py +0 -0
  178. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_config_isolation.py +0 -0
  179. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_estimate_claims.py +0 -0
  180. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_file_lists_are_batched.py +0 -0
  181. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_pinning.py +0 -0
  182. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_primary_estimate.py +0 -0
  183. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_provenance.py +0 -0
  184. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
  185. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_scoring_path.py +0 -0
  186. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_spread_range.py +0 -0
  187. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_analyzer_xml_bounds.py +0 -0
  188. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_anchor_and_mode.py +0 -0
  189. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_anchor_caveat_and_counts_follow_the_run.py +0 -0
  190. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_anchor_disclosure.py +0 -0
  191. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_annotations_match_behaviour.py +0 -0
  192. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_anticipated_refusals.py +0 -0
  193. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_architecture.py +0 -0
  194. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_artifact_write_route_class.py +0 -0
  195. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_aspect_coverage.py +0 -0
  196. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_asset_snapshot_class.py +0 -0
  197. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
  198. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_attestation.py +0 -0
  199. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_audit_components.py +0 -0
  200. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_authorization_freshness.py +0 -0
  201. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_authorship_gates.py +0 -0
  202. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_backfill.py +0 -0
  203. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_band_concealment_class.py +0 -0
  204. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_band_concealment_p3.py +0 -0
  205. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_band_pressures.py +0 -0
  206. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_bands.py +0 -0
  207. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_behaviour_suites_are_tests.py +0 -0
  208. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_body_or_signature_class.py +0 -0
  209. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_both_setup_paths_ask_the_same_stage.py +0 -0
  210. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_build_output_is_not_the_repositorys_code.py +0 -0
  211. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_c_declarations.py +0 -0
  212. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_calibration_corpus.py +0 -0
  213. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_calibration_drift.py +0 -0
  214. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_calibration_tooling.py +0 -0
  215. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_catalog_selection.py +0 -0
  216. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_catalog_tier_promise.py +0 -0
  217. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_chat_leads_with_the_work_order.py +0 -0
  218. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_chat_primary_docs.py +0 -0
  219. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  220. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_checkstyle_adapter.py +0 -0
  221. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_checkstyle_catalog.py +0 -0
  222. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_child_sandbox.py +0 -0
  223. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_ci_history_recipe.py +0 -0
  224. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  225. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_claimed_languages.py +0 -0
  226. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_clean_sees_the_weakened_oracle.py +0 -0
  227. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cli.py +0 -0
  228. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_clone_group_class.py +0 -0
  229. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cobol_declarations.py +0 -0
  230. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_code_scanning_gets_alerts_not_the_record.py +0 -0
  231. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cognitive_complexity.py +0 -0
  232. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cohesion_with_nothing_to_read_is_not_applicable.py +0 -0
  233. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cohort_statistics.py +0 -0
  234. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_concealment_properties.py +0 -0
  235. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_config_shape.py +0 -0
  236. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_conformance_reads_the_operators_ask.py +0 -0
  237. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_consent_and_grant.py +0 -0
  238. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_consent_is_per_repository.py +0 -0
  239. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_consent_survives_setup_and_is_asked.py +0 -0
  240. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_consent_without_command_has_a_remedy.py +0 -0
  241. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_consumer_migration.py +0 -0
  242. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_contract_claims.py +0 -0
  243. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_corpus_note_counts_come_from_the_corpus.py +0 -0
  244. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_corroborate.py +0 -0
  245. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_coverage_by_language.py +0 -0
  246. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_coverage_config_reaches_children.py +0 -0
  247. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_coverage_formats.py +0 -0
  248. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_cpp_declarations.py +0 -0
  249. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_criteria_completion.py +0 -0
  250. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_csharp_declarations.py +0 -0
  251. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_current_state_docs_name_every_parsed_language.py +0 -0
  252. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_d15_composition.py +0 -0
  253. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_d15_goal_directed.py +0 -0
  254. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_dead_code.py +0 -0
  255. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declaration_criteria_scope.py +0 -0
  256. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declaration_edge_cases.py +0 -0
  257. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declaration_grading.py +0 -0
  258. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declaration_ranges.py +0 -0
  259. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declaration_source.py +0 -0
  260. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declarative_parsers.py +0 -0
  261. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declared_capabilities_match_the_delegate.py +0 -0
  262. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_declared_imports.py +0 -0
  263. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_delegated_security_pillar.py +0 -0
  264. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_demo_tree.py +0 -0
  265. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_derivation_mix.py +0 -0
  266. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_determinism.py +0 -0
  267. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_dimension_ratchet.py +0 -0
  268. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_direct_runner_availability_class.py +0 -0
  269. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_discovery.py +0 -0
  270. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_doc_claims.py +0 -0
  271. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_docs_links.py +0 -0
  272. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_economic_context.py +0 -0
  273. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_empty_output_not_clean.py +0 -0
  274. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
  275. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_environment_work_order.py +0 -0
  276. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_built_presentation_is_offered.py +0 -0
  277. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_language_counts_its_own_loop.py +0 -0
  278. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_language_has_a_loop_fixture.py +0 -0
  279. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_pool_install_is_the_same_pool.py +0 -0
  280. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_question_can_be_answered.py +0 -0
  281. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_every_surface_says_what_the_run_found.py +0 -0
  282. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_evidence_invariants.py +0 -0
  283. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_evidence_normalization.py +0 -0
  284. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_evidence_properties.py +0 -0
  285. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_example_config_opens_claimed_languages.py +0 -0
  286. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_exclude_additional_keeps_the_defaults.py +0 -0
  287. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_exclusion_dialects.py +0 -0
  288. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_exposure_never_outranks_band.py +0 -0
  289. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_falsifier_standard.py +0 -0
  290. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_file_list_cap_class.py +0 -0
  291. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_finding_identity.py +0 -0
  292. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_first_run_elicitation.py +0 -0
  293. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_first_run_prompt.py +0 -0
  294. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_first_run_reelicitation.py +0 -0
  295. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_first_stage_setup_wording_holds.py +0 -0
  296. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_fix_breadth_window.py +0 -0
  297. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_fixed_form_fortran.py +0 -0
  298. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_format_ask.py +0 -0
  299. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_fortran_declarations.py +0 -0
  300. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_fortran_metrics.py +0 -0
  301. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_fortran_practice.py +0 -0
  302. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_git_argv.py +0 -0
  303. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_git_read_only.py +0 -0
  304. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_git_readonly_class.py +0 -0
  305. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_go_declarations.py +0 -0
  306. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_grammar_constructs.py +0 -0
  307. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_grammar_token_coverage.py +0 -0
  308. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_grant_only_user_tier.py +0 -0
  309. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_grok_audit_of_3_11.py +0 -0
  310. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_history.py +0 -0
  311. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_history_boundary.py +0 -0
  312. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_history_manifest.py +0 -0
  313. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_history_schema2.py +0 -0
  314. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_history_window.py +0 -0
  315. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_hostile_prompt.py +0 -0
  316. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_html_executive.py +0 -0
  317. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_html_section_parity_class.py +0 -0
  318. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_identity_docs.py +0 -0
  319. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_identity_resolution.py +0 -0
  320. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_idiom_divergence.py +0 -0
  321. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_in_loop_budgets.py +0 -0
  322. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_in_loop_check.py +0 -0
  323. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_installed_wheel_runtime.py +0 -0
  324. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_instruction_targets.py +0 -0
  325. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_java_range_guard.py +0 -0
  326. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_java_ranges.py +0 -0
  327. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_java_scored.py +0 -0
  328. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_java_wiring.py +0 -0
  329. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_js_complexity_operators.py +0 -0
  330. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_js_declarations.py +0 -0
  331. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_kotlin_declarations.py +0 -0
  332. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_kotlin_metrics.py +0 -0
  333. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_language_coverage.py +0 -0
  334. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_language_support_honesty.py +0 -0
  335. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_list_tools_publishes_the_answer_path.py +0 -0
  336. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_maintenance_signals.py +0 -0
  337. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mcp_baseline_payload.py +0 -0
  338. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mcp_format_contract.py +0 -0
  339. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mcp_history.py +0 -0
  340. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mcp_server.py +0 -0
  341. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mcp_start_failure_names_what_is_installed.py +0 -0
  342. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_migration_1_0.py +0 -0
  343. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_missing_security_scanners_are_named_before_the_run.py +0 -0
  344. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_mutation_recorded.py +0 -0
  345. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_near_duplicates.py +0 -0
  346. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_network_disclosure.py +0 -0
  347. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
  348. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_operator_named_paths.py +0 -0
  349. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_operator_named_reads.py +0 -0
  350. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_oracle_weakening_precision_bar.py +0 -0
  351. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pairing_reads_imports.py +0 -0
  352. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pattern_budget.py +0 -0
  353. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_phase6_claims.py +0 -0
  354. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_php_declarations.py +0 -0
  355. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pillars_and_practice.py +0 -0
  356. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_platform_claim.py +0 -0
  357. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pmd_adapter.py +0 -0
  358. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pmd_audit_closures.py +0 -0
  359. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_policy_claims.py +0 -0
  360. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_pool_runs_by_config.py +0 -0
  361. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_population_floors.py +0 -0
  362. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_practice_nested_gates_class.py +0 -0
  363. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_precommit_staged.py +0 -0
  364. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_preflight_before_consent_runs_nothing_from_the_tree.py +0 -0
  365. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_presentation_refusals.py +0 -0
  366. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_previous_release_reached_pypi.py +0 -0
  367. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_promises.py +0 -0
  368. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  369. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_prompt_escalation_once.py +0 -0
  370. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_prompt_honesty.py +0 -0
  371. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_prompt_location_escalation_class.py +0 -0
  372. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_prove_falsifiers.py +0 -0
  373. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_python_complexity.py +0 -0
  374. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_python_declarations.py +0 -0
  375. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_read_boundary.py +0 -0
  376. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_readme_claims.py +0 -0
  377. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_recurrence.py +0 -0
  378. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_regular_file_reads_work_without_o_nonblock.py +0 -0
  379. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_release_needs_an_empty_ledger.py +0 -0
  380. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_release_plan.py +0 -0
  381. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_release_plan_status.py +0 -0
  382. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_rendered_docs.py +0 -0
  383. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_report_remedy_copy.py +0 -0
  384. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_root_grants.py +0 -0
  385. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  386. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_ruby_declarations.py +0 -0
  387. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_run_comparison.py +0 -0
  388. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_runner.py +0 -0
  389. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_rust_declarations.py +0 -0
  390. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_sarif.py +0 -0
  391. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scan_history.py +0 -0
  392. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scan_scope.py +0 -0
  393. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scanner_fingerprint_covers_the_measurement_path.py +0 -0
  394. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scanner_unsafe_direction.py +0 -0
  395. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scanning.py +0 -0
  396. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_schema_fidelity.py +0 -0
  397. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scope_conformance.py +0 -0
  398. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_scoring_calibration.py +0 -0
  399. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_security_delegate_versions_agree.py +0 -0
  400. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_security_findings_keep_their_handoff.py +0 -0
  401. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_security_pillar_asserts_a_scanner_set.py +0 -0
  402. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_security_pillar_runs_and_shows.py +0 -0
  403. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_selection_covers_every_parsed_language.py +0 -0
  404. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_semantic_findings_stay_inside_the_audited_files.py +0 -0
  405. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_semantic_policy.py +0 -0
  406. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_answers_are_the_same_setup.py +0 -0
  407. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_gate_completeness.py +0 -0
  408. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_gate_independent_contract.py +0 -0
  409. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_instruction_describes_its_own_reply.py +0 -0
  410. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_precondition.py +0 -0
  411. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_setup_writes_a_valid_config.py +0 -0
  412. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_shell_declarations.py +0 -0
  413. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_shell_metrics.py +0 -0
  414. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_skill_install.py +0 -0
  415. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_sonar_resolve.py +0 -0
  416. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_source_index.py +0 -0
  417. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_spotbugs_adapter.py +0 -0
  418. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_spotbugs_catalog.py +0 -0
  419. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_stage8_contract.py +0 -0
  420. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_stamped_documents_stay_honest.py +0 -0
  421. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_stdout_outputs.py +0 -0
  422. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_suite_isolation.py +0 -0
  423. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_swift_declarations.py +0 -0
  424. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_tdd_structure.py +0 -0
  425. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_terminal_asks_the_same_questions.py +0 -0
  426. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_test_commands.py +0 -0
  427. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_test_execution_class.py +0 -0
  428. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_agent_knows_when_it_is_stale.py +0 -0
  429. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_changelog_covers_the_shipping_version.py +0 -0
  430. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_chat_payload_has_a_budget.py +0 -0
  431. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_condition_says_what_it_measured.py +0 -0
  432. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_handoff_rules_are_their_own_module.py +0 -0
  433. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_pillar_row_reads_cleanly.py +0 -0
  434. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_presentation_question_stays_answerable.py +0 -0
  435. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_previous_release_was_tagged.py +0 -0
  436. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_prompt_does_not_take_back_what_it_withheld.py +0 -0
  437. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_prompt_keeps_listing_what_it_did_not_withhold.py +0 -0
  438. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_release_process_describes_itself.py +0 -0
  439. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_release_record_stays_well_formed.py +0 -0
  440. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_report_is_saved_not_sent.py +0 -0
  441. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_security_run_has_a_configurable_limit.py +0 -0
  442. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_security_work_order_is_drawn.py +0 -0
  443. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_suite_names_the_program_it_ran.py +0 -0
  444. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_tree_cannot_redirect_a_read.py +0 -0
  445. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_the_version_has_one_source.py +0 -0
  446. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_three_presentations.py +0 -0
  447. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_tool_resolution.py +0 -0
  448. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  449. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_tree_chosen_spawn.py +0 -0
  450. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_tree_reads_use_the_primitive.py +0 -0
  451. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_trends.py +0 -0
  452. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_type_fields_not_functions_class.py +0 -0
  453. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_uat_falsifiers.py +0 -0
  454. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_unanchored_set_matches_corpus.py +0 -0
  455. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_unread_code.py +0 -0
  456. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_user_config_tier.py +0 -0
  457. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_verification_audit_closures.py +0 -0
  458. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_verified_grade.py +0 -0
  459. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_version_claim.py +0 -0
  460. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_version_stamping.py +0 -0
  461. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_wheel_contents.py +0 -0
  462. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_withheld_work_keeps_its_boundary.py +0 -0
  463. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_work_items_state_their_own_finding.py +0 -0
  464. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_work_order.py +0 -0
  465. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  466. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_work_order_items.py +0 -0
  467. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_work_order_selection.py +0 -0
  468. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_workflow_supply_chain.py +0 -0
  469. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_write_boundary.py +0 -0
  470. {maintainability_agent-4.2.0 → maintainability_agent-4.3.0}/tests/test_write_route_class.py +0 -0
  471. {maintainability_agent-4.2.0 → maintainability_agent-4.3.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: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -47,7 +47,7 @@ Dynamic: license-file
47
47
  **A deterministic, offline maintainability audit whose output is a _bounded
48
48
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
49
49
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
50
- Version **4.2.0**.
50
+ Version **4.3.0**.
51
51
 
52
52
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
53
53
  >
@@ -509,7 +509,7 @@ instead of an invokable skill:
509
509
  This repo ships `action.yml`, usable as a composite action:
510
510
 
511
511
  ```yaml
512
- - uses: marshallguillory86/maintainability-agent@v4.2.0
512
+ - uses: marshallguillory86/maintainability-agent@v4.3.0
513
513
  with:
514
514
  config: maintainability-agent.json
515
515
  changed-only: main...HEAD
@@ -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 **4.2.0**.
8
+ Version **4.3.0**.
9
9
 
10
10
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
11
11
  >
@@ -467,7 +467,7 @@ instead of an invokable skill:
467
467
  This repo ships `action.yml`, usable as a composite action:
468
468
 
469
469
  ```yaml
470
- - uses: marshallguillory86/maintainability-agent@v4.2.0
470
+ - uses: marshallguillory86/maintainability-agent@v4.3.0
471
471
  with:
472
472
  config: maintainability-agent.json
473
473
  changed-only: main...HEAD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -47,7 +47,7 @@ Dynamic: license-file
47
47
  **A deterministic, offline maintainability audit whose output is a _bounded
48
48
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
49
49
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
50
- Version **4.2.0**.
50
+ Version **4.3.0**.
51
51
 
52
52
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
53
53
  >
@@ -509,7 +509,7 @@ instead of an invokable skill:
509
509
  This repo ships `action.yml`, usable as a composite action:
510
510
 
511
511
  ```yaml
512
- - uses: marshallguillory86/maintainability-agent@v4.2.0
512
+ - uses: marshallguillory86/maintainability-agent@v4.3.0
513
513
  with:
514
514
  config: maintainability-agent.json
515
515
  changed-only: main...HEAD
@@ -22,6 +22,7 @@ src/maintainability_audit/_banner.py
22
22
  src/maintainability_audit/_built_ins.py
23
23
  src/maintainability_audit/_calibration.py
24
24
  src/maintainability_audit/_catalog.py
25
+ src/maintainability_audit/_changed_code_policy.py
25
26
  src/maintainability_audit/_charts.py
26
27
  src/maintainability_audit/_cognitive.py
27
28
  src/maintainability_audit/_config_defaults.py
@@ -179,6 +180,8 @@ tests/test_analyzer_provenance_exclusions.py
179
180
  tests/test_analyzer_scoring_path.py
180
181
  tests/test_analyzer_spread_range.py
181
182
  tests/test_analyzer_xml_bounds.py
183
+ tests/test_analyzers_against_the_real_tools.py
184
+ tests/test_analyzers_report_what_actually_failed.py
182
185
  tests/test_anchor_and_mode.py
183
186
  tests/test_anchor_caveat_and_counts_follow_the_run.py
184
187
  tests/test_anchor_disclosure.py
@@ -208,6 +211,7 @@ tests/test_calibration_drift.py
208
211
  tests/test_calibration_tooling.py
209
212
  tests/test_catalog_selection.py
210
213
  tests/test_catalog_tier_promise.py
214
+ tests/test_changed_code_policy.py
211
215
  tests/test_chat_leads_with_the_work_order.py
212
216
  tests/test_chat_primary_docs.py
213
217
  tests/test_check_refuses_plus_only_fragments.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "4.2.0"
3
+ __version__ = "4.3.0"
@@ -118,6 +118,36 @@ def _format_default(_base: Path, tree: str) -> tuple[str, ...]:
118
118
  return (tree, f"{tree}/**")
119
119
 
120
120
 
121
+ _REGEX_DIALECTS = frozenset({"regex", "rel_regex"})
122
+
123
+
124
+ def _name_as_regex(pattern: str) -> str:
125
+ """A shell-style name as a regex that finds it as a path component anywhere.
126
+
127
+ `*` and `?` stay inside one component, as they do for the built-in
128
+ scan's own matcher; the name matches at the start of the path or after
129
+ a `/`, and ends at a `/` or the end, so `.venv/` is not `venv_tools.py`.
130
+ Works for `re.match` on an absolute path (pylint) and `re.search` on a
131
+ relative one (mypy) alike.
132
+ """
133
+ body = "".join("[^/]*" if ch == "*" else "[^/]" if ch == "?" else re.escape(ch)
134
+ for ch in pattern.strip("/"))
135
+ return f"(?:^|.*/){body}(?:/|$)"
136
+
137
+
138
+ def _names_as_paths(excludes: Sequence[str], root: Path) -> tuple[str, ...]:
139
+ """Plain path names as absolute paths under the root; wildcards dropped.
140
+
141
+ A path dialect (interrogate's `--exclude`) names locations, so
142
+ `calibration/.corpus/` becomes `<root>/calibration/.corpus`. A wildcard
143
+ such as `*.min.js` names no location and cannot be spelled here; it is
144
+ left out, which can only under-exclude — the scan's own filter still
145
+ applies it to what the tool reports.
146
+ """
147
+ return tuple(str(root / pattern.strip("/")) for pattern in excludes
148
+ if not any(ch in pattern for ch in "*?["))
149
+
150
+
121
151
  _TREE_FORMATTERS = {
122
152
  "fnmatch": _format_fnmatch,
123
153
  "regex": _format_regex,
@@ -267,7 +297,7 @@ class BaseAdapter:
267
297
  """
268
298
  if not self.exclude_flag:
269
299
  return ()
270
- entries = tuple(excludes) + self.tree_patterns(
300
+ entries = self.operator_patterns(excludes, root) + self.tree_patterns(
271
301
  getattr(excludes, "trees", ()), root
272
302
  )
273
303
  if not entries:
@@ -279,6 +309,21 @@ class BaseAdapter:
279
309
  return tuple(repeated)
280
310
  return (self.exclude_flag, self.exclude_separator.join(entries))
281
311
 
312
+ def operator_patterns(self, excludes: Sequence[str], root: Path | None = None) -> tuple[str, ...]:
313
+ """The operator's exclude names, spelled for this tool's matcher.
314
+
315
+ They are shell-style names — `.venv/`, `*.egg-info/` — and for most
316
+ dialects they pass through as written. A regex dialect compiles
317
+ them: pylint's `--ignore-paths` refused `*.egg-info` ("nothing to
318
+ repeat"), exited with an argument error, and analysed nothing, on
319
+ every repository whose config carried a glob (the default does).
320
+ """
321
+ if self.exclude_dialect == "abspath":
322
+ return _names_as_paths(excludes, Path(root) if root is not None else Path("."))
323
+ if self.exclude_dialect not in _REGEX_DIALECTS:
324
+ return tuple(excludes)
325
+ return tuple(_name_as_regex(pattern) for pattern in excludes)
326
+
282
327
  def tree_patterns(
283
328
  self, trees: Sequence[str], root: Path | None = None
284
329
  ) -> tuple[str, ...]:
@@ -447,6 +447,7 @@ def _attempt(root: Path, adapter: Any, probe: Probe, timeout: int,
447
447
  )
448
448
 
449
449
  result, parsed = _run_batches(adapter, root, excludes, timeout)
450
+ result = _silent_failure(adapter.slug, result, parsed)
450
451
  # Filtered before the counts are taken, not after. Recording 48
451
452
  # measurements and reporting 6 describes an activity rather than a
452
453
  # result, which is the defect this project keeps finding.
@@ -500,6 +501,24 @@ def _run_batches(adapter: Any, root: Path, excludes: Sequence[str],
500
501
  return _merged_result(results, len(invocations)), _merged_extraction(parsed)
501
502
 
502
503
 
504
+ def _silent_failure(slug: str, result: ToolResult, parsed: Extraction) -> ToolResult:
505
+ """A tool that wrote nothing failed, whatever its exit code says.
506
+
507
+ pylint's argument error exits 2, which is also its "error messages
508
+ issued" bit, so a run that analysed nothing counted as one that worked
509
+ and its empty output was reported as unreadable JSON while stderr held
510
+ the reason. secure-code-agent recorded the same class as its D30: let
511
+ the output decide, and let the failure carry what the tool said.
512
+ """
513
+ if not (parsed.parse_error and result.usable and not (result.stdout or "").strip()):
514
+ return result
515
+ said = " ".join((result.stderr or "").split())[:400]
516
+ if not said:
517
+ return result
518
+ return replace(result, outcome=Outcome.FAILED,
519
+ detail=f"{slug} exited {result.exit_code} and wrote no output; it said: {said}")
520
+
521
+
503
522
  def _merged_result(results: list[ToolResult], planned: int) -> ToolResult:
504
523
  failed = next((r for r in results if not r.usable), None)
505
524
  basis = failed or results[0]
@@ -0,0 +1,98 @@
1
+ """Code a change touches is held to a stricter bar (Decision 15).
2
+
3
+ A repository adopting a quality gate cannot fix every old long function
4
+ first, and a gate that fails on all of them is a gate nobody turns on.
5
+ `policy.changed_code` sets stricter function limits, and on a run against a
6
+ change only the functions that change touched are held to them; untouched
7
+ code is judged by the standard as before.
8
+
9
+ A function is *touched* when the change added or altered a line inside it —
10
+ `git diff --unified=0` lines, so context does not count and a pure deletion
11
+ touches nothing. Classes are not held to it: their budget is a container's,
12
+ and their methods are functions in their own right.
13
+
14
+ Two rules from the decision, enforced here rather than trusted:
15
+
16
+ - **A policy only tightens.** A limit looser than the standard threshold is
17
+ refused when the configuration loads, by name, as `PolicyError` — the
18
+ refusal both doors already turn into a message.
19
+ - **It never moves the grade.** Its result is `report["policy"]`, beside the
20
+ score rather than inside `hard_gate_failures`, which the scorer reads.
21
+ `--fail-on-gate` reads both.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from typing import Any
27
+
28
+ from ._catalog import PolicyError
29
+
30
+ #: Each policy key: the standard threshold it may only tighten, the
31
+ #: function-metric field it reads, and the name a failure reports.
32
+ LIMITS: dict[str, tuple[str, str, str]] = {
33
+ "max_function_lines": ("max_function_lines", "lines", "function_lines"),
34
+ "max_complexity": ("max_complexity", "complexity", "complexity"),
35
+ "max_cognitive_complexity": ("max_cognitive_complexity", "cognitive", "cognitive_complexity"),
36
+ }
37
+
38
+
39
+ def changed_code_limits(config: dict[str, Any]) -> dict[str, int]:
40
+ """The configured limits, or empty when the repository sets none."""
41
+ return dict((config.get("policy") or {}).get("changed_code") or {})
42
+
43
+
44
+ def validate(config: dict[str, Any]) -> None:
45
+ """Refuse a limit that is unknown, not a positive integer, or looser than the standard."""
46
+ thresholds = config.get("thresholds") or {}
47
+ for key, value in changed_code_limits(config).items():
48
+ if key not in LIMITS:
49
+ raise PolicyError(
50
+ f"unknown policy.changed_code key {key!r}; expected one of {sorted(LIMITS)}")
51
+ if isinstance(value, bool) or not isinstance(value, int) or value < 1:
52
+ raise PolicyError(f"policy.changed_code.{key} must be a positive integer, not {value!r}")
53
+ standard = thresholds.get(LIMITS[key][0])
54
+ if isinstance(standard, int) and value > standard:
55
+ raise PolicyError(
56
+ f"policy.changed_code.{key} is {value}, looser than the standard "
57
+ f"thresholds.{LIMITS[key][0]} of {standard}; a policy may only tighten")
58
+
59
+
60
+ def evaluate(function_metrics: list[Any], touched_lines: dict[str, set[int]],
61
+ config: dict[str, Any], revspec: str) -> dict[str, Any] | None:
62
+ """Every touched function's breaches of the policy, or None without a policy."""
63
+ limits = changed_code_limits(config)
64
+ if not limits:
65
+ return None
66
+ touched = [metric for metric in function_metrics if _touched(metric, touched_lines)]
67
+ return {
68
+ "revspec": revspec,
69
+ "limits": limits,
70
+ "touched_functions": len(touched),
71
+ "failures": [failure for metric in touched for failure in _breaches(metric, limits)],
72
+ }
73
+
74
+
75
+ def failures(report: dict[str, Any]) -> list[dict[str, Any]]:
76
+ """The policy's failures in a finished report; empty when no policy ran."""
77
+ return list((report.get("policy") or {}).get("failures") or [])
78
+
79
+
80
+ def _touched(metric: Any, touched_lines: dict[str, set[int]]) -> bool:
81
+ if getattr(metric, "kind", "function") == "class":
82
+ return False
83
+ lines = touched_lines.get(metric.path)
84
+ if not lines:
85
+ return False
86
+ end = metric.start_line + metric.lines
87
+ return any(metric.start_line <= line < end for line in lines)
88
+
89
+
90
+ def _breaches(metric: Any, limits: dict[str, int]) -> list[dict[str, Any]]:
91
+ found = []
92
+ for key, limit in limits.items():
93
+ _standard, field, measure = LIMITS[key]
94
+ value = getattr(metric, field, None)
95
+ if isinstance(value, int) and value > limit:
96
+ found.append({"path": metric.path, "name": metric.name, "start_line": metric.start_line,
97
+ "measure": measure, "value": value, "limit": limit})
98
+ return found
@@ -18,6 +18,7 @@ import argparse
18
18
  import sys
19
19
  from pathlib import Path
20
20
 
21
+ from ._changed_code_policy import failures as policy_failures
21
22
  from .baseline import findings_not_in_baseline
22
23
  from .git_tools import added_lines, changed_paths, removed_lines
23
24
 
@@ -147,7 +148,7 @@ def audit_exit_code(args: argparse.Namespace, report: dict) -> int:
147
148
  root = Path(report["root"])
148
149
  if findings_not_in_baseline(report, args.baseline, root):
149
150
  return 1
150
- if args.fail_on_gate and report["hard_gate_failures"]:
151
+ if args.fail_on_gate and (report["hard_gate_failures"] or policy_failures(report)):
151
152
  return 1
152
153
  conformance = _conformance_exit(args, report)
153
154
  if conformance:
@@ -318,15 +318,36 @@ def _work_order_section(report: dict[str, Any]) -> list[str]:
318
318
 
319
319
  def _hard_gate_section(report: dict[str, Any]) -> list[str]:
320
320
  failures = report.get("hard_gate_failures") or []
321
+ rows: list[str] = []
322
+ if failures:
323
+ rows = [
324
+ "<h2>Hard gates</h2>",
325
+ "<table><tr><th>Severity</th><th>Gate</th></tr>",
326
+ ]
327
+ rows.extend(
328
+ f"<tr><td class='sev-Severe'>Severe</td><td>{escape(str(gate))}</td></tr>"
329
+ for gate in failures
330
+ )
331
+ rows.append("</table>")
332
+ return rows + _policy_section(report)
333
+
334
+
335
+ def _policy_section(report: dict[str, Any]) -> list[str]:
336
+ """The changed-code policy beside the gates, as the markdown prints it (Decision 15)."""
337
+ policy = report.get("policy")
338
+ failures = (policy or {}).get("failures") or []
321
339
  if not failures:
322
340
  return []
323
341
  rows = [
324
- "<h2>Hard gates</h2>",
325
- "<table><tr><th>Severity</th><th>Gate</th></tr>",
342
+ "<h2>Changed-code policy</h2>",
343
+ f"<p class='muted'>Functions touched by {escape(str(policy.get('revspec')))} are held to "
344
+ "this repository's stricter limits. The grade is unaffected.</p>",
345
+ "<table><tr><th>Location</th><th>Function</th><th>Measure</th><th>Value</th><th>Limit</th></tr>",
326
346
  ]
327
347
  rows.extend(
328
- f"<tr><td class='sev-Severe'>Severe</td><td>{escape(str(gate))}</td></tr>"
329
- for gate in failures
348
+ f"<tr><td>{escape(str(f['path']))}:{f['start_line']}</td><td>{escape(str(f['name']))}</td>"
349
+ f"<td>{escape(str(f['measure']))}</td><td>{f['value']}</td><td>{f['limit']}</td></tr>"
350
+ for f in failures
330
351
  )
331
352
  rows.append("</table>")
332
353
  return rows
@@ -21,6 +21,7 @@ from typing import Any
21
21
 
22
22
  from ._calibration import CALIBRATION_C
23
23
  from ._catalog import PRESENTATIONS
24
+ from ._changed_code_policy import failures as policy_failures
24
25
  from ._grant_ledger import (
25
26
  ALLOWED_ROOTS_ENV as ALLOWED_ROOTS_ENV, # noqa: PLC0414 - re-export
26
27
  )
@@ -396,7 +397,8 @@ def _top_level_result(report: dict[str, Any], root: Path, status: str,
396
397
  "audit_ran": True,
397
398
  "source_commit": probe_git(["rev-parse", "HEAD"], root) or None,
398
399
  "worktree_dirty": bool(status),
399
- "gate_passed": not report["hard_gate_failures"],
400
+ # The changed-code policy is a gate too (Decision 15); the CLI reads both.
401
+ "gate_passed": not (report["hard_gate_failures"] or policy_failures(report)),
400
402
  # Stated at the top level so a caller cannot mistake an audit that
401
403
  # ran six built-in detectors for one that ran ten tools. Two
402
404
  # reports with different coverage are not comparable (P8).
@@ -321,10 +321,12 @@ class CohesionAdapter(BaseAdapter):
321
321
  super().__init__(
322
322
  slug="cohesion", emits="metric", executable="cohesion",
323
323
  concepts=("cohesion",), exclude_dialect="files",
324
- # Its CLI takes files or a directory and has no version flag,
325
- # so availability is answered from package metadata, the same
326
- # arrangement multimetric already uses.
327
- distribution="cohesion",
324
+ # Its CLI takes files or a directory and has no version flag, so
325
+ # the version comes from package metadata — and availability
326
+ # from `--help`, the arrangement multimetric uses. The probe was
327
+ # `--version`, which argparse rejects with exit 2, so cohesion
328
+ # was recorded as failed without ever being asked to run.
329
+ version_flag="--help", distribution="cohesion",
328
330
  )
329
331
 
330
332
  def has_targets(self, root: Path, excludes: Sequence[str] = ()) -> bool:
@@ -134,7 +134,10 @@ class InterrogateAdapter(BaseAdapter):
134
134
  super().__init__(
135
135
  slug="interrogate", emits="metric", executable="interrogate",
136
136
  concepts=("documentation",), findings_exit_codes=(0, 1),
137
- exclude_flag="--exclude", exclude_separator=" ",
137
+ # One `--exclude` per path: interrogate names one location per
138
+ # flag, and a space-joined list named none, so excluded trees
139
+ # were analysed and one unparseable file in them crashed it.
140
+ exclude_flag="--exclude", exclude_repeat=True,
138
141
  exclude_dialect="abspath",
139
142
  )
140
143
 
@@ -7,6 +7,7 @@ from typing import Any
7
7
  # Re-exported: the defaults live in `_config_defaults`, this module is
8
8
  # still the door every caller comes through.
9
9
  from . import __version__ as _package_version
10
+ from ._changed_code_policy import validate as validate_changed_code_policy
10
11
  from ._config_defaults import DEFAULT_CONFIG, DEFAULT_IDIOM_GROUPS
11
12
  from ._operator_reads import (
12
13
  MAX_OPERATOR_FILE_BYTES as MAX_OPERATOR_FILE_BYTES,
@@ -164,6 +165,7 @@ def load_config(path: str | None) -> dict[str, Any]:
164
165
  _merge_tier(config, user_tier)
165
166
  if path:
166
167
  _merge_tier(config, _host_authority_stripped(_configured(Path(path))))
168
+ validate_changed_code_policy(config)
167
169
  return config
168
170
 
169
171
 
@@ -178,11 +178,32 @@ def render_markdown(report: dict[str, Any], *, complete: bool = True) -> str:
178
178
 
179
179
 
180
180
  def _hard_gate_lines(report: dict[str, Any]) -> list[str]:
181
- """The hard-gate list, printed the same way wherever it appears."""
182
- if not report["hard_gate_failures"]:
181
+ """The hard-gate list, printed the same way wherever it appears.
182
+
183
+ The changed-code policy follows it: also a gate, never a grade
184
+ (Decision 15), so it is printed wherever the gates are.
185
+ """
186
+ lines: list[str] = []
187
+ if report["hard_gate_failures"]:
188
+ lines += ["## Hard Gate Failures", "",
189
+ *(f"- {gate}" for gate in report["hard_gate_failures"]), ""]
190
+ return lines + _policy_lines(report)
191
+
192
+
193
+ def _policy_lines(report: dict[str, Any]) -> list[str]:
194
+ policy = report.get("policy")
195
+ if not policy:
183
196
  return []
184
- return ["## Hard Gate Failures", "",
185
- *(f"- {gate}" for gate in report["hard_gate_failures"]), ""]
197
+ failures = policy.get("failures") or []
198
+ head = (f"{policy.get('touched_functions', 0)} function(s) touched by "
199
+ f"`{policy.get('revspec')}` are held to this repository's stricter limits; "
200
+ "the grade is unaffected.")
201
+ if not failures:
202
+ return ["## Changed-code policy", "", head + " All of them meet it.", ""]
203
+ rows = [f"| `{f['path']}:{f['start_line']}` | `{f['name']}` | {f['measure']} | {f['value']} | {f['limit']} |"
204
+ for f in failures]
205
+ return ["## Changed-code policy", "", head, "",
206
+ "| Location | Function | Measure | Value | Limit |", "|---|---|---|---|---|", *rows, ""]
186
207
 
187
208
 
188
209
  def _no_work_order_lines() -> list[str]:
@@ -16,6 +16,8 @@ from typing import Any
16
16
 
17
17
  from ._analyzer_sections import analyzer_sections
18
18
  from ._built_ins import record_built_in_counts
19
+ from ._changed_code_policy import changed_code_limits
20
+ from ._changed_code_policy import evaluate as evaluate_changed_code_policy
19
21
  from ._delegated_pillar import read_delegated
20
22
  from ._discovery import Provenance, discover
21
23
  from ._economics import economic_context_from, economic_impact, reorder_by_exposure
@@ -36,7 +38,7 @@ from .deadcode import dead_declarations
36
38
  from .declarations import DECLARATION_SUFFIXES
37
39
  from .duplication import duplicate_blocks, risk_findings
38
40
  from .evidence import REPORT_SCHEMA_VERSION, SCHEMA_VERSION_KEY
39
- from .git_tools import probe_git, worktree_status
41
+ from .git_tools import added_lines, probe_git, worktree_status
40
42
  from .history import history_section
41
43
  from .idioms import divergent_idioms
42
44
  from .metrics import (
@@ -463,6 +465,32 @@ def _pillars_with_delegation(
463
465
  return pillars
464
466
 
465
467
 
468
+ def _attach_economics(report: dict[str, Any], config: dict[str, Any]) -> None:
469
+ """ADR 004 v1, after scoring on purpose.
470
+
471
+ Nothing money-shaped exists until the score document is final, so no
472
+ path from these numbers into the estimate or the grade can exist to be
473
+ misused.
474
+ """
475
+ context = economic_context_from(config)
476
+ if context is not None:
477
+ report["economic_impact"] = economic_impact(report, context)
478
+ reorder_by_exposure(report)
479
+
480
+
481
+ def _attach_policy(report: dict[str, Any], root: Path, config: dict[str, Any],
482
+ function_metrics: list[FunctionMetric], changed_revspec: str | None) -> None:
483
+ """The changed-code policy, beside the score and never inside it (Decision 15).
484
+
485
+ Only a repository that set a policy pays for the diff; without one
486
+ nothing new runs.
487
+ """
488
+ if not (changed_revspec and changed_code_limits(config)):
489
+ return
490
+ touched = {path: {n for n, _ in rows} for path, rows in added_lines(root, changed_revspec).items()}
491
+ report["policy"] = evaluate_changed_code_policy(function_metrics, touched, config, changed_revspec)
492
+
493
+
466
494
  def build_report(
467
495
  root: Path,
468
496
  config: dict[str, Any],
@@ -528,6 +556,7 @@ def build_report(
528
556
  report["tdd_structure"] = describe_tdd(root, file_metrics, function_metrics, source)
529
557
  _attach_test_suite(report, root, config)
530
558
  report["score"] = score_report(report, analyzer["pressures"])
559
+ _attach_policy(report, root, config, function_metrics, changed_revspec)
531
560
  # Condition rolls up aspects; practice stays a separate axis (ADR 007).
532
561
  report["practice"] = practice_level(root, config).as_dict()
533
562
  report["pillars"] = _pillars_with_delegation(report, root, security_pillar, changed_revspec, config)
@@ -535,11 +564,5 @@ def build_report(
535
564
  # Last, because every item's delta is a rubric recomputation and the
536
565
  # rubric needs the scored report to recompute against.
537
566
  report["work_order"] = work_order(report, thresholds=config["thresholds"])
538
- # ADR 004 v1, after scoring on purpose: nothing money-shaped exists
539
- # until the score document is final, so no path from these numbers
540
- # into the estimate or the grade can exist to be misused.
541
- context = economic_context_from(config)
542
- if context is not None:
543
- report["economic_impact"] = economic_impact(report, context)
544
- reorder_by_exposure(report)
567
+ _attach_economics(report, config)
545
568
  return report
@@ -0,0 +1,42 @@
1
+ """D226's fixes, against the installed tools.
2
+
3
+ Covers existing behaviour: these run the real interrogate and cohesion and
4
+ skip where a tool is not installed, so in an environment without them they
5
+ pass without proving anything. The falsifiers for the same changes are in
6
+ `test_analyzers_report_what_actually_failed.py` and need no tool; these
7
+ check that the fixes hold against the tools themselves.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import shutil
13
+ import subprocess
14
+ from pathlib import Path
15
+ from types import SimpleNamespace
16
+
17
+ import pytest
18
+
19
+ from maintainability_audit import _analysis
20
+ from maintainability_audit._runner import Outcome
21
+ from maintainability_audit._tool_adapters import ADAPTERS
22
+
23
+
24
+ @pytest.mark.skipif(shutil.which("cohesion") is None, reason="cohesion is not installed here")
25
+ def test_cohesions_availability_probe_is_a_flag_it_has() -> None:
26
+ probe = subprocess.run(list(ADAPTERS["cohesion"]().version_argv()), capture_output=True, text=True)
27
+
28
+ assert probe.returncode == 0, probe.stderr
29
+
30
+
31
+ @pytest.mark.skipif(shutil.which("interrogate") is None, reason="interrogate is not installed here")
32
+ def test_an_excluded_unparseable_file_no_longer_hides_the_percentage(tmp_path: Path) -> None:
33
+ (tmp_path / "app.py").write_text('"""Documented."""\n\n\ndef f():\n """Yes."""\n', encoding="utf-8")
34
+ (tmp_path / "vendor_corpus").mkdir()
35
+ (tmp_path / "vendor_corpus" / "old.py").write_text('print "python 2"\n', encoding="utf-8")
36
+ probe = SimpleNamespace(check=lambda slug, argv: SimpleNamespace(
37
+ usable=True, version="interrogate", outcome=Outcome.RAN, detail=""))
38
+
39
+ coverage = _analysis._attempt(tmp_path, ADAPTERS["interrogate"](), probe, 60, _analysis.Analysis(),
40
+ ("vendor_corpus/",))
41
+
42
+ assert coverage.outcome == "ran" and coverage.measurements == 1, coverage.detail or coverage.parse_error