maintainability-agent 3.6.1__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.1/src/maintainability_agent.egg-info → maintainability_agent-3.6.2}/PKG-INFO +2 -2
  2. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/README.md +1 -1
  3. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/pyproject.toml +1 -1
  4. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
  5. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/SOURCES.txt +1 -0
  6. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/__init__.py +1 -1
  7. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit.py +6 -1
  8. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_prompt_sections.py +57 -9
  9. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order.py +3 -2
  10. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_view.py +13 -4
  11. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/config.py +1 -1
  12. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/prompts.py +30 -14
  13. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/renderers.py +2 -8
  14. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/report.py +19 -3
  15. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declaration_grading.py +11 -2
  16. maintainability_agent-3.6.2/tests/test_every_surface_says_what_the_run_found.py +239 -0
  17. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/LICENSE +0 -0
  18. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/setup.cfg +0 -0
  19. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  20. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  21. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/requires.txt +0 -0
  22. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  23. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/__main__.py +0 -0
  24. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_adapters.py +0 -0
  25. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_analysis.py +0 -0
  26. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_analyzer_sections.py +0 -0
  27. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_anchor.py +0 -0
  28. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_arguments.py +0 -0
  29. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_aspects.py +0 -0
  30. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  31. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_assets/standard.md +0 -0
  32. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_attestation.py +0 -0
  33. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_backfill.py +0 -0
  34. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_bands.py +0 -0
  35. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_banner.py +0 -0
  36. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_built_ins.py +0 -0
  37. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_calibration.py +0 -0
  38. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_catalog.py +0 -0
  39. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_charts.py +0 -0
  40. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_cognitive.py +0 -0
  41. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_config_defaults.py +0 -0
  42. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_conformance.py +0 -0
  43. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_corroborate.py +0 -0
  44. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_coverage_notes.py +0 -0
  45. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_criteria_scope.py +0 -0
  46. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_delegated_pillar.py +0 -0
  47. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_derive.py +0 -0
  48. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_discovery.py +0 -0
  49. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_documents.py +0 -0
  50. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics.py +0 -0
  51. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_economics_view.py +0 -0
  52. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_environment.py +0 -0
  53. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_reader.py +0 -0
  54. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_evidence_view.py +0 -0
  55. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_finding_match.py +0 -0
  56. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_first_run.py +0 -0
  57. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_formula.py +0 -0
  58. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_gates.py +0 -0
  59. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_generic.py +0 -0
  60. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_grammar.py +0 -0
  61. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_grant_ledger.py +0 -0
  62. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_history_view.py +0 -0
  63. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_hostile_prompt.py +0 -0
  64. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_hotspots.py +0 -0
  65. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_report_sections.py +0 -0
  66. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_html_view.py +0 -0
  67. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_identity.py +0 -0
  68. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop.py +0 -0
  69. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_in_loop_view.py +0 -0
  70. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_jvm_adapters.py +0 -0
  71. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_markdown_sections.py +0 -0
  72. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_masking.py +0 -0
  73. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_audit.py +0 -0
  74. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_gate.py +0 -0
  75. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_grants.py +0 -0
  76. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_refusals.py +0 -0
  77. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_resources.py +0 -0
  78. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_mcp_setup.py +0 -0
  79. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_metric_adapters.py +0 -0
  80. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_metrics_types.py +0 -0
  81. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_operator_reads.py +0 -0
  82. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_pillars.py +0 -0
  83. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_practice.py +0 -0
  84. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_install.py +0 -0
  85. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_precommit_view.py +0 -0
  86. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_pressures.py +0 -0
  87. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_c.py +0 -0
  88. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cobol.py +0 -0
  89. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_core.py +0 -0
  90. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_cpp.py +0 -0
  91. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_csharp.py +0 -0
  92. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_fortran.py +0 -0
  93. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_go.py +0 -0
  94. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_java.py +0 -0
  95. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_js.py +0 -0
  96. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_php.py +0 -0
  97. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_ruby.py +0 -0
  98. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_rust.py +0 -0
  99. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ranges_swift.py +0 -0
  100. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratchet.py +0 -0
  101. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_ratio_adapters.py +0 -0
  102. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_recurrence.py +0 -0
  103. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_run_comparison.py +0 -0
  104. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_runner.py +0 -0
  105. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_safe_write.py +0 -0
  106. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_history.py +0 -0
  107. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_scan_view.py +0 -0
  108. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_second_source.py +0 -0
  109. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_selection.py +0 -0
  110. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic.py +0 -0
  111. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_policy.py +0 -0
  112. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_ts.py +0 -0
  113. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_semantic_view.py +0 -0
  114. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_errors.py +0 -0
  115. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_setup_persist.py +0 -0
  116. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  117. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  118. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  119. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  120. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  121. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  122. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_skill_install.py +0 -0
  123. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_stored_grants.py +0 -0
  124. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_tdd_view.py +0 -0
  125. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_commands.py +0 -0
  126. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_execution.py +0 -0
  127. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_test_pairing.py +0 -0
  128. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_tokens.py +0 -0
  129. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_tool_adapters.py +0 -0
  130. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_trends.py +0 -0
  131. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_user_config.py +0 -0
  132. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_verdict_adapters.py +0 -0
  133. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_verification.py +0 -0
  134. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_work_order_weights.py +0 -0
  135. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/_xml.py +0 -0
  136. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/baseline.py +0 -0
  137. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/cli.py +0 -0
  138. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/deadcode.py +0 -0
  139. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/declarations.py +0 -0
  140. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/duplication.py +0 -0
  141. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/evidence.py +0 -0
  142. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/git_tools.py +0 -0
  143. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/history.py +0 -0
  144. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/idioms.py +0 -0
  145. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/instructions.py +0 -0
  146. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/mcp_server.py +0 -0
  147. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/metrics.py +0 -0
  148. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/sarif.py +0 -0
  149. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/scoring.py +0 -0
  150. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/similarity.py +0 -0
  151. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/src/maintainability_audit/source.py +0 -0
  152. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_acquisition_trust.py +0 -0
  153. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_adapter_docs.py +0 -0
  154. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_adapter_recordings.py +0 -0
  155. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_adapters.py +0 -0
  156. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_added_lines.py +0 -0
  157. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analysis_coverage.py +0 -0
  158. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analysis_execution.py +0 -0
  159. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_bridge.py +0 -0
  160. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_config_isolation.py +0 -0
  161. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_estimate_claims.py +0 -0
  162. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_pinning.py +0 -0
  163. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_primary_estimate.py +0 -0
  164. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance.py +0 -0
  165. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_provenance_exclusions.py +0 -0
  166. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_scoring_path.py +0 -0
  167. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_spread_range.py +0 -0
  168. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_analyzer_xml_bounds.py +0 -0
  169. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_anchor_and_mode.py +0 -0
  170. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_anchor_caveat_and_counts_follow_the_run.py +0 -0
  171. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_anchor_disclosure.py +0 -0
  172. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_annotations_match_behaviour.py +0 -0
  173. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_anticipated_refusals.py +0 -0
  174. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_architecture.py +0 -0
  175. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_artifact_write_route_class.py +0 -0
  176. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_aspect_coverage.py +0 -0
  177. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_asset_snapshot_class.py +0 -0
  178. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_ast_reading_resolves_spellings.py +0 -0
  179. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_attestation.py +0 -0
  180. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_audit_components.py +0 -0
  181. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_authorization_freshness.py +0 -0
  182. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_authorship_gates.py +0 -0
  183. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_backfill.py +0 -0
  184. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_band_concealment_class.py +0 -0
  185. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_band_concealment_p3.py +0 -0
  186. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_band_pressures.py +0 -0
  187. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_bands.py +0 -0
  188. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_body_or_signature_class.py +0 -0
  189. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_c_declarations.py +0 -0
  190. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_calibration_corpus.py +0 -0
  191. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_calibration_drift.py +0 -0
  192. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_calibration_tooling.py +0 -0
  193. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_catalog_selection.py +0 -0
  194. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_catalog_tier_promise.py +0 -0
  195. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_chat_leads_with_the_work_order.py +0 -0
  196. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_chat_primary_docs.py +0 -0
  197. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  198. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_checkstyle_adapter.py +0 -0
  199. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_checkstyle_catalog.py +0 -0
  200. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_child_sandbox.py +0 -0
  201. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_ci_history_recipe.py +0 -0
  202. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  203. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_claimed_languages.py +0 -0
  204. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_cli.py +0 -0
  205. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_clone_group_class.py +0 -0
  206. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_cobol_declarations.py +0 -0
  207. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_cognitive_complexity.py +0 -0
  208. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_cohort_statistics.py +0 -0
  209. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_concealment_properties.py +0 -0
  210. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_config_shape.py +0 -0
  211. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_consent_and_grant.py +0 -0
  212. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_consumer_migration.py +0 -0
  213. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_contract_claims.py +0 -0
  214. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_corroborate.py +0 -0
  215. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_coverage_by_language.py +0 -0
  216. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_cpp_declarations.py +0 -0
  217. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_criteria_completion.py +0 -0
  218. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_csharp_declarations.py +0 -0
  219. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_d15_composition.py +0 -0
  220. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_d15_goal_directed.py +0 -0
  221. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_dead_code.py +0 -0
  222. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declaration_criteria_scope.py +0 -0
  223. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declaration_edge_cases.py +0 -0
  224. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declaration_ranges.py +0 -0
  225. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declaration_source.py +0 -0
  226. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declarative_parsers.py +0 -0
  227. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declared_authorship.py +0 -0
  228. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_declared_imports.py +0 -0
  229. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_delegated_security_pillar.py +0 -0
  230. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_demo_tree.py +0 -0
  231. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_derivation_mix.py +0 -0
  232. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_determinism.py +0 -0
  233. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_dimension_ratchet.py +0 -0
  234. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_direct_runner_availability_class.py +0 -0
  235. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_discovery.py +0 -0
  236. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_doc_claims.py +0 -0
  237. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_docs_links.py +0 -0
  238. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_economic_context.py +0 -0
  239. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean.py +0 -0
  240. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_empty_output_not_clean_adapters.py +0 -0
  241. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_environment_work_order.py +0 -0
  242. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_evidence_invariants.py +0 -0
  243. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_evidence_normalization.py +0 -0
  244. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_evidence_properties.py +0 -0
  245. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_example_config_opens_claimed_languages.py +0 -0
  246. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_exclusion_dialects.py +0 -0
  247. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_exposure_never_outranks_band.py +0 -0
  248. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_falsifier_standard.py +0 -0
  249. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_file_list_cap_class.py +0 -0
  250. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_finding_identity.py +0 -0
  251. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_first_run_elicitation.py +0 -0
  252. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_first_run_prompt.py +0 -0
  253. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_first_run_reelicitation.py +0 -0
  254. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_fix_breadth_window.py +0 -0
  255. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_fixed_form_fortran.py +0 -0
  256. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_format_ask.py +0 -0
  257. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_fortran_declarations.py +0 -0
  258. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_fortran_metrics.py +0 -0
  259. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_fortran_practice.py +0 -0
  260. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_git_argv.py +0 -0
  261. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_git_read_only.py +0 -0
  262. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_git_readonly_class.py +0 -0
  263. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_go_declarations.py +0 -0
  264. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_grammar_constructs.py +0 -0
  265. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_grammar_token_coverage.py +0 -0
  266. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_grant_only_user_tier.py +0 -0
  267. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_history.py +0 -0
  268. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_history_boundary.py +0 -0
  269. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_history_manifest.py +0 -0
  270. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_history_schema2.py +0 -0
  271. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_history_window.py +0 -0
  272. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_hostile_prompt.py +0 -0
  273. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_html_executive.py +0 -0
  274. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_html_section_parity_class.py +0 -0
  275. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_identity_docs.py +0 -0
  276. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_identity_resolution.py +0 -0
  277. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_idiom_divergence.py +0 -0
  278. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_in_loop_budgets.py +0 -0
  279. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_in_loop_check.py +0 -0
  280. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_installed_wheel_runtime.py +0 -0
  281. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_instruction_targets.py +0 -0
  282. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_java_range_guard.py +0 -0
  283. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_java_ranges.py +0 -0
  284. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_java_scored.py +0 -0
  285. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_java_wiring.py +0 -0
  286. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_js_complexity_operators.py +0 -0
  287. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_js_declarations.py +0 -0
  288. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_language_coverage.py +0 -0
  289. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_language_support_honesty.py +0 -0
  290. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_mcp_baseline_payload.py +0 -0
  291. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_mcp_format_contract.py +0 -0
  292. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_mcp_history.py +0 -0
  293. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_mcp_server.py +0 -0
  294. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_migration_1_0.py +0 -0
  295. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_near_duplicates.py +0 -0
  296. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_network_disclosure.py +0 -0
  297. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_one_setup_across_surfaces_class.py +0 -0
  298. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_operator_named_paths.py +0 -0
  299. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_operator_named_reads.py +0 -0
  300. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pairing_reads_imports.py +0 -0
  301. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pattern_budget.py +0 -0
  302. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_phase6_claims.py +0 -0
  303. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_php_declarations.py +0 -0
  304. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pillars_and_practice.py +0 -0
  305. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_platform_claim.py +0 -0
  306. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pmd_adapter.py +0 -0
  307. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pmd_audit_closures.py +0 -0
  308. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_policy_claims.py +0 -0
  309. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_pool_runs_by_config.py +0 -0
  310. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_population_floors.py +0 -0
  311. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_practice_nested_gates_class.py +0 -0
  312. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_precommit_staged.py +0 -0
  313. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_presentation_refusals.py +0 -0
  314. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_promises.py +0 -0
  315. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  316. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_prompt_escalation_once.py +0 -0
  317. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_prompt_honesty.py +0 -0
  318. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_prompt_location_escalation_class.py +0 -0
  319. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_prove_falsifiers.py +0 -0
  320. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_python_complexity.py +0 -0
  321. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_python_declarations.py +0 -0
  322. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_read_boundary.py +0 -0
  323. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_readme_claims.py +0 -0
  324. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_recurrence.py +0 -0
  325. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_release_needs_an_empty_ledger.py +0 -0
  326. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_release_plan.py +0 -0
  327. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_release_plan_status.py +0 -0
  328. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_report_remedy_copy.py +0 -0
  329. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_roles_recorded.py +0 -0
  330. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_root_grants.py +0 -0
  331. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  332. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_ruby_declarations.py +0 -0
  333. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_run_comparison.py +0 -0
  334. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_runner.py +0 -0
  335. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_rust_declarations.py +0 -0
  336. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_sarif.py +0 -0
  337. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scan_history.py +0 -0
  338. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scan_scope.py +0 -0
  339. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scanner_unsafe_direction.py +0 -0
  340. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scanning.py +0 -0
  341. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_schema_fidelity.py +0 -0
  342. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scope_conformance.py +0 -0
  343. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_scoring_calibration.py +0 -0
  344. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_semantic_policy.py +0 -0
  345. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_setup_gate_completeness.py +0 -0
  346. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_setup_gate_independent_contract.py +0 -0
  347. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_setup_precondition.py +0 -0
  348. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_skill_install.py +0 -0
  349. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_sonar_resolve.py +0 -0
  350. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_source_index.py +0 -0
  351. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_spotbugs_adapter.py +0 -0
  352. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_spotbugs_catalog.py +0 -0
  353. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_stage8_contract.py +0 -0
  354. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_stdout_outputs.py +0 -0
  355. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_suite_isolation.py +0 -0
  356. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_swift_declarations.py +0 -0
  357. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_tdd_structure.py +0 -0
  358. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_terminal_asks_the_same_questions.py +0 -0
  359. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_test_commands.py +0 -0
  360. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_test_execution_class.py +0 -0
  361. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_three_presentations.py +0 -0
  362. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_tool_resolution.py +0 -0
  363. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  364. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_tree_chosen_spawn.py +0 -0
  365. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_tree_reads_use_the_primitive.py +0 -0
  366. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_trends.py +0 -0
  367. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_type_fields_not_functions_class.py +0 -0
  368. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_uat_falsifiers.py +0 -0
  369. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_unanchored_set_matches_corpus.py +0 -0
  370. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_unread_code.py +0 -0
  371. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_user_config_tier.py +0 -0
  372. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_verification_audit_closures.py +0 -0
  373. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_verified_grade.py +0 -0
  374. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_version_claim.py +0 -0
  375. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_wheel_contents.py +0 -0
  376. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_work_items_state_their_own_finding.py +0 -0
  377. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_work_order.py +0 -0
  378. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  379. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_work_order_items.py +0 -0
  380. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_work_order_selection.py +0 -0
  381. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_workflow_supply_chain.py +0 -0
  382. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_write_boundary.py +0 -0
  383. {maintainability_agent-3.6.1 → maintainability_agent-3.6.2}/tests/test_write_route_class.py +0 -0
  384. {maintainability_agent-3.6.1 → 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.1
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.1**.
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.1**.
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.1"
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.1
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.1**.
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
@@ -236,6 +236,7 @@ tests/test_economic_context.py
236
236
  tests/test_empty_output_not_clean.py
237
237
  tests/test_empty_output_not_clean_adapters.py
238
238
  tests/test_environment_work_order.py
239
+ tests/test_every_surface_says_what_the_run_found.py
239
240
  tests/test_evidence_invariants.py
240
241
  tests/test_evidence_normalization.py
241
242
  tests/test_evidence_properties.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "3.6.1"
3
+ __version__ = "3.6.2"
@@ -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,
@@ -288,7 +293,7 @@ def staged_findings(report: dict[str, Any]) -> list[dict[str, Any]]:
288
293
  from ._work_order import _items_from_files, _items_from_hotspots, band_of
289
294
 
290
295
  items: list[dict[str, Any]] = []
291
- 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):
292
297
  weight = entry.pop("weight")
293
298
  rationale = entry.pop("rationale", None) or weight.rationale
294
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,15 +215,9 @@ 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
222
  # What the order is, not what it is worth (D169): `prompt_items`
175
223
  # promotes risk-5 classes and keeps one item per class, so this
@@ -483,8 +483,9 @@ def prompt_items(items: list[dict[str, Any]], limit: int = 12,
483
483
  escalated: set[str] | None = None) -> list[dict[str, Any]]:
484
484
  """Agent subset: no major projects, no escalated returns; Severe leads.
485
485
 
486
- Economic reorder may bury a risk-5 item under hot-file Fill-Ins. The
487
- 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.
488
489
  """
489
490
  blocked = escalated or set()
490
491
  eligible = [
@@ -85,10 +85,11 @@ def item_prompt_block(item: dict[str, Any], root_label: str = ".") -> list[str]:
85
85
  #: The order sentence, by which sort actually produced the list (D169).
86
86
  #:
87
87
  #: `reorder_by_exposure` re-sorts the stored work order by recurrence and
88
- #: churn whenever an economic context is configured, ignoring band. The
89
- #: heading went on saying "ordered by what it costs to leave against what
90
- #: it costs to fix" over a list that sort had replaced, so the table and the
91
- #: prompt named different first items and neither said why.
88
+ #: churn whenever an economic context is configured — within each band
89
+ #: since D170, across bands before it. The heading went on saying "ordered
90
+ #: by what it costs to leave against what it costs to fix" over a list that
91
+ #: sort had reordered, so the table and the prompt named different first
92
+ #: items and neither said why.
92
93
  _ORDER_BY_BAND = (
93
94
  "Ordered by what it costs to leave against what it costs to fix "
94
95
  "(see the standard)."
@@ -97,6 +98,14 @@ _ORDER_BY_EXPOSURE = (
97
98
  "Ordered by band, then by exposure within each band — how often a "
98
99
  "finding came back and how much its file changes (ADR 004)."
99
100
  )
101
+ #: What a run with no work order says, on every skin that would otherwise
102
+ #: hand over a task (D173). The chat report said this while the prompt from
103
+ #: the same run asked for "the smallest coherent patch".
104
+ NOTHING_TO_DO = (
105
+ "**Nothing to do.** No finding reached a band worth a work-order "
106
+ "item, so there is no prompt to paste. The evidence behind that is "
107
+ "below."
108
+ )
100
109
  _BAND_IS_PER_CLASS = (
101
110
  "A band is declared per kind of finding in the standard, not sized per "
102
111
  "item: each target states that item's own reading."
@@ -20,7 +20,7 @@ from ._operator_reads import (
20
20
  # still the door every caller comes through.
21
21
  __all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
22
22
 
23
- VERSION = "3.6.1"
23
+ VERSION = "3.6.2"
24
24
 
25
25
  PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
26
26
 
@@ -32,23 +32,17 @@ def render_ai_prompt(report: dict[str, Any]) -> str:
32
32
  """
33
33
  summary = report["summary"]
34
34
  score = report["score"]
35
+ # A run with nothing in scope hands over no task (D173): the chat report
36
+ # from the same run said "Nothing to do" while this file asked for a
37
+ # patch and listed warn-band hotspots the work order had refused.
38
+ has_work = prompt_has_work(report)
35
39
  lines = [
36
40
  "# AI Remediation Prompt",
37
41
  "",
38
42
  "You are working in a git repository that has just produced a maintainability audit.",
39
43
  "",
40
- "Your task is to fix the highest-value maintainability issues in a small, reviewable change.",
41
- "",
42
- "Rules:",
43
- "",
44
- "- Do not rewrite the whole codebase.",
45
- "- Do not change public behavior unless a finding explicitly requires it.",
46
- "- Prefer existing architecture, naming, and local patterns.",
47
- "- Add or update tests for meaningful behavior before changing production code where practical.",
48
- "- Keep unrelated refactors out of scope.",
49
- "- If a finding is a false positive, explain why and leave the code unchanged.",
50
- "- After changes, run the repo's native tests/lints and this maintainability audit again.",
51
- "",
44
+ *(_TASK if has_work else ()),
45
+ *_RULES,
52
46
  ]
53
47
  # The product, before anything describing the run that produced it.
54
48
  lines.extend(prompt_escalation_note(report))
@@ -82,11 +76,32 @@ def render_ai_prompt(report: dict[str, Any]) -> str:
82
76
  lines.extend(prompt_tdd_section(report))
83
77
  lines.extend(prompt_semantic_section(report))
84
78
  lines.extend(prompt_pressure_section(score, (report.get("summary") or {}).get("languages")))
85
- lines.extend(prompt_focus_sections(report))
86
- lines.extend(prompt_deliverable())
79
+ if has_work:
80
+ lines.extend(prompt_focus_sections(report))
81
+ lines.extend(prompt_deliverable())
87
82
  return "\n".join(lines)
88
83
 
89
84
 
85
+ _TASK = (
86
+ "Your task is to fix the highest-value maintainability issues in a small, reviewable change.",
87
+ "",
88
+ )
89
+ # Kept on every prompt: they bound what an agent may do, and a run with
90
+ # nothing in scope is still bounded by them.
91
+ _RULES = (
92
+ "Rules:",
93
+ "",
94
+ "- Do not rewrite the whole codebase.",
95
+ "- Do not change public behavior unless a finding explicitly requires it.",
96
+ "- Prefer existing architecture, naming, and local patterns.",
97
+ "- Add or update tests for meaningful behavior before changing production code where practical.",
98
+ "- Keep unrelated refactors out of scope.",
99
+ "- If a finding is a false positive, explain why and leave the code unchanged.",
100
+ "- After changes, run the repo's native tests/lints and this maintainability audit again.",
101
+ "",
102
+ )
103
+
104
+
90
105
  def render_agent_instructions(report: dict[str, Any]) -> str:
91
106
  return "\n".join(
92
107
  [
@@ -138,6 +153,7 @@ from ._prompt_sections import ( # noqa: E402,F401 - re-export after the split
138
153
  prompt_deliverable,
139
154
  prompt_escalation_note,
140
155
  prompt_focus_sections,
156
+ prompt_has_work,
141
157
  prompt_pressure_section,
142
158
  prompt_semantic_section,
143
159
  prompt_tdd_section,
@@ -32,7 +32,7 @@ from ._scan_view import (
32
32
  )
33
33
  from ._semantic_view import semantic_markdown, without_semantic_suffixes
34
34
  from ._tdd_view import tdd_structure_markdown
35
- from ._work_order_view import work_order_markdown, work_order_selection_markdown
35
+ from ._work_order_view import NOTHING_TO_DO, work_order_markdown, work_order_selection_markdown
36
36
 
37
37
 
38
38
  def _pool_ran(report: dict[str, Any]) -> bool:
@@ -188,13 +188,7 @@ def _no_work_order_lines() -> list[str]:
188
188
  "nothing met the bands" from "this tool does not do that" — and the
189
189
  second reading is the one a stranger takes on a first run.
190
190
  """
191
- return [
192
- "## Work Order", "",
193
- "**Nothing to do.** No finding reached a band worth a work-order "
194
- "item, so there is no prompt to paste. The evidence behind that is "
195
- "below.",
196
- "",
197
- ]
191
+ return ["## Work Order", "", NOTHING_TO_DO, ""]
198
192
 
199
193
 
200
194
  def _bounded_markdown(report: dict[str, Any], score: dict[str, Any],
@@ -367,17 +367,33 @@ def _assemble(
367
367
  }
368
368
 
369
369
 
370
- def _attach_semantics(report: dict[str, Any], root: Path, config: dict[str, Any]) -> None:
370
+ def _attach_semantics(
371
+ report: dict[str, Any], root: Path, config: dict[str, Any],
372
+ only_paths: set[str] | None = None,
373
+ ) -> None:
371
374
  """ADR 003 option C, after the score is sealed and before the work
372
375
  order reads it: semantic results are findings and prompt material,
373
376
  never rubric input — nothing from here reaches `score_report`.
377
+
378
+ **A changed-only run keeps the findings its paths hold (D174).** The
379
+ semantic walk reads the whole tree, so a changed-only audit of two
380
+ commits nominated a TypeScript fixture neither commit touched and
381
+ handed it to the prompt. A finding with no located source path cannot
382
+ be placed in or out of the change, and is not work anyone can act on
383
+ either (`_items_from_semantic` drops it), so it is left out here too.
374
384
  """
375
385
  semantic = semantic_findings(
376
386
  root,
377
387
  policy=load_semantic_policy(config),
378
388
  type_analysis=discover_type_analysis(root),
379
389
  )
380
- report["semantic_findings"] = semantic["findings"]
390
+ findings = semantic["findings"]
391
+ if only_paths is not None:
392
+ findings = [
393
+ finding for finding in findings
394
+ if ((finding.get("source_evidence") or {}).get("path")) in only_paths
395
+ ]
396
+ report["semantic_findings"] = findings
381
397
  report["semantic_coverage"] = semantic["coverage"]
382
398
 
383
399
 
@@ -475,7 +491,7 @@ def build_report(
475
491
  # Condition rolls up aspects; practice stays a separate axis (ADR 007).
476
492
  report["practice"] = practice_level(root, config).as_dict()
477
493
  report["pillars"] = _pillars_with_delegation(report, root, security_pillar)
478
- _attach_semantics(report, root, config)
494
+ _attach_semantics(report, root, config, only_paths)
479
495
  # Last, because every item's delta is a rubric recomputation and the
480
496
  # rubric needs the scored report to recompute against.
481
497
  report["work_order"] = work_order(report, thresholds=config["thresholds"])
@@ -174,8 +174,17 @@ def test_function_hotspot_still_reports_its_complexity() -> None:
174
174
 
175
175
  def test_class_label_reaches_the_prompt_the_pr_comment_and_sarif() -> None:
176
176
  report = flagged_class_report()
177
-
178
- assert "`ScanWorker` (class) (260 lines, warn)" in render_ai_prompt(report)
177
+ # The prompt lists hotspots only when it hands over work (D173); a
178
+ # warn-only run is "Nothing to do" there. Give the prompt one item so
179
+ # its hotspot section — where the label is checked — renders.
180
+ prompted = {**report, "work_order": [{
181
+ "finding_class": "oversized-declaration", "title": "ScanWorker in scanner.py",
182
+ "path": "scanner.py", "line": 1, "band": "quick-win", "risk": 4, "effort": 2,
183
+ "target": "t", "rationale": "r", "verification": "v", "class_delta": 0.0,
184
+ "class_count": 1, "fingerprint": "fp", "severity": 1.0,
185
+ }]}
186
+
187
+ assert "`ScanWorker` (class) (260 lines, warn)" in render_ai_prompt(prompted)
179
188
  assert "`ScanWorker` (class) (260 lines, warn)" in render_pr_comment(report)
180
189
  message = report_to_sarif(report)["runs"][0]["results"][0]["message"]["text"]
181
190
  assert message == "ScanWorker (class) (260 lines, warn)."
@@ -0,0 +1,239 @@
1
+ """Every surface of one run says what that run found, and nothing else.
2
+
3
+ D171–D174, from Grok's hostile audit of `77de21c` (3.6.0 + 3.6.1). Each is
4
+ one surface telling a different story from the report it belongs to:
5
+
6
+ * D171 — the pre-commit hook worded a declaration unlike the audit.
7
+ * D172 — the prompt named a source for an estimate that was not issued.
8
+ * D173 — the prompt asked for a patch on a run whose report said
9
+ "Nothing to do".
10
+ * D174 — a changed-only run handed the prompt a finding from a file the
11
+ change never touched.
12
+
13
+ Populations are derived: declarations from every grammar fixture on disk,
14
+ dimensions from the score document, the "patch" instructions from
15
+ `prompt_deliverable` itself, and semantic findings from a tree carrying the
16
+ semantic fixture at several locations. Each sweep asserts it is not empty.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import copy
21
+ import shutil
22
+ import subprocess
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ import pytest
27
+
28
+ ROOT = Path(__file__).resolve().parents[1]
29
+ GRAMMAR = ROOT / "tests" / "fixtures" / "grammar"
30
+
31
+
32
+ def _failing_everything() -> dict[str, Any]:
33
+ """Every declaration breaches; class and function budgets differ, so a
34
+ target naming the wrong one is visible."""
35
+ from maintainability_audit.config import load_config
36
+
37
+ config = copy.deepcopy(load_config(None))
38
+ config["thresholds"].update({
39
+ "max_function_lines": 3, "warn_function_lines": 2,
40
+ "max_class_lines": 1, "warn_class_lines": 1,
41
+ "max_complexity": 0, "warn_complexity": 0,
42
+ })
43
+ return config
44
+
45
+
46
+ def _git(repo: Path, *args: str) -> None:
47
+ subprocess.run(["git", "-C", str(repo), *args], check=True, capture_output=True)
48
+
49
+
50
+ def test_the_hook_words_every_declaration_as_the_audit_does(tmp_path) -> None:
51
+ """D171: `staged_findings` and the audit give one target per declaration.
52
+
53
+ D164 passed thresholds to `_items_from_hotspots` from `build_report` and
54
+ `check_content` but not from the hook, so a staged 2876-line class read
55
+ "a class is graded on length alone" where the audit read "against the
56
+ 300-line class limit".
57
+ """
58
+ from maintainability_audit._precommit import staged_findings, staged_report
59
+ from maintainability_audit.report import build_report
60
+
61
+ fixtures = sorted(GRAMMAR.rglob("constructs.*"))
62
+ assert fixtures, f"no grammar fixtures under {GRAMMAR}; this sweep would pass vacuously"
63
+ repo = tmp_path / "repo"
64
+ repo.mkdir()
65
+ _git(repo, "init", "-q")
66
+ for fixture in fixtures:
67
+ shutil.copy(fixture, repo / fixture.name)
68
+ _git(repo, "add", ".")
69
+ config = _failing_everything()
70
+
71
+ def targets(items: list[dict[str, Any]]) -> dict[tuple[str, int], str]:
72
+ return {(item["path"], item["line"]): item["target"] for item in items
73
+ if item["finding_class"] == "oversized-declaration"}
74
+
75
+ hook = targets(staged_findings(staged_report(repo, config)))
76
+ audit = targets(build_report(repo, config, run_analyzers=False)["work_order"])
77
+ assert any("-line class limit" in target for target in audit.values()), (
78
+ "the audit produced no class targets, so the class half was never compared"
79
+ )
80
+ shared = hook.keys() & audit.keys()
81
+ assert shared, "the hook and the audit located no declaration in common"
82
+ differing = {key: (hook[key], audit[key]) for key in shared if hook[key] != audit[key]}
83
+ assert not differing, f"hook and audit word these declarations differently: {list(differing.items())[:3]}"
84
+
85
+
86
+ def _unscored_report(root: Path) -> dict[str, Any]:
87
+ from maintainability_audit.config import load_config
88
+ from maintainability_audit.report import build_report
89
+
90
+ root.mkdir()
91
+ body = "".join(f" value = {line}\n" for line in range(900))
92
+ (root / "module.py").write_text(f"def value():\n{body} return value\n", encoding="utf-8")
93
+ report = build_report(root, load_config(None), run_analyzers=False)
94
+ assert report["score"]["maintainability_estimate"] is None, "the tree was scored; the floors did not hold"
95
+ return report
96
+
97
+
98
+ @pytest.mark.usefixtures("real_population_floors")
99
+ def test_no_prompt_names_a_source_for_an_estimate_that_was_not_issued(tmp_path) -> None:
100
+ """D172: with no estimate, neither caveat branch attributes one.
101
+
102
+ `prompt_analyzer_caveat` said "the maintainability estimate above uses the
103
+ analyzer readings" beside "Maintainability estimate: Not scored". The
104
+ other branch — "comes from the built-in detectors" — made the same claim
105
+ about the same absent number.
106
+ """
107
+ from maintainability_audit.prompts import render_ai_prompt
108
+
109
+ base = _unscored_report(tmp_path / "tree")
110
+ dimensions = sorted(base["score"]["dimensions"])
111
+ assert dimensions, "the score document names no dimensions"
112
+ states = [[], *([name] for name in dimensions)]
113
+ wrong = []
114
+ for scored in states:
115
+ report = copy.deepcopy(base)
116
+ report["analyzer_measurements"] = [{"tool": "lizard"}]
117
+ report["score"]["analyzer_scored_dimensions"] = scored
118
+ prompt = render_ai_prompt(report)
119
+ if "maintainability estimate above" in prompt.lower():
120
+ wrong.append(scored)
121
+ assert not wrong, f"unscored prompts attributing an estimate, by scored dimensions: {wrong}"
122
+
123
+
124
+ def _deliverable_lines() -> list[str]:
125
+ from maintainability_audit._prompt_sections import prompt_deliverable
126
+
127
+ lines = [line for line in prompt_deliverable() if len(line.strip()) > 12]
128
+ assert lines, "prompt_deliverable produced no instruction lines"
129
+ return lines
130
+
131
+
132
+ def _task_lines(prompt: str) -> list[str]:
133
+ handed = [line for line in _deliverable_lines() if line in prompt]
134
+ if "Your task is to fix" in prompt:
135
+ handed.append("Your task is to fix")
136
+ if "Function hotspots to inspect first" in prompt:
137
+ handed.append("Function hotspots to inspect first")
138
+ return handed
139
+
140
+
141
+ def test_a_run_with_no_work_order_hands_the_prompt_no_task(tmp_path) -> None:
142
+ """D173: a warn-only run is "Nothing to do" in the chat report and the prompt alike."""
143
+ from maintainability_audit._work_order_view import NOTHING_TO_DO
144
+ from maintainability_audit.config import load_config
145
+ from maintainability_audit.prompts import render_ai_prompt
146
+ from maintainability_audit.renderers import render_markdown
147
+ from maintainability_audit.report import build_report
148
+
149
+ config = load_config(None)
150
+ thresholds = config["thresholds"]
151
+ between = (thresholds["warn_function_lines"] + thresholds["max_function_lines"]) // 2
152
+ tree = tmp_path / "warn"
153
+ tree.mkdir()
154
+ body = "".join(f" v = {line}\n" for line in range(between - 2))
155
+ (tree / "module.py").write_text(f"def warned():\n{body} return v\n", encoding="utf-8")
156
+ report = build_report(tree, config, run_analyzers=False)
157
+ assert report["function_hotspots"], "no hotspot at all; the warn band was never reached"
158
+ assert report["work_order"] == [], f"the tree produced work: {report['work_order']}"
159
+ assert NOTHING_TO_DO in render_markdown(report, complete=False)
160
+
161
+ prompt = render_ai_prompt(report)
162
+ assert NOTHING_TO_DO in prompt, "the prompt does not say what the chat report says"
163
+ assert not _task_lines(prompt), f"a 'Nothing to do' run's prompt still hands over: {_task_lines(prompt)}"
164
+
165
+
166
+ def test_a_work_order_withheld_whole_hands_the_prompt_no_task(tmp_path) -> None:
167
+ """D173's second case: every item withheld from the prompt is not a job either."""
168
+ from maintainability_audit.config import load_config
169
+ from maintainability_audit.prompts import render_ai_prompt
170
+ from maintainability_audit.report import build_report
171
+
172
+ tree = tmp_path / "tree"
173
+ tree.mkdir()
174
+ (tree / "a.py").write_text("def a():\n return 1\n", encoding="utf-8")
175
+ report = build_report(tree, load_config(None), run_analyzers=False)
176
+ report["work_order"] = [{
177
+ "finding_class": "duplicate-block", "title": "duplicated block in a.py", "path": "a.py",
178
+ "line": 1, "band": "major-project", "risk": 4, "effort": 4, "target": "t",
179
+ "rationale": "r", "verification": "v", "class_delta": 0.0, "class_count": 1,
180
+ "fingerprint": "fp", "severity": 1.0,
181
+ }]
182
+ prompt = render_ai_prompt(report)
183
+ assert "Nothing in scope for this prompt" in prompt
184
+ assert not _task_lines(prompt), f"a fully withheld work order still hands over: {_task_lines(prompt)}"
185
+
186
+
187
+ def test_a_prompt_with_work_still_hands_over_its_task(tmp_path) -> None:
188
+ """D173 must not strip the task where there is one.
189
+
190
+ Covers existing behaviour: a run with work already carried its task and
191
+ deliverable; this guards the D173 narrowing against removing them.
192
+ """
193
+ from maintainability_audit.config import load_config
194
+ from maintainability_audit.prompts import render_ai_prompt
195
+ from maintainability_audit.report import build_report
196
+
197
+ tree = tmp_path / "tree"
198
+ tree.mkdir()
199
+ body = "".join(f" v = {line}\n" for line in range(120))
200
+ (tree / "module.py").write_text(f"def huge():\n{body} return v\n", encoding="utf-8")
201
+ report = build_report(tree, load_config(None), run_analyzers=False)
202
+ assert report["work_order"], "the fixture produced no work"
203
+ prompt = render_ai_prompt(report)
204
+ assert all(line in prompt for line in _deliverable_lines())
205
+ assert "Your task is to fix" in prompt
206
+
207
+
208
+ def test_a_changed_only_run_hands_over_no_semantic_finding_outside_its_paths(tmp_path) -> None:
209
+ """D174: a semantic finding is kept exactly where its source path is in the change.
210
+
211
+ The semantic walk reads the whole tree; changed-only over two commits
212
+ handed the prompt `tests/fixtures/semantic_ts/src/operations.ts`, which
213
+ neither touched. This repository holds that one located finding, so a
214
+ population drawn from it would be the sample itself: the tree here
215
+ carries every copy of the semantic fixture at more than one location,
216
+ and a change that touches one of them.
217
+ """
218
+ from maintainability_audit._semantic import semantic_findings
219
+ from maintainability_audit._semantic_ts import discover_type_analysis
220
+ from maintainability_audit.config import load_config
221
+ from maintainability_audit.prompts import render_ai_prompt
222
+ from maintainability_audit.report import build_report
223
+
224
+ fixture = ROOT / "tests" / "fixtures" / "semantic_ts"
225
+ tree = tmp_path / "tree"
226
+ for place in ("lib/alpha", "services/beta", "tools/gamma"):
227
+ shutil.copytree(fixture, tree / place)
228
+ full = semantic_findings(tree, type_analysis=discover_type_analysis(tree))["findings"]
229
+ located = sorted({(finding.get("source_evidence") or {}).get("path") for finding in full} - {None})
230
+ assert len(located) >= 2, f"the tree located {located}; nothing to keep one of and drop the rest"
231
+ changed = located[0]
232
+ report = build_report(tree, load_config(None), only_paths={changed},
233
+ changed_revspec="HEAD~1...HEAD", run_analyzers=False)
234
+ kept = sorted({(finding.get("source_evidence") or {}).get("path")
235
+ for finding in report["semantic_findings"]})
236
+ assert kept == [changed], f"changed-only over {changed} kept semantic findings at {kept}"
237
+ prompt = render_ai_prompt(report)
238
+ named = [path for path in located[1:] if path in prompt]
239
+ assert not named, f"the changed-only prompt names files outside the change: {named}"