maintainability-agent 4.0.1__tar.gz → 4.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. {maintainability_agent-4.0.1/src/maintainability_agent.egg-info → maintainability_agent-4.2.0}/PKG-INFO +17 -4
  2. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/README.md +16 -3
  3. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0/src/maintainability_agent.egg-info}/PKG-INFO +17 -4
  4. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_agent.egg-info/SOURCES.txt +7 -0
  5. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/__init__.py +1 -1
  6. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_adapters.py +17 -1
  7. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_analysis.py +46 -4
  8. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_calibration.py +9 -0
  9. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_jvm_adapters.py +8 -8
  10. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_metric_adapters.py +22 -31
  11. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_operator_reads.py +3 -1
  12. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_runner.py +35 -0
  13. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_security_delegate.py +23 -1
  14. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_verdict_adapters.py +4 -1
  15. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/config.py +19 -2
  16. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/report.py +5 -4
  17. maintainability_agent-4.2.0/tests/test_a_rendered_docs_site_is_not_scored_as_source.py +61 -0
  18. maintainability_agent-4.2.0/tests/test_analyzer_file_lists_are_batched.py +114 -0
  19. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_provenance.py +10 -21
  20. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_calibration_tooling.py +116 -0
  21. maintainability_agent-4.2.0/tests/test_cohesion_with_nothing_to_read_is_not_applicable.py +37 -0
  22. maintainability_agent-4.2.0/tests/test_exclude_additional_keeps_the_defaults.py +53 -0
  23. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_file_list_cap_class.py +17 -15
  24. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_readme_claims.py +16 -0
  25. maintainability_agent-4.2.0/tests/test_regular_file_reads_work_without_o_nonblock.py +28 -0
  26. maintainability_agent-4.2.0/tests/test_scanner_fingerprint_covers_the_measurement_path.py +75 -0
  27. maintainability_agent-4.2.0/tests/test_the_security_run_has_a_configurable_limit.py +61 -0
  28. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/LICENSE +0 -0
  29. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/pyproject.toml +0 -0
  30. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/setup.cfg +0 -0
  31. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  32. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  33. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
  34. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  35. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/__main__.py +0 -0
  36. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_analyzer_sections.py +0 -0
  37. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_anchor.py +0 -0
  38. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_arguments.py +0 -0
  39. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_aspects.py +0 -0
  40. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  41. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_assets/standard.md +0 -0
  42. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_attestation.py +0 -0
  43. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_backfill.py +0 -0
  44. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_bands.py +0 -0
  45. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_banner.py +0 -0
  46. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_built_ins.py +0 -0
  47. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_catalog.py +0 -0
  48. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_charts.py +0 -0
  49. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_cognitive.py +0 -0
  50. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_config_defaults.py +0 -0
  51. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_conformance.py +0 -0
  52. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_corroborate.py +0 -0
  53. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_coverage_notes.py +0 -0
  54. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_criteria_scope.py +0 -0
  55. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_delegated_pillar.py +0 -0
  56. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_derive.py +0 -0
  57. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_discovery.py +0 -0
  58. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_documents.py +0 -0
  59. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_economics.py +0 -0
  60. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_economics_view.py +0 -0
  61. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_environment.py +0 -0
  62. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_evidence_reader.py +0 -0
  63. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_evidence_view.py +0 -0
  64. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_finding_match.py +0 -0
  65. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_first_run.py +0 -0
  66. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_formula.py +0 -0
  67. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_gates.py +0 -0
  68. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_generic.py +0 -0
  69. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_grammar.py +0 -0
  70. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_grant_ledger.py +0 -0
  71. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_handoff.py +0 -0
  72. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_history_view.py +0 -0
  73. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
  74. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_hotspots.py +0 -0
  75. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_html_report_sections.py +0 -0
  76. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_html_view.py +0 -0
  77. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_identity.py +0 -0
  78. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_in_loop.py +0 -0
  79. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_in_loop_view.py +0 -0
  80. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_markdown_sections.py +0 -0
  81. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_masking.py +0 -0
  82. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_audit.py +0 -0
  83. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_gate.py +0 -0
  84. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_grants.py +0 -0
  85. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
  86. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_resources.py +0 -0
  87. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_mcp_setup.py +0 -0
  88. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_metrics_types.py +0 -0
  89. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_oracle.py +0 -0
  90. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_pillars.py +0 -0
  91. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_practice.py +0 -0
  92. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_precommit.py +0 -0
  93. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_precommit_install.py +0 -0
  94. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_precommit_view.py +0 -0
  95. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_pressures.py +0 -0
  96. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_prompt_sections.py +0 -0
  97. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_c.py +0 -0
  98. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_cobol.py +0 -0
  99. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_core.py +0 -0
  100. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
  101. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
  102. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
  103. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_go.py +0 -0
  104. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_java.py +0 -0
  105. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_js.py +0 -0
  106. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_kotlin.py +0 -0
  107. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_php.py +0 -0
  108. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_ruby.py +0 -0
  109. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_rust.py +0 -0
  110. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_shell.py +0 -0
  111. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ranges_swift.py +0 -0
  112. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ratchet.py +0 -0
  113. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_ratio_adapters.py +0 -0
  114. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_recurrence.py +0 -0
  115. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_run_comparison.py +0 -0
  116. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_running_version.py +0 -0
  117. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_safe_write.py +0 -0
  118. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_scan_history.py +0 -0
  119. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_scan_view.py +0 -0
  120. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_second_source.py +0 -0
  121. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_security_work_order.py +0 -0
  122. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_selection.py +0 -0
  123. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_semantic.py +0 -0
  124. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_semantic_policy.py +0 -0
  125. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_semantic_ts.py +0 -0
  126. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_semantic_view.py +0 -0
  127. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_setup_errors.py +0 -0
  128. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_setup_persist.py +0 -0
  129. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  130. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  131. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  132. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  133. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  134. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  135. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_skill_install.py +0 -0
  136. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_stored_grants.py +0 -0
  137. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_tdd_view.py +0 -0
  138. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_test_commands.py +0 -0
  139. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_test_execution.py +0 -0
  140. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_test_pairing.py +0 -0
  141. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_tokens.py +0 -0
  142. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_tool_adapters.py +0 -0
  143. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_trends.py +0 -0
  144. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_user_config.py +0 -0
  145. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_verification.py +0 -0
  146. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_work_order.py +0 -0
  147. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_work_order_view.py +0 -0
  148. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_work_order_weights.py +0 -0
  149. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/_xml.py +0 -0
  150. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/baseline.py +0 -0
  151. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/cli.py +0 -0
  152. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/deadcode.py +0 -0
  153. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/declarations.py +0 -0
  154. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/duplication.py +0 -0
  155. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/evidence.py +0 -0
  156. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/git_tools.py +0 -0
  157. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/history.py +0 -0
  158. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/idioms.py +0 -0
  159. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/instructions.py +0 -0
  160. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/mcp_server.py +0 -0
  161. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/metrics.py +0 -0
  162. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/prompts.py +0 -0
  163. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/renderers.py +0 -0
  164. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/sarif.py +0 -0
  165. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/scoring.py +0 -0
  166. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/similarity.py +0 -0
  167. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/src/maintainability_audit/source.py +0 -0
  168. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_clone_names_every_copy.py +0 -0
  169. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_dangling_source_link_is_named_not_fatal.py +0 -0
  170. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_format_override_is_disclosed.py +0 -0
  171. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_matching_format_stays_silent.py +0 -0
  172. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_published_question_offers_what_it_accepts.py +0 -0
  173. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_a_setup_question_keeps_its_contract.py +0 -0
  174. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_acquisition_trust.py +0 -0
  175. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_adapter_docs.py +0 -0
  176. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_adapter_recordings.py +0 -0
  177. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_adapters.py +0 -0
  178. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_added_lines.py +0 -0
  179. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_an_absent_work_order_renders_nothing.py +0 -0
  180. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_an_unmeasured_pillar_reports_no_number.py +0 -0
  181. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analysis_coverage.py +0 -0
  182. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analysis_execution.py +0 -0
  183. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_bridge.py +0 -0
  184. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_config_isolation.py +0 -0
  185. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_estimate_claims.py +0 -0
  186. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_pinning.py +0 -0
  187. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_primary_estimate.py +0 -0
  188. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
  189. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_scoring_path.py +0 -0
  190. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_spread_range.py +0 -0
  191. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_analyzer_xml_bounds.py +0 -0
  192. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_anchor_and_mode.py +0 -0
  193. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_anchor_caveat_and_counts_follow_the_run.py +0 -0
  194. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_anchor_disclosure.py +0 -0
  195. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_annotations_match_behaviour.py +0 -0
  196. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_anticipated_refusals.py +0 -0
  197. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_architecture.py +0 -0
  198. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_artifact_write_route_class.py +0 -0
  199. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_aspect_coverage.py +0 -0
  200. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_asset_snapshot_class.py +0 -0
  201. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
  202. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_attestation.py +0 -0
  203. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_audit_components.py +0 -0
  204. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_authorization_freshness.py +0 -0
  205. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_authorship_gates.py +0 -0
  206. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_backfill.py +0 -0
  207. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_band_concealment_class.py +0 -0
  208. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_band_concealment_p3.py +0 -0
  209. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_band_pressures.py +0 -0
  210. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_bands.py +0 -0
  211. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_behaviour_suites_are_tests.py +0 -0
  212. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_body_or_signature_class.py +0 -0
  213. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_both_setup_paths_ask_the_same_stage.py +0 -0
  214. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_build_output_is_not_the_repositorys_code.py +0 -0
  215. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_c_declarations.py +0 -0
  216. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_calibration_corpus.py +0 -0
  217. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_calibration_drift.py +0 -0
  218. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_catalog_selection.py +0 -0
  219. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_catalog_tier_promise.py +0 -0
  220. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_chat_leads_with_the_work_order.py +0 -0
  221. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_chat_primary_docs.py +0 -0
  222. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  223. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_checkstyle_adapter.py +0 -0
  224. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_checkstyle_catalog.py +0 -0
  225. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_child_sandbox.py +0 -0
  226. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_ci_history_recipe.py +0 -0
  227. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  228. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_claimed_languages.py +0 -0
  229. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_clean_sees_the_weakened_oracle.py +0 -0
  230. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_cli.py +0 -0
  231. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_clone_group_class.py +0 -0
  232. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_cobol_declarations.py +0 -0
  233. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_code_scanning_gets_alerts_not_the_record.py +0 -0
  234. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_cognitive_complexity.py +0 -0
  235. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_cohort_statistics.py +0 -0
  236. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_concealment_properties.py +0 -0
  237. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_config_shape.py +0 -0
  238. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_conformance_reads_the_operators_ask.py +0 -0
  239. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_consent_and_grant.py +0 -0
  240. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_consent_is_per_repository.py +0 -0
  241. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_consent_survives_setup_and_is_asked.py +0 -0
  242. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_consent_without_command_has_a_remedy.py +0 -0
  243. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_consumer_migration.py +0 -0
  244. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_contract_claims.py +0 -0
  245. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_corpus_note_counts_come_from_the_corpus.py +0 -0
  246. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_corroborate.py +0 -0
  247. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_coverage_by_language.py +0 -0
  248. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_coverage_config_reaches_children.py +0 -0
  249. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_coverage_formats.py +0 -0
  250. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_cpp_declarations.py +0 -0
  251. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_criteria_completion.py +0 -0
  252. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_csharp_declarations.py +0 -0
  253. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_current_state_docs_name_every_parsed_language.py +0 -0
  254. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_d15_composition.py +0 -0
  255. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_d15_goal_directed.py +0 -0
  256. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_dead_code.py +0 -0
  257. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declaration_criteria_scope.py +0 -0
  258. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declaration_edge_cases.py +0 -0
  259. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declaration_grading.py +0 -0
  260. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declaration_ranges.py +0 -0
  261. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declaration_source.py +0 -0
  262. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declarative_parsers.py +0 -0
  263. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declared_capabilities_match_the_delegate.py +0 -0
  264. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_declared_imports.py +0 -0
  265. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_delegated_security_pillar.py +0 -0
  266. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_demo_tree.py +0 -0
  267. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_derivation_mix.py +0 -0
  268. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_determinism.py +0 -0
  269. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_dimension_ratchet.py +0 -0
  270. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_direct_runner_availability_class.py +0 -0
  271. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_discovery.py +0 -0
  272. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_doc_claims.py +0 -0
  273. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_docs_links.py +0 -0
  274. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_economic_context.py +0 -0
  275. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_empty_output_not_clean.py +0 -0
  276. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
  277. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_environment_work_order.py +0 -0
  278. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_built_presentation_is_offered.py +0 -0
  279. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_language_counts_its_own_loop.py +0 -0
  280. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_language_has_a_loop_fixture.py +0 -0
  281. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_pool_install_is_the_same_pool.py +0 -0
  282. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_question_can_be_answered.py +0 -0
  283. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_every_surface_says_what_the_run_found.py +0 -0
  284. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_evidence_invariants.py +0 -0
  285. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_evidence_normalization.py +0 -0
  286. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_evidence_properties.py +0 -0
  287. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_example_config_opens_claimed_languages.py +0 -0
  288. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_exclusion_dialects.py +0 -0
  289. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_exposure_never_outranks_band.py +0 -0
  290. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_falsifier_standard.py +0 -0
  291. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_finding_identity.py +0 -0
  292. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_first_run_elicitation.py +0 -0
  293. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_first_run_prompt.py +0 -0
  294. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_first_run_reelicitation.py +0 -0
  295. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_first_stage_setup_wording_holds.py +0 -0
  296. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_fix_breadth_window.py +0 -0
  297. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_fixed_form_fortran.py +0 -0
  298. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_format_ask.py +0 -0
  299. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_fortran_declarations.py +0 -0
  300. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_fortran_metrics.py +0 -0
  301. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_fortran_practice.py +0 -0
  302. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_git_argv.py +0 -0
  303. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_git_read_only.py +0 -0
  304. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_git_readonly_class.py +0 -0
  305. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_go_declarations.py +0 -0
  306. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_grammar_constructs.py +0 -0
  307. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_grammar_token_coverage.py +0 -0
  308. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_grant_only_user_tier.py +0 -0
  309. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_grok_audit_of_3_11.py +0 -0
  310. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_history.py +0 -0
  311. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_history_boundary.py +0 -0
  312. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_history_manifest.py +0 -0
  313. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_history_schema2.py +0 -0
  314. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_history_window.py +0 -0
  315. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_hostile_prompt.py +0 -0
  316. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_html_executive.py +0 -0
  317. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_html_section_parity_class.py +0 -0
  318. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_identity_docs.py +0 -0
  319. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_identity_resolution.py +0 -0
  320. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_idiom_divergence.py +0 -0
  321. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_in_loop_budgets.py +0 -0
  322. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_in_loop_check.py +0 -0
  323. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_installed_wheel_runtime.py +0 -0
  324. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_instruction_targets.py +0 -0
  325. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_java_range_guard.py +0 -0
  326. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_java_ranges.py +0 -0
  327. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_java_scored.py +0 -0
  328. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_java_wiring.py +0 -0
  329. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_js_complexity_operators.py +0 -0
  330. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_js_declarations.py +0 -0
  331. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_kotlin_declarations.py +0 -0
  332. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_kotlin_metrics.py +0 -0
  333. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_language_coverage.py +0 -0
  334. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_language_support_honesty.py +0 -0
  335. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_list_tools_publishes_the_answer_path.py +0 -0
  336. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_maintenance_signals.py +0 -0
  337. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mcp_baseline_payload.py +0 -0
  338. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mcp_format_contract.py +0 -0
  339. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mcp_history.py +0 -0
  340. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mcp_server.py +0 -0
  341. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mcp_start_failure_names_what_is_installed.py +0 -0
  342. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_migration_1_0.py +0 -0
  343. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_missing_security_scanners_are_named_before_the_run.py +0 -0
  344. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_mutation_recorded.py +0 -0
  345. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_near_duplicates.py +0 -0
  346. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_network_disclosure.py +0 -0
  347. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
  348. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_operator_named_paths.py +0 -0
  349. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_operator_named_reads.py +0 -0
  350. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_oracle_weakening_precision_bar.py +0 -0
  351. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pairing_reads_imports.py +0 -0
  352. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pattern_budget.py +0 -0
  353. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_phase6_claims.py +0 -0
  354. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_php_declarations.py +0 -0
  355. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pillars_and_practice.py +0 -0
  356. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_platform_claim.py +0 -0
  357. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pmd_adapter.py +0 -0
  358. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pmd_audit_closures.py +0 -0
  359. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_policy_claims.py +0 -0
  360. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_pool_runs_by_config.py +0 -0
  361. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_population_floors.py +0 -0
  362. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_practice_nested_gates_class.py +0 -0
  363. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_precommit_staged.py +0 -0
  364. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_preflight_before_consent_runs_nothing_from_the_tree.py +0 -0
  365. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_presentation_refusals.py +0 -0
  366. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_previous_release_reached_pypi.py +0 -0
  367. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_promises.py +0 -0
  368. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  369. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_prompt_escalation_once.py +0 -0
  370. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_prompt_honesty.py +0 -0
  371. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_prompt_location_escalation_class.py +0 -0
  372. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_prove_falsifiers.py +0 -0
  373. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_python_complexity.py +0 -0
  374. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_python_declarations.py +0 -0
  375. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_read_boundary.py +0 -0
  376. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_recurrence.py +0 -0
  377. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_release_needs_an_empty_ledger.py +0 -0
  378. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_release_plan.py +0 -0
  379. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_release_plan_status.py +0 -0
  380. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_rendered_docs.py +0 -0
  381. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_report_remedy_copy.py +0 -0
  382. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_root_grants.py +0 -0
  383. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  384. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_ruby_declarations.py +0 -0
  385. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_run_comparison.py +0 -0
  386. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_runner.py +0 -0
  387. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_rust_declarations.py +0 -0
  388. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_sarif.py +0 -0
  389. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scan_history.py +0 -0
  390. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scan_scope.py +0 -0
  391. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scanner_unsafe_direction.py +0 -0
  392. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scanning.py +0 -0
  393. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_schema_fidelity.py +0 -0
  394. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scope_conformance.py +0 -0
  395. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_scoring_calibration.py +0 -0
  396. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_security_delegate_versions_agree.py +0 -0
  397. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_security_findings_keep_their_handoff.py +0 -0
  398. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_security_pillar_asserts_a_scanner_set.py +0 -0
  399. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_security_pillar_runs_and_shows.py +0 -0
  400. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_selection_covers_every_parsed_language.py +0 -0
  401. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_semantic_findings_stay_inside_the_audited_files.py +0 -0
  402. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_semantic_policy.py +0 -0
  403. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_answers_are_the_same_setup.py +0 -0
  404. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_gate_completeness.py +0 -0
  405. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_gate_independent_contract.py +0 -0
  406. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_instruction_describes_its_own_reply.py +0 -0
  407. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_precondition.py +0 -0
  408. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_setup_writes_a_valid_config.py +0 -0
  409. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_shell_declarations.py +0 -0
  410. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_shell_metrics.py +0 -0
  411. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_skill_install.py +0 -0
  412. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_sonar_resolve.py +0 -0
  413. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_source_index.py +0 -0
  414. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_spotbugs_adapter.py +0 -0
  415. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_spotbugs_catalog.py +0 -0
  416. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_stage8_contract.py +0 -0
  417. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_stamped_documents_stay_honest.py +0 -0
  418. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_stdout_outputs.py +0 -0
  419. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_suite_isolation.py +0 -0
  420. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_swift_declarations.py +0 -0
  421. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_tdd_structure.py +0 -0
  422. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_terminal_asks_the_same_questions.py +0 -0
  423. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_test_commands.py +0 -0
  424. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_test_execution_class.py +0 -0
  425. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_agent_knows_when_it_is_stale.py +0 -0
  426. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_changelog_covers_the_shipping_version.py +0 -0
  427. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_chat_payload_has_a_budget.py +0 -0
  428. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_condition_says_what_it_measured.py +0 -0
  429. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_handoff_rules_are_their_own_module.py +0 -0
  430. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_pillar_row_reads_cleanly.py +0 -0
  431. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_presentation_question_stays_answerable.py +0 -0
  432. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_previous_release_was_tagged.py +0 -0
  433. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_prompt_does_not_take_back_what_it_withheld.py +0 -0
  434. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_prompt_keeps_listing_what_it_did_not_withhold.py +0 -0
  435. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_release_process_describes_itself.py +0 -0
  436. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_release_record_stays_well_formed.py +0 -0
  437. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_report_is_saved_not_sent.py +0 -0
  438. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_security_work_order_is_drawn.py +0 -0
  439. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_suite_names_the_program_it_ran.py +0 -0
  440. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_tree_cannot_redirect_a_read.py +0 -0
  441. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_the_version_has_one_source.py +0 -0
  442. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_three_presentations.py +0 -0
  443. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_tool_resolution.py +0 -0
  444. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  445. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_tree_chosen_spawn.py +0 -0
  446. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_tree_reads_use_the_primitive.py +0 -0
  447. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_trends.py +0 -0
  448. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_type_fields_not_functions_class.py +0 -0
  449. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_uat_falsifiers.py +0 -0
  450. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_unanchored_set_matches_corpus.py +0 -0
  451. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_unread_code.py +0 -0
  452. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_user_config_tier.py +0 -0
  453. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_verification_audit_closures.py +0 -0
  454. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_verified_grade.py +0 -0
  455. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_version_claim.py +0 -0
  456. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_version_stamping.py +0 -0
  457. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_wheel_contents.py +0 -0
  458. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_withheld_work_keeps_its_boundary.py +0 -0
  459. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_work_items_state_their_own_finding.py +0 -0
  460. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_work_order.py +0 -0
  461. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  462. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_work_order_items.py +0 -0
  463. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_work_order_selection.py +0 -0
  464. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_workflow_supply_chain.py +0 -0
  465. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_write_boundary.py +0 -0
  466. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_write_route_class.py +0 -0
  467. {maintainability_agent-4.0.1 → maintainability_agent-4.2.0}/tests/test_written_record.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 4.0.1
3
+ Version: 4.2.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.0.1**.
50
+ Version **4.2.0**.
51
51
 
52
52
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
53
53
  >
@@ -56,6 +56,11 @@ Version **4.0.1**.
56
56
  > taste, each pinned to the exact commit it was measured at, so anyone can
57
57
  > re-run the calibration and get the same numbers. The median of that corpus
58
58
  > scores a **B**. [How the corpus is chosen and measured](docs/standard.md#the-reference-corpus).
59
+ >
60
+ > So your grade places your code against those 201: a **B** means you are at
61
+ > the median of mature, widely used open source. The corpus is re-measured
62
+ > whenever the instrument changes — in 4.1.0 every file of even the largest
63
+ > repositories was read, and the scale came back unchanged to four decimals.
59
64
 
60
65
  **Languages parsed:** Python, Java, Kotlin, C, C++, C#, Go, Rust, PHP, Ruby,
61
66
  Swift, Shell, COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -93,7 +98,10 @@ you what it could not measure.
93
98
  **Install secure-code-agent for the security pillar.** Every audit runs it; it is
94
99
  installed alongside rather than as a dependency, so the two tools release
95
100
  independently. Without it the report says the security pillar was not measured
96
- and gives this command. Its scanners decide what it can grade — see
101
+ and gives this command. A full security run can take several minutes on a
102
+ large repository; the audit waits up to 15 minutes for it, and
103
+ `security.timeout_seconds` in `maintainability-agent.json` changes that. Its
104
+ scanners decide what it can grade — see
97
105
  [machine setup](docs/machine-setup.md#3-toolchain) for which to install, and
98
106
  don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
99
107
 
@@ -356,6 +364,11 @@ signals on:
356
364
  - an ISO/IEC 25010-inspired 0–5 estimate per category, and a verified grade —
357
365
  or a disclosed withholding when the evidence is thin.
358
366
 
367
+ **Large repositories are measured whole.** Every file is handed to the
368
+ analyzers, split across as many runs as the command line needs, so a big
369
+ codebase is read rather than sampled — FFmpeg's 4,687 files, not the first
370
+ 1,543 that fitted on one command line before 4.1.0.
371
+
359
372
  The analyzer is intentionally conservative and under-reports rather than
360
373
  over-reports: an unrecognized declaration costs one missed finding, never a
361
374
  cascade of false ones. Pair it with native tools (ESLint, Ruff, Radon, Semgrep,
@@ -496,7 +509,7 @@ instead of an invokable skill:
496
509
  This repo ships `action.yml`, usable as a composite action:
497
510
 
498
511
  ```yaml
499
- - uses: marshallguillory86/maintainability-agent@v4.0.1
512
+ - uses: marshallguillory86/maintainability-agent@v4.2.0
500
513
  with:
501
514
  config: maintainability-agent.json
502
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.0.1**.
8
+ Version **4.2.0**.
9
9
 
10
10
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
11
11
  >
@@ -14,6 +14,11 @@ Version **4.0.1**.
14
14
  > taste, each pinned to the exact commit it was measured at, so anyone can
15
15
  > re-run the calibration and get the same numbers. The median of that corpus
16
16
  > scores a **B**. [How the corpus is chosen and measured](docs/standard.md#the-reference-corpus).
17
+ >
18
+ > So your grade places your code against those 201: a **B** means you are at
19
+ > the median of mature, widely used open source. The corpus is re-measured
20
+ > whenever the instrument changes — in 4.1.0 every file of even the largest
21
+ > repositories was read, and the scale came back unchanged to four decimals.
17
22
 
18
23
  **Languages parsed:** Python, Java, Kotlin, C, C++, C#, Go, Rust, PHP, Ruby,
19
24
  Swift, Shell, COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -51,7 +56,10 @@ you what it could not measure.
51
56
  **Install secure-code-agent for the security pillar.** Every audit runs it; it is
52
57
  installed alongside rather than as a dependency, so the two tools release
53
58
  independently. Without it the report says the security pillar was not measured
54
- and gives this command. Its scanners decide what it can grade — see
59
+ and gives this command. A full security run can take several minutes on a
60
+ large repository; the audit waits up to 15 minutes for it, and
61
+ `security.timeout_seconds` in `maintainability-agent.json` changes that. Its
62
+ scanners decide what it can grade — see
55
63
  [machine setup](docs/machine-setup.md#3-toolchain) for which to install, and
56
64
  don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
57
65
 
@@ -314,6 +322,11 @@ signals on:
314
322
  - an ISO/IEC 25010-inspired 0–5 estimate per category, and a verified grade —
315
323
  or a disclosed withholding when the evidence is thin.
316
324
 
325
+ **Large repositories are measured whole.** Every file is handed to the
326
+ analyzers, split across as many runs as the command line needs, so a big
327
+ codebase is read rather than sampled — FFmpeg's 4,687 files, not the first
328
+ 1,543 that fitted on one command line before 4.1.0.
329
+
317
330
  The analyzer is intentionally conservative and under-reports rather than
318
331
  over-reports: an unrecognized declaration costs one missed finding, never a
319
332
  cascade of false ones. Pair it with native tools (ESLint, Ruff, Radon, Semgrep,
@@ -454,7 +467,7 @@ instead of an invokable skill:
454
467
  This repo ships `action.yml`, usable as a composite action:
455
468
 
456
469
  ```yaml
457
- - uses: marshallguillory86/maintainability-agent@v4.0.1
470
+ - uses: marshallguillory86/maintainability-agent@v4.2.0
458
471
  with:
459
472
  config: maintainability-agent.json
460
473
  changed-only: main...HEAD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 4.0.1
3
+ Version: 4.2.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.0.1**.
50
+ Version **4.2.0**.
51
51
 
52
52
  > ## **Calibrated against 201 mature open-source repositories in fifteen languages.**
53
53
  >
@@ -56,6 +56,11 @@ Version **4.0.1**.
56
56
  > taste, each pinned to the exact commit it was measured at, so anyone can
57
57
  > re-run the calibration and get the same numbers. The median of that corpus
58
58
  > scores a **B**. [How the corpus is chosen and measured](docs/standard.md#the-reference-corpus).
59
+ >
60
+ > So your grade places your code against those 201: a **B** means you are at
61
+ > the median of mature, widely used open source. The corpus is re-measured
62
+ > whenever the instrument changes — in 4.1.0 every file of even the largest
63
+ > repositories was read, and the scale came back unchanged to four decimals.
59
64
 
60
65
  **Languages parsed:** Python, Java, Kotlin, C, C++, C#, Go, Rust, PHP, Ruby,
61
66
  Swift, Shell, COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -93,7 +98,10 @@ you what it could not measure.
93
98
  **Install secure-code-agent for the security pillar.** Every audit runs it; it is
94
99
  installed alongside rather than as a dependency, so the two tools release
95
100
  independently. Without it the report says the security pillar was not measured
96
- and gives this command. Its scanners decide what it can grade — see
101
+ and gives this command. A full security run can take several minutes on a
102
+ large repository; the audit waits up to 15 minutes for it, and
103
+ `security.timeout_seconds` in `maintainability-agent.json` changes that. Its
104
+ scanners decide what it can grade — see
97
105
  [machine setup](docs/machine-setup.md#3-toolchain) for which to install, and
98
106
  don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
99
107
 
@@ -356,6 +364,11 @@ signals on:
356
364
  - an ISO/IEC 25010-inspired 0–5 estimate per category, and a verified grade —
357
365
  or a disclosed withholding when the evidence is thin.
358
366
 
367
+ **Large repositories are measured whole.** Every file is handed to the
368
+ analyzers, split across as many runs as the command line needs, so a big
369
+ codebase is read rather than sampled — FFmpeg's 4,687 files, not the first
370
+ 1,543 that fitted on one command line before 4.1.0.
371
+
359
372
  The analyzer is intentionally conservative and under-reports rather than
360
373
  over-reports: an unrecognized declaration costs one missed finding, never a
361
374
  cascade of false ones. Pair it with native tools (ESLint, Ruff, Radon, Semgrep,
@@ -496,7 +509,7 @@ instead of an invokable skill:
496
509
  This repo ships `action.yml`, usable as a composite action:
497
510
 
498
511
  ```yaml
499
- - uses: marshallguillory86/maintainability-agent@v4.0.1
512
+ - uses: marshallguillory86/maintainability-agent@v4.2.0
500
513
  with:
501
514
  config: maintainability-agent.json
502
515
  changed-only: main...HEAD
@@ -157,6 +157,7 @@ tests/test_a_dangling_source_link_is_named_not_fatal.py
157
157
  tests/test_a_format_override_is_disclosed.py
158
158
  tests/test_a_matching_format_stays_silent.py
159
159
  tests/test_a_published_question_offers_what_it_accepts.py
160
+ tests/test_a_rendered_docs_site_is_not_scored_as_source.py
160
161
  tests/test_a_setup_question_keeps_its_contract.py
161
162
  tests/test_acquisition_trust.py
162
163
  tests/test_adapter_docs.py
@@ -170,6 +171,7 @@ tests/test_analysis_execution.py
170
171
  tests/test_analyzer_bridge.py
171
172
  tests/test_analyzer_config_isolation.py
172
173
  tests/test_analyzer_estimate_claims.py
174
+ tests/test_analyzer_file_lists_are_batched.py
173
175
  tests/test_analyzer_pinning.py
174
176
  tests/test_analyzer_primary_estimate.py
175
177
  tests/test_analyzer_provenance.py
@@ -221,6 +223,7 @@ tests/test_clone_group_class.py
221
223
  tests/test_cobol_declarations.py
222
224
  tests/test_code_scanning_gets_alerts_not_the_record.py
223
225
  tests/test_cognitive_complexity.py
226
+ tests/test_cohesion_with_nothing_to_read_is_not_applicable.py
224
227
  tests/test_cohort_statistics.py
225
228
  tests/test_concealment_properties.py
226
229
  tests/test_config_shape.py
@@ -274,6 +277,7 @@ tests/test_evidence_invariants.py
274
277
  tests/test_evidence_normalization.py
275
278
  tests/test_evidence_properties.py
276
279
  tests/test_example_config_opens_claimed_languages.py
280
+ tests/test_exclude_additional_keeps_the_defaults.py
277
281
  tests/test_exclusion_dialects.py
278
282
  tests/test_exposure_never_outranks_band.py
279
283
  tests/test_falsifier_standard.py
@@ -365,6 +369,7 @@ tests/test_python_declarations.py
365
369
  tests/test_read_boundary.py
366
370
  tests/test_readme_claims.py
367
371
  tests/test_recurrence.py
372
+ tests/test_regular_file_reads_work_without_o_nonblock.py
368
373
  tests/test_release_needs_an_empty_ledger.py
369
374
  tests/test_release_plan.py
370
375
  tests/test_release_plan_status.py
@@ -379,6 +384,7 @@ tests/test_rust_declarations.py
379
384
  tests/test_sarif.py
380
385
  tests/test_scan_history.py
381
386
  tests/test_scan_scope.py
387
+ tests/test_scanner_fingerprint_covers_the_measurement_path.py
382
388
  tests/test_scanner_unsafe_direction.py
383
389
  tests/test_scanning.py
384
390
  tests/test_schema_fidelity.py
@@ -426,6 +432,7 @@ tests/test_the_prompt_keeps_listing_what_it_did_not_withhold.py
426
432
  tests/test_the_release_process_describes_itself.py
427
433
  tests/test_the_release_record_stays_well_formed.py
428
434
  tests/test_the_report_is_saved_not_sent.py
435
+ tests/test_the_security_run_has_a_configurable_limit.py
429
436
  tests/test_the_security_work_order_is_drawn.py
430
437
  tests/test_the_suite_names_the_program_it_ran.py
431
438
  tests/test_the_tree_cannot_redirect_a_read.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "4.0.1"
3
+ __version__ = "4.2.0"
@@ -35,7 +35,7 @@ from pathlib import Path
35
35
  from typing import Any, Protocol
36
36
 
37
37
  from ._metrics_types import Finding, Measurement
38
- from ._runner import Invocation, ToolResult
38
+ from ._runner import Invocation, ToolResult, batches
39
39
 
40
40
 
41
41
  class Exclusions(tuple): # noqa: SLOT001 - attribute is set once in __new__
@@ -315,6 +315,22 @@ class BaseAdapter:
315
315
  cwd=root if self.exclude_dialect == "rel_regex" else None,
316
316
  )
317
317
 
318
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...] | None:
319
+ """The explicit files this tool is handed, or None when it walks a directory."""
320
+ return None
321
+
322
+ def invocations(self, root: Path, excludes: Sequence[str] = ()) -> list[Invocation]:
323
+ """Every run needed to read the whole tree.
324
+
325
+ One, for a tool that walks a directory. For a tool handed explicit
326
+ files, one per batch that fits a command line — the list used to
327
+ be cut to one argv instead, so the largest trees were read in part.
328
+ """
329
+ files = self.target_files(root, excludes)
330
+ if not files:
331
+ return [self.invocation(root, excludes=excludes)]
332
+ return [self.invocation(root, batch, excludes=excludes) for batch in batches(files)]
333
+
318
334
  def parse(self, result: ToolResult) -> Extraction:
319
335
  if not result.usable:
320
336
  return Extraction(parse_error=result.detail or f"{self.slug} did not run")
@@ -37,7 +37,7 @@ from ._built_ins import BUILT_IN_SOURCES
37
37
  from ._catalog import CONCERNS, PolicyError, concepts_for, resolve_pool, settings_from
38
38
  from ._discovery import CATALOG_LANGUAGE, discover
39
39
  from ._metrics_types import KNOWN_SOURCE_SUFFIXES, Finding, Measurement
40
- from ._runner import Outcome, Probe, run
40
+ from ._runner import Outcome, Probe, ToolResult, run
41
41
  from ._selection import Selected, select_runnable
42
42
  from .config import acquisition_permitted
43
43
 
@@ -446,12 +446,11 @@ def _attempt(root: Path, adapter: Any, probe: Probe, timeout: int,
446
446
  ),
447
447
  )
448
448
 
449
- result = run(adapter.slug, adapter.invocation(root, excludes=excludes),
450
- timeout_seconds=timeout)
449
+ result, parsed = _run_batches(adapter, root, excludes, timeout)
451
450
  # Filtered before the counts are taken, not after. Recording 48
452
451
  # measurements and reporting 6 describes an activity rather than a
453
452
  # result, which is the defect this project keeps finding.
454
- extraction = _ours_only_extraction(adapter.parse(result), root, adapter, excludes, inventory)
453
+ extraction = _ours_only_extraction(parsed, root, adapter, excludes, inventory)
455
454
  # ADR 012: an artifact-read tool states its staleness on the row it
456
455
  # ran on, and its findings are labeled when the bytecode is older
457
456
  # than the source — the method existing was not the promise
@@ -477,6 +476,49 @@ def _attempt(root: Path, adapter: Any, probe: Probe, timeout: int,
477
476
  )
478
477
 
479
478
 
479
+ def _run_batches(adapter: Any, root: Path, excludes: Sequence[str],
480
+ timeout: int) -> tuple[ToolResult, Extraction]:
481
+ """Every run the adapter needs, each parsed as it finishes, then merged.
482
+
483
+ A tool handed explicit files runs once per batch that fits a command
484
+ line; each is parsed before the next, because some tools rewrite one
485
+ results file per run. A batch that fails stops the rest and its outcome
486
+ is the tool's: a partial reading must not pass for a whole one.
487
+ """
488
+ planned = getattr(adapter, "invocations", None)
489
+ invocations = planned(root, excludes) if planned else [adapter.invocation(root, excludes=excludes)]
490
+ results: list[ToolResult] = []
491
+ parsed: list[Extraction] = []
492
+ for invocation in invocations:
493
+ result = run(adapter.slug, invocation, timeout_seconds=timeout)
494
+ results.append(result)
495
+ parsed.append(adapter.parse(result))
496
+ if not result.usable:
497
+ break
498
+ if len(results) == 1:
499
+ return results[0], parsed[0]
500
+ return _merged_result(results, len(invocations)), _merged_extraction(parsed)
501
+
502
+
503
+ def _merged_result(results: list[ToolResult], planned: int) -> ToolResult:
504
+ failed = next((r for r in results if not r.usable), None)
505
+ basis = failed or results[0]
506
+ detail = (f"batch {len(results)} of {planned} failed: {failed.detail}" if failed
507
+ else f"read in {planned} batches, one command line each")
508
+ return replace(basis, detail=detail,
509
+ duration_seconds=sum(r.duration_seconds for r in results))
510
+
511
+
512
+ def _merged_extraction(parsed: list[Extraction]) -> Extraction:
513
+ return Extraction(
514
+ measurements=tuple(m for e in parsed for m in e.measurements),
515
+ findings=tuple(f for e in parsed for f in e.findings),
516
+ parse_error=next((e.parse_error for e in parsed if e.parse_error), None),
517
+ raw="\n".join(e.raw for e in parsed if e.raw),
518
+ truncated=any(e.truncated for e in parsed),
519
+ )
520
+
521
+
480
522
  def _collect(extraction: Extraction, adapter: Any, analysis: Analysis) -> None:
481
523
  # `measurements_only` is the enforcement point, not a formality: a
482
524
  # verdict emitter that started returning measurements would silently
@@ -219,6 +219,15 @@ CATEGORIES = ["modularity", "reusability", "analyzability", "modifiability", "te
219
219
  # moves 52 at the published decimal. Published grades move, so this is a
220
220
  # major version, on the same reasoning as 3.0.0. The corpus median still
221
221
  # rolls up to exactly 4.0000.
222
+ #
223
+ # **2026-10-03, every file read (4.1.0).** D220: analyzers handed a file
224
+ # list used to be cut to one command line, so the largest repositories were
225
+ # read in part (FFmpeg's multimetric saw 1,543 of 4,687 files). All 201 rows
226
+ # were re-measured with the list split across runs, and with the scanner
227
+ # fingerprint covering the whole measurement path (D221). Ten rows' analyzer
228
+ # readings moved; no built-in reading did. Every reference and CALIBRATION_C
229
+ # re-derived to the same four decimals, and no repository's score moved at
230
+ # the published decimal or changed grade, so the constants stand as shipped.
222
231
  DIMENSION_REFERENCES: dict[str, float] = {
223
232
  "file_size": 0.0871,
224
233
  "declarations": 0.0929,
@@ -78,14 +78,14 @@ class PmdAdapter(BaseAdapter):
78
78
  """
79
79
  return bool(expand_files(root, excludes, suffixes=(".java",)))
80
80
 
81
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
82
+ return expand_files(root, excludes, suffixes=(".java",))
83
+
81
84
  def invocation(
82
85
  self, root: Path, paths: Iterable[str] | None = None,
83
86
  excludes: Sequence[str] = (),
84
87
  ) -> Invocation:
85
- targets = (
86
- tuple(paths) if paths
87
- else expand_files(root, excludes, suffixes=(".java",))
88
- )
88
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
89
89
  dirs: tuple[str, ...] = ()
90
90
  for target in targets:
91
91
  dirs += ("--dir", target)
@@ -173,14 +173,14 @@ class CheckstyleAdapter(BaseAdapter):
173
173
  """Whether any .java file survives the exclusions (never spawn empty)."""
174
174
  return bool(expand_files(root, excludes, suffixes=(".java",)))
175
175
 
176
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
177
+ return expand_files(root, excludes, suffixes=(".java",))
178
+
176
179
  def invocation(
177
180
  self, root: Path, paths: Iterable[str] | None = None,
178
181
  excludes: Sequence[str] = (),
179
182
  ) -> Invocation:
180
- targets = (
181
- tuple(paths) if paths
182
- else expand_files(root, excludes, suffixes=(".java",))
183
- )
183
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
184
184
  return Invocation(
185
185
  argv=("checkstyle", "-c", "/google_checks.xml",
186
186
  "-f", "xml", *targets),
@@ -13,8 +13,6 @@ from __future__ import annotations
13
13
  import csv
14
14
  import io
15
15
  import json
16
- import logging
17
- import os
18
16
  import re
19
17
  import tempfile
20
18
  from collections.abc import Iterable, Sequence
@@ -31,16 +29,6 @@ def _rows(text: str) -> list[list[str]]:
31
29
 
32
30
  SOURCE_SUFFIXES = (".py", ".js", ".mjs", ".cjs", ".ts", ".java", ".c", ".cpp",
33
31
  ".h", ".go", ".rb", ".php")
34
- # A file list has to fit on a command line. The old fixed cap of 400 was
35
- # arbitrary and silent -- ~20 KB against an ARG_MAX of a megabyte -- so it
36
- # truncated ordinary trees for no OS reason and said nothing (e88b429 #5).
37
- # The budget is a quarter of the real ARG_MAX (room left for the exe, flags
38
- # and env); beyond it a single invocation genuinely cannot name every file,
39
- # and `expand_files` states the truncation through the logger, not silently.
40
- _ARG_MAX = os.sysconf("SC_ARG_MAX") if hasattr(os, "sysconf") else 262144
41
- _ARGV_BYTE_BUDGET = max(_ARG_MAX // 4, 131072)
42
-
43
- logger = logging.getLogger(__name__)
44
32
 
45
33
 
46
34
  def expand_files(
@@ -74,22 +62,8 @@ def expand_files(
74
62
  and not any(part in skip for part in path.parts)
75
63
  and not covers(path.relative_to(root).as_posix())
76
64
  ]
77
- kept: list[str] = []
78
- used = 0
79
- for name in eligible:
80
- used += len(name.encode("utf-8")) + 1 # +1 for the argv separator
81
- if used > _ARGV_BYTE_BUDGET and kept:
82
- break
83
- kept.append(name)
84
- if len(kept) < len(eligible):
85
- # Stated, not silent: a shortened file list is a shortened audit,
86
- # and the reader has to know the tool saw only part of the tree.
87
- logger.warning(
88
- "file list for %s truncated to %d of %d files (%d-byte argv budget); "
89
- "the remaining %d were not handed to the analyzer",
90
- root, len(kept), len(eligible), _ARGV_BYTE_BUDGET, len(eligible) - len(kept),
91
- )
92
- return tuple(kept)
65
+ return tuple(eligible)
66
+
93
67
 
94
68
 
95
69
 
@@ -224,6 +198,9 @@ class ComplexipyAdapter(BaseAdapter):
224
198
  )
225
199
  self._work = Path(tempfile.mkdtemp(prefix="complexipy-"))
226
200
 
201
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
202
+ return expand_files(root.resolve(), excludes)
203
+
227
204
  def invocation(
228
205
  self, root: Path, paths: Iterable[str] | None = None,
229
206
  excludes: Sequence[str] = (),
@@ -231,7 +208,7 @@ class ComplexipyAdapter(BaseAdapter):
231
208
  # complexipy has no exclusion flag, so the filtering is done by
232
209
  # naming files rather than handing it a directory. Without this it
233
210
  # walks .venv and attributes vendored complexity to the user.
234
- targets = tuple(paths) if paths else expand_files(root.resolve(), excludes)
211
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
235
212
  return Invocation(
236
213
  argv=(self.executable, *targets, "--output-format", "json", "--quiet"),
237
214
  findings_exit_codes=self.findings_exit_codes,
@@ -287,11 +264,14 @@ class MultimetricAdapter(BaseAdapter):
287
264
  version_flag="--help", distribution="multimetric",
288
265
  )
289
266
 
267
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
268
+ return expand_files(root, excludes)
269
+
290
270
  def invocation(
291
271
  self, root: Path, paths: Iterable[str] | None = None,
292
272
  excludes: Sequence[str] = (),
293
273
  ) -> Invocation:
294
- targets = tuple(paths) if paths else expand_files(root, excludes)
274
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
295
275
  return Invocation(argv=(self.executable, *targets))
296
276
 
297
277
  def _read(self, result: ToolResult) -> Extraction:
@@ -347,6 +327,17 @@ class CohesionAdapter(BaseAdapter):
347
327
  distribution="cohesion",
348
328
  )
349
329
 
330
+ def has_targets(self, root: Path, excludes: Sequence[str] = ()) -> bool:
331
+ """Whether any .py file survives the exclusions.
332
+
333
+ With none, cohesion was spawned with an empty `--files` and exited 2,
334
+ so every repository without Python recorded it as failed.
335
+ """
336
+ return bool(self.target_files(root, excludes))
337
+
338
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
339
+ return expand_files(root, excludes, suffixes=(".py",))
340
+
350
341
  def invocation(
351
342
  self, root: Path, paths: Iterable[str] | None = None,
352
343
  excludes: Sequence[str] = (),
@@ -354,7 +345,7 @@ class CohesionAdapter(BaseAdapter):
354
345
  # Explicit files: cohesion has no exclude flag, so what it must
355
346
  # not read is excluded by never being named — the same rule as
356
347
  # complexipy and multimetric.
357
- targets = tuple(paths) if paths else expand_files(root, excludes, suffixes=(".py",))
348
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
358
349
  return Invocation(argv=(self.executable, "--files", *targets))
359
350
 
360
351
  def _read(self, result: ToolResult) -> Extraction:
@@ -55,7 +55,9 @@ def open_regular_file(path: Path, why: str) -> int:
55
55
  """
56
56
  import stat as stat_module
57
57
 
58
- handle = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
58
+ # Windows has no `O_NONBLOCK` and no POSIX FIFO in the tree to guard
59
+ # against; using the flag unconditionally killed every read there.
60
+ handle = os.open(path, os.O_RDONLY | getattr(os, "O_NONBLOCK", 0))
59
61
  if not stat_module.S_ISREG(os.fstat(handle).st_mode):
60
62
  os.close(handle)
61
63
  raise PathNotAllowed(f"{path} is not a regular file. {why}")
@@ -35,6 +35,7 @@ import sys
35
35
  import sysconfig
36
36
  import tempfile
37
37
  import time
38
+ from collections.abc import Sequence
38
39
  from contextlib import suppress
39
40
  from dataclasses import dataclass, field
40
41
  from enum import StrEnum
@@ -63,6 +64,40 @@ class Outcome(StrEnum):
63
64
  FAILED = "failed"
64
65
 
65
66
 
67
+ # A file list has to fit on a command line. The old fixed cap of 400 was
68
+ # arbitrary and silent -- ~20 KB against an ARG_MAX of a megabyte -- so it
69
+ # truncated ordinary trees for no OS reason and said nothing (e88b429 #5).
70
+ # The budget is a quarter of the real ARG_MAX (room left for the exe, flags
71
+ # and env). Beyond it one invocation cannot name every file, so the list is
72
+ # split by `batches` and the tool runs once per batch; nothing is cut. The
73
+ # cut, stated in a log line, left FFmpeg's analyzers reading 1,543 of its
74
+ # 4,687 files in the 4.0.0 corpus run.
75
+ _ARG_MAX = os.sysconf("SC_ARG_MAX") if hasattr(os, "sysconf") else 262144
76
+ _ARGV_BYTE_BUDGET = max(_ARG_MAX // 4, 131072)
77
+
78
+
79
+ def batches(files: Sequence[str], budget: int | None = None) -> list[tuple[str, ...]]:
80
+ """The file list in order, split so each part fits one command line.
81
+
82
+ A single name longer than the budget still gets a batch of its own:
83
+ refusing it would drop a file, which is the defect this replaces.
84
+ """
85
+ limit = budget if budget is not None else _ARGV_BYTE_BUDGET
86
+ out: list[tuple[str, ...]] = []
87
+ current: list[str] = []
88
+ used = 0
89
+ for name in files:
90
+ size = len(name.encode("utf-8")) + 1 # +1 for the argv separator
91
+ if current and used + size > limit:
92
+ out.append(tuple(current))
93
+ current, used = [], 0
94
+ current.append(name)
95
+ used += size
96
+ if current:
97
+ out.append(tuple(current))
98
+ return out
99
+
100
+
66
101
  @dataclass(frozen=True)
67
102
  class Invocation:
68
103
  """How to run one tool. Described by adapters, executed only here."""
@@ -88,7 +88,29 @@ SUPPORTED_CEILING = (1,)
88
88
  REQUIREMENT = "secure-code-agent>=0.12.10,<1"
89
89
 
90
90
  #: How long the child may run before the pillar is reported as unmeasured.
91
- DEFAULT_TIMEOUT_SECONDS = 300
91
+ #: 300 until a full run on this repository took about 8½ minutes and both
92
+ #: audits of it reported the pillar unmeasured; 900 is about twice that.
93
+ #: Configurable as `security.timeout_seconds`, through `security_timeout`.
94
+ DEFAULT_TIMEOUT_SECONDS = 900
95
+
96
+
97
+ def security_timeout(config: dict[str, Any]) -> int:
98
+ """The configured limit for the security run, held to the analyzer band.
99
+
100
+ A repository naming a number is naming how long this host waits, so it
101
+ gets the clamp `analyzers.timeout_seconds` has (D40's family): 1 second
102
+ to 1 hour, and the default for anything that is not an integer.
103
+ """
104
+ from ._catalog import MAX_TIMEOUT_SECONDS, MIN_TIMEOUT_SECONDS
105
+
106
+ configured = (config.get("security") or {}).get("timeout_seconds", DEFAULT_TIMEOUT_SECONDS)
107
+ if isinstance(configured, bool):
108
+ return DEFAULT_TIMEOUT_SECONDS
109
+ try:
110
+ seconds = int(configured)
111
+ except (TypeError, ValueError):
112
+ return DEFAULT_TIMEOUT_SECONDS
113
+ return max(MIN_TIMEOUT_SECONDS, min(seconds, MAX_TIMEOUT_SECONDS))
92
114
 
93
115
  _ENTRY = "import sys; from secure_code_audit.cli import main; sys.exit(main())"
94
116
 
@@ -209,6 +209,9 @@ class PydocstyleAdapter(BaseAdapter):
209
209
  exclude_flag="--match-dir", exclude_separator="|", exclude_dialect="files",
210
210
  )
211
211
 
212
+ def target_files(self, root: Path, excludes: Sequence[str] = ()) -> tuple[str, ...]:
213
+ return expand_files(root, excludes, suffixes=(".py",))
214
+
212
215
  def invocation(
213
216
  self, root: Path, paths: Iterable[str] | None = None,
214
217
  excludes: Sequence[str] = (),
@@ -226,7 +229,7 @@ class PydocstyleAdapter(BaseAdapter):
226
229
  an include regex sitting beside an explicit file list can only
227
230
  narrow it further in ways nobody asked for.
228
231
  """
229
- targets = tuple(paths) if paths else expand_files(root, excludes, suffixes=(".py",))
232
+ targets = tuple(paths) if paths else self.target_files(root, excludes)
230
233
  return Invocation(
231
234
  argv=(self.executable, *self.extra_args, *targets),
232
235
  findings_exit_codes=self.findings_exit_codes,
@@ -161,12 +161,29 @@ def load_config(path: str | None) -> dict[str, Any]:
161
161
  return config
162
162
  config["analyzers"]["run"] = True
163
163
  if user_tier is not None:
164
- deep_update(config, user_tier)
164
+ _merge_tier(config, user_tier)
165
165
  if path:
166
- deep_update(config, _host_authority_stripped(_configured(Path(path))))
166
+ _merge_tier(config, _host_authority_stripped(_configured(Path(path))))
167
167
  return config
168
168
 
169
169
 
170
+ def _merge_tier(config: dict[str, Any], tier: dict[str, Any]) -> None:
171
+ """One tier over the ones before it, with `exclude_additional` appended.
172
+
173
+ `deep_update` replaces lists, so setting `paths.exclude_patterns` to add
174
+ one directory discarded every default exclusion and froze a copy that
175
+ drifts on the next release (#292). `exclude_additional` adds to whatever
176
+ the earlier tiers produced instead, so a repository can add without
177
+ restating.
178
+ """
179
+ added = list((tier.get("paths") or {}).get("exclude_additional") or [])
180
+ deep_update(config, tier)
181
+ paths = config["paths"]
182
+ paths.pop("exclude_additional", None)
183
+ paths["exclude_patterns"] = [*paths["exclude_patterns"],
184
+ *(p for p in added if p not in paths["exclude_patterns"])]
185
+
186
+
170
187
  #: The one key a repository may state and this tool will not act on,
171
188
  #: because acting on it runs a program of the tree's choosing on the host.
172
189
  #: The whole leaf is dropped, not merged.