maintainability-agent 3.6.0__tar.gz → 3.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. {maintainability_agent-3.6.0/src/maintainability_agent.egg-info → maintainability_agent-3.6.2}/PKG-INFO +2 -2
  2. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/README.md +1 -1
  3. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/pyproject.toml +1 -1
  4. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
  5. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/SOURCES.txt +4 -0
  6. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/__init__.py +1 -1
  7. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/standard.md +14 -2
  8. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics.py +11 -2
  9. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_view.py +21 -4
  10. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_view.py +3 -3
  11. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop.py +11 -4
  12. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit.py +10 -6
  13. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_prompt_sections.py +83 -16
  14. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order.py +84 -16
  15. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_view.py +35 -3
  16. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_weights.py +29 -10
  17. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/config.py +1 -1
  18. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/prompts.py +31 -15
  19. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/renderers.py +17 -11
  20. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/report.py +20 -4
  21. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/scoring.py +9 -5
  22. maintainability_agent-3.6.2/tests/test_anchor_caveat_and_counts_follow_the_run.py +164 -0
  23. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_grading.py +11 -2
  24. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_demo_tree.py +8 -1
  25. maintainability_agent-3.6.2/tests/test_every_surface_says_what_the_run_found.py +239 -0
  26. maintainability_agent-3.6.2/tests/test_exposure_never_outranks_band.py +66 -0
  27. maintainability_agent-3.6.2/tests/test_work_items_state_their_own_finding.py +313 -0
  28. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/LICENSE +0 -0
  29. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/setup.cfg +0 -0
  30. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  31. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  32. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/requires.txt +0 -0
  33. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  34. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/__main__.py +0 -0
  35. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_adapters.py +0 -0
  36. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_analysis.py +0 -0
  37. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_analyzer_sections.py +0 -0
  38. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_anchor.py +0 -0
  39. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_arguments.py +0 -0
  40. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_aspects.py +0 -0
  41. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  42. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_attestation.py +0 -0
  43. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_backfill.py +0 -0
  44. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_bands.py +0 -0
  45. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_banner.py +0 -0
  46. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_built_ins.py +0 -0
  47. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_calibration.py +0 -0
  48. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_catalog.py +0 -0
  49. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_charts.py +0 -0
  50. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_cognitive.py +0 -0
  51. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_config_defaults.py +0 -0
  52. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_conformance.py +0 -0
  53. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_corroborate.py +0 -0
  54. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_coverage_notes.py +0 -0
  55. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_criteria_scope.py +0 -0
  56. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_delegated_pillar.py +0 -0
  57. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_derive.py +0 -0
  58. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_discovery.py +0 -0
  59. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_documents.py +0 -0
  60. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics_view.py +0 -0
  61. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_environment.py +0 -0
  62. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_reader.py +0 -0
  63. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_finding_match.py +0 -0
  64. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_first_run.py +0 -0
  65. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_formula.py +0 -0
  66. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_gates.py +0 -0
  67. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_generic.py +0 -0
  68. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_grammar.py +0 -0
  69. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_grant_ledger.py +0 -0
  70. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_history_view.py +0 -0
  71. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_hostile_prompt.py +0 -0
  72. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_hotspots.py +0 -0
  73. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_report_sections.py +0 -0
  74. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_identity.py +0 -0
  75. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop_view.py +0 -0
  76. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_jvm_adapters.py +0 -0
  77. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_markdown_sections.py +0 -0
  78. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_masking.py +0 -0
  79. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_audit.py +0 -0
  80. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_gate.py +0 -0
  81. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_grants.py +0 -0
  82. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_refusals.py +0 -0
  83. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_resources.py +0 -0
  84. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_setup.py +0 -0
  85. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_metric_adapters.py +0 -0
  86. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_metrics_types.py +0 -0
  87. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_operator_reads.py +0 -0
  88. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_pillars.py +0 -0
  89. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_practice.py +0 -0
  90. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_install.py +0 -0
  91. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_view.py +0 -0
  92. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_pressures.py +0 -0
  93. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_c.py +0 -0
  94. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cobol.py +0 -0
  95. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_core.py +0 -0
  96. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cpp.py +0 -0
  97. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_csharp.py +0 -0
  98. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_fortran.py +0 -0
  99. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_go.py +0 -0
  100. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_java.py +0 -0
  101. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_js.py +0 -0
  102. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_php.py +0 -0
  103. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_ruby.py +0 -0
  104. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_rust.py +0 -0
  105. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_swift.py +0 -0
  106. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratchet.py +0 -0
  107. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratio_adapters.py +0 -0
  108. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_recurrence.py +0 -0
  109. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_run_comparison.py +0 -0
  110. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_runner.py +0 -0
  111. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_safe_write.py +0 -0
  112. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_history.py +0 -0
  113. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_view.py +0 -0
  114. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_second_source.py +0 -0
  115. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_selection.py +0 -0
  116. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic.py +0 -0
  117. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_policy.py +0 -0
  118. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_ts.py +0 -0
  119. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_view.py +0 -0
  120. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_errors.py +0 -0
  121. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_persist.py +0 -0
  122. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  123. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  124. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  125. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  126. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  127. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  128. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_install.py +0 -0
  129. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_stored_grants.py +0 -0
  130. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tdd_view.py +0 -0
  131. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_commands.py +0 -0
  132. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_execution.py +0 -0
  133. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_pairing.py +0 -0
  134. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tokens.py +0 -0
  135. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_tool_adapters.py +0 -0
  136. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_trends.py +0 -0
  137. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_user_config.py +0 -0
  138. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_verdict_adapters.py +0 -0
  139. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_verification.py +0 -0
  140. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/_xml.py +0 -0
  141. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/baseline.py +0 -0
  142. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/cli.py +0 -0
  143. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/deadcode.py +0 -0
  144. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/declarations.py +0 -0
  145. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/duplication.py +0 -0
  146. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/evidence.py +0 -0
  147. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/git_tools.py +0 -0
  148. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/history.py +0 -0
  149. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/idioms.py +0 -0
  150. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/instructions.py +0 -0
  151. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/mcp_server.py +0 -0
  152. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/metrics.py +0 -0
  153. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/sarif.py +0 -0
  154. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/similarity.py +0 -0
  155. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/src/maintainability_audit/source.py +0 -0
  156. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_acquisition_trust.py +0 -0
  157. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapter_docs.py +0 -0
  158. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapter_recordings.py +0 -0
  159. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_adapters.py +0 -0
  160. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_added_lines.py +0 -0
  161. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analysis_coverage.py +0 -0
  162. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analysis_execution.py +0 -0
  163. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_bridge.py +0 -0
  164. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_config_isolation.py +0 -0
  165. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_estimate_claims.py +0 -0
  166. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_pinning.py +0 -0
  167. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_primary_estimate.py +0 -0
  168. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance.py +0 -0
  169. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance_exclusions.py +0 -0
  170. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_scoring_path.py +0 -0
  171. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_spread_range.py +0 -0
  172. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_analyzer_xml_bounds.py +0 -0
  173. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anchor_and_mode.py +0 -0
  174. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anchor_disclosure.py +0 -0
  175. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_annotations_match_behaviour.py +0 -0
  176. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_anticipated_refusals.py +0 -0
  177. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_architecture.py +0 -0
  178. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_artifact_write_route_class.py +0 -0
  179. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_aspect_coverage.py +0 -0
  180. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_asset_snapshot_class.py +0 -0
  181. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ast_reading_resolves_spellings.py +0 -0
  182. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_attestation.py +0 -0
  183. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_audit_components.py +0 -0
  184. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_authorization_freshness.py +0 -0
  185. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_authorship_gates.py +0 -0
  186. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_backfill.py +0 -0
  187. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_concealment_class.py +0 -0
  188. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_concealment_p3.py +0 -0
  189. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_band_pressures.py +0 -0
  190. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_bands.py +0 -0
  191. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_body_or_signature_class.py +0 -0
  192. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_c_declarations.py +0 -0
  193. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_corpus.py +0 -0
  194. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_drift.py +0 -0
  195. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_calibration_tooling.py +0 -0
  196. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_catalog_selection.py +0 -0
  197. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_catalog_tier_promise.py +0 -0
  198. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_chat_leads_with_the_work_order.py +0 -0
  199. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_chat_primary_docs.py +0 -0
  200. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  201. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_checkstyle_adapter.py +0 -0
  202. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_checkstyle_catalog.py +0 -0
  203. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_child_sandbox.py +0 -0
  204. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ci_history_recipe.py +0 -0
  205. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  206. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_claimed_languages.py +0 -0
  207. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cli.py +0 -0
  208. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_clone_group_class.py +0 -0
  209. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cobol_declarations.py +0 -0
  210. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cognitive_complexity.py +0 -0
  211. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cohort_statistics.py +0 -0
  212. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_concealment_properties.py +0 -0
  213. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_config_shape.py +0 -0
  214. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_consent_and_grant.py +0 -0
  215. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_consumer_migration.py +0 -0
  216. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_contract_claims.py +0 -0
  217. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_corroborate.py +0 -0
  218. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_coverage_by_language.py +0 -0
  219. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_cpp_declarations.py +0 -0
  220. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_criteria_completion.py +0 -0
  221. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_csharp_declarations.py +0 -0
  222. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_d15_composition.py +0 -0
  223. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_d15_goal_directed.py +0 -0
  224. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_dead_code.py +0 -0
  225. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_criteria_scope.py +0 -0
  226. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_edge_cases.py +0 -0
  227. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_ranges.py +0 -0
  228. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declaration_source.py +0 -0
  229. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declarative_parsers.py +0 -0
  230. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declared_authorship.py +0 -0
  231. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_declared_imports.py +0 -0
  232. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_delegated_security_pillar.py +0 -0
  233. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_derivation_mix.py +0 -0
  234. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_determinism.py +0 -0
  235. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_dimension_ratchet.py +0 -0
  236. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_direct_runner_availability_class.py +0 -0
  237. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_discovery.py +0 -0
  238. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_doc_claims.py +0 -0
  239. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_docs_links.py +0 -0
  240. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_economic_context.py +0 -0
  241. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean.py +0 -0
  242. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean_adapters.py +0 -0
  243. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_environment_work_order.py +0 -0
  244. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_invariants.py +0 -0
  245. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_normalization.py +0 -0
  246. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_evidence_properties.py +0 -0
  247. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_example_config_opens_claimed_languages.py +0 -0
  248. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_exclusion_dialects.py +0 -0
  249. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_falsifier_standard.py +0 -0
  250. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_file_list_cap_class.py +0 -0
  251. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_finding_identity.py +0 -0
  252. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_elicitation.py +0 -0
  253. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_prompt.py +0 -0
  254. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_first_run_reelicitation.py +0 -0
  255. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fix_breadth_window.py +0 -0
  256. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fixed_form_fortran.py +0 -0
  257. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_format_ask.py +0 -0
  258. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_declarations.py +0 -0
  259. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_metrics.py +0 -0
  260. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_fortran_practice.py +0 -0
  261. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_argv.py +0 -0
  262. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_read_only.py +0 -0
  263. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_git_readonly_class.py +0 -0
  264. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_go_declarations.py +0 -0
  265. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grammar_constructs.py +0 -0
  266. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grammar_token_coverage.py +0 -0
  267. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_grant_only_user_tier.py +0 -0
  268. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history.py +0 -0
  269. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_boundary.py +0 -0
  270. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_manifest.py +0 -0
  271. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_schema2.py +0 -0
  272. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_history_window.py +0 -0
  273. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_hostile_prompt.py +0 -0
  274. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_html_executive.py +0 -0
  275. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_html_section_parity_class.py +0 -0
  276. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_identity_docs.py +0 -0
  277. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_identity_resolution.py +0 -0
  278. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_idiom_divergence.py +0 -0
  279. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_in_loop_budgets.py +0 -0
  280. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_in_loop_check.py +0 -0
  281. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_installed_wheel_runtime.py +0 -0
  282. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_instruction_targets.py +0 -0
  283. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_range_guard.py +0 -0
  284. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_ranges.py +0 -0
  285. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_scored.py +0 -0
  286. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_java_wiring.py +0 -0
  287. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_js_complexity_operators.py +0 -0
  288. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_js_declarations.py +0 -0
  289. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_language_coverage.py +0 -0
  290. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_language_support_honesty.py +0 -0
  291. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_baseline_payload.py +0 -0
  292. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_format_contract.py +0 -0
  293. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_history.py +0 -0
  294. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_mcp_server.py +0 -0
  295. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_migration_1_0.py +0 -0
  296. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_near_duplicates.py +0 -0
  297. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_network_disclosure.py +0 -0
  298. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_one_setup_across_surfaces_class.py +0 -0
  299. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_operator_named_paths.py +0 -0
  300. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_operator_named_reads.py +0 -0
  301. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pairing_reads_imports.py +0 -0
  302. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pattern_budget.py +0 -0
  303. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_phase6_claims.py +0 -0
  304. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_php_declarations.py +0 -0
  305. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pillars_and_practice.py +0 -0
  306. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_platform_claim.py +0 -0
  307. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pmd_adapter.py +0 -0
  308. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pmd_audit_closures.py +0 -0
  309. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_policy_claims.py +0 -0
  310. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_pool_runs_by_config.py +0 -0
  311. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_population_floors.py +0 -0
  312. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_practice_nested_gates_class.py +0 -0
  313. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_precommit_staged.py +0 -0
  314. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_presentation_refusals.py +0 -0
  315. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_promises.py +0 -0
  316. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  317. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_escalation_once.py +0 -0
  318. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_honesty.py +0 -0
  319. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prompt_location_escalation_class.py +0 -0
  320. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_prove_falsifiers.py +0 -0
  321. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_python_complexity.py +0 -0
  322. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_python_declarations.py +0 -0
  323. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_read_boundary.py +0 -0
  324. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_readme_claims.py +0 -0
  325. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_recurrence.py +0 -0
  326. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_needs_an_empty_ledger.py +0 -0
  327. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_plan.py +0 -0
  328. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_release_plan_status.py +0 -0
  329. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_report_remedy_copy.py +0 -0
  330. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_roles_recorded.py +0 -0
  331. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_root_grants.py +0 -0
  332. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  333. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_ruby_declarations.py +0 -0
  334. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_run_comparison.py +0 -0
  335. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_runner.py +0 -0
  336. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_rust_declarations.py +0 -0
  337. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_sarif.py +0 -0
  338. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scan_history.py +0 -0
  339. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scan_scope.py +0 -0
  340. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scanner_unsafe_direction.py +0 -0
  341. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scanning.py +0 -0
  342. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_schema_fidelity.py +0 -0
  343. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scope_conformance.py +0 -0
  344. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_scoring_calibration.py +0 -0
  345. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_semantic_policy.py +0 -0
  346. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_gate_completeness.py +0 -0
  347. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_gate_independent_contract.py +0 -0
  348. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_setup_precondition.py +0 -0
  349. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_skill_install.py +0 -0
  350. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_sonar_resolve.py +0 -0
  351. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_source_index.py +0 -0
  352. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_spotbugs_adapter.py +0 -0
  353. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_spotbugs_catalog.py +0 -0
  354. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_stage8_contract.py +0 -0
  355. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_stdout_outputs.py +0 -0
  356. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_suite_isolation.py +0 -0
  357. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_swift_declarations.py +0 -0
  358. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tdd_structure.py +0 -0
  359. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_terminal_asks_the_same_questions.py +0 -0
  360. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_test_commands.py +0 -0
  361. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_test_execution_class.py +0 -0
  362. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_three_presentations.py +0 -0
  363. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tool_resolution.py +0 -0
  364. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  365. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_chosen_spawn.py +0 -0
  366. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_tree_reads_use_the_primitive.py +0 -0
  367. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_trends.py +0 -0
  368. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_type_fields_not_functions_class.py +0 -0
  369. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_uat_falsifiers.py +0 -0
  370. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_unanchored_set_matches_corpus.py +0 -0
  371. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_unread_code.py +0 -0
  372. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_user_config_tier.py +0 -0
  373. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_verification_audit_closures.py +0 -0
  374. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_verified_grade.py +0 -0
  375. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_version_claim.py +0 -0
  376. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_wheel_contents.py +0 -0
  377. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order.py +0 -0
  378. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  379. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_items.py +0 -0
  380. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_work_order_selection.py +0 -0
  381. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_workflow_supply_chain.py +0 -0
  382. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_write_boundary.py +0 -0
  383. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_write_route_class.py +0 -0
  384. {maintainability_agent-3.6.0 → maintainability_agent-3.6.2}/tests/test_written_record.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 3.6.0
3
+ Version: 3.6.2
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -46,7 +46,7 @@ Dynamic: license-file
46
46
  **A deterministic, offline maintainability audit whose output is a _bounded
47
47
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
48
48
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
49
- Version **3.6.0**.
49
+ Version **3.6.2**.
50
50
 
51
51
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
52
52
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -5,7 +5,7 @@
5
5
  **A deterministic, offline maintainability audit whose output is a _bounded
6
6
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
7
7
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
8
- Version **3.6.0**.
8
+ Version **3.6.2**.
9
9
 
10
10
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
11
11
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "3.6.0"
7
+ version = "3.6.2"
8
8
  description = "Maintainability gate and AI remediation prompt generator for CI."
9
9
  readme = "README.md"
10
10
  # 3.11, not 3.10. `_discovery`, `_pillars` and `_runner` all import
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 3.6.0
3
+ Version: 3.6.2
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -46,7 +46,7 @@ Dynamic: license-file
46
46
  **A deterministic, offline maintainability audit whose output is a _bounded
47
47
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
48
48
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
49
- Version **3.6.0**.
49
+ Version **3.6.2**.
50
50
 
51
51
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
52
52
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -163,6 +163,7 @@ tests/test_analyzer_scoring_path.py
163
163
  tests/test_analyzer_spread_range.py
164
164
  tests/test_analyzer_xml_bounds.py
165
165
  tests/test_anchor_and_mode.py
166
+ tests/test_anchor_caveat_and_counts_follow_the_run.py
166
167
  tests/test_anchor_disclosure.py
167
168
  tests/test_annotations_match_behaviour.py
168
169
  tests/test_anticipated_refusals.py
@@ -235,11 +236,13 @@ tests/test_economic_context.py
235
236
  tests/test_empty_output_not_clean.py
236
237
  tests/test_empty_output_not_clean_adapters.py
237
238
  tests/test_environment_work_order.py
239
+ tests/test_every_surface_says_what_the_run_found.py
238
240
  tests/test_evidence_invariants.py
239
241
  tests/test_evidence_normalization.py
240
242
  tests/test_evidence_properties.py
241
243
  tests/test_example_config_opens_claimed_languages.py
242
244
  tests/test_exclusion_dialects.py
245
+ tests/test_exposure_never_outranks_band.py
243
246
  tests/test_falsifier_standard.py
244
247
  tests/test_file_list_cap_class.py
245
248
  tests/test_finding_identity.py
@@ -368,6 +371,7 @@ tests/test_verification_audit_closures.py
368
371
  tests/test_verified_grade.py
369
372
  tests/test_version_claim.py
370
373
  tests/test_wheel_contents.py
374
+ tests/test_work_items_state_their_own_finding.py
371
375
  tests/test_work_order.py
372
376
  tests/test_work_order_binds_to_this_interpreter.py
373
377
  tests/test_work_order_items.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "3.6.0"
3
+ __version__ = "3.6.2"
@@ -351,7 +351,7 @@ place it in one of four bands:
351
351
 
352
352
  | Finding class | Risk | Effort | Band | Why |
353
353
  |---|---:|---:|---|---|
354
- | `risk-pattern` | 5 | 1 | **quick-win** | a configured risk pattern is a rule this project chose to enforce on itself, and each hit is a single located line |
354
+ | `risk-pattern` | 5 | 1 | **quick-win** | a risk pattern is a rule the active configuration enforces, and each hit is a single located line |
355
355
  | `oversized-declaration` | 4 | 2 | **quick-win** | a long, branching function is where defects concentrate and where every future change has to be understood first; extracting one is bounded, local work |
356
356
  | `unpaired-hotspot` | 4 | 2 | **quick-win** | an oversized production unit with no paired test is where changes land unguarded; adding a characterization test is bounded, local work |
357
357
  | `duplicate-block` | 4 | 4 | **major-project** | duplicated logic means a fix applied in one place and missed in the others; deduplicating across a codebase is a design change, not a tidy-up |
@@ -360,6 +360,15 @@ place it in one of four bands:
360
360
  | `dead-code` | 2 | 1 | **fill-in** | unreachable code costs reading time and misleads a search, but deleting it is the cheapest change there is |
361
361
  | `competing-libraries` | 2 | 4 | **reconsider** | two libraries doing one job is a decision nobody made; converging on one is a migration across every call site |
362
362
 
363
+ **A band is a judgment about the class, not a size for the item.** The
364
+ effort above is declared once per finding class, so a 2876-line class and a
365
+ 90-line function share `oversized-declaration`'s band. The *Why* column is
366
+ that class-level judgment and is published here; a work item does not repeat
367
+ its effort claim. Each item instead states its own reading — its kind, and
368
+ each figure against the limit it is graded on (`currently 2876 lines against
369
+ the 300-line class limit`) — so a reader, or an agent sizing the work, has
370
+ the fact rather than the class's estimate of it (D164).
371
+
363
372
  **Why Major Projects are withheld from the agent prompt.** An agent told to
364
373
  deduplicate a pattern across forty files produces exactly the sprawling,
365
374
  unreviewable diff a bounded prompt exists to prevent. The work is real and
@@ -369,7 +378,10 @@ appears in the report; scoping it is a human's job first.
369
378
  what clearing that single finding moves the published score — honestly zero
370
379
  more often than not, because the overall is the mean of the *rounded*
371
380
  categories and is therefore a step function. `class_delta` is what clearing
372
- every finding of that class is worth, and it is what the ordering uses.
381
+ every finding of that class is worth, and it is what the band ordering uses
382
+ within a band. When an economic context is configured, ADR 004's exposure
383
+ sort takes its place *inside* each band — never across bands, so a Fill-In
384
+ never leads a Quick Win (D170) — and the work order's heading says so (D169).
373
385
  Neither is estimated: both come from re-running `score_report` over a summary
374
386
  with those findings removed. Per-item deltas do not sum to the whole.
375
387
 
@@ -133,18 +133,27 @@ def _exposure(item: dict[str, Any], churn: dict[str, int],
133
133
 
134
134
 
135
135
  def reorder_by_exposure(report: dict[str, Any]) -> None:
136
- """Most-exposed first, in place, keeping every item intact.
136
+ """Most-exposed first within each band, in place, keeping every item intact.
137
137
 
138
138
  Applied only when an economic context exists: exposure is the
139
139
  ordering that context asks for, and without one the risk-by-effort
140
140
  order stands untouched. The sort moves whole items, so severity,
141
141
  risk, effort, band and class delta stay on each one — the standard
142
142
  evidence is reordered, never erased.
143
+
144
+ **Band stays the primary key (D170).** This sorted on exposure alone,
145
+ so a Fill-In on a file that changes often led a Quick Win on a stable
146
+ one — the nit-loop ADR 007 §3 rule 5 forbids. ADR 004 asks for the work
147
+ order to be reordered by exposure; it never asked for exposure to
148
+ outrank band, so ordering within a band satisfies both as written.
143
149
  """
150
+ from ._work_order import BAND_ORDER
151
+
144
152
  churn = _churn_by_path(report)
145
153
  returns = _returns_by_fingerprint(report)
146
154
  items = report.get("work_order") or []
147
- items.sort(key=lambda item: (-_exposure(item, churn, returns),
155
+ items.sort(key=lambda item: (BAND_ORDER.get(item.get("band") or "", len(BAND_ORDER)),
156
+ -_exposure(item, churn, returns),
148
157
  item.get("title") or ""))
149
158
 
150
159
 
@@ -26,6 +26,7 @@ compatibility semantics.
26
26
  """
27
27
  from __future__ import annotations
28
28
 
29
+ from collections.abc import Iterable
29
30
  from typing import Any
30
31
 
31
32
  # A foundation, not the scoring layer: grammar is neither scoring nor
@@ -346,17 +347,33 @@ def test_suite_lines(block: dict[str, Any] | None) -> list[str]:
346
347
  return lines
347
348
 
348
349
 
349
- def unanchored_languages(score: dict[str, Any]) -> tuple[str, ...]:
350
+ def unanchored_languages(
351
+ score: dict[str, Any], present: Iterable[str] | None = None
352
+ ) -> tuple[str, ...]:
350
353
  """Parsed languages the reference corpus does not hold, from the report.
351
354
 
352
355
  Read off `score.reference` rather than imported from `_anchor`, so a
353
356
  report rendered from stored JSON discloses what *that* run's anchor
354
357
  omitted rather than what today's build omits.
358
+
359
+ ``present`` is the run's own language census, `summary.languages`
360
+ (D167). The anchor's gap is a fact about the corpus, but the caveat
361
+ is a claim about *this* grade: "a grade reported for code in COBOL is
362
+ provisional" printed on a Java tree tells the reader something false
363
+ about what they are looking at. ``None`` means the census is unknown —
364
+ a report stored before it existed — and keeps the whole list, because
365
+ a limit that cannot be ruled out is still disclosed.
355
366
  """
356
- return tuple((score.get("reference") or {}).get("unanchored_languages") or ())
367
+ names = tuple((score.get("reference") or {}).get("unanchored_languages") or ())
368
+ if present is None:
369
+ return names
370
+ here = set(present)
371
+ return tuple(name for name in names if name in here)
357
372
 
358
373
 
359
- def unanchored_caveat(score: dict[str, Any]) -> list[str]:
374
+ def unanchored_caveat(
375
+ score: dict[str, Any], present: Iterable[str] | None = None
376
+ ) -> list[str]:
360
377
  """The anchor's gap, in one sentence, for any skin that prints a grade.
361
378
 
362
379
  Lives here because all three skins were about to carry their own copy
@@ -365,7 +382,7 @@ def unanchored_caveat(score: dict[str, Any]) -> list[str]:
365
382
  disclosed only there is disclosed nowhere that matters, which is the
366
383
  shape this project already shipped once as F1.
367
384
  """
368
- names = unanchored_languages(score)
385
+ names = unanchored_languages(score, present)
369
386
  if not names:
370
387
  return []
371
388
  say = agreement(len(names))
@@ -90,9 +90,9 @@ def render_html(report: dict[str, Any], records: list[Any]) -> str:
90
90
  return "\n".join(parts)
91
91
 
92
92
 
93
- def _unanchored_html(score: dict[str, Any]) -> list[str]:
93
+ def _unanchored_html(score: dict[str, Any], present: Any = None) -> list[str]:
94
94
  """The anchor's gap, beside the letter rather than only in the JSON."""
95
- names = view.unanchored_languages(score)
95
+ names = view.unanchored_languages(score, present)
96
96
  if not names:
97
97
  return []
98
98
  say = agreement(len(names))
@@ -122,7 +122,7 @@ def _executive_strip(report: dict[str, Any], score: dict[str, Any],
122
122
  f"Source: {escape(view.estimate_source(score))}</div>",
123
123
  f"<div>{escape(view.status_sentence(score, report.get('analyzer_coverage') is not None))}</div>",
124
124
  f"<div>{gate}</div>",
125
- *_unanchored_html(score),
125
+ *_unanchored_html(score, (report.get("summary") or {}).get("languages")),
126
126
  f"<div>{escape(_direction_sentence(records))}</div>",
127
127
  "<table><tr><th>Severity</th><th>Findings</th></tr>",
128
128
  *count_rows,
@@ -37,6 +37,7 @@ import re
37
37
  from pathlib import Path
38
38
  from typing import Any
39
39
 
40
+ from ._work_order import _declaration_reading
40
41
  from .declarations import DECLARATION_SUFFIXES, detect_functions
41
42
  from .metrics import file_status
42
43
 
@@ -237,11 +238,17 @@ def _declaration_findings(
237
238
  # number. Never negative: it names a budget that failed.
238
239
  "breached": breaches[0]["budget"],
239
240
  "over_by": breaches[0]["over_by"],
241
+ # The work order's own wording, called rather than copied: the
242
+ # copy printed a class's complexity against a function limit
243
+ # after the work order stopped doing so (D164).
240
244
  "target": (
241
- f"reduce below the configured limits (currently {metric.lines} "
242
- f"lines against {_budget_for(metric.kind, thresholds)[0]}, "
243
- f"complexity {metric.complexity} against "
244
- f"{thresholds['max_complexity']})"
245
+ "reduce below the configured limits ("
246
+ + _declaration_reading(
247
+ {"lines": metric.lines, "complexity": metric.complexity,
248
+ "kind": metric.kind, "cognitive": metric.cognitive},
249
+ thresholds,
250
+ )
251
+ + ")"
245
252
  ),
246
253
  })
247
254
  return findings
@@ -171,6 +171,11 @@ def staged_report(root: Path, config: dict[str, Any]) -> dict[str, Any]:
171
171
  return {
172
172
  "root": str(root),
173
173
  "scanned": scannable,
174
+ # The limits these hotspots were graded against, so the work-order
175
+ # builder can name them. Without this the hook worded a class
176
+ # "graded on length alone" while the audit said "against the
177
+ # 300-line class limit" (D171).
178
+ "thresholds": thresholds,
174
179
  "largest_files": largest,
175
180
  "function_hotspots": hotspots,
176
181
  "risk_findings": risk,
@@ -204,13 +209,12 @@ def _risk_items(report: dict[str, Any]) -> list[dict[str, Any]]:
204
209
  "title": f"{entry['pattern']} added in {entry['path']}",
205
210
  "path": entry["path"], "line": entry["line"],
206
211
  "target": (
207
- f"remove or justify this {entry['pattern']} match; it is a "
208
- "pattern this repository's own configuration asked to be "
209
- "told about"
212
+ f"act on or justify this {entry['pattern']} match; it is a "
213
+ "risk pattern the active configuration enforces"
210
214
  ),
211
215
  "rationale": (
212
- "the repository declared this pattern as risky, and this "
213
- "change is adding a line that matches it"
216
+ "the active configuration declares this pattern risky, and "
217
+ "this change is adding a line that matches it"
214
218
  ),
215
219
  # Above a threshold breach and below an added suppression. A
216
220
  # risk pattern is what the repository asked to see; switching
@@ -289,7 +293,7 @@ def staged_findings(report: dict[str, Any]) -> list[dict[str, Any]]:
289
293
  from ._work_order import _items_from_files, _items_from_hotspots, band_of
290
294
 
291
295
  items: list[dict[str, Any]] = []
292
- for entry in _items_from_hotspots(report) + _items_from_files(report):
296
+ for entry in _items_from_hotspots(report, report.get("thresholds")) + _items_from_files(report):
293
297
  weight = entry.pop("weight")
294
298
  rationale = entry.pop("rationale", None) or weight.rationale
295
299
  items.append({**entry, "rationale": rationale,
@@ -89,7 +89,17 @@ def prompt_analyzer_caveat(report: dict[str, Any]) -> list[str]:
89
89
  """
90
90
  if not (report.get("analyzer_measurements") or report.get("analyzer_findings")):
91
91
  return []
92
- scored = (report.get("score") or {}).get("analyzer_scored_dimensions") or []
92
+ score = report.get("score") or {}
93
+ if not view.is_scored(score):
94
+ # No estimate was issued, so none can have a source (D172). The
95
+ # analyzer output is still evidence about the code, and says so.
96
+ return [
97
+ "**No maintainability estimate was issued for this run**, so none is "
98
+ "attributed to the analyzers. Their output is reported here as "
99
+ "evidence about the code, never as a change to a score.",
100
+ "",
101
+ ]
102
+ scored = score.get("analyzer_scored_dimensions") or []
93
103
  if scored:
94
104
  return [
95
105
  "**The maintainability estimate above uses the analyzer readings** for "
@@ -149,6 +159,50 @@ def _withheld_paragraph(report: dict[str, Any]) -> list[str]:
149
159
  ]
150
160
 
151
161
 
162
+ def _prompt_work_items(report: dict[str, Any]) -> list[dict[str, Any]]:
163
+ """The items this prompt hands to an agent, after withholding."""
164
+ # Withhold anything the history shows was fixed and came back
165
+ # twice. Naming it as a design candidate while asking an agent to
166
+ # patch it a third time would change nothing.
167
+ escalated = {
168
+ item["fingerprint"] for item in report.get("design_review_candidates") or []
169
+ }
170
+ return prompt_items(report.get("work_order") or [], escalated=escalated)
171
+
172
+
173
+ def prompt_has_work(report: dict[str, Any]) -> bool:
174
+ """Whether this prompt hands an agent anything to change (D173).
175
+
176
+ A report with no `work_order` key at all — stored before the field
177
+ existed, or assembled by hand — cannot say there is nothing to do, so
178
+ it keeps the prompt it always had rather than reading as "Nothing to
179
+ do" over findings it does carry.
180
+ """
181
+ return "work_order" not in report or bool(_prompt_work_items(report))
182
+
183
+
184
+ def _no_prompt_work(report: dict[str, Any]) -> list[str]:
185
+ """What the prompt says in place of a task when there is none (D173).
186
+
187
+ Two cases, because they are different facts. An empty work order is the
188
+ chat report's "Nothing to do", in the same words. A work order whose
189
+ every item was withheld — a Major Project, or a finding escalated for
190
+ design review — has work in it, none of it an agent's to patch.
191
+ """
192
+ if not report.get("work_order"):
193
+ from ._work_order_view import NOTHING_TO_DO
194
+
195
+ return [NOTHING_TO_DO, "", "Do not change code on the strength of this audit.", ""]
196
+ return [
197
+ "**Nothing in scope for this prompt.** Every work-order item needs a "
198
+ "design decision or keeps coming back, so none is handed to an agent. "
199
+ "They are in the report. Do not change code on the strength of this "
200
+ "prompt.",
201
+ "",
202
+ *_withheld_paragraph(report),
203
+ ]
204
+
205
+
152
206
  def prompt_work_order(report: dict[str, Any]) -> list[str]:
153
207
  """The ordered work, leading the prompt, Major Projects withheld.
154
208
 
@@ -161,18 +215,16 @@ def prompt_work_order(report: dict[str, Any]) -> list[str]:
161
215
  told to deduplicate a pattern across forty files produces exactly the
162
216
  sprawling, unreviewable diff a bounded prompt exists to prevent.
163
217
  """
164
- # Withhold anything the history shows was fixed and came back
165
- # twice. Naming it as a design candidate while asking an agent to
166
- # patch it a third time would change nothing.
167
- escalated = {
168
- item["fingerprint"] for item in report.get("design_review_candidates") or []
169
- }
170
- items = prompt_items(report.get("work_order") or [], escalated=escalated)
218
+ items = _prompt_work_items(report)
171
219
  if not items:
172
- return []
220
+ return _no_prompt_work(report) if "work_order" in report else []
173
221
  lines = [
174
- "Work in this order. The first items are the highest value for the "
175
- "least change; stop when the change stops being reviewable.",
222
+ # What the order is, not what it is worth (D169): `prompt_items`
223
+ # promotes risk-5 classes and keeps one item per class, so this
224
+ # list and the report's table can lead with different items.
225
+ "Work in this order: severe findings (risk 5) first, then the work "
226
+ "order's own order, one item per kind of finding. Stop when the "
227
+ "change stops being reviewable.",
176
228
  "",
177
229
  ]
178
230
  for index, item in enumerate(items, start=1):
@@ -217,7 +269,22 @@ DIMENSION_GUIDANCE = {
217
269
  }
218
270
 
219
271
 
220
- def prompt_pressure_section(score: dict[str, Any]) -> list[str]:
272
+ def corpus_span(score: dict[str, Any]) -> str:
273
+ """How much of what this scanner parses the corpus holds, counted (D168).
274
+
275
+ Read off `score.reference`, the two lists the corpus note is built
276
+ from. The prompt typed "eight of the ten parsed languages" while the
277
+ note on the same report said thirteen of fourteen: a count written
278
+ as prose goes stale the first time a language is added, and nothing
279
+ fails when it does.
280
+ """
281
+ reference = score.get("reference") or {}
282
+ held = len(reference.get("corpus_languages") or ())
283
+ parsed = held + len(reference.get("unanchored_languages") or ())
284
+ return f"{held} of the {parsed} parsed languages"
285
+
286
+
287
+ def prompt_pressure_section(score: dict[str, Any], present: Any = None) -> list[str]:
221
288
  """Tell the agent *what kind* of trouble this repo is in, and how much.
222
289
 
223
290
  A letter grade is not actionable. These figures are multiples of what
@@ -247,7 +314,7 @@ def prompt_pressure_section(score: dict[str, Any]) -> list[str]:
247
314
  if not view.is_scored(score):
248
315
  # The grade blockers still render below: those say *why* no
249
316
  # number was issued, which is exactly what this reader needs.
250
- return [*view.unanchored_caveat(score), *_grade_blocker_lines(score)]
317
+ return [*view.unanchored_caveat(score, present), *_grade_blocker_lines(score)]
251
318
  dimensions = score.get("dimensions") or {}
252
319
  elevated = sorted(
253
320
  # `is not None` first: an unmeasured dimension is legitimate --
@@ -259,13 +326,13 @@ def prompt_pressure_section(score: dict[str, Any]) -> list[str]:
259
326
  key=lambda item: -item[1],
260
327
  )
261
328
  # Unanchored languages are provisional here too, elevated or not.
262
- lines: list[str] = view.unanchored_caveat(score)
329
+ lines: list[str] = view.unanchored_caveat(score, present)
263
330
  if elevated:
264
331
  lines.extend(
265
332
  [
266
333
  "Where this repo is worse than typical real-world code",
267
- "(1.0x = the median of a mature open-source corpus of eight "
268
- "of the ten parsed languages; elevated dimensions only):",
334
+ f"(1.0x = the median of a mature open-source corpus of "
335
+ f"{corpus_span(score)}; elevated dimensions only):",
269
336
  "",
270
337
  ]
271
338
  )
@@ -17,7 +17,7 @@ from ._identity import (
17
17
  finding_fingerprints,
18
18
  risk_identities,
19
19
  )
20
- from ._work_order_weights import CLASS_RISK_EFFORT, ClassWeight
20
+ from ._work_order_weights import AUDIT_VERIFICATION, CLASS_RISK_EFFORT, ClassWeight
21
21
  from .scoring import score_report
22
22
 
23
23
 
@@ -36,6 +36,11 @@ class Band(StrEnum):
36
36
  HIGH_RISK = 3
37
37
  HIGH_EFFORT = 3
38
38
 
39
+ #: ADR 007 §3's order of the four cells, taken from `Band`'s declaration
40
+ #: order. Both sorts read it — the band sort here and `reorder_by_exposure`
41
+ #: — so no ordering can place a Fill-In above a Quick Win (D170).
42
+ BAND_ORDER = {band.value: rank for rank, band in enumerate(Band)}
43
+
39
44
 
40
45
  def band_of(risk: int, effort: int) -> Band:
41
46
  """Which of the four cells a finding falls in."""
@@ -76,7 +81,59 @@ def _delta_for(report: dict[str, Any], counter: str, amount: int) -> float:
76
81
  return round(max(0.0, (after or before) - before), 3)
77
82
 
78
83
 
79
- def _items_from_hotspots(report: dict[str, Any]) -> list[dict[str, Any]]:
84
+ def _declaration_reading(hotspot: dict[str, Any], thresholds: dict[str, int] | None) -> str:
85
+ """What this declaration measures, each figure against the limit it is graded on (D164).
86
+
87
+ A class is graded on length alone (`declarations.class_status`), so it
88
+ is given its length and the class budget and nothing else: its
89
+ complexity is the sum of its methods' branches, already counted
90
+ against those methods, and printing it beside a function limit
91
+ described a 2876-line class as a function with complexity 25. A
92
+ function is graded on lines, complexity and cognitive cost, so each
93
+ appears with its own limit. Without thresholds — a caller holding only
94
+ the report — the figures are stated bare rather than against a
95
+ default the repository may not use.
96
+ """
97
+ lines = hotspot["lines"]
98
+ if hotspot.get("kind") == "class":
99
+ if thresholds is None:
100
+ return f"currently {lines} lines; a class is graded on length alone"
101
+ limit = thresholds.get("max_class_lines", thresholds["max_function_lines"])
102
+ return f"currently {lines} lines against the {limit}-line class limit"
103
+ if thresholds is None:
104
+ return f"currently {lines} lines, complexity {hotspot['complexity']}"
105
+ parts = [
106
+ f"{lines} lines against {thresholds['max_function_lines']}",
107
+ f"complexity {hotspot['complexity']} against {thresholds['max_complexity']}",
108
+ ]
109
+ max_cognitive = thresholds.get("max_cognitive_complexity")
110
+ if max_cognitive is not None and hotspot.get("cognitive") is not None:
111
+ parts.append(f"cognitive {hotspot['cognitive']} against {max_cognitive}")
112
+ return "currently " + ", ".join(parts)
113
+
114
+
115
+ def _declaration_rationale(hotspot: dict[str, Any]) -> str:
116
+ """Why this declaration matters, without sizing the change it needs (D164).
117
+
118
+ The class weight's rationale ends "extracting one is bounded, local
119
+ work" — a judgment about the class of finding, published in the
120
+ standard beside its declared effort. Printed on one item it became a
121
+ claim about that item, and it was false for a 2876-line class. The
122
+ band stays declared per class; the item states what it is and its own
123
+ reading states how far past the limit it sits.
124
+ """
125
+ if hotspot.get("kind") == "class":
126
+ return ("an oversized class hides its own structure, and every change "
127
+ "to it is read against all of it")
128
+ if float(hotspot["complexity"]) <= 10:
129
+ return "a long function is where every future change has to be understood first"
130
+ return ("a long, branching function is where defects concentrate and where "
131
+ "every future change has to be understood first")
132
+
133
+
134
+ def _items_from_hotspots(
135
+ report: dict[str, Any], thresholds: dict[str, int] | None = None
136
+ ) -> list[dict[str, Any]]:
80
137
  """Declarations past a threshold, worst first."""
81
138
  weight = CLASS_RISK_EFFORT["oversized-declaration"]
82
139
  # Computed once over the whole population, because an ordinal is a
@@ -100,18 +157,13 @@ def _items_from_hotspots(report: dict[str, Any]) -> list[dict[str, Any]]:
100
157
  "line": hotspot["start_line"],
101
158
  "target": (
102
159
  f"reduce below the configured limits "
103
- f"(currently {hotspot['lines']} lines, complexity {hotspot['complexity']})"
160
+ f"({_declaration_reading(hotspot, thresholds)})"
104
161
  ),
105
162
  "severity": float(hotspot["lines"]) + 4.0 * float(hotspot["complexity"]),
106
163
  "fingerprint": identities[
107
164
  (hotspot["path"], hotspot["name"], hotspot["start_line"])
108
165
  ],
109
- "rationale": (
110
- "a long function is where every future change has to be "
111
- "understood first; extracting one is bounded, local work"
112
- if float(hotspot["complexity"]) <= 10
113
- else None
114
- ),
166
+ "rationale": _declaration_rationale(hotspot),
115
167
  "weight": weight,
116
168
  })
117
169
  return items
@@ -130,6 +182,11 @@ def _items_from_unpaired(report: dict[str, Any]) -> list[dict[str, Any]]:
130
182
  "path": path,
131
183
  "line": finding.get("line"),
132
184
  "target": f"add a paired test for `{name}`",
185
+ # Not the class rationale: "adding a characterization test is
186
+ # bounded, local work" sizes the item, and a 1907-line class
187
+ # with no test is not bounded work (D164).
188
+ "rationale": ("an oversized production unit with no paired test is "
189
+ "where changes land unguarded"),
133
190
  "severity": float(finding.get("lines") or 1),
134
191
  "weight": weight,
135
192
  })
@@ -234,11 +291,22 @@ def _items_from_counted(report: dict[str, Any]) -> list[dict[str, Any]]:
234
291
  }
235
292
  if name == "risk-pattern":
236
293
  item["fingerprint"] = risks[(path, finding["name"], finding["line"])]
294
+ # "remove the configured risk pattern" read, for a TODO, as
295
+ # "delete the comment" — which clears the finding and the
296
+ # score while the debt it records stays (D165).
297
+ item["target"] = (
298
+ f"act on what the `{finding['name']}` rule matched here, or "
299
+ "say why it stays; deleting the matched text alone hides "
300
+ "the finding without resolving it"
301
+ )
237
302
  items.append(item)
238
303
  return items
239
304
 
240
305
 
241
- def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list[dict[str, Any]]:
306
+ def work_order(
307
+ report: dict[str, Any], include_reconsider: bool = False,
308
+ thresholds: dict[str, int] | None = None,
309
+ ) -> list[dict[str, Any]]:
242
310
  """Every actionable finding, ordered by risk against effort.
243
311
 
244
312
  Quick Wins first, then Major Projects, then Fill-Ins; Reconsider is
@@ -247,7 +315,7 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
247
315
  value rather than by how many of something there are.
248
316
  """
249
317
  raw = (
250
- _items_from_hotspots(report)
318
+ _items_from_hotspots(report, thresholds)
251
319
  + _items_from_files(report)
252
320
  + _items_from_counted(report)
253
321
  + _items_from_idioms(report)
@@ -268,7 +336,6 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
268
336
  counts[entry["finding_class"]] = counts.get(entry["finding_class"], 0) + 1
269
337
  per_class: dict[str, float] = {}
270
338
  class_delta: dict[str, float] = {}
271
- ordering = {Band.QUICK_WIN: 0, Band.MAJOR_PROJECT: 1, Band.FILL_IN: 2, Band.RECONSIDER: 3}
272
339
  items: list[dict[str, Any]] = []
273
340
  for entry in raw:
274
341
  weight: ClassWeight = entry.pop("weight")
@@ -298,7 +365,7 @@ def work_order(report: dict[str, Any], include_reconsider: bool = False) -> list
298
365
 
299
366
  items.extend(_items_from_semantic(report))
300
367
  items.sort(key=lambda item: (
301
- ordering[Band(item["band"])], -item["class_delta"],
368
+ BAND_ORDER[item["band"]], -item["class_delta"],
302
369
  # Within a class every delta is identical, so severity is what
303
370
  # actually orders the work a reader will do first.
304
371
  -item["severity"], item["path"]))
@@ -358,7 +425,7 @@ def _semantic_item(
358
425
  "delta": 0.0,
359
426
  "class_delta": 0.0,
360
427
  "class_count": class_count,
361
- "verification": "python -m maintainability_audit --root . --format json",
428
+ "verification": AUDIT_VERIFICATION,
362
429
  }
363
430
 
364
431
 
@@ -416,8 +483,9 @@ def prompt_items(items: list[dict[str, Any]], limit: int = 12,
416
483
  escalated: set[str] | None = None) -> list[dict[str, Any]]:
417
484
  """Agent subset: no major projects, no escalated returns; Severe leads.
418
485
 
419
- Economic reorder may bury a risk-5 item under hot-file Fill-Ins. The
420
- table can stay exposure-ordered; the paste of 12 cannot drop Severe.
486
+ The economic reorder orders items by exposure within each band (D170),
487
+ so a risk-5 item can still sit below hotter Quick Wins of other classes.
488
+ The table can stay exposure-ordered; the paste of 12 cannot drop Severe.
421
489
  """
422
490
  blocked = escalated or set()
423
491
  eligible = [